## Automatically generated incremental diff ## From: linux-2.5.70-bk9 ## To: linux-2.5.70-bk10 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.5.70-bk9/Documentation/networking/ip-sysctl.txt linux-2.5.70-bk10/Documentation/networking/ip-sysctl.txt --- linux-2.5.70-bk9/Documentation/networking/ip-sysctl.txt 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/Documentation/networking/ip-sysctl.txt 2003-06-05 04:41:35.000000000 -0700 @@ -31,6 +31,11 @@ ipfrag_time - INTEGER Time in seconds to keep an IP fragment in memory. +ipfrag_secret_interval - INTEGER + Regeneration interval (in seconds) of the hash secret (or lifetime + for the hash secret) for IP fragments. + Default: 600 + INET peer storage: inet_peer_threshold - INTEGER @@ -515,6 +520,25 @@ Default: FALSE (as specified in RFC2553bis) +IPv6 Fragmentation: + +ip6frag_high_thresh - INTEGER + Maximum memory used to reassemble IPv6 fragments. When + ip6frag_high_thresh bytes of memory is allocated for this purpose, + the fragment handler will toss packets until ip6frag_low_thresh + is reached. + +ip6frag_low_thresh - INTEGER + See ip6frag_high_thresh + +ip6frag_time - INTEGER + Time in seconds to keep an IPv6 fragment in memory. + +ip6frag_secret_interval - INTEGER + Regeneration interval (in seconds) of the hash secret (or lifetime + for the hash secret) for IPv6 fragments. + Default: 600 + conf/default/*: Change the interface-specific default settings. diff -urN linux-2.5.70-bk9/Documentation/vm/hugetlbpage.txt linux-2.5.70-bk10/Documentation/vm/hugetlbpage.txt --- linux-2.5.70-bk9/Documentation/vm/hugetlbpage.txt 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/Documentation/vm/hugetlbpage.txt 2003-06-05 04:41:35.000000000 -0700 @@ -67,15 +67,22 @@ call, then it is required that system administrator mount a file system of type hugetlbfs: - mount none /mnt/huge -t hugetlbfs + mount none /mnt/huge -t hugetlbfs This command mounts a (pseudo) filesystem of type hugetlbfs on the directory -/mnt/huge. Any files created on /mnt/huge uses hugepages. An example is -given at the end of this document. +/mnt/huge. Any files created on /mnt/huge uses hugepages. The uid and gid +options sets the owner and group of the root of the file system. By default +the uid and gid of the current process are taken. The mode option sets the +mode of root of file system to value & 0777. This value is given in octal. +By default the value 0755 is picked. An example is given at the end of this +document. read and write system calls are not supported on files that reside on hugetlb file systems. +A regular chown, chgrp and chmod commands (with right permissions) could be +used to change the file attributes on hugetlbfs. + Also, it is important to note that no such mount command is required if the applications are going to use only shmat/shmget system calls. It is possible for same or different applications to use any combination of mmaps and shm* diff -urN linux-2.5.70-bk9/Makefile linux-2.5.70-bk10/Makefile --- linux-2.5.70-bk9/Makefile 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/Makefile 2003-06-05 04:41:35.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 70 -EXTRAVERSION = -bk9 +EXTRAVERSION = -bk10 # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -36,13 +36,36 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ ) -ARCH := $(SUBARCH) # Remove hyphens since they have special meaning in RPM filenames KERNELPATH=kernel-$(subst -,,$(KERNELRELEASE)) +# Cross compiling and selecting different set of gcc/bin-utils +# --------------------------------------------------------------------------- +# +# When performing cross compilation for other architectures ARCH shall be set +# to the target architecture. (See arch/* for the possibilities). +# ARCH can be set during invocation of make: +# make ARCH=ia64 +# Another way is to have ARCH set in the environment. +# The default ARCH is the host where make is executed. + +# CROSS_COMPILE specify the prefix used for all executables used +# during compilation. Only gcc and related bin-utils executables +# are prefixed with $(CROSS_COMPILE). +# CROSS_COMPILE can be set on the command line +# make CROSS_COMPILE=ia64-linux- +# Alternatively CROSS_COMPILE can be set in the environment. +# Default value for CROSS_COMPILE is not to prefix executables +# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= + +# Architecture as present in compile.h UTS_MACHINE := $(ARCH) +# SHELL used by kbuild CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) @@ -53,7 +76,6 @@ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2 -CROSS_COMPILE = # That's our default target when none is given on the command line # Note that 'modules' will be added as a prerequisite as well, @@ -783,25 +805,27 @@ help: @echo 'Cleaning targets:' - @echo ' clean - remove most generated files but keep the config' - @echo ' mrproper - remove all generated files + config + various backup files' + @echo ' clean - remove most generated files but keep the config' + @echo ' mrproper - remove all generated files + config + various backup files' @echo '' @echo 'Configuration targets:' - @echo ' oldconfig - Update current config utilising a line-oriented program' - @echo ' menuconfig - Update current config utilising a menu based program' - @echo ' xconfig - Update current config utilising a X-based program' - @echo ' defconfig - New config with default answer to all options' - @echo ' allmodconfig - New config selecting modules when possible' - @echo ' allyesconfig - New config where all options are accepted with yes' - @echo ' allnoconfig - New minimal config' + @echo ' oldconfig - Update current config utilising a line-oriented program' + @echo ' menuconfig - Update current config utilising a menu based program' + @echo ' xconfig - Update current config utilising a QT based front-end' + @echo ' gconfig - Update current config utilising a GTK based front-end' + @echo ' defconfig - New config with default answer to all options' + @echo ' allmodconfig - New config selecting modules when possible' + @echo ' allyesconfig - New config where all options are accepted with yes' + @echo ' allnoconfig - New minimal config' @echo '' @echo 'Other generic targets:' - @echo ' all - Build all targets marked with [*]' - @echo '* vmlinux - Build the bare kernel' - @echo '* modules - Build all modules' - @echo ' dir/file.[ois]- Build specified target only' - @echo ' rpm - Build a kernel as an RPM package' - @echo ' tags/TAGS - Generate tags file for editors' + @echo ' all - Build all targets marked with [*]' + @echo '* vmlinux - Build the bare kernel' + @echo '* modules - Build all modules' + @echo ' modules_install - Install all modules' + @echo ' dir/file.[ois] - Build specified target only' + @echo ' rpm - Build a kernel as an RPM package' + @echo ' tags/TAGS - Generate tags file for editors' @echo '' @echo 'Documentation targets:' @$(MAKE) --no-print-directory -f Documentation/DocBook/Makefile dochelp @@ -810,6 +834,9 @@ @$(if $(archhelp),$(archhelp),\ echo ' No architecture specific help defined for $(ARCH)') @echo '' + @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' + @echo ' make C=1 [targets] Check all c source with checker tool' + @echo '' @echo 'Execute "make" or "make all" to build all targets marked with [*] ' @echo 'For further info browse Documentation/kbuild/*' diff -urN linux-2.5.70-bk9/arch/alpha/kernel/sys_sio.c linux-2.5.70-bk10/arch/alpha/kernel/sys_sio.c --- linux-2.5.70-bk9/arch/alpha/kernel/sys_sio.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/arch/alpha/kernel/sys_sio.c 2003-06-05 04:41:35.000000000 -0700 @@ -85,10 +85,10 @@ sio_collect_irq_levels(void) { unsigned int level_bits = 0; - struct pci_dev *dev; + struct pci_dev *dev = NULL; /* Iterate through the devices, collecting IRQ levels. */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) continue; diff -urN linux-2.5.70-bk9/arch/arm/common/Makefile linux-2.5.70-bk10/arch/arm/common/Makefile --- linux-2.5.70-bk9/arch/arm/common/Makefile 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/common/Makefile 2003-06-05 04:41:35.000000000 -0700 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o - +obj-y += platform.o +obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o diff -urN linux-2.5.70-bk9/arch/arm/common/platform.c linux-2.5.70-bk10/arch/arm/common/platform.c --- linux-2.5.70-bk9/arch/arm/common/platform.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/arch/arm/common/platform.c 2003-06-05 04:41:35.000000000 -0700 @@ -0,0 +1,35 @@ +#include +#include +#include + +int __init platform_add_device(struct platform_device *dev) +{ + int i; + + for (i = 0; i < dev->num_resources; i++) { + struct resource *r = &dev->resource[i]; + + r->name = dev->dev.name; + + if (r->flags & IORESOURCE_MEM && + request_resource(&iomem_resource, r)) { + printk(KERN_ERR + "%s%d: failed to claim resource %d\n", + dev->name, dev->id, i); + break; + } + } + if (i == dev->num_resources) + platform_device_register(dev); + return 0; +} + +int __init platform_add_devices(struct platform_device **devs, int num) +{ + int i; + + for (i = 0; i < num; i++) + platform_add_device(devs[i]); + + return 0; +} diff -urN linux-2.5.70-bk9/arch/arm/common/sa1111.c linux-2.5.70-bk10/arch/arm/common/sa1111.c --- linux-2.5.70-bk9/arch/arm/common/sa1111.c 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/common/sa1111.c 2003-06-05 04:41:35.000000000 -0700 @@ -42,7 +42,7 @@ */ struct sa1111 { struct device *dev; - struct resource res; + unsigned long phys; int irq; spinlock_t lock; void *base; @@ -60,7 +60,6 @@ }, .skpcr_mask = SKPCR_UCLKEN, .devid = SA1111_DEVID_USB, - .dma_mask = 0xffffffffLL, .irq = { IRQ_USBPWR, IRQ_HCIM, @@ -470,6 +469,17 @@ #ifdef CONFIG_ARCH_SA1100 +static u32 sa1111_dma_mask[] = { + ~0, + ~(1 << 20), + ~(1 << 23), + ~(1 << 24), + ~(1 << 25), + ~(1 << 20), + ~(1 << 20), + 0, +}; + /* * Configure the SA1111 shared memory controller. */ @@ -483,26 +493,43 @@ smcr |= SMCR_CLAT; sa1111_writel(smcr, sachip->base + SA1111_SMCR); + + /* + * Now clear the bits in the DMA mask to work around the SA1111 + * DMA erratum (Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update, June 2000, Erratum #7). + */ + if (sachip->dev->dma_mask) + *sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2]; } #endif static void -sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset) +sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, + struct sa1111_dev *sadev, unsigned int offset) { snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id), "%4.4x", offset); + /* + * If the parent device has a DMA mask associated with it, + * propagate it down to the children. + */ + if (sachip->dev->dma_mask) { + sadev->dma_mask = *sachip->dev->dma_mask; + sadev->dev.dma_mask = &sadev->dma_mask; + } + sadev->dev.parent = sachip->dev; sadev->dev.bus = &sa1111_bus_type; - sadev->dev.dma_mask = &sadev->dma_mask; - sadev->res.start = sachip->res.start + offset; + sadev->res.start = sachip->phys + offset; sadev->res.end = sadev->res.start + 511; sadev->res.name = sadev->dev.name; sadev->res.flags = IORESOURCE_MEM; sadev->mapbase = sachip->base + offset; - if (request_resource(&sachip->res, &sadev->res)) { + if (request_resource(parent, &sadev->res)) { printk("SA1111: failed to allocate resource for %s\n", sadev->res.name); return; @@ -524,7 +551,7 @@ * %0 successful. */ static int __init -__sa1111_probe(struct device *me, unsigned long phys_addr, int irq) +__sa1111_probe(struct device *me, struct resource *mem, int irq) { struct sa1111 *sachip; unsigned long id; @@ -542,24 +569,17 @@ sachip->dev = me; dev_set_drvdata(sachip->dev, sachip); - sachip->res.name = me->name; - sachip->res.start = phys_addr; - sachip->res.end = phys_addr + 0x2000; + sachip->phys = mem->start; sachip->irq = irq; - if (request_resource(&iomem_resource, &sachip->res)) { - ret = -EBUSY; - goto out; - } - /* * Map the whole region. This also maps the * registers for our children. */ - sachip->base = ioremap(phys_addr, PAGE_SIZE * 2); + sachip->base = ioremap(mem->start, PAGE_SIZE * 2); if (!sachip->base) { ret = -ENOMEM; - goto release; + goto out; } /* @@ -611,9 +631,11 @@ * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available. */ - int_dev.irq[0] = irq; - sa1111_init_one_child(sachip, &int_dev, SA1111_INTC); - sa1111_init_irq(&int_dev); + if (irq != NO_IRQ) { + int_dev.irq[0] = irq; + sa1111_init_one_child(sachip, mem, &int_dev, SA1111_INTC); + sa1111_init_irq(&int_dev); + } g_sa1111 = sachip; @@ -626,14 +648,12 @@ for (i = 0; i < ARRAY_SIZE(devs); i++) if (has_devs & (1 << i)) - sa1111_init_one_child(sachip, devs[i], dev_offset[i]); + sa1111_init_one_child(sachip, mem, devs[i], dev_offset[i]); return 0; unmap: iounmap(sachip->base); - release: - release_resource(&sachip->res); out: kfree(sachip); return ret; @@ -649,7 +669,6 @@ } iounmap(sachip->base); - release_resource(&sachip->res); kfree(sachip); } @@ -874,7 +893,17 @@ static int sa1111_probe(struct device *dev) { - return -ENODEV; + struct platform_device *pdev = to_platform_device(dev); + struct resource *mem = NULL, *irq = NULL; + int i; + + for (i = 0; i < pdev->num_resources; i++) { + if (pdev->resource[i].flags & IORESOURCE_MEM) + mem = &pdev->resource[i]; + if (pdev->resource[i].flags & IORESOURCE_IRQ) + irq = &pdev->resource[i]; + } + return __sa1111_probe(dev, mem, irq ? irq->start : NO_IRQ); } static int sa1111_remove(struct device *dev) @@ -903,7 +932,7 @@ */ static struct device_driver sa1111_device_driver = { .name = "sa1111", - .bus = &system_bus_type, + .bus = &platform_bus_type, .probe = sa1111_probe, .remove = sa1111_remove, .suspend = sa1111_suspend, @@ -921,29 +950,6 @@ arch_initcall(sa1111_driver_init); -static struct sys_device sa1111_device = { - .name = "SA1111", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA1111", - .driver = &sa1111_device_driver, - }, -}; - -int sa1111_init(unsigned long phys, unsigned int irq) -{ - int ret; - - snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys); - - ret = sys_device_register(&sa1111_device); - if (ret) - printk("sa1111 device_register failed: %d\n", ret); - - return __sa1111_probe(&sa1111_device.dev, phys, irq); -} - /* * Get the parent device driver (us) structure * from a child function device diff -urN linux-2.5.70-bk9/arch/arm/kernel/bios32.c linux-2.5.70-bk10/arch/arm/kernel/bios32.c --- linux-2.5.70-bk9/arch/arm/kernel/bios32.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/kernel/bios32.c 2003-06-05 04:41:35.000000000 -0700 @@ -22,9 +22,9 @@ void pcibios_report_status(u_int status_mask, int warn) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { u16 status; /* diff -urN linux-2.5.70-bk9/arch/arm/kernel/process.c linux-2.5.70-bk10/arch/arm/kernel/process.c --- linux-2.5.70-bk9/arch/arm/kernel/process.c 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/kernel/process.c 2003-06-05 04:41:35.000000000 -0700 @@ -239,7 +239,7 @@ #define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define ll_free_task_struct(p) free_pages((unsigned long)(p),1) -struct thread_info *alloc_thread_info(void) +struct thread_info *alloc_thread_info(struct task_struct *task) { struct thread_info *thread = NULL; diff -urN linux-2.5.70-bk9/arch/arm/mach-footbridge/isa-irq.c linux-2.5.70-bk10/arch/arm/mach-footbridge/isa-irq.c --- linux-2.5.70-bk9/arch/arm/mach-footbridge/isa-irq.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-footbridge/isa-irq.c 2003-06-05 04:41:35.000000000 -0700 @@ -84,10 +84,6 @@ .unmask = isa_unmask_pic_hi_irq, }; -static void no_action(int irq, void *dev_id, struct pt_regs *regs) -{ -} - static void isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { diff -urN linux-2.5.70-bk9/arch/arm/mach-integrator/Makefile linux-2.5.70-bk10/arch/arm/mach-integrator/Makefile --- linux-2.5.70-bk9/arch/arm/mach-integrator/Makefile 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-integrator/Makefile 2003-06-05 04:41:35.000000000 -0700 @@ -4,10 +4,7 @@ # Object file lists. -obj-y := arch.o irq.o mm.o time.o -obj-m := -obj-n := -obj- := +obj-y := core.o time.o obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o diff -urN linux-2.5.70-bk9/arch/arm/mach-integrator/arch.c linux-2.5.70-bk10/arch/arm/mach-integrator/arch.c --- linux-2.5.70-bk9/arch/arm/mach-integrator/arch.c 2003-05-26 18:00:44.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-integrator/arch.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,40 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/arch.c - * - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include - -#include -#include -#include -#include - -#include - -extern void integrator_map_io(void); -extern void integrator_init_irq(void); - -MACHINE_START(INTEGRATOR, "ARM-Integrator") - MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") - BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) - BOOT_PARAMS(0x00000100) - MAPIO(integrator_map_io) - INITIRQ(integrator_init_irq) -MACHINE_END diff -urN linux-2.5.70-bk9/arch/arm/mach-integrator/core.c linux-2.5.70-bk10/arch/arm/mach-integrator/core.c --- linux-2.5.70-bk9/arch/arm/mach-integrator/core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/arch/arm/mach-integrator/core.c 2003-06-05 04:41:35.000000000 -0700 @@ -0,0 +1,135 @@ +/* + * linux/arch/arm/mach-integrator/arch.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Integrator interrupt controller (for header #0, + * just for now). + */ +#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) +#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET + +/* + * Logical Physical + * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) + * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) + * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k) + * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) + * ef000000 Cache flush + * f1000000 10000000 Core module registers + * f1100000 11000000 System controller registers + * f1200000 12000000 EBI registers + * f1300000 13000000 Counter/Timer + * f1400000 14000000 Interrupt controller + * f1500000 15000000 RTC + * f1600000 16000000 UART 0 + * f1700000 17000000 UART 1 + * f1a00000 1a000000 Debug LEDs + * f1b00000 1b000000 GPIO + */ + +static struct map_desc integrator_io_desc[] __initdata = { + { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_RTC_BASE), INTEGRATOR_RTC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, + { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, + { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, + { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE }, + { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE } +}; + +static void __init integrator_map_io(void) +{ + iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc)); +} + +#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) + +static void sc_mask_irq(unsigned int irq) +{ + writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); +} + +static void sc_unmask_irq(unsigned int irq) +{ + writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); +} + +static struct irqchip sc_chip = { + .ack = sc_mask_irq, + .mask = sc_mask_irq, + .unmask = sc_unmask_irq, +}; + +static void __init integrator_init_irq(void) +{ + unsigned int i; + + /* Disable all interrupts initially. */ + /* Do the core module ones */ + writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + + /* do the header card stuff next */ + writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); + writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); + + for (i = 0; i < NR_IRQS; i++) { + if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { + set_irq_chip(i, &sc_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } +} + +MACHINE_START(INTEGRATOR, "ARM-Integrator") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) + BOOT_PARAMS(0x00000100) + MAPIO(integrator_map_io) + INITIRQ(integrator_init_irq) +MACHINE_END diff -urN linux-2.5.70-bk9/arch/arm/mach-integrator/irq.c linux-2.5.70-bk10/arch/arm/mach-integrator/irq.c --- linux-2.5.70-bk9/arch/arm/mach-integrator/irq.c 2003-05-26 18:01:02.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-integrator/irq.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,76 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/irq.c - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -#include -#include -#include - -#include - -/* - * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx - * is the (PA >> 12). - * - * Setup a VA for the Integrator interrupt controller (for header #0, - * just for now). - */ -#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) -#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET - -#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) - -static void sc_mask_irq(unsigned int irq) -{ - __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); -} - -static void sc_unmask_irq(unsigned int irq) -{ - __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); -} - -static struct irqchip sc_chip = { - .ack = sc_mask_irq, - .mask = sc_mask_irq, - .unmask = sc_unmask_irq, -}; - -void __init integrator_init_irq(void) -{ - unsigned int i; - - /* Disable all interrupts initially. */ - /* Do the core module ones */ - __raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); - - /* do the header card stuff next */ - __raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); - __raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); - - for (i = 0; i < NR_IRQS; i++) { - if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { - set_irq_chip(i, &sc_chip); - set_irq_handler(i, do_level_IRQ); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - } - } -} diff -urN linux-2.5.70-bk9/arch/arm/mach-integrator/mm.c linux-2.5.70-bk10/arch/arm/mach-integrator/mm.c --- linux-2.5.70-bk9/arch/arm/mach-integrator/mm.c 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-integrator/mm.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,70 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/mm.c - * - * Extra MM routines for the ARM Integrator board - * - * Copyright (C) 1999,2000 Arm Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -#include -#include - -#include - -/* - * Logical Physical - * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) - * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) - * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k) - * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) - * ef000000 Cache flush - * f1000000 10000000 Core module registers - * f1100000 11000000 System controller registers - * f1200000 12000000 EBI registers - * f1300000 13000000 Counter/Timer - * f1400000 14000000 Interrupt controller - * f1500000 15000000 RTC - * f1600000 16000000 UART 0 - * f1700000 17000000 UART 1 - * f1a00000 1a000000 Debug LEDs - * f1b00000 1b000000 GPIO - */ - -static struct map_desc integrator_io_desc[] __initdata = { - { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_RTC_BASE), INTEGRATOR_RTC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, - { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, - { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, - { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE }, - { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE } -}; - -void __init integrator_map_io(void) -{ - iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc)); -} diff -urN linux-2.5.70-bk9/arch/arm/mach-integrator/pci_v3.c linux-2.5.70-bk10/arch/arm/mach-integrator/pci_v3.c --- linux-2.5.70-bk9/arch/arm/mach-integrator/pci_v3.c 2003-05-26 18:00:44.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-integrator/pci_v3.c 2003-06-05 04:41:35.000000000 -0700 @@ -441,7 +441,7 @@ return 1; } -static void v3_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs) { #ifdef CONFIG_DEBUG_LL unsigned long pc = instruction_pointer(regs); @@ -469,6 +469,7 @@ printascii(buf); } #endif + return IRQ_HANDLED; } int __init pci_v3_setup(int nr, struct pci_sys_data *sys) diff -urN linux-2.5.70-bk9/arch/arm/mach-pxa/lubbock.c linux-2.5.70-bk10/arch/arm/mach-pxa/lubbock.c --- linux-2.5.70-bk9/arch/arm/mach-pxa/lubbock.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-pxa/lubbock.c 2003-06-05 04:41:35.000000000 -0700 @@ -88,9 +88,36 @@ set_irq_type(IRQ_GPIO(0), IRQT_FALLING); } +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x10000000, + .end = 0x10001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = LUBBOCK_SA1111_IRQ, + .end = LUBBOCK_SA1111_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init lubbock_init(void) { - return sa1111_init(0x10000000, LUBBOCK_SA1111_IRQ); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } subsys_initcall(lubbock_init); diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/adsbitsy.c linux-2.5.70-bk10/arch/arm/mach-sa1100/adsbitsy.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/adsbitsy.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/adsbitsy.c 2003-06-05 04:41:35.000000000 -0700 @@ -27,6 +27,36 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x18000000, + .end = 0x18001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO0, + .end = IRQ_GPIO0, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init adsbitsy_init(void) { int ret; @@ -50,7 +80,7 @@ /* * Probe for SA1111. */ - ret = sa1111_init(0x18000000, IRQ_GPIO0); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret < 0) return ret; diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/badge4.c linux-2.5.70-bk10/arch/arm/mach-sa1100/badge4.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/badge4.c 2003-05-26 18:00:23.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/badge4.c 2003-06-05 04:41:35.000000000 -0700 @@ -35,6 +35,36 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = BADGE4_SA1111_BASE, + .end = BADGE4_SA1111_BASE + 0x00001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = BADGE4_IRQ_GPIO_SA1111, + .end = BADGE4_IRQ_GPIO_SA1111, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask; + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init badge4_sa1111_init(void) { /* @@ -46,7 +76,7 @@ /* * Probe for SA1111. */ - return sa1111_init(BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/dma.c linux-2.5.70-bk10/arch/arm/mach-sa1100/dma.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/dma.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/dma.c 2003-06-05 04:41:35.000000000 -0700 @@ -42,7 +42,7 @@ static spinlock_t dma_list_lock; -static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { dma_regs_t *dma_regs = dev_id; sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7); @@ -60,6 +60,7 @@ if (status & DCSR_DONEB) dma->callback(dma->data); } + return IRQ_HANDLED; } diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/generic.c linux-2.5.70-bk10/arch/arm/mach-sa1100/generic.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/generic.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/generic.c 2003-06-05 04:41:35.000000000 -0700 @@ -16,11 +16,13 @@ #include #include #include +#include #include #include #include #include +#include #include "generic.h" @@ -128,13 +130,88 @@ PMCR = PMCR_SF; } +static struct resource sa11x0udc_resources[] = { + [0] = { + .start = 0x80000000, + .end = 0x8000ffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sa11x0udc_device = { + .name = "sa11x0-udc", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [UDC]", + }, + .num_resources = ARRAY_SIZE(sa11x0udc_resources), + .resource = sa11x0udc_resources, +}; + +static struct resource sa11x0mcp_resources[] = { + [0] = { + .start = 0x80060000, + .end = 0x8006ffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sa11x0mcp_device = { + .name = "sa11x0-mcp", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [MCP]", + }, + .num_resources = ARRAY_SIZE(sa11x0mcp_resources), + .resource = sa11x0mcp_resources, +}; + +static struct resource sa11x0fb_resources[] = { + [0] = { + .start = 0xb0100000, + .end = 0xb010ffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LCD, + .end = IRQ_LCD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sa11x0fb_device = { + .name = "sa11x0-fb", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [LCD]", + }, + .num_resources = ARRAY_SIZE(sa11x0fb_resources), + .resource = sa11x0fb_resources, +}; + +static struct platform_device sa11x0pcmcia_device = { + .name = "sa11x0-pcmcia", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [PCMCIA]", + }, +}; + +static struct platform_device *sa11x0_devices[] __initdata = { + &sa11x0udc_device, + &sa11x0mcp_device, + &sa11x0pcmcia_device, + &sa11x0fb_device, +}; + static int __init sa1100_init(void) { pm_power_off = sa1100_power_off; - return 0; + + return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices)); } -core_initcall(sa1100_init); +arch_initcall(sa1100_init); void (*sa1100fb_backlight_power)(int on); void (*sa1100fb_lcd_power)(int on); diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/graphicsmaster.c linux-2.5.70-bk10/arch/arm/mach-sa1100/graphicsmaster.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/graphicsmaster.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/graphicsmaster.c 2003-06-05 04:41:35.000000000 -0700 @@ -24,6 +24,36 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x18000000, + .end = 0x18001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ADS_EXT_IRQ(0), + .end = ADS_EXT_IRQ(0), + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init graphicsmaster_init(void) { int ret; @@ -40,7 +70,7 @@ /* * Probe for SA1111. */ - ret = sa1111_init(0x18000000, ADS_EXT_IRQ(0)); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret < 0) return ret; diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/jornada720.c linux-2.5.70-bk10/arch/arm/mach-sa1100/jornada720.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/jornada720.c 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/jornada720.c 2003-06-05 04:41:35.000000000 -0700 @@ -24,6 +24,36 @@ #define JORTUCR_VAL 0x20000400 +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO1, + .end = IRQ_GPIO1, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init jornada720_init(void) { int ret = -ENODEV; @@ -43,7 +73,7 @@ PPSR &= ~(PPC_LDD3 | PPC_LDD4); PPDR |= PPC_LDD3 | PPC_LDD4; - ret = sa1111_init(0x40000000, IRQ_GPIO1); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } return ret; } diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/neponset.c linux-2.5.70-bk10/arch/arm/mach-sa1100/neponset.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/neponset.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/neponset.c 2003-06-05 04:41:35.000000000 -0700 @@ -79,33 +79,6 @@ } } -static inline void __init neponset_init_irq(void) -{ - /* - * Install handler for GPIO25. - */ - set_irq_type(IRQ_GPIO25, IRQT_RISING); - set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); - - /* - * We would set IRQ_GPIO25 to be a wake-up IRQ, but - * unfortunately something on the Neponset activates - * this IRQ on sleep (ethernet?) - */ -#if 0 - enable_irq_wake(IRQ_GPIO25); -#endif - - /* - * Setup other Neponset IRQs. SA1111 will be done by the - * generic SA1111 code. - */ - set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); - set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); - set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); - set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); -} - static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) { u_int mdm_ctl0 = MDM_CTL_0; @@ -164,6 +137,42 @@ .get_mctrl = neponset_get_mctrl, }; +static int neponset_probe(struct device *dev) +{ + sa1100_register_uart_fns(&neponset_port_fns); + + /* + * Install handler for GPIO25. + */ + set_irq_type(IRQ_GPIO25, IRQT_RISING); + set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); + + /* + * We would set IRQ_GPIO25 to be a wake-up IRQ, but + * unfortunately something on the Neponset activates + * this IRQ on sleep (ethernet?) + */ +#if 0 + enable_irq_wake(IRQ_GPIO25); +#endif + + /* + * Setup other Neponset IRQs. SA1111 will be done by the + * generic SA1111 code. + */ + set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); + set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); + set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); + set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); + + /* + * Disable GPIO 0/1 drivers so the buttons work on the module. + */ + NCR_0 = NCR_GP01_OFF; + + return 0; +} + /* * LDM power management. */ @@ -201,27 +210,63 @@ static struct device_driver neponset_device_driver = { .name = "neponset", - .bus = &system_bus_type, + .bus = &platform_bus_type, + .probe = neponset_probe, .suspend = neponset_suspend, .resume = neponset_resume, }; -static struct sys_device neponset_device = { - .name = "NEPONSET", +static struct resource neponset_resources[] = { + [0] = { + .start = 0x10000000, + .end = 0x17ffffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device neponset_device = { + .name = "neponset", .id = 0, - .root = NULL, .dev = { .name = "Neponset", - .bus_id = "neponset", - .bus = &system_bus_type, - .driver = &neponset_device_driver, + }, + .num_resources = ARRAY_SIZE(neponset_resources), + .resource = neponset_resources, +}; + +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_NEPONSET_SA1111, + .end = IRQ_NEPONSET_SA1111, + .flags = IORESOURCE_IRQ, }, }; +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &neponset_device, + &sa1111_device, +}; + static int __init neponset_init(void) { - int ret; - driver_register(&neponset_device_driver); /* @@ -248,29 +293,7 @@ return -ENODEV; } - ret = sys_device_register(&neponset_device); - if (ret) - return ret; - - sa1100_register_uart_fns(&neponset_port_fns); - - neponset_init_irq(); - - /* - * Disable GPIO 0/1 drivers so the buttons work on the module. - */ - NCR_0 = NCR_GP01_OFF; - - /* - * Neponset has SA1111 connected to CS4. We know that after - * reset the chip will be configured for variable latency IO. - */ - /* FIXME: setup MSC2 */ - - /* - * Probe and initialise the SA1111. - */ - return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } subsys_initcall(neponset_init); diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/pfs168.c linux-2.5.70-bk10/arch/arm/mach-sa1100/pfs168.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/pfs168.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/pfs168.c 2003-06-05 04:41:35.000000000 -0700 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,35 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO25, + .end = IRQ_GPIO25, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; static int __init pfs168_init(void) { @@ -32,10 +62,7 @@ */ sa1110_mb_disable(); - /* - * Probe for SA1111. - */ - return sa1111_init(0x40000000, IRQ_GPIO25); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } arch_initcall(pfs168_init); diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/system3.c linux-2.5.70-bk10/arch/arm/mach-sa1100/system3.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/system3.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/system3.c 2003-06-05 04:41:35.000000000 -0700 @@ -373,6 +373,36 @@ } } +static struct resource sa1111_resources[] = { + [0] = { + .start = PT_SA1111_BASE, + .end = PT_SA1111_BASE + 0x00001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SYSTEM3_SA1111, + .end = IRQ_SYSTEM3_SA1111, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init system3_init(void) { int ret = 0; @@ -405,7 +435,7 @@ /* * Probe for a SA1111. */ - ret = sa1111_init(PT_SA1111_BASE, IRQ_SYSTEM3_SA1111); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret < 0) { printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" ); goto DONE; diff -urN linux-2.5.70-bk9/arch/arm/mach-sa1100/xp860.c linux-2.5.70-bk10/arch/arm/mach-sa1100/xp860.c --- linux-2.5.70-bk9/arch/arm/mach-sa1100/xp860.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mach-sa1100/xp860.c 2003-06-05 04:41:35.000000000 -0700 @@ -30,6 +30,31 @@ while(1); } +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + /* * Note: I replaced the sa1111_init() without the full SA1111 initialisation * because this machine doesn't appear to use the DMA features. If this is @@ -39,19 +64,7 @@ { pm_power_off = xp860_power_off; - /* - * Probe for SA1111. - */ - ret = sa1111_probe(0x40000000); - if (ret < 0) - return ret; - - /* - * We found it. Wake the chip up. - */ - sa1111_wake(); - - return 0; + return platform_add_devices(devices, ARRAY_SIZE(devices)); } arch_initcall(xp860_init); diff -urN linux-2.5.70-bk9/arch/arm/mm/consistent.c linux-2.5.70-bk10/arch/arm/mm/consistent.c --- linux-2.5.70-bk9/arch/arm/mm/consistent.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/arch/arm/mm/consistent.c 2003-06-05 04:41:35.000000000 -0700 @@ -10,7 +10,7 @@ * DMA uncached mapping support. */ #include -#include +#include #include #include #include @@ -145,6 +145,7 @@ struct vm_region *c; unsigned long order, flags; void *ret = NULL; + int res; if (!consistent_pte) { printk(KERN_ERR "consistent_alloc: not initialised\n"); @@ -177,14 +178,19 @@ if (!c) goto no_remap; - spin_lock_irqsave(&consistent_lock, flags); - vm_region_dump(&consistent_head, "before alloc"); - /* * Attempt to allocate a virtual address in the * consistent mapping region. */ - if (!vm_region_alloc(&consistent_head, c, size)) { + spin_lock_irqsave(&consistent_lock, flags); + vm_region_dump(&consistent_head, "before alloc"); + + res = vm_region_alloc(&consistent_head, c, size); + + vm_region_dump(&consistent_head, "after alloc"); + spin_unlock_irqrestore(&consistent_lock, flags); + + if (!res) { pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); struct page *end = page + (1 << order); pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | @@ -218,9 +224,6 @@ ret = (void *)c->vm_start; } - vm_region_dump(&consistent_head, "after alloc"); - spin_unlock_irqrestore(&consistent_lock, flags); - no_remap: if (ret == NULL) { kfree(c); @@ -231,6 +234,22 @@ } /* + * Since we have the DMA mask available to us here, we could try to do + * a normal allocation, and only fall back to a "DMA" allocation if the + * resulting bus address does not satisfy the dma_mask requirements. + */ +void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) +{ + if (dev == NULL || *dev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + + return consistent_alloc(gfp, size, handle, 0); +} + +EXPORT_SYMBOL(dma_alloc_coherent); + +/* * free a page as defined by the above mapping. */ void consistent_free(void *vaddr, size_t size, dma_addr_t handle) diff -urN linux-2.5.70-bk9/arch/i386/Kconfig linux-2.5.70-bk10/arch/i386/Kconfig --- linux-2.5.70-bk9/arch/i386/Kconfig 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/arch/i386/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -1135,7 +1135,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -urN linux-2.5.70-bk9/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c linux-2.5.70-bk10/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c --- linux-2.5.70-bk9/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c 2003-06-05 04:41:35.000000000 -0700 @@ -186,7 +186,7 @@ **/ static __init struct pci_dev *gx_detect_chipset(void) { - struct pci_dev *gx_pci; + struct pci_dev *gx_pci = NULL; /* check if CPU is a MediaGX or a Geode. */ if ((current_cpu_data.x86_vendor != X86_VENDOR_NSC) && @@ -196,7 +196,7 @@ } /* detect which companion chip is used */ - pci_for_each_dev(gx_pci) { + while ((gx_pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) { if ((pci_match_device (gx_chipset_tbl, gx_pci)) != NULL) { return gx_pci; } diff -urN linux-2.5.70-bk9/arch/i386/pci/i386.c linux-2.5.70-bk10/arch/i386/pci/i386.c --- linux-2.5.70-bk9/arch/i386/pci/i386.c 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk10/arch/i386/pci/i386.c 2003-06-05 04:41:35.000000000 -0700 @@ -121,12 +121,12 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r, *pr; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -166,11 +166,11 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ diff -urN linux-2.5.70-bk9/arch/i386/pci/irq.c linux-2.5.70-bk10/arch/i386/pci/irq.c --- linux-2.5.70-bk9/arch/i386/pci/irq.c 2003-05-26 18:01:01.000000000 -0700 +++ linux-2.5.70-bk10/arch/i386/pci/irq.c 2003-06-05 04:41:35.000000000 -0700 @@ -573,7 +573,7 @@ int irq = 0; u32 mask; struct irq_router *r = pirq_router; - struct pci_dev *dev2; + struct pci_dev *dev2 = NULL; char *msg = NULL; /* Find IRQ pin */ @@ -665,7 +665,7 @@ printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ - pci_for_each_dev(dev2) { + while ((dev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); if (!pin) continue; @@ -693,11 +693,11 @@ static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u8 pin; DBG("PCI: IRQ fixup\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * If the BIOS has set an out of range IRQ number, just ignore it. * Also keep track of which IRQ's are already in use. @@ -712,7 +712,8 @@ pirq_penalty[dev->irq]++; } - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #ifdef CONFIG_X86_IO_APIC /* diff -urN linux-2.5.70-bk9/arch/ia64/Kconfig linux-2.5.70-bk10/arch/ia64/Kconfig --- linux-2.5.70-bk9/arch/ia64/Kconfig 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk10/arch/ia64/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -563,7 +563,7 @@ agent" (/sbin/hotplug) to load modules and set up software needed to use devices as you hotplug them. -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" source "drivers/pcmcia/Kconfig" diff -urN linux-2.5.70-bk9/arch/ia64/hp/common/sba_iommu.c linux-2.5.70-bk10/arch/ia64/hp/common/sba_iommu.c --- linux-2.5.70-bk9/arch/ia64/hp/common/sba_iommu.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/arch/ia64/hp/common/sba_iommu.c 2003-06-05 04:41:35.000000000 -0700 @@ -1413,7 +1413,7 @@ u32 iova_space_mask; int iov_order, tcnfg; int agp_found = 0; - struct pci_dev *device; + struct pci_dev *device = NULL; #ifdef FULL_VALID_PDIR unsigned long index; #endif @@ -1511,7 +1511,7 @@ ** We program the next pdir index after we stop w/ a key for ** the GART code to handshake on. */ - pci_for_each_dev(device) + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP); if (agp_found && reserve_sba_gart) { diff -urN linux-2.5.70-bk9/arch/ia64/sn/io/pci_bus_cvlink.c linux-2.5.70-bk10/arch/ia64/sn/io/pci_bus_cvlink.c --- linux-2.5.70-bk9/arch/ia64/sn/io/pci_bus_cvlink.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/arch/ia64/sn/io/pci_bus_cvlink.c 2003-06-05 04:41:35.000000000 -0700 @@ -375,7 +375,7 @@ /* * Initialize the device vertex in the pci_dev struct. */ - pci_for_each_dev(device_dev) { + while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { unsigned int irq; int idx; u16 cmd; diff -urN linux-2.5.70-bk9/arch/ia64/sn/io/pciba.c linux-2.5.70-bk10/arch/ia64/sn/io/pciba.c --- linux-2.5.70-bk9/arch/ia64/sn/io/pciba.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/arch/ia64/sn/io/pciba.c 2003-06-05 04:41:35.000000000 -0700 @@ -286,7 +286,7 @@ static status __init register_with_devfs(void) { - struct pci_dev * dev; + struct pci_dev * dev = NULL; devfs_handle_t device_dir_handle; char devfs_path[40]; @@ -297,7 +297,7 @@ /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { sprintf(devfs_path, "pci/%02x/%02x.%x", dev->bus->number, PCI_SLOT(dev->devfn), @@ -325,14 +325,14 @@ static status __init register_with_devfs(void) { - struct pci_dev * dev; + struct pci_dev * dev = NULL; devfs_handle_t device_dir_handle; TRACE(); /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { device_dir_handle = devfn_to_vertex(dev->bus->number, dev->devfn); if (device_dir_handle == NULL) diff -urN linux-2.5.70-bk9/arch/ia64/sn/io/sn2/pci_bus_cvlink.c linux-2.5.70-bk10/arch/ia64/sn/io/sn2/pci_bus_cvlink.c --- linux-2.5.70-bk9/arch/ia64/sn/io/sn2/pci_bus_cvlink.c 2003-05-26 18:00:22.000000000 -0700 +++ linux-2.5.70-bk10/arch/ia64/sn/io/sn2/pci_bus_cvlink.c 2003-06-05 04:41:35.000000000 -0700 @@ -325,7 +325,7 @@ /* * Initialize the device vertex in the pci_dev struct. */ - pci_for_each_dev(device_dev) { + while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { unsigned int irq; int idx; u16 cmd; diff -urN linux-2.5.70-bk9/arch/m68knommu/Kconfig linux-2.5.70-bk10/arch/m68knommu/Kconfig --- linux-2.5.70-bk9/arch/m68knommu/Kconfig 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk10/arch/m68knommu/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -488,7 +488,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -urN linux-2.5.70-bk9/arch/mips/ddb5074/pci.c linux-2.5.70-bk10/arch/mips/ddb5074/pci.c --- linux-2.5.70-bk9/arch/mips/ddb5074/pci.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips/ddb5074/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -181,9 +181,9 @@ static void __init ddb5074_pci_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->vendor == PCI_VENDOR_ID_NEC && dev->device == PCI_DEVICE_ID_NEC_NILE4) { /* @@ -227,10 +227,10 @@ static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int slot_num; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { slot_num = PCI_SLOT(dev->devfn); switch (slot_num) { case 0: diff -urN linux-2.5.70-bk9/arch/mips/ddb5476/pci.c linux-2.5.70-bk10/arch/mips/ddb5476/pci.c --- linux-2.5.70-bk9/arch/mips/ddb5476/pci.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips/ddb5476/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -187,9 +187,9 @@ static void __init ddb5476_pci_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->vendor == PCI_VENDOR_ID_NEC && dev->device == PCI_DEVICE_ID_NEC_VRC5476) { /* @@ -256,10 +256,10 @@ static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int slot_num; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { slot_num = PCI_SLOT(dev->devfn); switch (slot_num) { case 3: /* re-programmed to USB */ diff -urN linux-2.5.70-bk9/arch/mips/ddb5xxx/ddb5477/pci.c linux-2.5.70-bk10/arch/mips/ddb5xxx/ddb5477/pci.c --- linux-2.5.70-bk9/arch/mips/ddb5xxx/ddb5477/pci.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips/ddb5xxx/ddb5477/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -98,10 +98,10 @@ extern int vrc5477_irq_to_irq(int irq); void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int slot_num; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { slot_num = PCI_SLOT(dev->devfn); MIPS_ASSERT(slot_num < MAX_SLOT_NUM); MIPS_ASSERT(irq_map[slot_num] != 0xff); diff -urN linux-2.5.70-bk9/arch/mips/mips-boards/generic/pci.c linux-2.5.70-bk10/arch/mips/mips-boards/generic/pci.c --- linux-2.5.70-bk9/arch/mips/mips-boards/generic/pci.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips/mips-boards/generic/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -154,7 +154,7 @@ void __init pcibios_init(void) { #ifdef CONFIG_MIPS_MALTA - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; unsigned char reg_val; #endif @@ -178,7 +178,7 @@ GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE)); #ifdef CONFIG_MIPS_MALTA - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) && (PCI_SLOT(pdev->devfn) == 0x0a)) { diff -urN linux-2.5.70-bk9/arch/mips/sni/pci.c linux-2.5.70-bk10/arch/mips/sni/pci.c --- linux-2.5.70-bk9/arch/mips/sni/pci.c 2003-05-26 18:01:04.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips/sni/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -31,9 +31,9 @@ /* To do: Bring this uptodate ... */ static void pcimt_pcibios_fixup (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * TODO: Take care of RM300 revision D boards for where the * network slot became an ordinary PCI slot. diff -urN linux-2.5.70-bk9/arch/mips64/mips-boards/generic/pci.c linux-2.5.70-bk10/arch/mips64/mips-boards/generic/pci.c --- linux-2.5.70-bk9/arch/mips64/mips-boards/generic/pci.c 2003-05-26 18:00:23.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips64/mips-boards/generic/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -213,7 +213,7 @@ void __init pcibios_init(void) { #ifdef CONFIG_MIPS_MALTA - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; unsigned char reg_val; #endif @@ -237,7 +237,7 @@ GT_WRITE( GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); #ifdef CONFIG_MIPS_MALTA - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) && (PCI_SLOT(pdev->devfn) == 0x0a)) { diff -urN linux-2.5.70-bk9/arch/mips64/sgi-ip32/ip32-pci.c linux-2.5.70-bk10/arch/mips64/sgi-ip32/ip32-pci.c --- linux-2.5.70-bk9/arch/mips64/sgi-ip32/ip32-pci.c 2003-05-26 18:01:02.000000000 -0700 +++ linux-2.5.70-bk10/arch/mips64/sgi-ip32/ip32-pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -125,7 +125,7 @@ void __init pcibios_init (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u32 start, size; u16 cmd; u32 base_io = 0x3000; /* The first i/o address to assign after SCSI */ @@ -157,7 +157,7 @@ pci_scan_bus (0, &macepci_ops, NULL); #ifdef DEBUG_MACE_PCI - pci_for_each_dev (dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { printk ("Device: %d/%d/%d ARCS-assigned bus resource map\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); @@ -176,7 +176,8 @@ * which we must assign, and a 1-page memory region which is * assigned by the system firmware. */ - pci_for_each_dev (dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { switch (PCI_SLOT (dev->devfn)) { case 1: /* SCSI bus 0 */ dev->resource[0].start = 0x1000UL; @@ -230,7 +231,8 @@ printk ("Triggering PCI bridge interrupt...\n"); mace_write_32 (MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST); - pci_for_each_dev (dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { printk ("Device: %d/%d/%d final bus resource map\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); diff -urN linux-2.5.70-bk9/arch/ppc/kernel/pci.c linux-2.5.70-bk10/arch/ppc/kernel/pci.c --- linux-2.5.70-bk9/arch/ppc/kernel/pci.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc/kernel/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -548,12 +548,12 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -586,11 +586,11 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ @@ -881,7 +881,7 @@ { unsigned int *reg; struct pci_controller* hose; - struct pci_dev* dev; + struct pci_dev* dev = NULL; if (!have_of) return -ENODEV; @@ -905,7 +905,7 @@ */ if (!pci_to_OF_bus_map) return 0; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_to_OF_bus_map[dev->bus->number] != *bus) continue; if (dev->devfn != *devfn) diff -urN linux-2.5.70-bk9/arch/ppc/platforms/chrp_pci.c linux-2.5.70-bk10/arch/ppc/platforms/chrp_pci.c --- linux-2.5.70-bk9/arch/ppc/platforms/chrp_pci.c 2003-05-26 18:01:02.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc/platforms/chrp_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -154,11 +154,11 @@ void __init chrp_pcibios_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct device_node *np; /* PCI interrupts are controlled by the OpenPIC */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { np = pci_device_to_OF_node(dev); if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) dev->irq = np->intrs[0].line; diff -urN linux-2.5.70-bk9/arch/ppc/platforms/gemini_pci.c linux-2.5.70-bk10/arch/ppc/platforms/gemini_pci.c --- linux-2.5.70-bk9/arch/ppc/platforms/gemini_pci.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc/platforms/gemini_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -13,9 +13,9 @@ void __init gemini_pcibios_fixup(void) { int i; - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for(i = 0; i < 6; i++) { if (dev->resource[i].flags & IORESOURCE_IO) { dev->resource[i].start |= (0xfe << 24); diff -urN linux-2.5.70-bk9/arch/ppc/platforms/pmac_pci.c linux-2.5.70-bk10/arch/ppc/platforms/pmac_pci.c --- linux-2.5.70-bk9/arch/ppc/platforms/pmac_pci.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc/platforms/pmac_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -494,7 +494,7 @@ static void __init pcibios_fixup_OF_interrupts(void) { - struct pci_dev* dev; + struct pci_dev* dev = NULL; /* * Open Firmware often doesn't initialize the @@ -502,7 +502,7 @@ * should find the device node and apply the interrupt * obtained from the OF device-tree */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { struct device_node *node; node = pci_device_to_OF_node(dev); /* this is the node, see if it has interrupts */ @@ -590,7 +590,7 @@ struct device_node* nd; #ifdef CONFIG_BLK_DEV_IDE - struct pci_dev *dev; + struct pci_dev *dev = NULL; /* OF fails to initialize IDE controllers on macs * (and maybe other machines) @@ -602,7 +602,7 @@ * * -- BenH */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) pci_enable_device(dev); } diff -urN linux-2.5.70-bk9/arch/ppc/platforms/prep_pci.c linux-2.5.70-bk10/arch/ppc/platforms/prep_pci.c --- linux-2.5.70-bk9/arch/ppc/platforms/prep_pci.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc/platforms/prep_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -1171,7 +1171,7 @@ void __init prep_pcibios_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; extern unsigned char *Motherboard_map; extern unsigned char *Motherboard_routes; @@ -1180,7 +1180,7 @@ printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); if (OpenPIC_Addr) { /* PCI interrupts are controlled by the OpenPIC */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->bus->number == 0) { dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); @@ -1196,7 +1196,8 @@ return; } - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * Use our old hard-coded kludge to figure out what * irq this device uses. This is necessary on things diff -urN linux-2.5.70-bk9/arch/ppc64/Kconfig linux-2.5.70-bk10/arch/ppc64/Kconfig --- linux-2.5.70-bk9/arch/ppc64/Kconfig 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc64/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -241,7 +241,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" config PROC_DEVICETREE bool "Support for Open Firmware device tree in /proc" diff -urN linux-2.5.70-bk9/arch/ppc64/kernel/iSeries_pci.c linux-2.5.70-bk10/arch/ppc64/kernel/iSeries_pci.c --- linux-2.5.70-bk9/arch/ppc64/kernel/iSeries_pci.c 2003-05-26 18:01:00.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc64/kernel/iSeries_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -304,7 +304,7 @@ ***********************************************************************/ void __init pcibios_final_fixup(void) { - struct pci_dev* PciDev; + struct pci_dev* PciDev = NULL; struct iSeries_Device_Node* DeviceNode; char Buffer[256]; int DeviceCount = 0; @@ -315,7 +315,7 @@ /******************************************************/ mf_displaySrc(0xC9000100); - pci_for_each_dev(PciDev) { + while ((PciDev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, PciDev)) != NULL) { DeviceNode = find_Device_Node(PciDev); if(DeviceNode != NULL) { ++DeviceCount; diff -urN linux-2.5.70-bk9/arch/ppc64/kernel/pSeries_pci.c linux-2.5.70-bk10/arch/ppc64/kernel/pSeries_pci.c --- linux-2.5.70-bk9/arch/ppc64/kernel/pSeries_pci.c 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc64/kernel/pSeries_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -533,11 +533,11 @@ void __init pcibios_final_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; check_s7a(); - pci_for_each_dev(dev) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) pci_read_irq_line(dev); chrp_request_regions(); diff -urN linux-2.5.70-bk9/arch/ppc64/kernel/pci.c linux-2.5.70-bk10/arch/ppc64/kernel/pci.c --- linux-2.5.70-bk9/arch/ppc64/kernel/pci.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc64/kernel/pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -117,13 +117,13 @@ */ struct pci_dev *pci_find_dev_by_addr(unsigned long addr) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int i; unsigned long ioaddr; ioaddr = (addr > isa_io_base) ? addr - isa_io_base : 0; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) continue; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { diff -urN linux-2.5.70-bk9/arch/ppc64/kernel/pci_dma.c linux-2.5.70-bk10/arch/ppc64/kernel/pci_dma.c --- linux-2.5.70-bk9/arch/ppc64/kernel/pci_dma.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/arch/ppc64/kernel/pci_dma.c 2003-06-05 04:41:35.000000000 -0700 @@ -724,7 +724,7 @@ } void create_tce_tables(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct device_node *dn, *mydn; if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { @@ -737,7 +737,7 @@ * pci device_node. This means get_tce_table() won't need to search * up the device tree to find it. */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { mydn = dn = PCI_GET_DN(dev); while (dn && dn->tce_table == NULL) dn = dn->parent; diff -urN linux-2.5.70-bk9/arch/sh/kernel/pci-sh7751.c linux-2.5.70-bk10/arch/sh/kernel/pci-sh7751.c --- linux-2.5.70-bk9/arch/sh/kernel/pci-sh7751.c 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk10/arch/sh/kernel/pci-sh7751.c 2003-06-05 04:41:35.000000000 -0700 @@ -386,13 +386,13 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r, *pr; PCIDBG(2,"PCI: pcibios_allocate_resources pass %d called\n", pass); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -432,12 +432,12 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *devn = NULL; int idx; struct resource *r; PCIDBG(2,"PCI: pcibios_assign_resources called\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ diff -urN linux-2.5.70-bk9/arch/um/drivers/net_kern.c linux-2.5.70-bk10/arch/um/drivers/net_kern.c --- linux-2.5.70-bk9/arch/um/drivers/net_kern.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/arch/um/drivers/net_kern.c 2003-06-05 04:41:35.000000000 -0700 @@ -304,7 +304,7 @@ } memset(device, 0, sizeof(*device)); - device->list = INIT_LIST_HEAD(device->list); + INIT_LIST_HEAD(&device->list); device->index = n; spin_lock(&devices_lock); @@ -362,7 +362,7 @@ return 1; lp = dev->priv; - lp->list = INIT_LIST_HEAD(lp->list); + INIT_LIST_HEAD(&lp->list); spin_lock_init(&lp->lock); lp->dev = dev; lp->fd = -1; @@ -537,7 +537,7 @@ return(1); } - new->list = INIT_LIST_HEAD(new->list); + INIT_LIST_HEAD(&new->list); new->index = n; new->init = str; diff -urN linux-2.5.70-bk9/arch/v850/Kconfig linux-2.5.70-bk10/arch/v850/Kconfig --- linux-2.5.70-bk9/arch/v850/Kconfig 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/v850/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -230,7 +230,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -urN linux-2.5.70-bk9/arch/v850/kernel/rte_mb_a_pci.c linux-2.5.70-bk10/arch/v850/kernel/rte_mb_a_pci.c --- linux-2.5.70-bk9/arch/v850/kernel/rte_mb_a_pci.c 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk10/arch/v850/kernel/rte_mb_a_pci.c 2003-06-05 04:41:35.000000000 -0700 @@ -251,10 +251,10 @@ /* Resource allocation. */ static void __devinit pcibios_assign_resources (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct resource *r; - pci_for_each_dev (dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { unsigned di_num; unsigned class = dev->class >> 8; diff -urN linux-2.5.70-bk9/arch/x86_64/Kconfig linux-2.5.70-bk10/arch/x86_64/Kconfig --- linux-2.5.70-bk9/arch/x86_64/Kconfig 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/arch/x86_64/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -351,7 +351,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -urN linux-2.5.70-bk9/arch/x86_64/kernel/bluesmoke.c linux-2.5.70-bk10/arch/x86_64/kernel/bluesmoke.c --- linux-2.5.70-bk9/arch/x86_64/kernel/bluesmoke.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/arch/x86_64/kernel/bluesmoke.c 2003-06-05 04:41:35.000000000 -0700 @@ -125,9 +125,9 @@ static struct pci_dev *find_k8_nb(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int cpu = smp_processor_id(); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 && PCI_SLOT(dev->devfn) == (24U+cpu)) return dev; diff -urN linux-2.5.70-bk9/arch/x86_64/kernel/pci-gart.c linux-2.5.70-bk10/arch/x86_64/kernel/pci-gart.c --- linux-2.5.70-bk9/arch/x86_64/kernel/pci-gart.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/arch/x86_64/kernel/pci-gart.c 2003-06-05 04:41:35.000000000 -0700 @@ -67,7 +67,8 @@ #define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) #define for_all_nb(dev) \ - pci_for_each_dev(dev) \ + dev=NULL; \ + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) \ if (dev->bus->number == 0 && PCI_FUNC(dev->devfn) == 3 && \ (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31)) diff -urN linux-2.5.70-bk9/arch/x86_64/pci/irq.c linux-2.5.70-bk10/arch/x86_64/pci/irq.c --- linux-2.5.70-bk9/arch/x86_64/pci/irq.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/arch/x86_64/pci/irq.c 2003-06-05 04:41:35.000000000 -0700 @@ -391,7 +391,7 @@ int irq = 0; u32 mask; struct irq_router *r = pirq_router; - struct pci_dev *dev2; + struct pci_dev *dev2 = NULL; char *msg = NULL; /* Find IRQ pin */ @@ -483,7 +483,7 @@ printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ - pci_for_each_dev(dev2) { + while ((dev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); if (!pin) continue; @@ -511,11 +511,11 @@ void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u8 pin; DBG("PCI: IRQ fixup\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * If the BIOS has set an out of range IRQ number, just ignore it. * Also keep track of which IRQ's are already in use. @@ -530,7 +530,8 @@ pirq_penalty[dev->irq]++; } - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #ifdef CONFIG_X86_IO_APIC /* diff -urN linux-2.5.70-bk9/arch/x86_64/pci/x86-64.c linux-2.5.70-bk10/arch/x86_64/pci/x86-64.c --- linux-2.5.70-bk9/arch/x86_64/pci/x86-64.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk10/arch/x86_64/pci/x86-64.c 2003-06-05 04:41:35.000000000 -0700 @@ -121,12 +121,12 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r, *pr; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -166,11 +166,11 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ diff -urN linux-2.5.70-bk9/crypto/Kconfig linux-2.5.70-bk10/crypto/Kconfig --- linux-2.5.70-bk9/crypto/Kconfig 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/crypto/Kconfig 2003-06-05 04:41:35.000000000 -0700 @@ -6,16 +6,12 @@ config CRYPTO bool "Cryptographic API" - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m || INET6_IPCOMP=y || INET6_IPCOMP=m || IPV6_PRIVACY=y help This option provides the core Cryptographic API. config CRYPTO_HMAC bool "HMAC support" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m help HMAC: Keyed-Hashing for Message Authentication (RFC2104). This is required for IPSec. @@ -35,16 +31,12 @@ config CRYPTO_MD5 tristate "MD5 digest algorithm" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m || IPV6_PRIVACY=y help MD5 message digest algorithm (RFC1321). config CRYPTO_SHA1 tristate "SHA1 digest algorithm" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). @@ -72,7 +64,6 @@ config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" depends on CRYPTO - default y if INET_ESP=y || INET_ESP=m || INET6_ESP=y || INET6_ESP=m help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). @@ -138,7 +129,6 @@ config CRYPTO_DEFLATE tristate "Deflate compression algorithm" depends on CRYPTO - default y if INET_IPCOMP=y || INET_IPCOMP=m || INET6_IPCOMP=y || INET6_IPCOMP=m help This is the Deflate algorithm (RFC1951), specified for use in IPSec with the IPCOMP protocol (RFC3173, RFC2394). diff -urN linux-2.5.70-bk9/drivers/Makefile linux-2.5.70-bk10/drivers/Makefile --- linux-2.5.70-bk9/drivers/Makefile 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/drivers/Makefile 2003-06-05 04:41:35.000000000 -0700 @@ -46,7 +46,6 @@ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ -obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ obj-$(CONFIG_ISDN_BOOL) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ diff -urN linux-2.5.70-bk9/drivers/acpi/pci_irq.c linux-2.5.70-bk10/drivers/acpi/pci_irq.c --- linux-2.5.70-bk9/drivers/acpi/pci_irq.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/drivers/acpi/pci_irq.c 2003-06-05 04:41:35.000000000 -0700 @@ -402,7 +402,7 @@ iosapic_parse_prt(); #endif - pci_for_each_dev(dev) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) acpi_pci_irq_enable(dev); return_VALUE(0); diff -urN linux-2.5.70-bk9/drivers/atm/he.c linux-2.5.70-bk10/drivers/atm/he.c --- linux-2.5.70-bk9/drivers/atm/he.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/drivers/atm/he.c 2003-06-05 04:41:36.000000000 -0700 @@ -77,14 +77,6 @@ #include #include #include -#ifndef ATM_OC12_PCR -#define ATM_OC12_PCR (622080000/1080*1040/8/53) -#endif - -#ifdef BUS_INT_WAR -void sn_add_polled_interrupt(int irq, int interval); -void sn_delete_polled_interrupt(int irq); -#endif #define USE_TASKLET #define USE_HE_FIND_VCC @@ -171,22 +163,17 @@ static struct atmdev_ops he_ops = { - open: he_open, - close: he_close, - ioctl: he_ioctl, - send: he_send, - sg_send: he_sg_send, - phy_put: he_phy_put, - phy_get: he_phy_get, - proc_read: he_proc_read, - owner: THIS_MODULE + .open = he_open, + .close = he_close, + .ioctl = he_ioctl, + .send = he_send, + .sg_send = he_sg_send, + .phy_put = he_phy_put, + .phy_get = he_phy_get, + .proc_read = he_proc_read, + .owner = THIS_MODULE }; -/* see the comments in he.h about global_lock */ - -#define HE_SPIN_LOCK(dev, flags) spin_lock_irqsave(&(dev)->global_lock, flags) -#define HE_SPIN_UNLOCK(dev, flags) spin_unlock_irqrestore(&(dev)->global_lock, flags) - #define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while (0) #define he_readl(dev, reg) readl((dev)->membase + (reg)) @@ -233,26 +220,26 @@ /* figure 2.2 connection id */ -#define he_mkcid(dev, vpi, vci) (((vpi<<(dev)->vcibits) | vci) & 0x1fff) +#define he_mkcid(dev, vpi, vci) (((vpi << (dev)->vcibits) | vci) & 0x1fff) /* 2.5.1 per connection transmit state registers */ #define he_writel_tsr0(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 0) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 0) #define he_readl_tsr0(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 0) + he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 0) #define he_writel_tsr1(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 1) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 1) #define he_writel_tsr2(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 2) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 2) #define he_writel_tsr3(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 3) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 3) #define he_writel_tsr4(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 4) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 4) /* from page 2-20 * @@ -263,43 +250,43 @@ */ #define he_writel_tsr4_upper(dev, val, cid) \ - he_writel_internal(dev, val, CONFIG_TSRA | (cid<<3) | 4, \ + he_writel_internal(dev, val, CONFIG_TSRA | (cid << 3) | 4, \ CON_CTL_TCM \ | CON_BYTE_DISABLE_2 \ | CON_BYTE_DISABLE_1 \ | CON_BYTE_DISABLE_0) #define he_readl_tsr4(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 4) + he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 4) #define he_writel_tsr5(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 5) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 5) #define he_writel_tsr6(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 6) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 6) #define he_writel_tsr7(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 7) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 7) #define he_writel_tsr8(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 0) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 0) #define he_writel_tsr9(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 1) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 1) #define he_writel_tsr10(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 2) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 2) #define he_writel_tsr11(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 3) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 3) #define he_writel_tsr12(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 0) + he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 0) #define he_writel_tsr13(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 1) + he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 1) #define he_writel_tsr14(dev, val, cid) \ @@ -315,30 +302,30 @@ /* 2.7.1 per connection receive state registers */ #define he_writel_rsr0(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 0) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 0) #define he_readl_rsr0(dev, cid) \ - he_readl_rcm(dev, 0x00000 | (cid<<3) | 0) + he_readl_rcm(dev, 0x00000 | (cid << 3) | 0) #define he_writel_rsr1(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 1) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 1) #define he_writel_rsr2(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 2) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 2) #define he_writel_rsr3(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 3) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 3) #define he_writel_rsr4(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 4) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 4) #define he_writel_rsr5(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 5) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 5) #define he_writel_rsr6(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 6) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 6) #define he_writel_rsr7(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 7) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7) static __inline__ struct atm_vcc* he_find_vcc(struct he_dev *he_dev, unsigned cid) @@ -349,7 +336,7 @@ int vci; vpi = cid >> he_dev->vcibits; - vci = cid & ((1<vcibits)-1); + vci = cid & ((1 << he_dev->vcibits) - 1); spin_lock_irqsave(&he_dev->atm_dev->lock, flags); for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next) @@ -443,112 +430,112 @@ static unsigned rate_to_atmf(unsigned rate) /* cps to atm forum format */ { -#define NONZERO (1<<14) +#define NONZERO (1 << 14) - unsigned exp = 0; + unsigned exp = 0; - if (rate == 0) - return(0); + if (rate == 0) + return 0; - rate <<= 9; - while (rate > 0x3ff) { - ++exp; - rate >>= 1; - } + rate <<= 9; + while (rate > 0x3ff) { + ++exp; + rate >>= 1; + } - return (NONZERO | (exp << 9) | (rate & 0x1ff)); + return (NONZERO | (exp << 9) | (rate & 0x1ff)); } static void __init he_init_rx_lbfp0(struct he_dev *he_dev) { - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; - + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; + lbufd_index = 0; - lbm_offset = he_readl(he_dev, RCMLBM_BA); + lbm_offset = he_readl(he_dev, RCMLBM_BA); he_writel(he_dev, lbufd_index, RLBF0_H); - for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) { + for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) { lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; he_writel_rcm(he_dev, lbuf_addr, lbm_offset); he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } + if (++lbuf_count == lbufs_per_row) { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF0_T); + } + + he_writel(he_dev, lbufd_index - 2, RLBF0_T); he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); } static void __init he_init_rx_lbfp1(struct he_dev *he_dev) { - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; - + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; + lbufd_index = 1; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); + lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); he_writel(he_dev, lbufd_index, RLBF1_H); - for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) { + for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) { lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; he_writel_rcm(he_dev, lbuf_addr, lbm_offset); he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } + if (++lbuf_count == lbufs_per_row) { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF1_T); + } + + he_writel(he_dev, lbufd_index - 2, RLBF1_T); he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); } static void __init he_init_tx_lbfp(struct he_dev *he_dev) { - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; - + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; + lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); + lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); he_writel(he_dev, lbufd_index, TLBF_H); - for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) { + for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) { lbufd_index += 1; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; he_writel_rcm(he_dev, lbuf_addr, lbm_offset); he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } + if (++lbuf_count == lbufs_per_row) { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } lbm_offset += 2; - } - - he_writel(he_dev, lbufd_index - 1, TLBF_T); + } + + he_writel(he_dev, lbufd_index - 1, TLBF_T); } static int __init @@ -678,7 +665,7 @@ unsigned rate_atmf, exp, man; unsigned long long rate_cps; - int mult, buf, buf_limit = 4; + int mult, buf, buf_limit = 4; rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL); if (!rategrid) @@ -757,30 +744,31 @@ */ #ifdef notdef - buf = rate_cps * he_dev->tx_numbuffs / + buf = rate_cps * he_dev->tx_numbuffs / (he_dev->atm_dev->link_rate * 2); #else /* this is pretty, but avoids _divdu3 and is mostly correct */ - buf = 0; - mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; - if (rate_cps > (68 * mult)) - buf = 1; - if (rate_cps > (136 * mult)) - buf = 2; - if (rate_cps > (204 * mult)) - buf = 3; - if (rate_cps > (272 * mult)) + mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; + if (rate_cps > (272 * mult)) buf = 4; + else if (rate_cps > (204 * mult)) + buf = 3; + else if (rate_cps > (136 * mult)) + buf = 2; + else if (rate_cps > (68 * mult)) + buf = 1; + else + buf = 0; #endif - if (buf > buf_limit) + if (buf > buf_limit) buf = buf_limit; - reg = (reg<<16) | ((i<<8) | buf); + reg = (reg << 16) | ((i << 8) | buf); #define RTGTBL_OFFSET 0x400 if (rate_atmf & 0x1) he_writel_rcm(he_dev, reg, - CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf>>1)); + CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf >> 1)); ++rate_atmf; } @@ -839,7 +827,7 @@ he_dev->rbps_base[i].phys = dma_handle; } - he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE-1]; + he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE - 1]; he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32)); he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), @@ -848,7 +836,7 @@ G0_RBPS_BS + (group * 32)); he_writel(he_dev, RBP_THRESH(CONFIG_RBPS_THRESH) | - RBP_QSIZE(CONFIG_RBPS_SIZE-1) | + RBP_QSIZE(CONFIG_RBPS_SIZE - 1) | RBP_INT_ENB, G0_RBPS_QI + (group * 32)); #else /* !USE_RBPS */ @@ -902,7 +890,7 @@ he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); he_dev->rbpl_base[i].phys = dma_handle; } - he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE-1]; + he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1]; he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), @@ -911,7 +899,7 @@ G0_RBPL_BS + (group * 32)); he_writel(he_dev, RBP_THRESH(CONFIG_RBPL_THRESH) | - RBP_QSIZE(CONFIG_RBPL_SIZE-1) | + RBP_QSIZE(CONFIG_RBPL_SIZE - 1) | RBP_INT_ENB, G0_RBPL_QI + (group * 32)); @@ -929,7 +917,7 @@ he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16)); he_writel(he_dev, 0, G0_RBRQ_H + (group * 16)); he_writel(he_dev, - RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE-1), + RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE - 1), G0_RBRQ_Q + (group * 16)); if (irq_coalesce) { hprintk("coalescing interrupts\n"); @@ -967,7 +955,7 @@ /* 2.9.3.5 tail offset for each interrupt queue is located after the end of the interrupt queue */ - he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, + he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys); if (he_dev->irq_base == NULL) { hprintk("failed to allocate irq\n"); @@ -979,7 +967,7 @@ he_dev->irq_head = he_dev->irq_base; he_dev->irq_tail = he_dev->irq_base; - for (i=0; i < CONFIG_IRQ_SIZE; ++i) + for (i = 0; i < CONFIG_IRQ_SIZE; ++i) he_dev->irq_base[i].isw = ITYPE_INVALID; he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE); @@ -1014,23 +1002,18 @@ if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev)) { hprintk("irq %d already in use\n", he_dev->pci_dev->irq); return -EINVAL; - } + } he_dev->irq = he_dev->pci_dev->irq; -#ifdef BUS_INT_WAR - HPRINTK("sn_add_polled_interrupt(irq %d, 1)\n", he_dev->irq); - sn_add_polled_interrupt(he_dev->irq, 1); -#endif - return 0; } static int __init he_start(struct atm_dev *dev) { - struct he_dev *he_dev; - struct pci_dev *pci_dev; + struct he_dev *he_dev; + struct pci_dev *pci_dev; u16 command; u32 gen_cntl_0, host_cntl, lb_swap; @@ -1040,8 +1023,8 @@ unsigned int status, reg; int i, group; - he_dev = HE_DEV(dev); - pci_dev = he_dev->pci_dev; + he_dev = HE_DEV(dev); + pci_dev = he_dev->pci_dev; he_dev->membase = pci_dev->resource[0].start; HPRINTK("membase = 0x%lx irq = %d.\n", he_dev->membase, pci_dev->irq); @@ -1108,7 +1091,7 @@ hprintk("can't set up page mapping\n"); return -EINVAL; } - + /* 4.4 card reset */ he_writel(he_dev, 0x0, RESET_CNTL); he_writel(he_dev, 0xff, RESET_CNTL); @@ -1138,12 +1121,12 @@ pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); /* 4.7 read prom contents */ - for (i=0; iprod_id[i] = read_prom_byte(he_dev, PROD_ID + i); he_dev->media = read_prom_byte(he_dev, MEDIA); - for (i=0; i<6; ++i) + for (i = 0; i < 6; ++i) dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i); hprintk("%s%s, %x:%x:%x:%x:%x:%x\n", @@ -1323,15 +1306,15 @@ he_writel(he_dev, 0x0, TXAAL5_PROTO); he_writel(he_dev, PHY_INT_ENB | - (he_is622(he_dev) ? PTMR_PRE(67-1) : PTMR_PRE(50-1)), + (he_is622(he_dev) ? PTMR_PRE(67 - 1) : PTMR_PRE(50 - 1)), RH_CONFIG); /* 5.1.3 initialize connection memory */ - for (i=0; i < TCM_MEM_SIZE; ++i) + for (i = 0; i < TCM_MEM_SIZE; ++i) he_writel_tcm(he_dev, 0, i); - for (i=0; i < RCM_MEM_SIZE; ++i) + for (i = 0; i < RCM_MEM_SIZE; ++i) he_writel_rcm(he_dev, 0, i); /* @@ -1512,7 +1495,7 @@ } he_dev->tpd_head = he_dev->tpd_base; - he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS-1]; + he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS - 1]; #endif if (he_init_group(he_dev, 0) != 0) @@ -1608,8 +1591,8 @@ he_dev->irq_peak = 0; he_dev->rbrq_peak = 0; - he_dev->rbpl_peak = 0; - he_dev->tbrq_peak = 0; + he_dev->rbpl_peak = 0; + he_dev->tbrq_peak = 0; HPRINTK("hell bent for leather!\n"); @@ -1652,12 +1635,8 @@ he_dev->atm_dev->phy->stop(he_dev->atm_dev); #endif /* CONFIG_ATM_HE_USE_SUNI */ - if (he_dev->irq) { -#ifdef BUS_INT_WAR - sn_delete_polled_interrupt(he_dev->irq); -#endif + if (he_dev->irq) free_irq(he_dev->irq, he_dev); - } if (he_dev->irq_base) pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) @@ -1669,7 +1648,7 @@ if (he_dev->rbpl_base) { #ifdef USE_RBPL_POOL - for (i=0; irbpl_virt[i].virt; dma_addr_t dma_handle = he_dev->rbpl_base[i].phys; @@ -1691,7 +1670,7 @@ #ifdef USE_RBPS if (he_dev->rbps_base) { #ifdef USE_RBPS_POOL - for (i=0; irbps_virt[i].virt; dma_addr_t dma_handle = he_dev->rbps_base[i].phys; @@ -1790,7 +1769,7 @@ } #define AAL5_LEN(buf,len) \ - ((((unsigned char *)(buf))[(len)-6]<<8) | \ + ((((unsigned char *)(buf))[(len)-6] << 8) | \ (((unsigned char *)(buf))[(len)-5])) /* 2.10.1.2 receive @@ -1800,7 +1779,7 @@ */ #define TCP_CKSUM(buf,len) \ - ((((unsigned char *)(buf))[(len)-2]<<8) | \ + ((((unsigned char *)(buf))[(len)-2] << 8) | \ (((unsigned char *)(buf))[(len-1)])) static int @@ -2123,7 +2102,7 @@ if (moved) { he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); #ifdef CONFIG_IA64_SGI_SN2 - (void) he_readl(he_dev, G0_RBPL_T); + (void) he_readl(he_dev, G0_RBPL_T); #endif } } @@ -2155,7 +2134,7 @@ if (moved) { he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T); #ifdef CONFIG_IA64_SGI_SN2 - (void) he_readl(he_dev, G0_RBPS_T); + (void) he_readl(he_dev, G0_RBPS_T); #endif } } @@ -2171,7 +2150,7 @@ HPRINTK("tasklet (0x%lx)\n", data); #ifdef USE_TASKLET - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); #endif while (he_dev->irq_head != he_dev->irq_tail) { @@ -2209,10 +2188,10 @@ case ITYPE_PHY: HPRINTK("phy interrupt\n"); #ifdef CONFIG_ATM_HE_USE_SUNI - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt) he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); #endif break; case ITYPE_OTHER: @@ -2257,7 +2236,7 @@ (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ } #ifdef USE_TASKLET - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); #endif } @@ -2271,7 +2250,7 @@ if (he_dev == NULL) return IRQ_NONE; - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) | (*he_dev->irq_tailoffset << 2)); @@ -2301,7 +2280,7 @@ (void) he_readl(he_dev, INT_FIFO); #endif } - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); return IRQ_RETVAL(handled); } @@ -2416,11 +2395,11 @@ if (vcc->qos.txtp.traffic_class != ATM_NONE) { int pcr_goal; - pcr_goal = atm_pcr_goal(&vcc->qos.txtp); - if (pcr_goal == 0) - pcr_goal = he_dev->atm_dev->link_rate; - if (pcr_goal < 0) /* means round down, technically */ - pcr_goal = -pcr_goal; + pcr_goal = atm_pcr_goal(&vcc->qos.txtp); + if (pcr_goal == 0) + pcr_goal = he_dev->atm_dev->link_rate; + if (pcr_goal < 0) /* means round down, technically */ + pcr_goal = -pcr_goal; HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal); @@ -2438,9 +2417,9 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); tsr0 = he_readl_tsr0(he_dev, cid); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); if (TSR0_CONN_STATE(tsr0) != 0) { hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0); @@ -2467,7 +2446,7 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); /* also protects he_dev->cs_stper[] */ + spin_lock_irqsave(&he_dev->global_lock, flags); /* also protects he_dev->cs_stper[] */ /* find an unused cs_stper register */ for (reg = 0; reg < HE_NUM_CS_STPER; ++reg) @@ -2477,7 +2456,7 @@ if (reg == HE_NUM_CS_STPER) { err = -EBUSY; - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); goto open_failed; } @@ -2495,7 +2474,7 @@ he_writel_mbox(he_dev, rate_to_atmf(period/2), CS_STPER0 + reg); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal | TSR0_RC_INDEX(reg); @@ -2506,7 +2485,7 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); he_writel_tsr0(he_dev, tsr0, cid); he_writel_tsr4(he_dev, tsr4 | 1, cid); @@ -2528,7 +2507,7 @@ #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl_tsr0(he_dev, cid); #endif - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); } if (vcc->qos.rxtp.traffic_class != ATM_NONE) { @@ -2549,11 +2528,11 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); rsr0 = he_readl_rsr0(he_dev, cid); if (rsr0 & RSR0_OPEN_CONN) { - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0); err = -EBUSY; @@ -2578,14 +2557,14 @@ he_writel_rsr4(he_dev, rsr4, cid); he_writel_rsr1(he_dev, rsr1, cid); /* 5.1.11 last parameter initialized should be - the open/closed indication in rsr0 */ + the open/closed indication in rsr0 */ he_writel_rsr0(he_dev, rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid); #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl_rsr0(he_dev, cid); #endif - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); #ifndef USE_HE_FIND_VCC HE_LOOKUP_VCC(he_dev, cid) = vcc; @@ -2631,7 +2610,7 @@ /* wait for previous close (if any) to finish */ - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); while (he_readl(he_dev, RCC_STAT) & RCC_BUSY) { HPRINTK("close cid 0x%x RCC_BUSY\n", cid); udelay(250); @@ -2645,7 +2624,7 @@ (void) he_readl_rsr0(he_dev, cid); #endif he_writel_mbox(he_dev, cid, RXCON_CLOSE); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); timeout = schedule_timeout(30*HZ); @@ -2693,7 +2672,7 @@ /* 2.3.1.1 generic close operations with flush */ - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid); /* also clears TSR4_SESSION_ENDED */ #ifdef CONFIG_IA64_SGI_SN2 @@ -2724,7 +2703,7 @@ add_wait_queue(&he_vcc->tx_waitq, &wait); set_current_state(TASK_UNINTERRUPTIBLE); __enqueue_tpd(he_dev, tpd, cid); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); timeout = schedule_timeout(30*HZ); @@ -2736,7 +2715,7 @@ goto close_tx_incomplete; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); udelay(250); @@ -2761,7 +2740,7 @@ he_dev->total_bw -= he_dev->cs_stper[reg].pcr; } - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); HPRINTK("close tx cid 0x%x complete\n", cid); } @@ -2818,7 +2797,7 @@ return -EINVAL; } #endif - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); tpd = __alloc_tpd(he_dev); if (tpd == NULL) { @@ -2827,7 +2806,7 @@ else dev_kfree_skb_any(skb); atomic_inc(&vcc->stats->tx_err); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); return -ENOMEM; } @@ -2869,7 +2848,7 @@ else dev_kfree_skb_any(skb); atomic_inc(&vcc->stats->tx_err); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); return -ENOMEM; } tpd->status |= TPD_USERCELL; @@ -2884,7 +2863,7 @@ } - tpd->iovec[slot-1].len |= TPD_LST; + tpd->iovec[slot - 1].len |= TPD_LST; #else tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); tpd->length0 = skb->len | TPD_LST; @@ -2897,7 +2876,7 @@ ATM_SKB(skb)->vcc = vcc; __enqueue_tpd(he_dev, tpd, cid); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); atomic_inc(&vcc->stats->tx); @@ -2919,7 +2898,7 @@ copy_from_user(®, (struct he_ioctl_reg *) arg, sizeof(struct he_ioctl_reg)); - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); switch (reg.type) { case HE_REGTYPE_PCI: reg.val = he_readl(he_dev, reg.addr); @@ -2940,7 +2919,7 @@ err = -EINVAL; break; } - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); if (err == 0) copy_to_user((struct he_ioctl_reg *) arg, ®, sizeof(struct he_ioctl_reg)); @@ -2966,15 +2945,15 @@ HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr); - HE_SPIN_LOCK(he_dev, flags); - he_writel(he_dev, val, FRAMER + (addr*4)); + spin_lock_irqsave(&he_dev->global_lock, flags); + he_writel(he_dev, val, FRAMER + (addr*4)); #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl(he_dev, FRAMER + (addr*4)); #endif - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); } - + static unsigned char he_phy_get(struct atm_dev *atm_dev, unsigned long addr) { @@ -2982,9 +2961,9 @@ struct he_dev *he_dev = HE_DEV(atm_dev); unsigned reg; - HE_SPIN_LOCK(he_dev, flags); - reg = he_readl(he_dev, FRAMER + (addr*4)); - HE_SPIN_UNLOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); + reg = he_readl(he_dev, FRAMER + (addr*4)); + spin_unlock_irqrestore(&he_dev->global_lock, flags); HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg); return reg; @@ -2999,7 +2978,7 @@ #ifdef notdef struct he_rbrq *rbrq_tail; struct he_tpdrq *tpdrq_head; - int rbpl_head, rbpl_tail; + int rbpl_head, rbpl_tail; #endif static long mcc = 0, oec = 0, dcc = 0, cec = 0; @@ -3015,12 +2994,12 @@ if (!left--) return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n"); - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); mcc += he_readl(he_dev, MCC); oec += he_readl(he_dev, OEC); dcc += he_readl(he_dev, DCC); cec += he_readl(he_dev, CEC); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); if (!left--) return sprintf(page, "%16ld %16ld %13ld %17ld\n\n", @@ -3044,8 +3023,8 @@ #ifdef notdef - rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); - rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); + rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); + rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); inuse = rbpl_head - rbpl_tail; if (inuse < 0) @@ -3090,32 +3069,31 @@ he_writel(he_dev, val, HOST_CNTL); /* Send READ instruction */ - for (i=0; i=0; i--) { + /* Next, we need to send the byte address to read from */ + for (i = 7; i >= 0; i--) { he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); udelay(EEPROM_DELAY); he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); udelay(EEPROM_DELAY); } - j=0; + j = 0; val &= 0xFFFFF7FF; /* Turn off write enable */ he_writel(he_dev, val, HOST_CNTL); /* Now, we can read data from the EEPROM by clocking it in */ - for (i=7; i>=0; i--) { + for (i = 7; i >= 0; i--) { he_writel(he_dev, val | clocktab[j++], HOST_CNTL); - udelay(EEPROM_DELAY); - tmp_read = he_readl(he_dev, HOST_CNTL); - byte_read |= (unsigned char) - ((tmp_read & ID_DOUT) - >> ID_DOFFSET << i); + udelay(EEPROM_DELAY); + tmp_read = he_readl(he_dev, HOST_CNTL); + byte_read |= (unsigned char) + ((tmp_read & ID_DOUT) >> ID_DOFFSET << i); he_writel(he_dev, val | clocktab[j++], HOST_CNTL); udelay(EEPROM_DELAY); } @@ -3123,7 +3101,7 @@ he_writel(he_dev, val | ID_CS, HOST_CNTL); udelay(EEPROM_DELAY); - return (byte_read); + return byte_read; } MODULE_LICENSE("GPL"); @@ -3145,7 +3123,7 @@ static struct pci_device_id he_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { 0, } }; static struct pci_driver he_driver = { @@ -3157,12 +3135,12 @@ static int __init he_init(void) { - return pci_module_init(&he_driver); + return pci_module_init(&he_driver); } static void __exit he_cleanup(void) { - pci_unregister_driver(&he_driver); + pci_unregister_driver(&he_driver); } module_init(he_init); diff -urN linux-2.5.70-bk9/drivers/block/deadline-iosched.c linux-2.5.70-bk10/drivers/block/deadline-iosched.c --- linux-2.5.70-bk9/drivers/block/deadline-iosched.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/drivers/block/deadline-iosched.c 2003-06-05 04:41:36.000000000 -0700 @@ -121,6 +121,15 @@ __deadline_del_drq_hash(drq); } +static void +deadline_remove_merge_hints(request_queue_t *q, struct deadline_rq *drq) +{ + deadline_del_drq_hash(drq); + + if (q->last_merge == &drq->request->queuelist) + q->last_merge = NULL; +} + static inline void deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) { @@ -310,7 +319,7 @@ struct deadline_data *dd = q->elevator.elevator_data; list_del_init(&drq->fifo); - deadline_del_drq_hash(drq); + deadline_remove_merge_hints(q, drq); deadline_del_drq_rb(dd, drq); } } diff -urN linux-2.5.70-bk9/drivers/char/agp/amd-k8-agp.c linux-2.5.70-bk10/drivers/char/agp/amd-k8-agp.c --- linux-2.5.70-bk9/drivers/char/agp/amd-k8-agp.c 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/agp/amd-k8-agp.c 2003-06-05 04:41:36.000000000 -0700 @@ -244,7 +244,7 @@ const struct pci_device_id *ent) { struct agp_bridge_data *bridge; - struct pci_dev *loop_dev; + struct pci_dev *loop_dev = NULL; u8 rev_id; u8 cap_ptr; int i = 0; @@ -297,7 +297,7 @@ pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); /* cache pci_devs of northbridges. */ - pci_for_each_dev(loop_dev) { + while ((loop_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, loop_dev)) != NULL) { if (loop_dev->bus->number == 0 && PCI_FUNC(loop_dev->devfn) == 3 && PCI_SLOT(loop_dev->devfn) >=24 && diff -urN linux-2.5.70-bk9/drivers/char/agp/generic.c linux-2.5.70-bk10/drivers/char/agp/generic.c --- linux-2.5.70-bk9/drivers/char/agp/generic.c 2003-05-26 18:00:37.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/agp/generic.c 2003-06-05 04:41:36.000000000 -0700 @@ -462,12 +462,12 @@ //We need a function we pass an agp_device to. u32 agp_collect_device_status(u32 mode, u32 cmd) { - struct pci_dev *device; + struct pci_dev *device = NULL; u8 cap_ptr; u32 tmp; u32 agp3; - pci_for_each_dev(device) { + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (!cap_ptr) continue; @@ -502,14 +502,14 @@ void agp_device_command(u32 command, int agp_v3) { - struct pci_dev *device; + struct pci_dev *device = NULL; int mode; mode = command & 0x7; if (agp_v3) mode *= 4; - pci_for_each_dev(device) { + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); if (!agp) continue; diff -urN linux-2.5.70-bk9/drivers/char/agp/isoch.c linux-2.5.70-bk10/drivers/char/agp/isoch.c --- linux-2.5.70-bk9/drivers/char/agp/isoch.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/agp/isoch.c 2003-06-05 04:41:36.000000000 -0700 @@ -316,7 +316,7 @@ */ int agp_3_5_enable(struct agp_bridge_data *bridge) { - struct pci_dev *td = bridge->dev, *dev; + struct pci_dev *td = bridge->dev, *dev = NULL; u8 mcapndx; u32 isoch, arqsz; u32 tstatus, mstatus, ncapid; @@ -347,7 +347,7 @@ INIT_LIST_HEAD(head); /* Find all AGP devices, and add them to dev_list. */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); if (mcapndx == 0) continue; diff -urN linux-2.5.70-bk9/drivers/char/hw_random.c linux-2.5.70-bk10/drivers/char/hw_random.c --- linux-2.5.70-bk9/drivers/char/hw_random.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/hw_random.c 2003-06-05 04:41:36.000000000 -0700 @@ -573,13 +573,13 @@ static int __init rng_init (void) { int rc; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; const struct pci_device_id *ent; DPRINTK ("ENTER\n"); /* Probe for Intel, AMD RNGs */ - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { ent = pci_match_device (rng_pci_tbl, pdev); if (ent) { rng_ops = &rng_vendor_ops[ent->driver_data]; diff -urN linux-2.5.70-bk9/drivers/char/n_hdlc.c linux-2.5.70-bk10/drivers/char/n_hdlc.c --- linux-2.5.70-bk9/drivers/char/n_hdlc.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/n_hdlc.c 2003-06-05 04:41:36.000000000 -0700 @@ -6,7 +6,8 @@ * Microgate and SyncLink are registered trademarks of Microgate Corporation * * Adapted from ppp.c, written by Michael Callahan , - * Al Longyear , Paul Mackerras + * Al Longyear , + * Paul Mackerras * * Original release 01/11/99 * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $ @@ -96,32 +97,19 @@ #include #include +#include #include #include #include #include /* used in new tty drivers */ #include /* used in new tty drivers */ +#include + #include #include #include -#include - -#include - -#ifdef CONFIG_KERNELD -#include -#endif - -#define GET_USER(error,value,addr) error = get_user(value,addr) -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -#define PUT_USER(error,value,addr) error = put_user(value,addr) -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - #include -typedef ssize_t rw_ret_t; -typedef size_t rw_count_t; - /* * Buffers for individual HDLC frames */ @@ -130,91 +118,90 @@ #define MAX_RX_BUF_COUNT 60 #define DEFAULT_TX_BUF_COUNT 1 +struct n_hdlc_buf { + struct n_hdlc_buf *link; + int count; + char buf[1]; +}; -typedef struct _n_hdlc_buf -{ - struct _n_hdlc_buf *link; - int count; - char buf[1]; -} N_HDLC_BUF; - -#define N_HDLC_BUF_SIZE (sizeof(N_HDLC_BUF)+maxframe) +#define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe) -typedef struct _n_hdlc_buf_list -{ - N_HDLC_BUF *head; - N_HDLC_BUF *tail; - int count; - spinlock_t spinlock; - -} N_HDLC_BUF_LIST; +struct n_hdlc_buf_list { + struct n_hdlc_buf *head; + struct n_hdlc_buf *tail; + int count; + spinlock_t spinlock; +}; -/* - * Per device instance data structure +/** + * struct n_hdlc - per device instance data structure + * @magic - magic value for structure + * @flags - miscellaneous control flags + * @tty - ptr to TTY structure + * @backup_tty - TTY to use if tty gets closed + * @tbusy - reentrancy flag for tx wakeup code + * @woke_up - FIXME: describe this field + * @tbuf - currently transmitting tx buffer + * @tx_buf_list - list of pending transmit frame buffers + * @rx_buf_list - list of received frame buffers + * @tx_free_buf_list - list unused transmit frame buffers + * @rx_free_buf_list - list unused received frame buffers */ struct n_hdlc { - int magic; /* magic value for structure */ - __u32 flags; /* miscellaneous control flags */ - - struct tty_struct *tty; /* ptr to TTY structure */ - struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ - - int tbusy; /* reentrancy flag for tx wakeup code */ - int woke_up; - N_HDLC_BUF *tbuf; /* currently transmitting tx buffer */ - N_HDLC_BUF_LIST tx_buf_list; /* list of pending transmit frame buffers */ - N_HDLC_BUF_LIST rx_buf_list; /* list of received frame buffers */ - N_HDLC_BUF_LIST tx_free_buf_list; /* list unused transmit frame buffers */ - N_HDLC_BUF_LIST rx_free_buf_list; /* list unused received frame buffers */ + int magic; + __u32 flags; + struct tty_struct *tty; + struct tty_struct *backup_tty; + int tbusy; + int woke_up; + struct n_hdlc_buf *tbuf; + struct n_hdlc_buf_list tx_buf_list; + struct n_hdlc_buf_list rx_buf_list; + struct n_hdlc_buf_list tx_free_buf_list; + struct n_hdlc_buf_list rx_free_buf_list; }; /* * HDLC buffer list manipulation functions */ -static void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list); -static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf); -static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list); +static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list); +static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, + struct n_hdlc_buf *buf); +static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); /* Local functions */ static struct n_hdlc *n_hdlc_alloc (void); -MODULE_PARM(debuglevel, "i"); -MODULE_PARM(maxframe, "i"); - - /* debug level can be set by insmod for debugging purposes */ #define DEBUG_LEVEL_INFO 1 static int debuglevel; /* max frame size for memory allocations */ -static ssize_t maxframe=4096; +static ssize_t maxframe = 4096; /* TTY callbacks */ -static rw_ret_t n_hdlc_tty_read(struct tty_struct *, - struct file *, __u8 *, rw_count_t); -static rw_ret_t n_hdlc_tty_write(struct tty_struct *, - struct file *, const __u8 *, rw_count_t); -static int n_hdlc_tty_ioctl(struct tty_struct *, - struct file *, unsigned int, unsigned long); -static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp, - poll_table * wait); -static int n_hdlc_tty_open (struct tty_struct *); -static void n_hdlc_tty_close (struct tty_struct *); -static int n_hdlc_tty_room (struct tty_struct *tty); -static void n_hdlc_tty_receive (struct tty_struct *tty, - const __u8 * cp, char *fp, int count); -static void n_hdlc_tty_wakeup (struct tty_struct *tty); +static int n_hdlc_tty_read(struct tty_struct *tty, struct file *file, + __u8 *buf, size_t nr); +static int n_hdlc_tty_write(struct tty_struct *tty, struct file *file, + const __u8 *buf, size_t nr); +static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, + poll_table *wait); +static int n_hdlc_tty_open(struct tty_struct *tty); +static void n_hdlc_tty_close(struct tty_struct *tty); +static int n_hdlc_tty_room(struct tty_struct *tty); +static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, + char *fp, int count); +static void n_hdlc_tty_wakeup(struct tty_struct *tty); #define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) #define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data)) #define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) -/* Define this string only once for all macro invocations */ -static char szVersion[] = HDLC_VERSION; - static struct tty_ldisc n_hdlc_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, @@ -230,15 +217,14 @@ .write_wakeup = n_hdlc_tty_wakeup, }; -/* n_hdlc_release() - * - * release an n_hdlc per device line discipline info structure - * +/** + * n_hdlc_release - release an n_hdlc per device line discipline info structure + * @n_hdlc - per device line discipline info structure */ -static void n_hdlc_release (struct n_hdlc *n_hdlc) +static void n_hdlc_release(struct n_hdlc *n_hdlc) { struct tty_struct *tty = n_hdlc2tty (n_hdlc); - N_HDLC_BUF *buf; + struct n_hdlc_buf *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); @@ -285,10 +271,12 @@ } /* end of n_hdlc_release() */ -/* n_hdlc_tty_close() +/** + * n_hdlc_tty_close - line discipline close + * @tty - pointer to tty info structure * - * Called when the line discipline is changed to something - * else, the tty is closed, or the tty detects a hangup. + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. */ static void n_hdlc_tty_close(struct tty_struct *tty) { @@ -322,12 +310,11 @@ } /* end of n_hdlc_tty_close() */ -/* n_hdlc_tty_open - * - * called when line discipline changed to n_hdlc - * - * Arguments: tty pointer to tty info structure - * Return Value: 0 if success, otherwise error code +/** + * n_hdlc_tty_open - called when line discipline changed to n_hdlc + * @tty - pointer to tty info structure + * + * Returns 0 if success, otherwise error code */ static int n_hdlc_tty_open (struct tty_struct *tty) { @@ -373,22 +360,20 @@ } /* end of n_tty_hdlc_open() */ -/* n_hdlc_send_frames() - * - * send frames on pending send buffer list until the - * driver does not accept a frame (busy) - * this function is called after adding a frame to the - * send buffer list and by the tty wakeup callback - * - * Arguments: n_hdlc pointer to ldisc instance data - * tty pointer to tty instance data - * Return Value: None +/** + * n_hdlc_send_frames - send frames on pending send buffer list + * @n_hdlc - pointer to ldisc instance data + * @tty - pointer to tty instance data + * + * Send frames on pending send buffer list until the driver does not accept a + * frame (busy) this function is called after adding a frame to the send buffer + * list and by the tty wakeup callback. */ -static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty) +static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) { register int actual; unsigned long flags; - N_HDLC_BUF *tbuf; + struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); @@ -431,7 +416,7 @@ __FILE__,__LINE__,tbuf); /* free current transmit buffer */ - n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); + n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); /* this tx buffer is done */ n_hdlc->tbuf = NULL; @@ -469,17 +454,15 @@ } /* end of n_hdlc_send_frames() */ -/* n_hdlc_tty_wakeup() +/** + * n_hdlc_tty_wakeup - Callback for transmit wakeup + * @tty - pointer to associated tty instance data * - * Callback for transmit wakeup. Called when low level - * device driver can accept more send data. - * - * Arguments: tty pointer to associated tty instance data - * Return Value: None + * Called when low level device driver can accept more send data. */ -static void n_hdlc_tty_wakeup (struct tty_struct *tty) +static void n_hdlc_tty_wakeup(struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty2n_hdlc(tty); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__); @@ -496,16 +479,14 @@ } /* end of n_hdlc_tty_wakeup() */ -/* n_hdlc_tty_room() - * - * Callback function from tty driver. Return the amount of - * space left in the receiver's buffer to decide if remote - * transmitter is to be throttled. +/** + * n_hdlc_tty_room - Return the amount of space left in the receiver's buffer + * @tty - pointer to associated tty instance data * - * Arguments: tty pointer to associated tty instance data - * Return Value: number of bytes left in receive buffer + * Callback function from tty driver. Return the amount of space left in the + * receiver's buffer to decide if remote transmitter is to be throttled. */ -static int n_hdlc_tty_room (struct tty_struct *tty) +static int n_hdlc_tty_room(struct tty_struct *tty) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__); @@ -514,23 +495,21 @@ return 65536; } /* end of n_hdlc_tty_root() */ -/* n_hdlc_tty_receive() - * - * Called by tty low level driver when receive data is - * available. Data is interpreted as one HDLC frame. - * - * Arguments: tty pointer to tty isntance data - * data pointer to received data - * flags pointer to flags for data - * count count of received data in bytes - * - * Return Value: None +/** + * n_hdlc_tty_receive - Called by tty driver when receive data is available + * @tty - pointer to tty instance data + * @data - pointer to received data + * @flags - pointer to flags for data + * @count - count of received data in bytes + * + * Called by tty low level driver when receive data is available. Data is + * interpreted as one HDLC frame. */ -static void n_hdlc_tty_receive(struct tty_struct *tty, - const __u8 * data, char *flags, int count) +static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, + char *flags, int count) { register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); - register N_HDLC_BUF *buf; + register struct n_hdlc_buf *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", @@ -560,7 +539,7 @@ /* no buffers in free list, attempt to allocate another rx buffer */ /* unless the maximum count has been reached */ if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) - buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC); + buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC); } if (!buf) { @@ -575,7 +554,7 @@ buf->count=count; /* add HDLC buffer to list of received frames */ - n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); + n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf); /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&tty->read_wait); @@ -584,28 +563,22 @@ } /* end of n_hdlc_tty_receive() */ -/* n_hdlc_tty_read() - * - * Called to retreive one frame of data (if available) - * - * Arguments: - * - * tty pointer to tty instance data - * file pointer to open file object - * buf pointer to returned data buffer - * nr size of returned data buffer +/** + * n_hdlc_tty_read - Called to retreive one frame of data (if available) + * @tty - pointer to tty instance data + * @file - pointer to open file object + * @buf - pointer to returned data buffer + * @nr - size of returned data buffer * - * Return Value: - * - * Number of bytes returned or error code + * Returns the number of bytes returned or error code. */ -static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty, - struct file *file, __u8 * buf, rw_count_t nr) +static int n_hdlc_tty_read(struct tty_struct *tty, struct file *file, + __u8 *buf, size_t nr) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int error; - rw_ret_t ret; - N_HDLC_BUF *rbuf; + int ret; + struct n_hdlc_buf *rbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); @@ -644,16 +617,15 @@ return -EINTR; } - if (rbuf->count > nr) { + if (rbuf->count > nr) /* frame too large for caller's buffer (discard frame) */ - ret = (rw_ret_t)-EOVERFLOW; - } else { + ret = -EOVERFLOW; + else { /* Copy the data to the caller's buffer */ - COPY_TO_USER(error,buf,rbuf->buf,rbuf->count); - if (error) - ret = (rw_ret_t)error; + if (copy_to_user(buf, rbuf->buf, rbuf->count)) + ret = -EFAULT; else - ret = (rw_ret_t)rbuf->count; + ret = rbuf->count; } /* return HDLC buffer to free list unless the free list */ @@ -668,24 +640,22 @@ } /* end of n_hdlc_tty_read() */ -/* n_hdlc_tty_write() - * - * write a single frame of data to device - * - * Arguments: tty pointer to associated tty device instance data - * file pointer to file object data - * data pointer to transmit data (one frame) - * count size of transmit frame in bytes +/** + * n_hdlc_tty_write - write a single frame of data to device + * @tty - pointer to associated tty device instance data + * @file - pointer to file object data + * @data - pointer to transmit data (one frame) + * @count - size of transmit frame in bytes * - * Return Value: number of bytes written (or error code) + * Returns the number of bytes written (or error code). */ -static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file, - const __u8 * data, rw_count_t count) +static int n_hdlc_tty_write(struct tty_struct *tty, struct file *file, + const __u8 *data, size_t count) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; DECLARE_WAITQUEUE(wait, current); - N_HDLC_BUF *tbuf; + struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_write() called count=%d\n", @@ -735,10 +705,10 @@ if (!error) { /* Retrieve the user's buffer */ - COPY_FROM_USER (error, tbuf->buf, data, count); - if (error) { + if (copy_from_user(tbuf->buf, data, count)) { /* return tx buffer to free list */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); + error = -EFAULT; } else { /* Send the data */ tbuf->count = error = count; @@ -751,21 +721,17 @@ } /* end of n_hdlc_tty_write() */ -/* n_hdlc_tty_ioctl() - * - * Process IOCTL system call for the tty device. +/** + * n_hdlc_tty_ioctl - process IOCTL system call for the tty device. + * @tty - pointer to tty instance data + * @file - pointer to open file object for device + * @cmd - IOCTL command code + * @arg - argument for IOCTL call (cmd dependent) * - * Arguments: - * - * tty pointer to tty instance data - * file pointer to open file object for device - * cmd IOCTL command code - * arg argument for IOCTL call (cmd dependent) - * - * Return Value: Command dependent + * Returns command dependent result. */ -static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; @@ -790,7 +756,7 @@ else count = 0; spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); - PUT_USER (error, count, (int *) arg); + error = put_user(count, (int *)arg); break; case TIOCOUTQ: @@ -802,7 +768,7 @@ if (n_hdlc->tx_buf_list.head) count += n_hdlc->tx_buf_list.head->count; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags); - PUT_USER (error, count, (int*)arg); + error = put_user(count, (int*)arg); break; default: @@ -813,24 +779,18 @@ } /* end of n_hdlc_tty_ioctl() */ -/* n_hdlc_tty_poll() - * - * TTY callback for poll system call. Determine which - * operations (read/write) will not block and return - * info to caller. - * - * Arguments: - * - * tty pointer to tty instance data - * filp pointer to open file object for device - * poll_table wait queue for operations - * - * Return Value: - * - * bit mask containing info on which ops will not block +/** + * n_hdlc_tty_poll - TTY callback for poll system call + * @tty - pointer to tty instance data + * @filp - pointer to open file object for device + * @poll_table - wait queue for operations + * + * Determine which operations (read/write) will not block and return info + * to caller. + * Returns a bit mask containing info on which ops will not block. */ -static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, - struct file *filp, poll_table * wait) +static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, + poll_table *wait) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); unsigned int mask = 0; @@ -858,20 +818,17 @@ return mask; } /* end of n_hdlc_tty_poll() */ -/* n_hdlc_alloc() - * - * Allocate an n_hdlc instance data structure +/** + * n_hdlc_alloc - allocate an n_hdlc instance data structure * - * Arguments: None - * Return Value: pointer to structure if success, otherwise 0 + * Returns a pointer to newly created structure if success, otherwise %NULL */ -static struct n_hdlc *n_hdlc_alloc (void) +static struct n_hdlc *n_hdlc_alloc(void) { - struct n_hdlc *n_hdlc; - N_HDLC_BUF *buf; - int i; - - n_hdlc = (struct n_hdlc *)kmalloc(sizeof(struct n_hdlc), GFP_KERNEL); + struct n_hdlc_buf *buf; + int i; + struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL); + if (!n_hdlc) return 0; @@ -884,7 +841,7 @@ /* allocate free rx buffer list */ for(i=0;irx_free_buf_list,buf); else if (debuglevel >= DEBUG_LEVEL_INFO) @@ -893,7 +850,7 @@ /* allocate free tx buffer list */ for(i=0;itx_free_buf_list,buf); else if (debuglevel >= DEBUG_LEVEL_INFO) @@ -908,31 +865,23 @@ } /* end of n_hdlc_alloc() */ -/* n_hdlc_buf_list_init() - * - * initialize specified HDLC buffer list - * - * Arguments: list pointer to buffer list - * Return Value: None +/** + * n_hdlc_buf_list_init - initialize specified HDLC buffer list + * @list - pointer to buffer list */ -static void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list) +static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list) { - memset(list,0,sizeof(N_HDLC_BUF_LIST)); + memset(list, 0, sizeof(*list)); spin_lock_init(&list->spinlock); } /* end of n_hdlc_buf_list_init() */ -/* n_hdlc_buf_put() - * - * add specified HDLC buffer to tail of specified list - * - * Arguments: - * - * list pointer to buffer list - * buf pointer to buffer - * - * Return Value: None +/** + * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list + * @list - pointer to buffer list + * @buf - pointer to buffer */ -static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf) +static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, + struct n_hdlc_buf *buf) { unsigned long flags; spin_lock_irqsave(&list->spinlock,flags); @@ -949,23 +898,18 @@ } /* end of n_hdlc_buf_put() */ -/* n_hdlc_buf_get() - * - * remove and return an HDLC buffer from the - * head of the specified HDLC buffer list - * - * Arguments: - * - * list pointer to HDLC buffer list - * - * Return Value: - * - * pointer to HDLC buffer if available, otherwise NULL +/** + * n_hdlc_buf_get - remove and return an HDLC buffer from list + * @list - pointer to HDLC buffer list + * + * Remove and return an HDLC buffer from the head of the specified HDLC buffer + * list. + * Returns a pointer to HDLC buffer if available, otherwise %NULL. */ -static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list) +static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list) { unsigned long flags; - N_HDLC_BUF *buf; + struct n_hdlc_buf *buf; spin_lock_irqsave(&list->spinlock,flags); buf = list->head; @@ -981,42 +925,60 @@ } /* end of n_hdlc_buf_get() */ +static char hdlc_banner[] __initdata = + KERN_INFO "HDLC line discipline: version " HDLC_VERSION + ", maxframe=%u\n"; +static char hdlc_register_ok[] __initdata = + KERN_INFO "N_HDLC line discipline registered.\n"; +static char hdlc_register_fail[] __initdata = + KERN_ERR "error registering line discipline: %d\n"; +static char hdlc_init_fail[] __initdata = + KERN_INFO "N_HDLC: init failure %d\n"; + static int __init n_hdlc_init(void) { - int status; + int status; /* range check maxframe arg */ - if ( maxframe<4096) - maxframe=4096; - else if ( maxframe>65535) - maxframe=65535; + if (maxframe < 4096) + maxframe = 4096; + else if (maxframe > 65535) + maxframe = 65535; - printk("HDLC line discipline: version %s, maxframe=%u\n", - szVersion, maxframe); + printk(hdlc_banner, maxframe); status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); if (!status) - printk (KERN_INFO"N_HDLC line discipline registered.\n"); + printk(hdlc_register_ok); else - printk (KERN_ERR"error registering line discipline: %d\n",status); + printk(hdlc_register_fail, status); if (status) - printk(KERN_INFO"N_HDLC: init failure %d\n", status); - return (status); + printk(hdlc_init_fail, status); + return status; } /* end of init_module() */ +static char hdlc_unregister_ok[] __exitdata = + KERN_INFO "N_HDLC: line discipline unregistered\n"; +static char hdlc_unregister_fail[] __exitdata = + KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n"; + static void __exit n_hdlc_exit(void) { - int status; /* Release tty registration of line discipline */ - if ((status = tty_register_ldisc(N_HDLC, NULL))) - printk("N_HDLC: can't unregister line discipline (err = %d)\n", status); + int status = tty_register_ldisc(N_HDLC, NULL); + + if (status) + printk(hdlc_unregister_fail, status); else - printk("N_HDLC: line discipline unregistered\n"); + printk(hdlc_unregister_ok); } module_init(n_hdlc_init); module_exit(n_hdlc_exit); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com"); +MODULE_PARM(debuglevel, "i"); +MODULE_PARM(maxframe, "i"); diff -urN linux-2.5.70-bk9/drivers/char/watchdog/amd7xx_tco.c linux-2.5.70-bk10/drivers/char/watchdog/amd7xx_tco.c --- linux-2.5.70-bk9/drivers/char/watchdog/amd7xx_tco.c 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/watchdog/amd7xx_tco.c 2003-06-05 04:41:36.000000000 -0700 @@ -309,7 +309,8 @@ sema_init(&open_sem, 1); spin_lock_init(&amdtco_lock); - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_match_device (amdtco_pci_tbl, dev) != NULL) goto found_one; } diff -urN linux-2.5.70-bk9/drivers/char/watchdog/i810-tco.c linux-2.5.70-bk10/drivers/char/watchdog/i810-tco.c --- linux-2.5.70-bk9/drivers/char/watchdog/i810-tco.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk10/drivers/char/watchdog/i810-tco.c 2003-06-05 04:41:36.000000000 -0700 @@ -315,14 +315,14 @@ static unsigned char __init i810tco_getdevice (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u8 val1, val2; u16 badr; /* * Find the PCI device */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_match_device(i810tco_pci_tbl, dev)) { i810tco_pci = dev; break; diff -urN linux-2.5.70-bk9/drivers/hotplug/Kconfig linux-2.5.70-bk10/drivers/hotplug/Kconfig --- linux-2.5.70-bk9/drivers/hotplug/Kconfig 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/Kconfig 1969-12-31 16:00:00.000000000 -0800 @@ -1,120 +0,0 @@ -# -# PCI Hotplug support -# - -menu "PCI Hotplug Support" - depends on HOTPLUG - -config HOTPLUG_PCI - tristate "Support for PCI Hotplug (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL - ---help--- - Say Y here if you have a motherboard with a PCI Hotplug controller. - This allows you to add and remove PCI cards while the machine is - powered up and running. The file system pcihpfs must be mounted - in order to interact with any PCI Hotplug controllers. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called pci_hotplug. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -config HOTPLUG_PCI_COMPAQ - tristate "Compaq PCI Hotplug driver" - depends on HOTPLUG_PCI && X86 - help - Say Y here if you have a motherboard with a Compaq PCI Hotplug - controller. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpqphp. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -config HOTPLUG_PCI_COMPAQ_NVRAM - bool "Save configuration into NVRAM on Compaq servers" - depends on HOTPLUG_PCI_COMPAQ - help - Say Y here if you have a Compaq server that has a PCI Hotplug - controller. This will allow the PCI Hotplug driver to store the PCI - system configuration options in NVRAM. - - When in doubt, say N. - -config HOTPLUG_PCI_IBM - tristate "IBM PCI Hotplug driver" - depends on HOTPLUG_PCI && X86_IO_APIC && X86 - help - Say Y here if you have a motherboard with a IBM PCI Hotplug - controller. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpqphp. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -config HOTPLUG_PCI_ACPI - tristate "ACPI PCI Hotplug driver" - depends on ACPI_BUS && HOTPLUG_PCI - help - Say Y here if you have a system that supports PCI Hotplug using - ACPI. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called acpiphp. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -config HOTPLUG_PCI_CPCI - tristate "CompactPCI Hotplug driver" - depends on HOTPLUG_PCI - help - Say Y here if you have a CompactPCI system card with CompactPCI - hotswap support per the PICMG 2.1 specification. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpci_hotplug. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -config HOTPLUG_PCI_CPCI_ZT5550 - tristate "Ziatech ZT5550 CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 - help - Say Y here if you have an Performance Technologies (formerly Intel, - formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpcihp_zt5550. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -config HOTPLUG_PCI_CPCI_GENERIC - tristate "Generic port I/O CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 - help - Say Y here if you have a CompactPCI system card that exposes the #ENUM - hotswap signal as a bit in a system register that can be read through - standard port I/O. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpcihp_generic. If you want to compile it - as a module, say M here and read . - - When in doubt, say N. - -endmenu - diff -urN linux-2.5.70-bk9/drivers/hotplug/Makefile linux-2.5.70-bk10/drivers/hotplug/Makefile --- linux-2.5.70-bk9/drivers/hotplug/Makefile 2003-05-26 18:00:44.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/Makefile 1969-12-31 16:00:00.000000000 -0800 @@ -1,44 +0,0 @@ -# -# Makefile for the Linux kernel pci hotplug controller drivers. -# - -obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o -obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o -obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o -obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o -obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o -obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o - -pci_hotplug-objs := pci_hotplug_core.o - -ifdef CONFIG_HOTPLUG_PCI_CPCI -pci_hotplug-objs += cpci_hotplug_core.o \ - cpci_hotplug_pci.o -endif - -cpqphp-objs := cpqphp_core.o \ - cpqphp_ctrl.o \ - cpqphp_sysfs.o \ - cpqphp_pci.o - -ibmphp-objs := ibmphp_core.o \ - ibmphp_ebda.o \ - ibmphp_pci.o \ - ibmphp_res.o \ - ibmphp_hpc.o - -acpiphp-objs := acpiphp_core.o \ - acpiphp_glue.o \ - acpiphp_pci.o \ - acpiphp_res.o - -ifdef CONFIG_HOTPLUG_PCI_ACPI - EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi - ifdef CONFIG_ACPI_DEBUG - EXTRA_CFLAGS += -DACPI_DEBUG_OUTPUT - endif -endif - -ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) - cpqphp-objs += cpqphp_nvram.o -endif diff -urN linux-2.5.70-bk9/drivers/hotplug/acpiphp.h linux-2.5.70-bk10/drivers/hotplug/acpiphp.h --- linux-2.5.70-bk9/drivers/hotplug/acpiphp.h 2003-05-26 18:01:00.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/acpiphp.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,262 +0,0 @@ -/* - * ACPI PCI Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * , - * - * - */ - -#ifndef _ACPIPHP_H -#define _ACPIPHP_H - -#include -#include "pci_hotplug.h" - -#define dbg(format, arg...) \ - do { \ - if (acpiphp_debug) \ - printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## arg); \ - } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) - -#define SLOT_MAGIC 0x67267322 -/* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ - -struct acpiphp_bridge; -struct acpiphp_slot; -struct pci_resource; - -/* - * struct slot - slot information for each *physical* slot - */ -struct slot { - u32 magic; - u8 number; - struct hotplug_slot *hotplug_slot; - struct list_head slot_list; - - struct acpiphp_slot *acpi_slot; -}; - -/* - * struct pci_resource - describes pci resource (mem, pfmem, io, bus) - */ -struct pci_resource { - struct pci_resource * next; - u64 base; - u32 length; -}; - -/** - * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters - * @cache_line_size in DWORD - * @latency_timer in PCI clock - * @enable_SERR 0 or 1 - * @enable_PERR 0 or 1 - */ -struct hpp_param { - u8 cache_line_size; - u8 latency_timer; - u8 enable_SERR; - u8 enable_PERR; -}; - - -/** - * struct acpiphp_bridge - PCI bridge information - * - * for each bridge device in ACPI namespace - */ -struct acpiphp_bridge { - struct list_head list; - acpi_handle handle; - struct acpiphp_slot *slots; - int type; - int nr_slots; - - u8 seg; - u8 bus; - u8 sub; - - u32 flags; - - /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ - struct pci_bus *pci_bus; - - /* PCI-to-PCI bridge device */ - struct pci_dev *pci_dev; - - /* ACPI 2.0 _HPP parameters */ - struct hpp_param hpp; - - spinlock_t res_lock; - - /* available resources on this bus */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; -}; - - -/** - * struct acpiphp_slot - PCI slot information - * - * PCI slot information for each *physical* PCI slot - */ -struct acpiphp_slot { - struct acpiphp_slot *next; - struct acpiphp_bridge *bridge; /* parent */ - struct list_head funcs; /* one slot may have different - objects (i.e. for each function) */ - struct semaphore crit_sect; - - u32 id; /* slot id (serial #) for hotplug core */ - u8 device; /* pci device# */ - - u32 sun; /* ACPI _SUN (slot unique number) */ - u32 slotno; /* slot number relative to bridge */ - u32 flags; /* see below */ -}; - - -/** - * struct acpiphp_func - PCI function information - * - * PCI function information for each object in ACPI namespace - * typically 8 objects per slot (i.e. for each PCI function) - */ -struct acpiphp_func { - struct acpiphp_slot *slot; /* parent */ - - struct list_head sibling; - struct pci_dev *pci_dev; - - acpi_handle handle; - - u8 function; /* pci function# */ - u32 flags; /* see below */ - - /* resources used for this function */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; -}; - - -/* PCI bus bridge HID */ -#define ACPI_PCI_HOST_HID "PNP0A03" - -/* PCI BRIDGE type */ -#define BRIDGE_TYPE_HOST 0 -#define BRIDGE_TYPE_P2P 1 - -/* ACPI _STA method value (ignore bit 4; battery present) */ -#define ACPI_STA_PRESENT (0x00000001) -#define ACPI_STA_ENABLED (0x00000002) -#define ACPI_STA_SHOW_IN_UI (0x00000004) -#define ACPI_STA_FUNCTIONING (0x00000008) -#define ACPI_STA_ALL (0x0000000f) - -/* bridge flags */ -#define BRIDGE_HAS_STA (0x00000001) -#define BRIDGE_HAS_EJ0 (0x00000002) -#define BRIDGE_HAS_HPP (0x00000004) -#define BRIDGE_HAS_PS0 (0x00000010) -#define BRIDGE_HAS_PS1 (0x00000020) -#define BRIDGE_HAS_PS2 (0x00000040) -#define BRIDGE_HAS_PS3 (0x00000080) - -/* slot flags */ - -#define SLOT_POWEREDON (0x00000001) -#define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (x000000004) - -/* function flags */ - -#define FUNC_HAS_STA (0x00000001) -#define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_PS0 (0x00000010) -#define FUNC_HAS_PS1 (0x00000020) -#define FUNC_HAS_PS2 (0x00000040) -#define FUNC_HAS_PS3 (0x00000080) - -/* not yet */ -#define SLOT_SUPPORT_66MHZ (0x00010000) -#define SLOT_SUPPORT_100MHZ (0x00020000) -#define SLOT_SUPPORT_133MHZ (0x00040000) -#define SLOT_SUPPORT_PCIX (0x00080000) - -/* function prototypes */ - -/* acpiphp_glue.c */ -extern int acpiphp_glue_init (void); -extern void acpiphp_glue_exit (void); -extern int acpiphp_get_num_slots (void); -extern struct acpiphp_slot *get_slot_from_id (int id); -typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); -extern int acpiphp_for_each_slot (acpiphp_callback fn, void *data); - -extern int acpiphp_check_bridge (struct acpiphp_bridge *bridge); -extern int acpiphp_enable_slot (struct acpiphp_slot *slot); -extern int acpiphp_disable_slot (struct acpiphp_slot *slot); -extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); - -/* acpiphp_pci.c */ -extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); -extern int acpiphp_configure_slot (struct acpiphp_slot *slot); -extern int acpiphp_configure_function (struct acpiphp_func *func); -extern int acpiphp_unconfigure_function (struct acpiphp_func *func); -extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); -extern int acpiphp_init_func_resource (struct acpiphp_func *func); - -/* acpiphp_res.c */ -extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); -extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); -extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); -extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); -extern void acpiphp_free_resource (struct pci_resource **res); -extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ -extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ - -/* variables */ -extern int acpiphp_debug; - -#endif /* _ACPIPHP_H */ diff -urN linux-2.5.70-bk9/drivers/hotplug/acpiphp_core.c linux-2.5.70-bk10/drivers/hotplug/acpiphp_core.c --- linux-2.5.70-bk9/drivers/hotplug/acpiphp_core.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/acpiphp_core.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,505 +0,0 @@ -/* - * ACPI PCI Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * , - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci_hotplug.h" -#include "acpiphp.h" - -static LIST_HEAD(slot_list); - -#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) - #define MY_NAME "acpiphp" -#else - #define MY_NAME THIS_MODULE->name -#endif - -static int debug; -int acpiphp_debug; - -/* local variables */ -static int num_slots; - -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " -#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -static int enable_slot (struct hotplug_slot *slot); -static int disable_slot (struct hotplug_slot *slot); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); - -static struct hotplug_slot_ops acpi_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL\n", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot\n", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!\n", function); - return -1; - } - return 0; -} - - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check(slot, function)) - return NULL; - return slot; -} - - -/** - * enable_slot - power on and enable a slot - * @hotplug_slot: slot to enable - * - * Actual tasks are done in acpiphp_enable_slot() - * - */ -static int enable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* enable the specified slot */ - retval = acpiphp_enable_slot(slot->acpi_slot); - - return retval; -} - - -/** - * disable_slot - disable and power off a slot - * @hotplug_slot: slot to disable - * - * Actual tasks are done in acpiphp_disable_slot() - * - */ -static int disable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* disable the specified slot */ - retval = acpiphp_disable_slot(slot->acpi_slot); - - return retval; -} - - -/** - * set_attention_status - set attention LED - * - * TBD: - * ACPI doesn't have known method to manipulate - * attention status LED. - * - */ -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - int retval = 0; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - switch (status) { - case 0: - /* FIXME turn light off */ - hotplug_slot->info->attention_status = 0; - break; - - case 1: - default: - /* FIXME turn light on */ - hotplug_slot->info->attention_status = 1; - break; - } - - return retval; -} - - -/** - * hardware_test - hardware test - * - * We have nothing to do for now... - * - */ -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - err("No hardware tests are defined for this driver\n"); - retval = -ENODEV; - - return retval; -} - - -/** - * get_power_status - get power status of a slot - * @hotplug_slot: slot to get status - * @value: pointer to store status - * - * Some platforms may not implement _STA method properly. - * In that case, the value returned may not be reliable. - * - */ -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_power_status(slot->acpi_slot); - - return retval; -} - - -/** - * get_attention_status - get attention LED status - * - * TBD: - * ACPI doesn't provide any formal means to access attention LED status. - * - */ -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - int retval = 0; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = hotplug_slot->info->attention_status; - - return retval; -} - - -/** - * get_latch_status - get latch status of a slot - * @hotplug_slot: slot to get status - * @value: pointer to store status - * - * ACPI doesn't provide any formal means to access latch status. - * Instead, we fake latch status from _STA - * - */ -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_latch_status(slot->acpi_slot); - - return retval; -} - - -/** - * get_adapter_status - get adapter status of a slot - * @hotplug_slot: slot to get status - * @value: pointer to store status - * - * ACPI doesn't provide any formal means to access adapter status. - * Instead, we fake adapter status from _STA - * - */ -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_adapter_status(slot->acpi_slot); - - return retval; -} - - -/* return dummy value because ACPI doesn't provide any method... */ -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return -ENODEV; - - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - - -/* return dummy value because ACPI doesn't provide any method... */ -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return -ENODEV; - - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - - -static int init_acpi (void) -{ - int retval; - - /* initialize internal data structure etc. */ - retval = acpiphp_glue_init(); - - /* read initial number of slots */ - if (!retval) { - num_slots = acpiphp_get_num_slots(); - if (num_slots == 0) - retval = -ENODEV; - } - - return retval; -} - - -/** - * make_slot_name - make a slot name that appears in pcihpfs - * @slot: slot to name - * - */ -static void make_slot_name (struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", - slot->acpi_slot->sun, - slot->acpi_slot->bridge->bus, - slot->acpi_slot->device); -} - -/** - * init_slots - initialize 'struct slot' structures for each slot - * - */ -static int init_slots (void) -{ - struct slot *slot; - int retval = 0; - int i; - - for (i = 0; i < num_slots; ++i) { - slot = kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - memset(slot, 0, sizeof(struct slot)); - - slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot->hotplug_slot) { - kfree(slot); - return -ENOMEM; - } - memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); - - slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!slot->hotplug_slot->info) { - kfree(slot->hotplug_slot); - kfree(slot); - return -ENOMEM; - } - memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); - - slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!slot->hotplug_slot->name) { - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot); - kfree(slot); - return -ENOMEM; - } - - slot->magic = SLOT_MAGIC; - slot->number = i; - - slot->hotplug_slot->private = slot; - slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; - - slot->acpi_slot = get_slot_from_id(i); - slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); - slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot); - slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); - slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); - - make_slot_name(slot); - - retval = pci_hp_register(slot->hotplug_slot); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - return retval; - } - - /* add slot to our internal list */ - list_add(&slot->slot_list, &slot_list); - info("Slot [%s] registered\n", slot->hotplug_slot->name); - } - - return retval; -} - - -static void cleanup_slots (void) -{ - struct list_head *tmp, *n; - struct slot *slot; - - list_for_each_safe (tmp, n, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - } - - return; -} - - -static int __init acpiphp_init(void) -{ - int retval; - - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - - acpiphp_debug = debug; - - /* read all the ACPI info from the system */ - retval = init_acpi(); - if (retval) - return retval; - - retval = init_slots(); - if (retval) - return retval; - - return 0; -} - - -static void __exit acpiphp_exit(void) -{ - cleanup_slots(); - /* deallocate internal data structures etc. */ - acpiphp_glue_exit(); -} - -module_init(acpiphp_init); -module_exit(acpiphp_exit); diff -urN linux-2.5.70-bk9/drivers/hotplug/acpiphp_glue.c linux-2.5.70-bk10/drivers/hotplug/acpiphp_glue.c --- linux-2.5.70-bk9/drivers/hotplug/acpiphp_glue.c 2003-05-26 18:00:28.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/acpiphp_glue.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1359 +0,0 @@ -/* - * ACPI PCI HotPlug glue functions to ACPI CA subsystem - * - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "pci_hotplug.h" -#include "acpiphp.h" - -static LIST_HEAD(bridge_list); - -#define MY_NAME "acpiphp_glue" - -static void handle_hotplug_event_bridge (acpi_handle, u32, void *); -static void handle_hotplug_event_func (acpi_handle, u32, void *); - -/* - * initialization & terminatation routines - */ - -/** - * is_ejectable - determine if a slot is ejectable - * @handle: handle to acpi namespace - * - * Ejectable slot should satisfy at least these conditions: - * - * 1. has _ADR method - * 2. has _EJ0 method - * - * optionally - * - * 1. has _STA method - * 2. has _PS0 method - * 3. has _PS3 method - * 4. .. - * - */ -static int is_ejectable (acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_ADR", &tmp); - if (ACPI_FAILURE(status)) { - return 0; - } - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) { - return 0; - } - - return 1; -} - - -/* callback routine to check the existence of ejectable slots */ -static acpi_status -is_ejectable_slot (acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - if (is_ejectable(handle)) { - (*count)++; - /* only one ejectable slot is enough */ - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - - -/* callback routine to register each ACPI PCI slot object */ -static acpi_status -register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; - struct acpiphp_slot *slot; - struct acpiphp_func *newfunc; - acpi_handle tmp; - acpi_status status = AE_OK; - unsigned long adr, sun; - int device, function; - static int num_slots = 0; /* XXX if we support I/O node hotplug... */ - - status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); - - if (ACPI_FAILURE(status)) - return AE_OK; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - - if (ACPI_FAILURE(status)) - return AE_OK; - - device = (adr >> 16) & 0xffff; - function = adr & 0xffff; - - newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL); - if (!newfunc) - return AE_NO_MEMORY; - memset(newfunc, 0, sizeof(struct acpiphp_func)); - - INIT_LIST_HEAD(&newfunc->sibling); - newfunc->handle = handle; - newfunc->function = function; - newfunc->flags = FUNC_HAS_EJ0; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) - newfunc->flags |= FUNC_HAS_STA; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) - newfunc->flags |= FUNC_HAS_PS0; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) - newfunc->flags |= FUNC_HAS_PS3; - - status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) - sun = -1; - - /* search for objects that share the same slot */ - for (slot = bridge->slots; slot; slot = slot->next) - if (slot->device == device) { - if (slot->sun != sun) - warn("sibling found, but _SUN doesn't match!\n"); - break; - } - - if (!slot) { - slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); - if (!slot) { - kfree(newfunc); - return AE_NO_MEMORY; - } - - memset(slot, 0, sizeof(struct acpiphp_slot)); - slot->bridge = bridge; - slot->id = num_slots++; - slot->device = device; - slot->sun = sun; - INIT_LIST_HEAD(&slot->funcs); - init_MUTEX(&slot->crit_sect); - - slot->next = bridge->slots; - bridge->slots = slot; - - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", - slot->bridge->bus, slot->device, slot->sun); - } - - newfunc->slot = slot; - list_add_tail(&newfunc->sibling, &slot->funcs); - - /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_find_slot(bridge->bus, - PCI_DEVFN(device, function)); - if (newfunc->pci_dev) { - if (acpiphp_init_func_resource(newfunc) < 0) { - kfree(newfunc); - return AE_ERROR; - } - slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); - } - - /* install notify handler */ - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - newfunc); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - kfree(newfunc); - return status; - } - - return AE_OK; -} - - -/* see if it's worth looking at this bridge */ -static int detect_ejectable_slots (acpi_handle *bridge_handle) -{ - acpi_status status; - int count; - - count = 0; - - /* only check slots defined directly below bridge object */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, - is_ejectable_slot, (void *)&count, NULL); - - return count; -} - - -/* decode ACPI _CRS data and convert into our internal resource list - * TBD: _TRA, etc. - */ -static acpi_status -decode_acpi_resource (struct acpi_resource *resource, void *context) -{ - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; - struct acpi_resource_address64 address; - struct pci_resource *res; - - if (resource->id != ACPI_RSTYPE_ADDRESS16 && - resource->id != ACPI_RSTYPE_ADDRESS32 && - resource->id != ACPI_RSTYPE_ADDRESS64) - return AE_OK; - - acpi_resource_to_address64(resource, &address); - - if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { - dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, address.min_address_range, address.max_address_range); - res = acpiphp_make_resource(address.min_address_range, - address.address_length); - if (!res) { - err("out of memory\n"); - return AE_OK; - } - - switch (address.resource_type) { - case ACPI_MEMORY_RANGE: - if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { - res->next = bridge->p_mem_head; - bridge->p_mem_head = res; - } else { - res->next = bridge->mem_head; - bridge->mem_head = res; - } - break; - case ACPI_IO_RANGE: - res->next = bridge->io_head; - bridge->io_head = res; - break; - case ACPI_BUS_NUMBER_RANGE: - res->next = bridge->bus_head; - bridge->bus_head = res; - break; - default: - /* invalid type */ - kfree(res); - break; - } - } - - return AE_OK; -} - - -/* find pci_bus structure associated to specific bus number */ -static struct pci_bus *find_pci_bus(const struct list_head *list, int bus) -{ - const struct list_head *l; - - list_for_each (l, list) { - struct pci_bus *b = pci_bus_b(l); - if (b->number == bus) - return b; - - if (!list_empty(&b->children)) { - /* XXX recursive call */ - b = find_pci_bus(&b->children, bus); - - if (b) - return b; - } - } - - return NULL; -} - - -/* decode ACPI 2.0 _HPP hot plug parameters */ -static void decode_hpp(struct acpiphp_bridge *bridge) -{ - acpi_status status; - struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, - .pointer = NULL}; - union acpi_object *package; - int i; - - /* default numbers */ - bridge->hpp.cache_line_size = 0x10; - bridge->hpp.latency_timer = 0x40; - bridge->hpp.enable_SERR = 0; - bridge->hpp.enable_PERR = 0; - - status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); - - if (ACPI_FAILURE(status)) { - dbg("_HPP evaluation failed\n"); - return; - } - - package = (union acpi_object *) buffer.pointer; - - if (!package || package->type != ACPI_TYPE_PACKAGE || - package->package.count != 4 || !package->package.elements) { - err("invalid _HPP object; ignoring\n"); - goto err_exit; - } - - for (i = 0; i < 4; i++) { - if (package->package.elements[i].type != ACPI_TYPE_INTEGER) { - err("invalid _HPP parameter type; ignoring\n"); - goto err_exit; - } - } - - bridge->hpp.cache_line_size = package->package.elements[0].integer.value; - bridge->hpp.latency_timer = package->package.elements[1].integer.value; - bridge->hpp.enable_SERR = package->package.elements[2].integer.value; - bridge->hpp.enable_PERR = package->package.elements[3].integer.value; - - dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n", - bridge->hpp.cache_line_size, - bridge->hpp.latency_timer, - bridge->hpp.enable_SERR, - bridge->hpp.enable_PERR); - - bridge->flags |= BRIDGE_HAS_HPP; - - err_exit: - kfree(buffer.pointer); -} - - -/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ -static void init_bridge_misc (struct acpiphp_bridge *bridge) -{ - acpi_status status; - - /* decode ACPI 2.0 _HPP (hot plug parameters) */ - decode_hpp(bridge); - - /* subtract all resources already allocated */ - acpiphp_detect_pci_resource(bridge); - - /* register all slot objects under this bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, - register_slot, bridge, NULL); - - /* install notify handler */ - status = acpi_install_notify_handler(bridge->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - } - - list_add(&bridge->list, &bridge_list); - - dbg("Bridge resource:\n"); - acpiphp_dump_resource(bridge); -} - - -/* allocate and initialize host bridge data structure */ -static void add_host_bridge (acpi_handle *handle, int seg, int bus) -{ - acpi_status status; - struct acpiphp_bridge *bridge; - - bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) - return; - - memset(bridge, 0, sizeof(struct acpiphp_bridge)); - - bridge->type = BRIDGE_TYPE_HOST; - bridge->handle = handle; - bridge->seg = seg; - bridge->bus = bus; - - bridge->pci_bus = find_pci_bus(&pci_root_buses, bus); - - bridge->res_lock = SPIN_LOCK_UNLOCKED; - - /* to be overridden when we decode _CRS */ - bridge->sub = bridge->bus; - - /* decode resources */ - - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - decode_acpi_resource, bridge); - - if (ACPI_FAILURE(status)) { - err("failed to decode bridge resources\n"); - kfree(bridge); - return; - } - - acpiphp_resource_sort_and_combine(&bridge->io_head); - acpiphp_resource_sort_and_combine(&bridge->mem_head); - acpiphp_resource_sort_and_combine(&bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&bridge->bus_head); - - dbg("ACPI _CRS resource:\n"); - acpiphp_dump_resource(bridge); - - if (bridge->bus_head) { - bridge->bus = bridge->bus_head->base; - bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; - } - - init_bridge_misc(bridge); -} - - -/* allocate and initialize PCI-to-PCI bridge data structure */ -static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn) -{ - struct acpiphp_bridge *bridge; - u8 tmp8; - u16 tmp16; - u64 base64, limit64; - u32 base, limit, base32u, limit32u; - - bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) { - err("out of memory\n"); - return; - } - - memset(bridge, 0, sizeof(struct acpiphp_bridge)); - - bridge->type = BRIDGE_TYPE_P2P; - bridge->handle = handle; - bridge->seg = seg; - - bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); - if (!bridge->pci_dev) { - err("Can't get pci_dev\n"); - kfree(bridge); - return; - } - - bridge->pci_bus = bridge->pci_dev->subordinate; - if (!bridge->pci_bus) { - err("This is not a PCI-to-PCI bridge!\n"); - kfree(bridge); - return; - } - - bridge->res_lock = SPIN_LOCK_UNLOCKED; - - bridge->bus = bridge->pci_bus->number; - bridge->sub = bridge->pci_bus->subordinate; - - /* - * decode resources under this P2P bridge - */ - - /* I/O resources */ - pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); - base = tmp8; - pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); - limit = tmp8; - - switch (base & PCI_IO_RANGE_TYPE_MASK) { - case PCI_IO_RANGE_TYPE_16: - base = (base << 8) & 0xf000; - limit = ((limit << 8) & 0xf000) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("16bit I/O range: %04x-%04x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case PCI_IO_RANGE_TYPE_32: - pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); - base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); - pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); - limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit I/O range: %08x-%08x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case 0x0f: - dbg("I/O space unsupported\n"); - break; - default: - warn("Unknown I/O range type\n"); - } - - /* Memory resources (mandatory for P2P bridge) */ - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); - base = (tmp16 & 0xfff0) << 16; - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); - limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; - bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Memory range: %08x-%08x\n", - (u32)bridge->mem_head->base, - (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); - - /* Prefetchable Memory resources (optional) */ - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); - base = tmp16; - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); - limit = tmp16; - - switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { - case PCI_PREF_RANGE_TYPE_32: - base = (base & 0xfff0) << 16; - limit = ((limit & 0xfff0) << 16) | 0xfffff; - bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Prefetchable memory range: %08x-%08x\n", - (u32)bridge->p_mem_head->base, - (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); - break; - case PCI_PREF_RANGE_TYPE_64: - pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); - pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); - base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); - limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; - - bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", - (u32)(bridge->p_mem_head->base >> 32), - (u32)(bridge->p_mem_head->base & 0xffffffff), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); - break; - case 0x0f: - break; - default: - warn("Unknown prefetchale memory type\n"); - } - - init_bridge_misc(bridge); -} - - -/* callback routine to find P2P bridges */ -static acpi_status -find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - acpi_handle dummy_handle; - unsigned long *segbus = context; - unsigned long tmp; - int seg, bus, device, function; - struct pci_dev *dev; - - /* get PCI address */ - seg = (*segbus >> 8) & 0xff; - bus = *segbus & 0xff; - - status = acpi_get_handle(handle, "_ADR", &dummy_handle); - if (ACPI_FAILURE(status)) - return AE_OK; /* continue */ - - status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dbg("%s: _ADR evaluation failure\n", __FUNCTION__); - return AE_OK; - } - - device = (tmp >> 16) & 0xffff; - function = tmp & 0xffff; - - dev = pci_find_slot(bus, PCI_DEVFN(device, function)); - - if (!dev) - return AE_OK; - - if (!dev->subordinate) - return AE_OK; - - /* check if this bridge has ejectable slots */ - if (detect_ejectable_slots(handle) > 0) { - dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name); - add_p2p_bridge(handle, seg, bus, device, function); - } - - return AE_OK; -} - - -/* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridges(struct acpi_device *device) -{ - acpi_handle *handle = device->handle; - acpi_status status; - unsigned long tmp; - int seg, bus; - acpi_handle dummy_handle; - - /* if the bridge doesn't have _STA, we assume it is always there */ - status = acpi_get_handle(handle, "_STA", &dummy_handle); - if (ACPI_SUCCESS(status)) { - status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dbg("%s: _STA evaluation failure\n", __FUNCTION__); - return 0; - } - if ((tmp & ACPI_STA_FUNCTIONING) == 0) - /* don't register this object */ - return 0; - } - - /* get PCI segment number */ - status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); - - seg = ACPI_SUCCESS(status) ? tmp : 0; - - /* get PCI bus number */ - status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); - - if (ACPI_SUCCESS(status)) { - bus = tmp; - } else { - warn("can't get bus number, assuming 0\n"); - bus = 0; - } - - /* check if this bridge has ejectable slots */ - if (detect_ejectable_slots(handle) > 0) { - dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle, seg, bus); - return 0; - } - - tmp = seg << 8 | bus; - - /* search P2P bridges under this host bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - find_p2p_bridge, &tmp, NULL); - - if (ACPI_FAILURE(status)) - warn("find_p2p_bridge faied (error code = 0x%x)\n",status); - - return 0; -} - - -static int power_on_slot (struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - struct list_head *l; - int retval = 0; - - /* is this already enabled? */ - if (slot->flags & SLOT_POWEREDON) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } - } - } - - /* TBD: evaluate _STA to check if the slot is enabled */ - - slot->flags |= SLOT_POWEREDON; - - err_exit: - return retval; -} - - -static int power_off_slot (struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - struct list_head *l; - struct acpi_object_list arg_list; - union acpi_object arg; - - int retval = 0; - - /* is this already enabled? */ - if ((slot->flags & SLOT_POWEREDON) == 0) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_PS3) { - dbg("%s: executing _PS3 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS3 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } - } - } - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_EJ0) { - dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } - } - } - - /* TBD: evaluate _STA to check if the slot is disabled */ - - slot->flags &= (~SLOT_POWEREDON); - - err_exit: - return retval; -} - - -/** - * enable_device - enable, configure a slot - * @slot: slot to be enabled - * - * This function should be called per *physical slot*, - * not per each slot object in ACPI namespace. - * - */ -static int enable_device (struct acpiphp_slot *slot) -{ - u8 bus; - struct pci_dev *dev; - struct pci_bus *child; - struct list_head *l; - struct acpiphp_func *func; - int retval = 0; - int num; - - if (slot->flags & SLOT_ENABLED) - goto err_exit; - - /* sanity check: dev should be NULL when hot-plugged in */ - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); - if (dev) { - /* This case shouldn't happen */ - err("pci_dev structure already exists.\n"); - retval = -1; - goto err_exit; - } - - /* allocate resources to device */ - retval = acpiphp_configure_slot(slot); - if (retval) - goto err_exit; - - /* returned `dev' is the *first function* only! */ - num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); - if (num) - pci_bus_add_devices(slot->bridge->pci_bus); - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); - - if (!dev) { - err("No new device found\n"); - retval = -1; - goto err_exit; - } - - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); - pci_do_scan_bus(child); - } - - /* associate pci_dev to our representation */ - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - func->pci_dev = pci_find_slot(slot->bridge->bus, - PCI_DEVFN(slot->device, - func->function)); - if (!func->pci_dev) - continue; - - /* configure device */ - retval = acpiphp_configure_function(func); - if (retval) - goto err_exit; - } - - slot->flags |= SLOT_ENABLED; - - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - - err_exit: - return retval; -} - - -/** - * disable_device - disable a slot - */ -static int disable_device (struct acpiphp_slot *slot) -{ - int retval = 0; - struct acpiphp_func *func; - struct list_head *l; - - /* is this slot already disabled? */ - if (!(slot->flags & SLOT_ENABLED)) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->pci_dev) { - if (acpiphp_unconfigure_function(func) == 0) { - func->pci_dev = NULL; - } else { - err("failed to unconfigure device\n"); - retval = -1; - goto err_exit; - } - } - } - - slot->flags &= (~SLOT_ENABLED); - - err_exit: - return retval; -} - - -/** - * get_slot_status - get ACPI slot status - * - * if a slot has _STA for each function and if any one of them - * returned non-zero status, return it - * - * if a slot doesn't have _STA and if any one of its functions' - * configuration space is configured, return 0x0f as a _STA - * - * otherwise return 0 - */ -static unsigned int get_slot_status (struct acpiphp_slot *slot) -{ - acpi_status status; - unsigned long sta = 0; - u32 dvid; - struct list_head *l; - struct acpiphp_func *func; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_STA) { - status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta) - break; - } else { - pci_bus_read_config_dword(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { - sta = ACPI_STA_ALL; - break; - } - } - } - - return (unsigned int)sta; -} - - -/* - * ACPI event handlers - */ - -/** - * handle_hotplug_event_bridge - handle ACPI event on bridges - * - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_bridge structure - * - * handles ACPI event notification on {host,p2p} bridges - * - */ -static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *context) -{ - struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - bridge = (struct acpiphp_bridge *)context; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check */ - dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } -} - - -/** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) - * - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_func structure - * - * handles ACPI event notification on slots - * - */ -static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *context) -{ - struct acpiphp_func *func; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - func = (struct acpiphp_func *)context; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_enable_slot(func->slot); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check : re-enumerate from parent bus */ - dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(func->slot->bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - acpiphp_disable_slot(func->slot); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } -} - -static struct acpi_driver acpi_pci_hp_driver = { - .name = "pci_hp", - .class = "", - .ids = ACPI_PCI_HOST_HID, - .ops = { - .add = add_bridges, - } -}; - -/** - * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures - * - */ -int acpiphp_glue_init (void) -{ - acpi_status status; - - if (list_empty(&pci_root_buses)) - return -1; - - status = acpi_bus_register_driver(&acpi_pci_hp_driver); - - if (ACPI_FAILURE(status)) { - err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); - return -1; - } - - return 0; -} - - -/** - * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures - * - * This function frees all data allocated in acpiphp_glue_init() - */ -void acpiphp_glue_exit (void) -{ - struct list_head *l1, *l2, *n1, *n2; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot, *next; - struct acpiphp_func *func; - acpi_status status; - - list_for_each_safe (l1, n1, &bridge_list) { - bridge = (struct acpiphp_bridge *)l1; - slot = bridge->slots; - while (slot) { - next = slot->next; - list_for_each_safe (l2, n2, &slot->funcs) { - func = list_entry(l2, struct acpiphp_func, sibling); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - acpiphp_free_resource(&func->bus_head); - status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - kfree(func); - } - kfree(slot); - slot = next; - } - status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - - acpiphp_free_resource(&bridge->io_head); - acpiphp_free_resource(&bridge->mem_head); - acpiphp_free_resource(&bridge->p_mem_head); - acpiphp_free_resource(&bridge->bus_head); - - kfree(bridge); - } -} - - -/** - * acpiphp_get_num_slots - count number of slots in a system - */ -int acpiphp_get_num_slots (void) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - int num_slots; - - num_slots = 0; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); - num_slots += bridge->nr_slots; - } - - dbg("Total %dslots\n", num_slots); - return num_slots; -} - - -/** - * acpiphp_for_each_slot - call function for each slot - * @fn: callback function - * @data: context to be passed to callback function - * - */ -int acpiphp_for_each_slot(acpiphp_callback fn, void *data) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - int retval = 0; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) { - retval = fn(slot, data); - if (!retval) - goto err_exit; - } - } - - err_exit: - return retval; -} - - -/* search matching slot from id */ -struct acpiphp_slot *get_slot_from_id (int id) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) - if (slot->id == id) - return slot; - } - - /* should never happen! */ - err("%s: no object for id %d\n",__FUNCTION__, id); - return 0; -} - - -/** - * acpiphp_enable_slot - power on slot - */ -int acpiphp_enable_slot (struct acpiphp_slot *slot) -{ - int retval; - - down(&slot->crit_sect); - - /* wake up all functions */ - retval = power_on_slot(slot); - if (retval) - goto err_exit; - - if (get_slot_status(slot) == ACPI_STA_ALL) - /* configure all functions */ - retval = enable_device(slot); - - err_exit: - up(&slot->crit_sect); - return retval; -} - - -/** - * acpiphp_disable_slot - power off slot - */ -int acpiphp_disable_slot (struct acpiphp_slot *slot) -{ - int retval = 0; - - down(&slot->crit_sect); - - /* unconfigure all functions */ - retval = disable_device(slot); - if (retval) - goto err_exit; - - /* power off all functions */ - retval = power_off_slot(slot); - if (retval) - goto err_exit; - - acpiphp_resource_sort_and_combine(&slot->bridge->io_head); - acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - - err_exit: - up(&slot->crit_sect); - return retval; -} - - -/** - * acpiphp_check_bridge - re-enumerate devices - */ -int acpiphp_check_bridge (struct acpiphp_bridge *bridge) -{ - struct acpiphp_slot *slot; - unsigned int sta; - int retval = 0; - int enabled, disabled; - - enabled = disabled = 0; - - for (slot = bridge->slots; slot; slot = slot->next) { - sta = get_slot_status(slot); - if (slot->flags & SLOT_ENABLED) { - /* if enabled but not present, disable */ - if (sta != ACPI_STA_ALL) { - retval = acpiphp_disable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - up(&slot->crit_sect); - goto err_exit; - } - enabled++; - } - } else { - /* if disabled but present, enable */ - if (sta == ACPI_STA_ALL) { - retval = acpiphp_enable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - up(&slot->crit_sect); - goto err_exit; - } - disabled++; - } - } - } - - dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); - - err_exit: - return retval; -} - - -/* - * slot enabled: 1 - * slot disabled: 0 - */ -u8 acpiphp_get_power_status (struct acpiphp_slot *slot) -{ - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_ENABLED) ? 1 : 0; -} - - -/* - * attention LED ON: 1 - * OFF: 0 - * - * TBD - * no direct attention led status information via ACPI - * - */ -u8 acpiphp_get_attention_status (struct acpiphp_slot *slot) -{ - return 0; -} - - -/* - * latch closed: 1 - * latch open: 0 - */ -u8 acpiphp_get_latch_status (struct acpiphp_slot *slot) -{ - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; -} - - -/* - * adapter presence : 1 - * absence : 0 - */ -u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot) -{ - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta == 0) ? 0 : 1; -} diff -urN linux-2.5.70-bk9/drivers/hotplug/acpiphp_pci.c linux-2.5.70-bk10/drivers/hotplug/acpiphp_pci.c --- linux-2.5.70-bk9/drivers/hotplug/acpiphp_pci.c 2003-05-26 18:00:19.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/acpiphp_pci.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,510 +0,0 @@ -/* - * ACPI PCI HotPlug PCI configuration space management - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_pci" - - -/* allocate mem/pmem/io resource to a new function */ -static int init_config_space (struct acpiphp_func *func) -{ - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct acpiphp_bridge *bridge; - struct pci_resource *res; - struct pci_bus *pbus; - int bus, device, function; - unsigned int devfn; - u16 tmp; - - bridge = func->slot->bridge; - pbus = bridge->pci_bus; - bus = bridge->bus; - device = func->slot->device; - function = func->function; - devfn = PCI_DEVFN(device, function); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_bus_write_config_dword(pbus, devfn, - address[count], 0xFFFFFFFF); - pci_bus_read_config_dword(pbus, devfn, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); - - if (bar & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - - len = bar & 0xFFFFFFFC; - len = ~len + 1; - - dbg("len in IO %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_io_resource(&bridge->io_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested io for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in PFMEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->p_mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("inside the pfmem 64 case, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in MEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("inside mem 64 case, reg. mem, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->mem_head; - func->mem_head = res; - - } - } - } - - /* disable expansion rom */ - pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); - - /* set PCI parameters from _HPP */ - pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); - pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); - - pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); - if (bridge->hpp.enable_SERR) - tmp |= PCI_COMMAND_SERR; - if (bridge->hpp.enable_PERR) - tmp |= PCI_COMMAND_PARITY; - pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); - - return 0; -} - -/* detect_used_resource - subtract resource under dev from bridge */ -static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) -{ - u32 bar, len; - u64 base; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct pci_resource *res; - - dbg("Device %s\n", dev->slot_name); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); - - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->io_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } - } - - pci_write_config_dword(dev, address[count], bar); - } - - return 0; -} - - -/* detect_pci_resource_bus - subtract resource under pci_bus */ -static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus) -{ - struct list_head *l; - struct pci_dev *dev; - - list_for_each (l, &bus->devices) { - dev = pci_dev_b(l); - detect_used_resource(bridge, dev); - /* XXX recursive call */ - if (dev->subordinate) - detect_used_resource_bus(bridge, dev->subordinate); - } -} - - -/** - * acpiphp_detect_pci_resource - detect resources under bridge - * @bridge: detect all resources already used under this bridge - * - * collect all resources already allocated for all devices under a bridge. - */ -int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) -{ - detect_used_resource_bus(bridge, bridge->pci_bus); - - return 0; -} - - -/** - * acpiphp_init_slot_resource - gather resource usage information of a slot - * @slot: ACPI slot object to be checked, should have valid pci_dev member - * - * TBD: PCI-to-PCI bridge case - * use pci_dev->resource[] - */ -int acpiphp_init_func_resource (struct acpiphp_func *func) -{ - u64 base; - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct pci_resource *res; - struct pci_dev *dev; - - dev = func->pci_dev; - dbg("Hot-pluggable device %s\n", dev->slot_name); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); - - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->mem_head; - func->mem_head = res; - - } - } - - pci_write_config_dword(dev, address[count], bar); - } -#if 1 - acpiphp_dump_func_resource(func); -#endif - - return 0; - - no_memory: - err("out of memory\n"); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - - return -1; -} - - -/** - * acpiphp_configure_slot - allocate PCI resources - * @slot: slot to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_slot (struct acpiphp_slot *slot) -{ - struct acpiphp_func *func; - struct list_head *l; - u8 hdr; - u32 dvid; - int retval = 0; - int is_multi = 0; - - pci_bus_read_config_byte(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, 0), - PCI_HEADER_TYPE, &hdr); - - if (hdr & 0x80) - is_multi = 1; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - if (is_multi || func->function == 0) { - pci_bus_read_config_dword(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { - retval = init_config_space(func); - if (retval) - break; - } - } - } - - return retval; -} - -/** - * acpiphp_configure_function - configure PCI function - * @func: function to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_function (struct acpiphp_func *func) -{ - /* all handled by the pci core now */ - return 0; -} - -/** - * acpiphp_unconfigure_function - unconfigure PCI function - * @func: function to be unconfigured - * - */ -int acpiphp_unconfigure_function (struct acpiphp_func *func) -{ - struct acpiphp_bridge *bridge; - int retval = 0; - - /* if pci_dev is NULL, ignore it */ - if (!func->pci_dev) - goto err_exit; - - pci_remove_bus_device(func->pci_dev); - - /* free all resources */ - bridge = func->slot->bridge; - - spin_lock(&bridge->res_lock); - acpiphp_move_resource(&func->io_head, &bridge->io_head); - acpiphp_move_resource(&func->mem_head, &bridge->mem_head); - acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); - acpiphp_move_resource(&func->bus_head, &bridge->bus_head); - spin_unlock(&bridge->res_lock); - - err_exit: - return retval; -} diff -urN linux-2.5.70-bk9/drivers/hotplug/acpiphp_res.c linux-2.5.70-bk10/drivers/hotplug/acpiphp_res.c --- linux-2.5.70-bk9/drivers/hotplug/acpiphp_res.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/acpiphp_res.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,699 +0,0 @@ -/* - * ACPI PCI HotPlug Utility functions - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to , - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_res" - - -/* - * sort_by_size - sort nodes by their length, smallest first - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - - -/* - * sort_by_max_size - sort nodes by their length, largest first - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - -/** - * get_io_resource - get resource for I/O ports - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - * - * difference from get_resource is handling of ISA aliasing space. - * - */ -struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return node; -} - - -/** - * get_max_resource - get the largest resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - */ -struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_max_size(head)) - return NULL; - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_qword - max->base)) < size) - continue; - - split_node = acpiphp_make_resource(max->base, temp_qword - max->base); - - if (!split_node) - return NULL; - - max->base = temp_qword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* this one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - temp_qword = ((max->base + max->length) & ~(size - 1)); - - split_node = acpiphp_make_resource(temp_qword, - max->length + max->base - temp_qword); - - if (!split_node) - return NULL; - - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return max; - } - - /* If we get here, we couldn't find one */ - return NULL; -} - - -/** - * get_resource - get resource (mem, pfmem) - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, (u32)node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - -/** - * get_resource_with_base - get resource with specific base address - * - * this function - * returns the first node of "size" length located at specified base address. - * If it finds a node larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - if (node->base > base) - continue; - - if ((node->base + node->length) < (base + size)) - continue; - - if (node->base < base) { - dbg(": split 1\n"); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = base; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } - - dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg(": split 2\n"); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg(": got one!!!\n"); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - - -/** - * acpiphp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int acpiphp_resource_sort_and_combine (struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - if (!(*head)) - return 1; - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return 0; /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(u32)(*head)->base); - dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return 0; -} - - -/** - * acpiphp_make_resource - make resource structure - * @base: base address of a resource - * @length: length of a resource - */ -struct pci_resource *acpiphp_make_resource (u64 base, u32 length) -{ - struct pci_resource *res; - - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (res) { - memset(res, 0, sizeof(struct pci_resource)); - res->base = base; - res->length = length; - } - - return res; -} - - -/** - * acpiphp_move_resource - move linked resources from one to another - * @from: head of linked resource list - * @to: head of linked resource list - */ -void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) -{ - struct pci_resource *tmp; - - while (*from) { - tmp = (*from)->next; - (*from)->next = *to; - *to = *from; - *from = tmp; - } - - /* *from = NULL is guaranteed */ -} - - -/** - * acpiphp_free_resource - free all linked resources - * @res: head of linked resource list - */ -void acpiphp_free_resource (struct pci_resource **res) -{ - struct pci_resource *tmp; - - while (*res) { - tmp = (*res)->next; - kfree(*res); - *res = tmp; - } - - /* *res = NULL is guaranteed */ -} - - -/* debug support functions; will go away sometime :) */ -static void dump_resource(struct pci_resource *head) -{ - struct pci_resource *p; - int cnt; - - p = head; - cnt = 0; - - while (p) { - dbg("[%02d] %08x - %08x\n", - cnt++, (u32)p->base, (u32)p->base + p->length - 1); - p = p->next; - } -} - -void acpiphp_dump_resource(struct acpiphp_bridge *bridge) -{ - dbg("I/O resource:\n"); - dump_resource(bridge->io_head); - dbg("MEM resource:\n"); - dump_resource(bridge->mem_head); - dbg("PMEM resource:\n"); - dump_resource(bridge->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(bridge->bus_head); -} - -void acpiphp_dump_func_resource(struct acpiphp_func *func) -{ - dbg("I/O resource:\n"); - dump_resource(func->io_head); - dbg("MEM resource:\n"); - dump_resource(func->mem_head); - dbg("PMEM resource:\n"); - dump_resource(func->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(func->bus_head); -} diff -urN linux-2.5.70-bk9/drivers/hotplug/cpci_hotplug.h linux-2.5.70-bk10/drivers/hotplug/cpci_hotplug.h --- linux-2.5.70-bk9/drivers/hotplug/cpci_hotplug.h 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpci_hotplug.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,100 +0,0 @@ -/* - * CompactPCI Hot Plug Core Functions - * - * Copyright (c) 2002 SOMA Networks, Inc. - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ - -#ifndef _CPCI_HOTPLUG_H -#define _CPCI_HOTPLUG_H - -#include -#include - -/* PICMG 2.12 R2.0 HS CSR bits: */ -#define HS_CSR_INS 0x0080 -#define HS_CSR_EXT 0x0040 -#define HS_CSR_PI 0x0030 -#define HS_CSR_LOO 0x0008 -#define HS_CSR_PIE 0x0004 -#define HS_CSR_EIM 0x0002 -#define HS_CSR_DHA 0x0001 - -#define SLOT_MAGIC 0x67267322 -struct slot { - u32 magic; - u8 number; - unsigned int devfn; - struct pci_bus *bus; - struct pci_dev *dev; - unsigned int extracting; - struct hotplug_slot *hotplug_slot; - struct list_head slot_list; -}; - -struct cpci_hp_controller_ops { - int (*query_enum) (void); - int (*enable_irq) (void); - int (*disable_irq) (void); - int (*check_irq) (void *dev_id); - int (*hardware_test) (struct slot* slot, u32 value); - u8 (*get_power) (struct slot* slot); - int (*set_power) (struct slot* slot, int value); -}; - -struct cpci_hp_controller { - unsigned int irq; - unsigned long irq_flags; - char *devname; - void *dev_id; - char *name; - struct cpci_hp_controller_ops *ops; -}; - -extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); -extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); -extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); -extern int cpci_hp_unregister_bus(struct pci_bus *bus); -extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn); -extern int cpci_hp_start(void); -extern int cpci_hp_stop(void); - -/* - * Internal function prototypes, these functions should not be used by - * board/chassis drivers. - */ -extern u8 cpci_get_attention_status(struct slot *slot); -extern u8 cpci_get_latch_status(struct slot *slot); -extern u8 cpci_get_adapter_status(struct slot *slot); -extern u16 cpci_get_hs_csr(struct slot * slot); -extern u16 cpci_set_hs_csr(struct slot * slot, u16 hs_csr); -extern int cpci_set_attention_status(struct slot *slot, int status); -extern int cpci_check_and_clear_ins(struct slot * slot); -extern int cpci_check_ext(struct slot * slot); -extern int cpci_clear_ext(struct slot * slot); -extern int cpci_led_on(struct slot * slot); -extern int cpci_led_off(struct slot * slot); -extern int cpci_configure_slot(struct slot *slot); -extern int cpci_unconfigure_slot(struct slot *slot); - -#endif /* _CPCI_HOTPLUG_H */ diff -urN linux-2.5.70-bk9/drivers/hotplug/cpci_hotplug_core.c linux-2.5.70-bk10/drivers/hotplug/cpci_hotplug_core.c --- linux-2.5.70-bk9/drivers/hotplug/cpci_hotplug_core.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpci_hotplug_core.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,919 +0,0 @@ -/* - * CompactPCI Hot Plug Driver - * - * Copyright (c) 2002 SOMA Networks, Inc. - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci_hotplug.h" -#include "cpci_hotplug.h" - -#define DRIVER_VERSION "0.2" -#define DRIVER_AUTHOR "Scott Murray " -#define DRIVER_DESC "CompactPCI Hot Plug Core" - -#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) -#define MY_NAME "cpci_hotplug" -#else -#define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if(cpci_debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -/* local variables */ -static spinlock_t list_lock; -static LIST_HEAD(slot_list); -static int slots; -int cpci_debug; -static struct cpci_hp_controller *controller; -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */ -static int thread_finished = 1; - -static int enable_slot(struct hotplug_slot *slot); -static int disable_slot(struct hotplug_slot *slot); -static int set_attention_status(struct hotplug_slot *slot, u8 value); -static int get_power_status(struct hotplug_slot *slot, u8 * value); -static int get_attention_status(struct hotplug_slot *slot, u8 * value); -static int get_latch_status(struct hotplug_slot *slot, u8 * value); -static int get_adapter_status(struct hotplug_slot *slot, u8 * value); - -static struct hotplug_slot_ops cpci_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .hardware_test = NULL, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, -}; - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int -slot_paranoia_check(struct slot *slot, const char *function) -{ - if(!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if(slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if(!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot * -get_slot(struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if(!hotplug_slot) { - dbg("%s - hotplug_slot == NULL", function); - return NULL; - } - - slot = (struct slot *) hotplug_slot->private; - if(slot_paranoia_check(slot, function)) - return NULL; - return slot; -} - -static int -update_latch_status(struct hotplug_slot *hotplug_slot, u8 value) -{ - struct hotplug_slot_info info; - - if(!(hotplug_slot && hotplug_slot->info)) - return -EINVAL; - memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); - info.latch_status = value; - return pci_hp_change_slot_info(hotplug_slot, &info); -} - -static int -update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value) -{ - struct hotplug_slot_info info; - - if(!(hotplug_slot && hotplug_slot->info)) - return -EINVAL; - memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); - info.adapter_status = value; - return pci_hp_change_slot_info(hotplug_slot, &info); -} - -static int -enable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if(slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); - - if(controller->ops->set_power) { - retval = controller->ops->set_power(slot, 1); - } - - return retval; -} - -static int -disable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if(slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); - - /* Unconfigure device */ - dbg("%s - unconfiguring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if((retval = cpci_unconfigure_slot(slot))) { - err("%s - could not unconfigure slot %s", - __FUNCTION__, slot->hotplug_slot->name); - return retval; - } - dbg("%s - finished unconfiguring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - - /* Clear EXT (by setting it) */ - if(cpci_clear_ext(slot)) { - err("%s - could not clear EXT for slot %s", - __FUNCTION__, slot->hotplug_slot->name); - retval = -ENODEV; - } - cpci_led_on(slot); - - if(controller->ops->set_power) { - retval = controller->ops->set_power(slot, 0); - } - - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - - slot->extracting = 0; - - return retval; -} - -static u8 -cpci_get_power_status(struct slot *slot) -{ - u8 power = 1; - - if(controller->ops->get_power) { - power = controller->ops->get_power(slot); - } - return power; -} - -static int -get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if(slot == NULL) - return -ENODEV; - *value = cpci_get_power_status(slot); - return 0; -} - -static int -get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if(slot == NULL) - return -ENODEV; - *value = cpci_get_attention_status(slot); - return 0; -} - -static int -set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if(slot == NULL) - return -ENODEV; - switch (status) { - case 0: - cpci_set_attention_status(slot, 0); - break; - - case 1: - default: - cpci_set_attention_status(slot, 1); - break; - } - - return 0; -} - -static int -get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - if(hotplug_slot == NULL || hotplug_slot->info == NULL) - return -ENODEV; - *value = hotplug_slot->info->latch_status; - return 0; -} - -static int -get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - if(hotplug_slot == NULL || hotplug_slot->info == NULL) - return -ENODEV; - *value = hotplug_slot->info->adapter_status; - return 0; -} - -#define SLOT_NAME_SIZE 6 -static void -make_slot_name(struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, - SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); -} - -int -cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) -{ - struct slot *slot; - struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; - char *name; - int status = 0; - int i; - - if(!(controller && bus)) { - return -ENODEV; - } - if(last < first) { - return -EINVAL; - } - - /* - * Create a structure for each slot, and register that slot - * with the pci_hotplug subsystem. - */ - for (i = first; i <= last; ++i) { - slot = kmalloc(sizeof (struct slot), GFP_KERNEL); - if(!slot) - return -ENOMEM; - memset(slot, 0, sizeof (struct slot)); - - hotplug_slot = - kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); - if(!hotplug_slot) { - kfree(slot); - return -ENOMEM; - } - memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); - slot->hotplug_slot = hotplug_slot; - - info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL); - if(!info) { - kfree(hotplug_slot); - kfree(slot); - return -ENOMEM; - } - memset(info, 0, sizeof (struct hotplug_slot_info)); - hotplug_slot->info = info; - - name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if(!name) { - kfree(info); - kfree(hotplug_slot); - kfree(slot); - return -ENOMEM; - } - hotplug_slot->name = name; - - slot->magic = SLOT_MAGIC; - slot->bus = bus; - slot->number = i; - slot->devfn = PCI_DEVFN(i, 0); - - hotplug_slot->private = slot; - make_slot_name(slot); - hotplug_slot->ops = &cpci_hotplug_slot_ops; - - /* - * Initialize the slot info structure with some known - * good values. - */ - dbg("initializing slot %s", slot->hotplug_slot->name); - info->power_status = cpci_get_power_status(slot); - info->attention_status = cpci_get_attention_status(slot); - - dbg("registering slot %s", slot->hotplug_slot->name); - status = pci_hp_register(slot->hotplug_slot); - if(status) { - err("pci_hp_register failed with error %d", status); - kfree(info); - kfree(name); - kfree(hotplug_slot); - kfree(slot); - return status; - } - - /* Add slot to our internal list */ - spin_lock(&list_lock); - list_add(&slot->slot_list, &slot_list); - slots++; - spin_unlock(&list_lock); - } - return status; -} - -int -cpci_hp_unregister_bus(struct pci_bus *bus) -{ - struct slot *slot; - struct list_head *tmp; - int status; - - if(!bus) { - return -ENODEV; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return -1; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus) { - dbg("deregistering slot %s", slot->hotplug_slot->name); - status = pci_hp_deregister(slot->hotplug_slot); - if(status) { - err("pci_hp_deregister failed with error %d", - status); - return status; - } - - list_del(&slot->slot_list); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - - slots--; - } - } - spin_unlock(&list_lock); - return 0; -} - -struct slot * -cpci_find_slot(struct pci_bus *bus, unsigned int devfn) -{ - struct slot *slot; - struct slot *found; - struct list_head *tmp; - - if(!bus) { - return NULL; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return NULL; - } - found = NULL; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus && slot->devfn == devfn) { - found = slot; - break; - } - } - spin_unlock(&list_lock); - return found; -} - -/* This is the interrupt mode interrupt handler */ -irqreturn_t -cpci_hp_intr(int irq, void *data, struct pt_regs *regs) -{ - dbg("entered cpci_hp_intr"); - - /* Check to see if it was our interrupt */ - if((controller->irq_flags & SA_SHIRQ) && - !controller->ops->check_irq(controller->dev_id)) { - dbg("exited cpci_hp_intr, not our interrupt"); - return IRQ_NONE; - } - - /* Disable ENUM interrupt */ - controller->ops->disable_irq(); - - /* Trigger processing by the event thread */ - dbg("Signal event_semaphore"); - up(&event_semaphore); - dbg("exited cpci_hp_intr"); - return IRQ_HANDLED; -} - -/* - * According to PICMG 2.12 R2.0, section 6.3.2, upon - * initialization, the system driver shall clear the - * INS bits of the cold-inserted devices. - */ -static int -init_slots(void) -{ - struct slot *slot; - struct list_head *tmp; - struct pci_dev* dev; - - dbg("%s - enter", __FUNCTION__); - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return -1; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - dbg("%s - looking at slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { - dbg("%s - cleared INS for slot %s", - __FUNCTION__, slot->hotplug_slot->name); - dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); - if(dev) { - if(update_adapter_status(slot->hotplug_slot, 1)) { - warn("failure to update adapter file"); - } - if(update_latch_status(slot->hotplug_slot, 1)) { - warn("failure to update latch file"); - } - slot->dev = dev; - } else { - err("%s - no driver attached to device in slot %s", - __FUNCTION__, slot->hotplug_slot->name); - } - } - } - spin_unlock(&list_lock); - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int -check_slots(void) -{ - struct slot *slot; - struct list_head *tmp; - int extracted; - int inserted; - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - err("no slots registered, shutting down"); - return -1; - } - extracted = inserted = 0; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - dbg("%s - looking at slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { - u16 hs_csr; - - /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ - if(slot->dev) { - warn("slot %s already inserted", slot->hotplug_slot->name); - inserted++; - continue; - } - - /* Process insertion */ - dbg("%s - slot %s inserted", - __FUNCTION__, slot->hotplug_slot->name); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR (1) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - /* Configure device */ - dbg("%s - configuring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if(cpci_configure_slot(slot)) { - err("%s - could not configure slot %s", - __FUNCTION__, slot->hotplug_slot->name); - continue; - } - dbg("%s - finished configuring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR (2) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - if(update_latch_status(slot->hotplug_slot, 1)) { - warn("failure to update latch file"); - } - - if(update_adapter_status(slot->hotplug_slot, 1)) { - warn("failure to update adapter file"); - } - - cpci_led_off(slot); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR (3) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - inserted++; - } else if(cpci_check_ext(slot)) { - u16 hs_csr; - - /* Process extraction request */ - dbg("%s - slot %s extracted", - __FUNCTION__, slot->hotplug_slot->name); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - if(!slot->extracting) { - if(update_latch_status(slot->hotplug_slot, 0)) { - warn("failure to update latch file"); - } - slot->extracting = 1; - } - extracted++; - } - } - spin_unlock(&list_lock); - if(inserted || extracted) { - return extracted; - } - else { - err("cannot find ENUM# source, shutting down"); - return -1; - } -} - -/* This is the interrupt mode worker thread body */ -static int -event_thread(void *data) -{ - int rc; - struct slot *slot; - struct list_head *tmp; - - lock_kernel(); - daemonize("cpci_hp_eventd"); - unlock_kernel(); - - dbg("%s - event thread started", __FUNCTION__); - while(1) { - dbg("event thread sleeping"); - down_interruptible(&event_semaphore); - dbg("event thread woken, thread_finished = %d", - thread_finished); - if(thread_finished || signal_pending(current)) - break; - while(controller->ops->query_enum()) { - rc = check_slots(); - if(rc > 0) { - /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); - thread_finished = 1; - break; - } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - slot->extracting = 0; - } - } - - /* Re-enable ENUM# interrupt */ - dbg("%s - re-enabling irq", __FUNCTION__); - controller->ops->enable_irq(); - } - - dbg("%s - event thread signals exit", __FUNCTION__); - up(&thread_exit); - return 0; -} - -/* This is the polling mode worker thread body */ -static int -poll_thread(void *data) -{ - int rc; - struct slot *slot; - struct list_head *tmp; - - lock_kernel(); - daemonize("cpci_hp_polld"); - unlock_kernel(); - - while(1) { - if(thread_finished || signal_pending(current)) - break; - - while(controller->ops->query_enum()) { - rc = check_slots(); - if(rc > 0) { - /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); - thread_finished = 1; - break; - } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - slot->extracting = 0; - } - } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); - } - dbg("poll thread signals exit"); - up(&thread_exit); - return 0; -} - -static int -cpci_start_thread(void) -{ - int pid; - - /* initialize our semaphores */ - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&thread_exit); - thread_finished = 0; - - if(controller->irq) { - pid = kernel_thread(event_thread, 0, 0); - } else { - pid = kernel_thread(poll_thread, 0, 0); - } - if(pid < 0) { - err("Can't start up our thread"); - return -1; - } - dbg("Our thread pid = %d", pid); - return 0; -} - -static void -cpci_stop_thread(void) -{ - thread_finished = 1; - dbg("thread finish command given"); - if(controller->irq) { - up(&event_semaphore); - } - dbg("wait for thread to exit"); - down(&thread_exit); -} - -int -cpci_hp_register_controller(struct cpci_hp_controller *new_controller) -{ - int status = 0; - - if(!controller) { - controller = new_controller; - if(controller->irq) { - if(request_irq(controller->irq, - cpci_hp_intr, - controller->irq_flags, - MY_NAME, controller->dev_id)) { - err("Can't get irq %d for the hotplug cPCI controller", controller->irq); - status = -ENODEV; - } - dbg("%s - acquired controller irq %d", __FUNCTION__, - controller->irq); - } - } else { - err("cPCI hotplug controller already registered"); - status = -1; - } - return status; -} - -int -cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) -{ - int status = 0; - - if(controller) { - if(!thread_finished) { - cpci_stop_thread(); - } - if(controller->irq) { - free_irq(controller->irq, controller->dev_id); - } - controller = NULL; - } else { - status = -ENODEV; - } - return status; -} - -int -cpci_hp_start(void) -{ - static int first = 1; - int status; - - dbg("%s - enter", __FUNCTION__); - if(!controller) { - return -ENODEV; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return -ENODEV; - } - spin_unlock(&list_lock); - - if(first) { - status = init_slots(); - if(status) { - return status; - } - first = 0; - } - - status = cpci_start_thread(); - if(status) { - return status; - } - dbg("%s - thread started", __FUNCTION__); - - if(controller->irq) { - /* Start enum interrupt processing */ - dbg("%s - enabling irq", __FUNCTION__); - controller->ops->enable_irq(); - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -int -cpci_hp_stop(void) -{ - if(!controller) { - return -ENODEV; - } - - if(controller->irq) { - /* Stop enum interrupt processing */ - dbg("%s - disabling irq", __FUNCTION__); - controller->ops->disable_irq(); - } - cpci_stop_thread(); - return 0; -} - -static void __exit -cleanup_slots(void) -{ - struct list_head *tmp; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem, - * and free up all memory that we had allocated. - */ - spin_lock(&list_lock); - if(!slots) { - goto null_cleanup; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - } - null_cleanup: - spin_unlock(&list_lock); - return; -} - -int __init -cpci_hotplug_init(int debug) -{ - spin_lock_init(&list_lock); - cpci_debug = debug; - - info(DRIVER_DESC " version: " DRIVER_VERSION); - return 0; -} - -void __exit -cpci_hotplug_exit(void) -{ - /* - * Clean everything up. - */ - cleanup_slots(); -} - - -EXPORT_SYMBOL_GPL(cpci_hp_register_controller); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); -EXPORT_SYMBOL_GPL(cpci_hp_register_bus); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); -EXPORT_SYMBOL_GPL(cpci_find_slot); -EXPORT_SYMBOL_GPL(cpci_hp_start); -EXPORT_SYMBOL_GPL(cpci_hp_stop); diff -urN linux-2.5.70-bk9/drivers/hotplug/cpci_hotplug_pci.c linux-2.5.70-bk10/drivers/hotplug/cpci_hotplug_pci.c --- linux-2.5.70-bk9/drivers/hotplug/cpci_hotplug_pci.c 2003-05-26 18:00:42.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpci_hotplug_pci.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,647 +0,0 @@ -/* - * CompactPCI Hot Plug Driver PCI functions - * - * Copyright (c) 2002 by SOMA Networks, Inc. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ - -#include -#include -#include -#include -#include -#include "pci_hotplug.h" -#include "cpci_hotplug.h" - -#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) -#define MY_NAME "cpci_hotplug" -#else -#define MY_NAME THIS_MODULE->name -#endif - -extern int cpci_debug; - -#define dbg(format, arg...) \ - do { \ - if(cpci_debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) - - -u8 cpci_get_attention_status(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - return hs_csr & 0x0008 ? 1 : 0; -} - -int cpci_set_attention_status(struct slot* slot, int status) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - if(status) { - hs_csr |= HS_CSR_LOO; - } else { - hs_csr &= ~HS_CSR_LOO; - } - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return 0; - } - return 1; -} - -u16 cpci_get_hs_csr(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0xFFFF; - } - - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0xFFFF; - } - return hs_csr; -} - -u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr) -{ - int hs_cap; - u16 new_hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0xFFFF; - } - - /* Write out the new value */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return 0xFFFF; - } - - /* Read back what we just wrote out */ - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &new_hs_csr)) { - return 0xFFFF; - } - return new_hs_csr; -} - -int cpci_check_and_clear_ins(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - int ins = 0; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - if(hs_csr & HS_CSR_INS) { - /* Clear INS (by setting it) */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - ins = 0; - } - ins = 1; - } - return ins; -} - -int cpci_check_ext(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - int ext = 0; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - if(hs_csr & HS_CSR_EXT) { - ext = 1; - } - return ext; -} - -int cpci_clear_ext(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return -ENODEV; - } - if(hs_csr & HS_CSR_EXT) { - /* Clear EXT (by setting it) */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return -ENODEV; - } - } - return 0; -} - -int cpci_led_on(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return -ENODEV; - } - if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { - /* Set LOO */ - hs_csr |= HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - err("Could not set LOO for slot %s", - slot->hotplug_slot->name); - return -ENODEV; - } - } - return 0; -} - -int cpci_led_off(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return -ENODEV; - } - if(hs_csr & HS_CSR_LOO) { - /* Clear LOO */ - hs_csr &= ~HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - err("Could not clear LOO for slot %s", - slot->hotplug_slot->name); - return -ENODEV; - } - } - return 0; -} - - -/* - * Device configuration functions - */ - -static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) -{ - u8 irq_pin; - int r; - - dbg("%s - enter", __FUNCTION__); - - /* NOTE: device already setup from prior scan */ - - /* FIXME: How would we know if we need to enable the expansion ROM? */ - pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L); - - /* Assign resources */ - dbg("assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - for (r = 0; r < 6; r++) { - struct resource *res = dev->resource + r; - if(res->flags) - pci_assign_resource(dev, r); - } - dbg("finished assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - - /* Does this function have an interrupt at all? */ - dbg("checking for function interrupt"); - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); - if(irq_pin) { - dbg("function uses interrupt pin %d", irq_pin); - } - - /* - * Need to explicitly set irq field to 0 so that it'll get assigned - * by the pcibios platform dependent code called by pci_enable_device. - */ - dev->irq = 0; - - dbg("enabling device"); - pci_enable_device(dev); /* XXX check return */ - dbg("now dev->irq = %d", dev->irq); - if(irq_pin && dev->irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - - /* Can't use pci_insert_device at the moment, do it manually for now */ - pci_proc_attach_device(dev); - dbg("notifying drivers"); - //pci_announce_device_to_drivers(dev); - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) -{ - int rc; - struct pci_bus* child; - struct resource* r; - u8 max, n; - u16 command; - - dbg("%s - enter", __FUNCTION__); - - /* Do basic bridge initialization */ - rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); - if(rc) { - printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__); - } - - /* - * Set parent bridge's subordinate field so that configuration space - * access will work in pci_scan_bridge and friends. - */ - max = pci_max_busnr(); - bus->subordinate = max + 1; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1); - - /* Scan behind bridge */ - n = pci_scan_bridge(bus, dev, max, 2); - child = pci_find_bus(max + 1); - if (!child) - return -ENODEV; -#ifdef CONFIG_PROC_FS - pci_proc_attach_bus(child); -#endif - /* - * Update parent bridge's subordinate field if there were more bridges - * behind the bridge that was scanned. - */ - if(n > max) { - bus->subordinate = n; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n); - } - - /* - * Update the bridge resources of the bridge to accommodate devices - * behind it. - */ - pci_bus_size_bridges(child); - pci_bus_assign_resources(child); - - /* Enable resource mapping via command register */ - command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - r = child->resource[0]; - if(r && r->start) { - command |= PCI_COMMAND_IO; - } - r = child->resource[1]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - r = child->resource[2]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - rc = pci_write_config_word(dev, PCI_COMMAND, command); - if(rc) { - err("Error setting command register"); - return rc; - } - - /* Set bridge control register */ - command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA; - rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command); - if(rc) { - err("Error setting bridge control register"); - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - int rc; - struct pci_dev *dev = wrapped_dev->dev; - struct pci_bus *bus = wrapped_bus->bus; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - - /* - * We need to fix up the hotplug representation with the Linux - * representation. - */ - slot = cpci_find_slot(dev->bus, dev->devfn); - if(slot) { - slot->dev = dev; - } - - /* If it's a bridge, scan behind it for devices */ - if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - rc = cpci_configure_bridge(bus, dev); - if(rc) - return rc; - } - - /* Actually configure device */ - if(dev) { - rc = cpci_configure_dev(bus, dev); - if(rc) - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - struct pci_dev *dev = wrapped_dev->dev; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - if(!dev) - return -ENODEV; - - /* Remove the Linux representation */ - if(pci_remove_device_safe(dev) == 0) { - kfree(dev); - } else { - err("Could not remove device\n"); - return -1; - } - - /* - * Now remove the hotplug representation. - */ - slot = cpci_find_slot(dev->bus, dev->devfn); - if(slot) { - slot->dev = NULL; - } else { - dbg("No hotplug representation for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus, - struct pci_dev_wrapped *wrapped_dev) -{ - struct pci_bus *bus = wrapped_bus->bus; - struct pci_bus *parent = bus->self->bus; - - dbg("%s - enter", __FUNCTION__); - - /* The cleanup code for proc entries regarding buses should be in the kernel... */ - if(bus->procdir) - dbg("detach_pci_bus %s", bus->procdir->name); - pci_proc_detach_bus(bus); - - /* The cleanup code should live in the kernel... */ - bus->self->subordinate = NULL; - - /* unlink from parent bus */ - list_del(&bus->node); - - /* Now, remove */ - if(bus) - kfree(bus); - - /* Update parent's subordinate field */ - if(parent) { - u8 n = pci_bus_max_busnr(parent); - if(n < parent->subordinate) { - parent->subordinate = n; - pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n); - } - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static struct pci_visit configure_functions = { - .visit_pci_dev = configure_visit_pci_dev, -}; - -static struct pci_visit unconfigure_functions_phase2 = { - .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, - .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 -}; - - -int cpci_configure_slot(struct slot* slot) -{ - int rc = 0; - - dbg("%s - enter", __FUNCTION__); - - if(slot->dev == NULL) { - dbg("pci_dev null, finding %02x:%02x:%x", - slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); - slot->dev = pci_find_slot(slot->bus->number, slot->devfn); - } - - /* Still NULL? Well then scan for it! */ - if(slot->dev == NULL) { - dbg("pci_dev still null"); - - /* - * This will generate pci_dev structures for all functions, but - * we will only call this case when lookup fails. - */ - slot->dev = pci_scan_slot(slot->bus, slot->devfn); - if(slot->dev == NULL) { - err("Could not find PCI device for slot %02x", slot->number); - return 0; - } - } - dbg("slot->dev = %p", slot->dev); - if(slot->dev) { - struct pci_dev *dev; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; - int i; - - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - - for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, - PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i)); - if(!dev) - continue; - wrapped_dev.dev = dev; - wrapped_bus.bus = slot->dev->bus; - rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); - } - } - - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; -} - -int cpci_unconfigure_slot(struct slot* slot) -{ - int rc = 0; - int i; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; - struct pci_dev *dev; - - dbg("%s - enter", __FUNCTION__); - - if(!slot->dev) { - err("No device for slot %02x\n", slot->number); - return -ENODEV; - } - - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - - for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, - PCI_DEVFN(PCI_SLOT(slot->devfn), i)); - if(dev) { - wrapped_dev.dev = dev; - wrapped_bus.bus = dev->bus; - dbg("%s - unconfigure phase 2", __FUNCTION__); - rc = pci_visit_dev(&unconfigure_functions_phase2, - &wrapped_dev, &wrapped_bus); - if(rc) - break; - } - } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; -} diff -urN linux-2.5.70-bk9/drivers/hotplug/cpcihp_generic.c linux-2.5.70-bk10/drivers/hotplug/cpcihp_generic.c --- linux-2.5.70-bk9/drivers/hotplug/cpcihp_generic.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpcihp_generic.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,290 +0,0 @@ -/* - * cpcihp_generic.c - * - * Generic port I/O CompactPCI driver - * - * Copyright 2002 SOMA Networks, Inc. - * Copyright 2001 Intel San Luis Obispo - * Copyright 2000,2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This generic CompactPCI hotplug driver should allow using the PCI hotplug - * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit - * in a system register that can be read through standard port I/O. - * - * Send feedback to - */ - -#include -#include -#include -#include -#include -#include "cpci_hotplug.h" - -#define DRIVER_VERSION "0.1" -#define DRIVER_AUTHOR "Scott Murray " -#define DRIVER_DESC "Generic port I/O CompactPCI Hot Plug Driver" - -#if !defined(CONFIG_HOTPLUG_CPCI_GENERIC_MODULE) -#define MY_NAME "cpcihp_generic" -#else -#define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if(debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -/* local variables */ -static int debug; -static char* bridge; -static u8 bridge_busnr; -static u8 bridge_slot; -static struct pci_bus *bus; -static u8 first_slot; -static u8 last_slot; -static u16 port; -static unsigned int enum_bit; -static u8 enum_mask; - -static struct cpci_hp_controller_ops generic_hpc_ops; -static struct cpci_hp_controller generic_hpc; - -/* The following allows configuring the driver when it's compiled into the kernel */ -#ifndef MODULE -static int __init cpcihp_generic_setup(char* str) -{ - char* p; - unsigned long tmp; - - if(!str) - return -EINVAL; - bridge = str; - - p = strchr(str, ','); - str = p + 1; - if(!(p && *str && *p == ',')) - goto setup_error; - tmp = simple_strtoul(str, &p, 0); - if(p == str || tmp > 0xff) { - err("hotplug bus first slot number out of range"); - goto setup_error; - } - first_slot = (u8) tmp; - - str = p + 1; - if(!(*str && *p == ',')) - return -EINVAL; - tmp = simple_strtoul(str, &p, 0); - if(p == str || tmp > 0xff) { - err("hotplug bus last slot number out of range"); - goto setup_error; - } - last_slot = (u8) tmp; - - str = p + 1; - if(!(*str && *p == ',')) - goto setup_error; - tmp = simple_strtoul(str, &p, 0); - if(p == str || tmp > 0xffff) { - err("port number out of range"); - goto setup_error; - } - port = (u16) tmp; - - str = p + 1; - if(!(*str && *p == ',')) - goto setup_error; - tmp = simple_strtoul(str, &p, 0); - if(p == str) { - err("invalid #ENUM bit number"); - goto setup_error; - } - enum_bit = (u8) tmp; - - str = p + 1; - if(*str && *p == ',') { - tmp = simple_strtoul(str, &p, 0); - if(p != str) - debug = (int) tmp; - } - return 0; -setup_error: - bridge = NULL; - return -EINVAL; -} - -__setup("cpcihp_generic=", cpcihp_generic_setup); -#endif - -static int __init validate_parameters(void) -{ - char* str; - char* p; - unsigned long tmp; - - if(!bridge) { - info("not configured, disabling."); - return 1; - } - str = bridge; - if(!*str) - return -EINVAL; - - tmp = simple_strtoul(str, &p, 16); - if(p == str || tmp > 0xff) { - err("Invalid hotplug bus bridge device bus number"); - return -EINVAL; - } - bridge_busnr = (u8) tmp; - dbg("bridge_busnr = 0x%02x", bridge_busnr); - if(*p != ':') { - err("Invalid hotplug bus bridge device"); - return -EINVAL; - } - str = p + 1; - tmp = simple_strtoul(str, &p, 16); - if(p == str || tmp > 0x1f) { - err("Invalid hotplug bus bridge device slot number"); - return -EINVAL; - } - bridge_slot = (u8) tmp; - dbg("bridge_slot = 0x%02x", bridge_slot); - - dbg("first_slot = 0x%02x", first_slot); - dbg("last_slot = 0x%02x", last_slot); - if(!(first_slot && last_slot)) { - err("Need to specify first_slot and last_slot"); - return -EINVAL; - } - if(last_slot < first_slot) { - err("first_slot must be less than last_slot"); - return -EINVAL; - } - - dbg("port = 0x%04x", port); - dbg("enum_bit = 0x%02x", enum_bit); - if(enum_bit > 7) { - err("Invalid #ENUM bit"); - return -EINVAL; - } - enum_mask = 1 << enum_bit; - return 0; -} - -static int query_enum(void) -{ - u8 value; - - value = inb_p(port); - return ((value & enum_mask) == enum_mask); -} - -static int __init cpcihp_generic_init(void) -{ - int status; - struct resource* r; - struct pci_dev* dev; - - info(DRIVER_DESC " version: " DRIVER_VERSION); - status = validate_parameters(); - if(status != 0) - return status; - - r = request_region(port, 1, "#ENUM hotswap signal register"); - if(!r) - return -EBUSY; - - dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0)); - if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { - err("Invalid bridge device %s", bridge); - return -EINVAL; - } - bus = dev->subordinate; - - memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller)); - generic_hpc_ops.query_enum = query_enum; - generic_hpc.ops = &generic_hpc_ops; - - status = cpci_hp_register_controller(&generic_hpc); - if(status != 0) { - err("Could not register cPCI hotplug controller"); - return -ENODEV; - } - dbg("registered controller"); - - status = cpci_hp_register_bus(bus, first_slot, last_slot); - if(status != 0) { - err("Could not register cPCI hotplug bus"); - goto init_bus_register_error; - } - dbg("registered bus"); - - status = cpci_hp_start(); - if(status != 0) { - err("Could not started cPCI hotplug system"); - goto init_start_error; - } - dbg("started cpci hp system"); - return 0; -init_start_error: - cpci_hp_unregister_bus(bus); -init_bus_register_error: - cpci_hp_unregister_controller(&generic_hpc); - err("status = %d", status); - return status; - -} - -static void __exit cpcihp_generic_exit(void) -{ - cpci_hp_stop(); - cpci_hp_unregister_bus(bus); - cpci_hp_unregister_controller(&generic_hpc); - release_region(port, 1); -} - -module_init(cpcihp_generic_init); -module_exit(cpcihp_generic_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -MODULE_PARM(bridge, "s"); -MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, : (bus and slot are in hexadecimal)"); -MODULE_PARM(first_slot, "b"); -MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number"); -MODULE_PARM(last_slot, "b"); -MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number"); -MODULE_PARM(port, "h"); -MODULE_PARM_DESC(port, "#ENUM signal I/O port"); -MODULE_PARM(enum_bit, "i"); -MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)"); diff -urN linux-2.5.70-bk9/drivers/hotplug/cpcihp_zt5550.c linux-2.5.70-bk10/drivers/hotplug/cpcihp_zt5550.c --- linux-2.5.70-bk9/drivers/hotplug/cpcihp_zt5550.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpcihp_zt5550.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,306 +0,0 @@ -/* - * cpcihp_zt5550.c - * - * Intel/Ziatech ZT5550 CompactPCI Host Controller driver - * - * Copyright 2002 SOMA Networks, Inc. - * Copyright 2001 Intel San Luis Obispo - * Copyright 2000,2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ - -#include -#include -#include -#include -#include -#include "cpci_hotplug.h" -#include "cpcihp_zt5550.h" - -#define DRIVER_VERSION "0.2" -#define DRIVER_AUTHOR "Scott Murray " -#define DRIVER_DESC "ZT5550 CompactPCI Hot Plug Driver" - -#if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE) -#define MY_NAME "cpcihp_zt5550" -#else -#define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if(debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -/* local variables */ -static int debug; -static int poll; -static struct cpci_hp_controller_ops zt5550_hpc_ops; -static struct cpci_hp_controller zt5550_hpc; - -/* Primary cPCI bus bridge device */ -static struct pci_dev *bus0_dev; -static struct pci_bus *bus0; - -/* Host controller device */ -static struct pci_dev *hc_dev; - -/* Host controller register addresses */ -static void *hc_registers; -static void *csr_hc_index; -static void *csr_hc_data; -static void *csr_int_status; -static void *csr_int_mask; - - -static int zt5550_hc_config(struct pci_dev *pdev) -{ - /* Since we know that no boards exist with two HC chips, treat it as an error */ - if(hc_dev) { - err("too many host controller devices?"); - return -EBUSY; - } - hc_dev = pdev; - dbg("hc_dev = %p", hc_dev); - dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); - dbg("pci resource len %lx", pci_resource_len(hc_dev, 1)); - - if(!request_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1), MY_NAME)) { - err("cannot reserve MMIO region"); - return -ENOMEM; - } - - hc_registers = - ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); - if(!hc_registers) { - err("cannot remap MMIO region %lx @ %lx", - pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); - release_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1)); - return -ENODEV; - } - - csr_hc_index = hc_registers + CSR_HCINDEX; - csr_hc_data = hc_registers + CSR_HCDATA; - csr_int_status = hc_registers + CSR_INTSTAT; - csr_int_mask = hc_registers + CSR_INTMASK; - - /* - * Disable host control, fault and serial interrupts - */ - dbg("disabling host control, fault and serial interrupts"); - writeb((u8) HC_INT_MASK_REG, csr_hc_index); - writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data); - dbg("disabled host control, fault and serial interrupts"); - - /* - * Disable timer0, timer1 and ENUM interrupts - */ - dbg("disabling timer0, timer1 and ENUM interrupts"); - writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); - dbg("disabled timer0, timer1 and ENUM interrupts"); - return 0; -} - -static int zt5550_hc_cleanup(void) -{ - if(!hc_dev) - return -ENODEV; - release_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1)); - return 0; -} - -static int zt5550_hc_query_enum(void) -{ - u8 value; - - value = inb_p(ENUM_PORT); - return ((value & ENUM_MASK) == ENUM_MASK); -} - -static int zt5550_hc_check_irq(void *dev_id) -{ - int ret; - u8 reg; - - ret = 0; - if(dev_id == zt5550_hpc.dev_id) { - reg = readb(csr_int_status); - if(reg) - ret = 1; - } - return ret; -} - -static int zt5550_hc_enable_irq(void) -{ - u8 reg; - - if(hc_dev == NULL) { - return -ENODEV; - } - reg = readb(csr_int_mask); - reg = reg & ~ENUM_INT_MASK; - writeb(reg, csr_int_mask); - return 0; -} - -int zt5550_hc_disable_irq(void) -{ - u8 reg; - - if(hc_dev == NULL) { - return -ENODEV; - } - - reg = readb(csr_int_mask); - reg = reg | ENUM_INT_MASK; - writeb(reg, csr_int_mask); - return 0; -} - -static int __devinit zt5550_hc_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int status; - - status = zt5550_hc_config(pdev); - if(status != 0) { - return status; - } - dbg("returned from zt5550_hc_config"); - - memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); - zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; - zt5550_hpc.ops = &zt5550_hpc_ops; - if(!poll) { - zt5550_hpc.irq = hc_dev->irq; - zt5550_hpc.irq_flags = SA_SHIRQ; - zt5550_hpc.dev_id = hc_dev; - - zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; - zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; - zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; - } else { - info("using ENUM# polling mode"); - } - - status = cpci_hp_register_controller(&zt5550_hpc); - if(status != 0) { - err("could not register cPCI hotplug controller"); - goto init_hc_error; - } - dbg("registered controller"); - - /* Look for first device matching cPCI bus's bridge vendor and device IDs */ - if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC, - PCI_DEVICE_ID_DEC_21154, NULL))) { - status = -ENODEV; - goto init_register_error; - } - bus0 = bus0_dev->subordinate; - - status = cpci_hp_register_bus(bus0, 0x0a, 0x0f); - if(status != 0) { - err("could not register cPCI hotplug bus"); - goto init_register_error; - } - dbg("registered bus"); - - status = cpci_hp_start(); - if(status != 0) { - err("could not started cPCI hotplug system"); - cpci_hp_unregister_bus(bus0); - goto init_register_error; - } - dbg("started cpci hp system"); - - return 0; -init_register_error: - cpci_hp_unregister_controller(&zt5550_hpc); -init_hc_error: - err("status = %d", status); - zt5550_hc_cleanup(); - return status; - -} - -static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) -{ - cpci_hp_stop(); - cpci_hp_unregister_bus(bus0); - cpci_hp_unregister_controller(&zt5550_hpc); - zt5550_hc_cleanup(); -} - - -static struct pci_device_id zt5550_hc_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); - -static struct pci_driver zt5550_hc_driver = { - .name = "zt5550_hc", - .id_table = zt5550_hc_pci_tbl, - .probe = zt5550_hc_init_one, - .remove = __devexit_p(zt5550_hc_remove_one), -}; - -static int __init zt5550_init(void) -{ - struct resource* r; - - info(DRIVER_DESC " version: " DRIVER_VERSION); - r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); - if(!r) - return -EBUSY; - - return pci_module_init(&zt5550_hc_driver); -} - -static void __exit -zt5550_exit(void) -{ - pci_unregister_driver(&zt5550_hc_driver); - release_region(ENUM_PORT, 1); -} - -module_init(zt5550_init); -module_exit(zt5550_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -MODULE_PARM(poll, "i"); -MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); diff -urN linux-2.5.70-bk9/drivers/hotplug/cpcihp_zt5550.h linux-2.5.70-bk10/drivers/hotplug/cpcihp_zt5550.h --- linux-2.5.70-bk9/drivers/hotplug/cpcihp_zt5550.h 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpcihp_zt5550.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,79 +0,0 @@ -/* - * cpcihp_zt5550.h - * - * Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions - * - * Copyright 2002 SOMA Networks, Inc. - * Copyright 2001 Intel San Luis Obispo - * Copyright 2000,2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ - -#ifndef _CPCIHP_ZT5550_H -#define _CPCIHP_ZT5550_H - -/* Direct registers */ -#define CSR_HCINDEX 0x00 -#define CSR_HCDATA 0x04 -#define CSR_INTSTAT 0x08 -#define CSR_INTMASK 0x09 -#define CSR_CNT0CMD 0x0C -#define CSR_CNT1CMD 0x0E -#define CSR_CNT0 0x10 -#define CSR_CNT1 0x14 - -/* Masks for interrupt bits in CSR_INTMASK direct register */ -#define CNT0_INT_MASK 0x01 -#define CNT1_INT_MASK 0x02 -#define ENUM_INT_MASK 0x04 -#define ALL_DIRECT_INTS_MASK 0x07 - -/* Indexed registers (through CSR_INDEX, CSR_DATA) */ -#define HC_INT_MASK_REG 0x04 -#define HC_STATUS_REG 0x08 -#define HC_CMD_REG 0x0C -#define ARB_CONFIG_GNT_REG 0x10 -#define ARB_CONFIG_CFG_REG 0x12 -#define ARB_CONFIG_REG 0x10 -#define ISOL_CONFIG_REG 0x18 -#define FAULT_STATUS_REG 0x20 -#define FAULT_CONFIG_REG 0x24 -#define WD_CONFIG_REG 0x2C -#define HC_DIAG_REG 0x30 -#define SERIAL_COMM_REG 0x34 -#define SERIAL_OUT_REG 0x38 -#define SERIAL_IN_REG 0x3C - -/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */ -#define SERIAL_INT_MASK 0x01 -#define FAULT_INT_MASK 0x02 -#define HCF_INT_MASK 0x04 -#define ALL_INDEXED_INTS_MASK 0x07 - -/* Digital I/O port storing ENUM# */ -#define ENUM_PORT 0xE1 -/* Mask to get to the ENUM# bit on the bus */ -#define ENUM_MASK 0x40 - -#endif /* _CPCIHP_ZT5550_H */ diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp.h linux-2.5.70-bk10/drivers/hotplug/cpqphp.h --- linux-2.5.70-bk9/drivers/hotplug/cpqphp.h 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,912 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ -#ifndef _CPQPHP_H -#define _CPQPHP_H - -#include "pci_hotplug.h" -#include -#include /* for read? and write? functions */ -#include /* for delays */ - -#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) - #define MY_NAME "cpqphp.o" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) - - - -struct smbios_system_slot { - u8 type; - u8 length; - u16 handle; - u8 name_string_num; - u8 slot_type; - u8 slot_width; - u8 slot_current_usage; - u8 slot_length; - u16 slot_number; - u8 properties1; - u8 properties2; -} __attribute__ ((packed)); - -/* offsets to the smbios generic type based on the above structure layout */ -enum smbios_system_slot_offsets { - SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), - SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), - SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), - SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), - SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), - SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), - SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), - SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), - SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), - SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), - SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), -}; - -struct smbios_generic { - u8 type; - u8 length; - u16 handle; -} __attribute__ ((packed)); - -/* offsets to the smbios generic type based on the above structure layout */ -enum smbios_generic_offsets { - SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), - SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), - SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), -}; - -struct smbios_entry_point { - char anchor[4]; - u8 ep_checksum; - u8 ep_length; - u8 major_version; - u8 minor_version; - u16 max_size_entry; - u8 ep_rev; - u8 reserved[5]; - char int_anchor[5]; - u8 int_checksum; - u16 st_length; - u32 st_address; - u16 number_of_entrys; - u8 bcd_rev; -} __attribute__ ((packed)); - -/* offsets to the smbios entry point based on the above structure layout */ -enum smbios_entry_point_offsets { - ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), - EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), - EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), - MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), - MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), - MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), - EP_REV = offsetof(struct smbios_entry_point, ep_rev), - INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), - INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), - ST_LENGTH = offsetof(struct smbios_entry_point, st_length), - ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), - NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), - BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), -}; - -struct ctrl_reg { /* offset */ - u8 slot_RST; /* 0x00 */ - u8 slot_enable; /* 0x01 */ - u16 misc; /* 0x02 */ - u32 led_control; /* 0x04 */ - u32 int_input_clear; /* 0x08 */ - u32 int_mask; /* 0x0a */ - u8 reserved0; /* 0x10 */ - u8 reserved1; /* 0x11 */ - u8 reserved2; /* 0x12 */ - u8 gen_output_AB; /* 0x13 */ - u32 non_int_input; /* 0x14 */ - u32 reserved3; /* 0x18 */ - u32 reserved4; /* 0x1a */ - u32 reserved5; /* 0x20 */ - u8 reserved6; /* 0x24 */ - u8 reserved7; /* 0x25 */ - u16 reserved8; /* 0x26 */ - u8 slot_mask; /* 0x28 */ - u8 reserved9; /* 0x29 */ - u8 reserved10; /* 0x2a */ - u8 reserved11; /* 0x2b */ - u8 slot_SERR; /* 0x2c */ - u8 slot_power; /* 0x2d */ - u8 reserved12; /* 0x2e */ - u8 reserved13; /* 0x2f */ - u8 next_curr_freq; /* 0x30 */ - u8 reset_freq_mode; /* 0x31 */ -} __attribute__ ((packed)); - -/* offsets to the controller registers based on the above structure layout */ -enum ctrl_offsets { - SLOT_RST = offsetof(struct ctrl_reg, slot_RST), - SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), - MISC = offsetof(struct ctrl_reg, misc), - LED_CONTROL = offsetof(struct ctrl_reg, led_control), - INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), - INT_MASK = offsetof(struct ctrl_reg, int_mask), - CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), - CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), - CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), - GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), - NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), - CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), - CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), - CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), - CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), - CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), - CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), - SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), - CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), - CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), - CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), - SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), - SLOT_POWER = offsetof(struct ctrl_reg, slot_power), - NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), - RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), -}; - -struct hrt { - char sig0; - char sig1; - char sig2; - char sig3; - u16 unused_IRQ; - u16 PCIIRQ; - u8 number_of_entries; - u8 revision; - u16 reserved1; - u32 reserved2; -} __attribute__ ((packed)); - -/* offsets to the hotplug resource table registers based on the above structure layout */ -enum hrt_offsets { - SIG0 = offsetof(struct hrt, sig0), - SIG1 = offsetof(struct hrt, sig1), - SIG2 = offsetof(struct hrt, sig2), - SIG3 = offsetof(struct hrt, sig3), - UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), - PCIIRQ = offsetof(struct hrt, PCIIRQ), - NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), - REVISION = offsetof(struct hrt, revision), - HRT_RESERVED1 = offsetof(struct hrt, reserved1), - HRT_RESERVED2 = offsetof(struct hrt, reserved2), -}; - -struct slot_rt { - u8 dev_func; - u8 primary_bus; - u8 secondary_bus; - u8 max_bus; - u16 io_base; - u16 io_length; - u16 mem_base; - u16 mem_length; - u16 pre_mem_base; - u16 pre_mem_length; -} __attribute__ ((packed)); - -/* offsets to the hotplug slot resource table registers based on the above structure layout */ -enum slot_rt_offsets { - DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), -}; - -struct pci_func { - struct pci_func *next; - u8 bus; - u8 device; - u8 function; - u8 is_a_board; - u16 status; - u8 configured; - u8 switch_save; - u8 presence_save; - u32 base_length[0x06]; - u8 base_type[0x06]; - u16 reserved2; - u32 config_space[0x20]; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct timer_list *p_task_event; - struct pci_dev* pci_dev; -}; - -#define SLOT_MAGIC 0x67267321 -struct slot { - u32 magic; - struct slot *next; - u8 bus; - u8 device; - u8 number; - u8 is_a_board; - u8 configured; - u8 state; - u8 switch_save; - u8 presence_save; - u32 capabilities; - u16 reserved2; - struct timer_list task_event; - u8 hp_slot; - struct controller *ctrl; - void *p_sm_slot; - struct hotplug_slot *hotplug_slot; -}; - -struct pci_resource { - struct pci_resource * next; - u32 base; - u32 length; -}; - -struct event_info { - u32 event_type; - u8 hp_slot; -}; - -struct controller { - struct controller *next; - u32 ctrl_int_comp; - struct semaphore crit_sect; /* critical section semaphore */ - void *hpc_reg; /* cookie for our pci controller location */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct pci_dev *pci_dev; - struct pci_bus *pci_bus; - struct event_info event_queue[10]; - struct slot *slot; - u8 next_event; - u8 interrupt; - u8 cfgspc_irq; - u8 bus; /* bus number for the pci hotplug controller */ - u8 rev; - u8 slot_device_offset; - u8 first_slot; - u8 add_support; - u8 push_flag; - enum pci_bus_speed speed; - enum pci_bus_speed speed_capability; - u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ - u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ - u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ - u8 alternate_base_address; /* 0 = not supported, 1 = supported */ - u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ - u8 pcix_speed_capability; /* PCI-X */ - u8 pcix_support; /* PCI-X */ - u16 vendor_id; - struct work_struct int_task_event; - wait_queue_head_t queue; /* sleep & wake process */ -}; - -struct irq_mapping { - u8 barber_pole; - u8 valid_INT; - u8 interrupt[4]; -}; - -struct resource_lists { - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct irq_mapping *irqs; -}; - -#define ROM_PHY_ADDR 0x0F0000 -#define ROM_PHY_LEN 0x00ffff - -#define PCI_HPC_ID 0xA0F7 -#define PCI_SUB_HPC_ID 0xA2F7 -#define PCI_SUB_HPC_ID2 0xA2F8 -#define PCI_SUB_HPC_ID3 0xA2F9 -#define PCI_SUB_HPC_ID_INTC 0xA2FA -#define PCI_SUB_HPC_ID4 0xA2FD - -#define INT_BUTTON_IGNORE 0 -#define INT_PRESENCE_ON 1 -#define INT_PRESENCE_OFF 2 -#define INT_SWITCH_CLOSE 3 -#define INT_SWITCH_OPEN 4 -#define INT_POWER_FAULT 5 -#define INT_POWER_FAULT_CLEAR 6 -#define INT_BUTTON_PRESS 7 -#define INT_BUTTON_RELEASE 8 -#define INT_BUTTON_CANCEL 9 - -#define STATIC_STATE 0 -#define BLINKINGON_STATE 1 -#define BLINKINGOFF_STATE 2 -#define POWERON_STATE 3 -#define POWEROFF_STATE 4 - -#define PCISLOT_INTERLOCK_CLOSED 0x00000001 -#define PCISLOT_ADAPTER_PRESENT 0x00000002 -#define PCISLOT_POWERED 0x00000004 -#define PCISLOT_66_MHZ_OPERATION 0x00000008 -#define PCISLOT_64_BIT_OPERATION 0x00000010 -#define PCISLOT_REPLACE_SUPPORTED 0x00000020 -#define PCISLOT_ADD_SUPPORTED 0x00000040 -#define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 -#define PCISLOT_66_MHZ_SUPPORTED 0x00000100 -#define PCISLOT_64_BIT_SUPPORTED 0x00000200 - - - -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - - -#define INTERLOCK_OPEN 0x00000002 -#define ADD_NOT_SUPPORTED 0x00000003 -#define CARD_FUNCTIONING 0x00000005 -#define ADAPTER_NOT_SAME 0x00000006 -#define NO_ADAPTER_PRESENT 0x00000009 -#define NOT_ENOUGH_RESOURCES 0x0000000B -#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C -#define POWER_FAILURE 0x0000000E - -#define REMOVE_NOT_SUPPORTED 0x00000003 - - -/* - * error Messages - */ -#define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" -#define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" -#define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" -#define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" -#define msg_button_on "PCI slot #%d - powering on due to button press.\n" -#define msg_button_off "PCI slot #%d - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" - - -/* sysfs functions for the hotplug controller info */ -extern void cpqhp_create_ctrl_files (struct controller *ctrl); - -/* controller functions */ -extern void cpqhp_pushbutton_thread (unsigned long event_pointer); -extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs); -extern int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start); -extern int cpqhp_event_start_thread (void); -extern void cpqhp_event_stop_thread (void); -extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); -extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); -extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); - -/* resource functions */ -extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); - -/* pci functions */ -extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); -extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); -extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); -extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); -extern void cpqhp_destroy_board_resources (struct pci_func * func); -extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); -extern void cpqhp_destroy_resource_list (struct resource_lists * resources); -extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); -extern int cpqhp_unconfigure_device (struct pci_func* func); -extern struct slot *cpqhp_find_slot (struct controller *ctrl, u8 device); - -/* Global variables */ -extern int cpqhp_debug; -extern struct controller *cpqhp_ctrl_list; -extern struct pci_func *cpqhp_slot_list[256]; - -/* these can be gotten rid of, but for debugging they are purty */ -extern u8 cpqhp_nic_irq; -extern u8 cpqhp_disk_irq; - - - -/* inline functions */ - - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check (slot, function)) - return NULL; - return slot; -} - -/* - * return_resource - * - * Puts node back in the resource list pointed to by head - * - */ -static inline void return_resource (struct pci_resource **head, struct pci_resource *node) -{ - if (!node || !head) - return; - node->next = *head; - *head = node; -} - -static inline void set_SOGO (struct controller *ctrl) -{ - u16 misc; - - misc = readw(ctrl->hpc_reg + MISC); - misc = (misc | 0x0001) & 0xFFFB; - writew(misc, ctrl->hpc_reg + MISC); -} - - -static inline void amber_LED_on (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control |= (0x01010000L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline void amber_LED_off (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= ~(0x01010000L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline int read_amber_LED (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= (0x01010000L << slot); - - return led_control ? 1 : 0; -} - - -static inline void green_LED_on (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control |= 0x0101L << slot; - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - -static inline void green_LED_off (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= ~(0x0101L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline void green_LED_blink (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= ~(0x0101L << slot); - led_control |= (0x0001L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline void slot_disable (struct controller *ctrl, u8 slot) -{ - u8 slot_enable; - - slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); - slot_enable &= ~(0x01 << slot); - writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); -} - - -static inline void slot_enable (struct controller *ctrl, u8 slot) -{ - u8 slot_enable; - - slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); - slot_enable |= (0x01 << slot); - writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); -} - - -static inline u8 is_slot_enabled (struct controller *ctrl, u8 slot) -{ - u8 slot_enable; - - slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); - slot_enable &= (0x01 << slot); - return slot_enable ? 1 : 0; -} - - -static inline u8 read_slot_enable (struct controller *ctrl) -{ - return readb(ctrl->hpc_reg + SLOT_ENABLE); -} - - -/* - * get_controller_speed - find the current frequency/mode of controller. - * - * @ctrl: controller to get frequency/mode for. - * - * Returns controller speed. - * - */ -static inline u8 get_controller_speed (struct controller *ctrl) -{ - u8 curr_freq; - u16 misc; - - if (ctrl->pcix_support) { - curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); - if ((curr_freq & 0xB0) == 0xB0) - return PCI_SPEED_133MHz_PCIX; - if ((curr_freq & 0xA0) == 0xA0) - return PCI_SPEED_100MHz_PCIX; - if ((curr_freq & 0x90) == 0x90) - return PCI_SPEED_66MHz_PCIX; - if (curr_freq & 0x10) - return PCI_SPEED_66MHz; - - return PCI_SPEED_33MHz; - } - - misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; -} - - -/* - * get_adapter_speed - find the max supported frequency/mode of adapter. - * - * @ctrl: hotplug controller. - * @hp_slot: hotplug slot where adapter is installed. - * - * Returns adapter speed. - * - */ -static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot) -{ - u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); - dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); - if (ctrl->pcix_support) { - if (temp_dword & (0x10000 << hp_slot)) - return PCI_SPEED_133MHz_PCIX; - if (temp_dword & (0x100 << hp_slot)) - return PCI_SPEED_66MHz_PCIX; - } - - if (temp_dword & (0x01 << hp_slot)) - return PCI_SPEED_66MHz; - - return PCI_SPEED_33MHz; -} - -static inline void enable_slot_power (struct controller *ctrl, u8 slot) -{ - u8 slot_power; - - slot_power = readb(ctrl->hpc_reg + SLOT_POWER); - slot_power |= (0x01 << slot); - writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); -} - -static inline void disable_slot_power (struct controller *ctrl, u8 slot) -{ - u8 slot_power; - - slot_power = readb(ctrl->hpc_reg + SLOT_POWER); - slot_power &= ~(0x01 << slot); - writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); -} - - -static inline int cpq_get_attention_status (struct controller *ctrl, struct slot *slot) -{ - u8 hp_slot; - - if (slot == NULL) - return 1; - - hp_slot = slot->device - ctrl->slot_device_offset; - - return read_amber_LED (ctrl, hp_slot); -} - - -static inline int get_slot_enabled (struct controller *ctrl, struct slot *slot) -{ - u8 hp_slot; - - if (slot == NULL) - return 1; - - hp_slot = slot->device - ctrl->slot_device_offset; - - return is_slot_enabled (ctrl, hp_slot); -} - - -static inline int cpq_get_latch_status (struct controller *ctrl, struct slot *slot) -{ - u32 status; - u8 hp_slot; - - if (slot == NULL) - return 1; - - hp_slot = slot->device - ctrl->slot_device_offset; - dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", - __FUNCTION__, slot->device, ctrl->slot_device_offset); - - status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); - - return(status == 0) ? 1 : 0; -} - - -static inline int get_presence_status (struct controller *ctrl, struct slot *slot) -{ - int presence_save = 0; - u8 hp_slot; - u32 tempdword; - - if (slot == NULL) - return 0; - - hp_slot = slot->device - ctrl->slot_device_offset; - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; - - return presence_save; -} - -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name (char *buffer, int buffer_size, struct slot *slot) -{ - snprintf (buffer, buffer_size, "%d", slot->number); -} - - -static inline int wait_for_ctrl_irq (struct controller *ctrl) -{ - DECLARE_WAITQUEUE(wait, current); - int retval = 0; - - dbg("%s - start\n", __FUNCTION__); - add_wait_queue(&ctrl->queue, &wait); - set_current_state(TASK_INTERRUPTIBLE); - /* Sleep for up to 1 second to wait for the LED to change. */ - schedule_timeout(1*HZ); - set_current_state(TASK_RUNNING); - remove_wait_queue(&ctrl->queue, &wait); - if (signal_pending(current)) - retval = -EINTR; - - dbg("%s - end\n", __FUNCTION__); - return retval; -} - - -/** - * set_controller_speed - set the frequency and/or mode of a specific - * controller segment. - * - * @ctrl: controller to change frequency/mode for. - * @adapter_speed: the speed of the adapter we want to match. - * @hp_slot: the slot number where the adapter is installed. - * - * Returns 0 if we successfully change frequency and/or mode to match the - * adapter speed. - * - */ -static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot) -{ - struct slot *slot; - u8 reg; - u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); - u16 reg16; - u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); - - if (ctrl->speed == adapter_speed) - return 0; - - /* We don't allow freq/mode changes if we find another adapter running - * in another slot on this controller */ - for(slot = ctrl->slot; slot; slot = slot->next) { - if (slot->device == (hp_slot + ctrl->slot_device_offset)) - continue; - if (!slot->hotplug_slot && !slot->hotplug_slot->info) - continue; - if (slot->hotplug_slot->info->adapter_status == 0) - continue; - /* If another adapter is running on the same segment but at a - * lower speed/mode, we allow the new adapter to function at - * this rate if supported */ - if (ctrl->speed < adapter_speed) - return 0; - - return 1; - } - - /* If the controller doesn't support freq/mode changes and the - * controller is running at a higher mode, we bail */ - if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) - return 1; - - /* But we allow the adapter to run at a lower rate if possible */ - if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) - return 0; - - /* We try to set the max speed supported by both the adapter and - * controller */ - if (ctrl->speed_capability < adapter_speed) { - if (ctrl->speed == ctrl->speed_capability) - return 0; - adapter_speed = ctrl->speed_capability; - } - - writel(0x0L, ctrl->hpc_reg + LED_CONTROL); - writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); - wait_for_ctrl_irq(ctrl); - - if (adapter_speed != PCI_SPEED_133MHz_PCIX) - reg = 0xF5; - else - reg = 0xF4; - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - - reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); - reg16 &= ~0x000F; - switch(adapter_speed) { - case(PCI_SPEED_133MHz_PCIX): - reg = 0x75; - reg16 |= 0xB; - break; - case(PCI_SPEED_100MHz_PCIX): - reg = 0x74; - reg16 |= 0xA; - break; - case(PCI_SPEED_66MHz_PCIX): - reg = 0x73; - reg16 |= 0x9; - break; - case(PCI_SPEED_66MHz): - reg = 0x73; - reg16 |= 0x1; - break; - default: /* 33MHz PCI 2.2 */ - reg = 0x71; - break; - - } - reg16 |= 0xB << 12; - writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); - - mdelay(5); - - /* Reenable interrupts */ - writel(0, ctrl->hpc_reg + INT_MASK); - - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - - /* Restart state machine */ - reg = ~0xF; - pci_read_config_byte(ctrl->pci_dev, 0x43, ®); - pci_write_config_byte(ctrl->pci_dev, 0x43, reg); - - /* Only if mode change...*/ - if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || - ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) - set_SOGO(ctrl); - - wait_for_ctrl_irq(ctrl); - mdelay(1100); - - /* Restore LED/Slot state */ - writel(leds, ctrl->hpc_reg + LED_CONTROL); - writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); - wait_for_ctrl_irq(ctrl); - - ctrl->speed = adapter_speed; - slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - info("Successfully changed frequency/mode for adapter in slot %d\n", - slot->number); - return 0; -} - -#endif - diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp_core.c linux-2.5.70-bk10/drivers/hotplug/cpqphp_core.c --- linux-2.5.70-bk9/drivers/hotplug/cpqphp_core.c 2003-05-26 18:00:19.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp_core.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1541 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, - * Torben Mathiasen - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "cpqphp.h" -#include "cpqphp_nvram.h" -#include "../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ - - -/* Global variables */ -int cpqhp_debug; -struct controller *cpqhp_ctrl_list; /* = NULL */ -struct pci_func *cpqhp_slot_list[256]; - -/* local variables */ -static void *smbios_table; -static void *smbios_start; -static void *cpqhp_rom_start; -static u8 power_mode; -static int debug; - -#define DRIVER_VERSION "0.9.7" -#define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman " -#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -MODULE_PARM(power_mode, "b"); -MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); - -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -#define CPQHPC_MODULE_MINOR 208 - -static int one_time_init (void); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int process_SI (struct hotplug_slot *slot); -static int process_SS (struct hotplug_slot *slot); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); -static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); - -static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = process_SI, - .disable_slot = process_SS, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - -static inline int is_slot64bit (struct slot *slot) -{ - if (!slot || !slot->p_sm_slot) - return 0; - - if (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) - return 1; - - return 0; -} - -static inline int is_slot66mhz (struct slot *slot) -{ - if (!slot || !slot->p_sm_slot) - return 0; - - if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) - return 1; - - return 0; -} - -/** - * detect_SMBIOS_pointer - find the system Management BIOS Table in the specified region of memory. - * - * @begin: begin pointer for region to be scanned. - * @end: end pointer for region to be scanned. - * - * Returns pointer to the head of the SMBIOS tables (or NULL) - * - */ -static void * detect_SMBIOS_pointer(void *begin, void *end) -{ - void *fp; - void *endp; - u8 temp1, temp2, temp3, temp4; - int status = 0; - - endp = (end - sizeof(u32) + 1); - - for (fp = begin; fp <= endp; fp += 16) { - temp1 = readb(fp); - temp2 = readb(fp+1); - temp3 = readb(fp+2); - temp4 = readb(fp+3); - if (temp1 == '_' && - temp2 == 'S' && - temp3 == 'M' && - temp4 == '_') { - status = 1; - break; - } - } - - if (!status) - fp = NULL; - - dbg("Discovered SMBIOS Entry point at %p\n", fp); - - return fp; -} - -/** - * init_SERR - Initializes the per slot SERR generation. - * - * For unexpected switch opens - * - */ -static int init_SERR(struct controller * ctrl) -{ - u32 tempdword; - u32 number_of_slots; - u8 physical_slot; - - if (!ctrl) - return 1; - - tempdword = ctrl->first_slot; - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // Loop through slots - while (number_of_slots) { - physical_slot = tempdword; - writeb(0, ctrl->hpc_reg + SLOT_SERR); - tempdword++; - number_of_slots--; - } - - return 0; -} - - -/* nice debugging output */ -static int pci_print_IRQ_route (void) -{ - struct irq_routing_table *routing_table; - int len; - int loop; - - u8 tbus, tdevice, tslot; - - routing_table = pcibios_get_irq_routing_table(); - if (routing_table == NULL) { - err("No BIOS Routing Table??? Not good\n"); - return -ENOMEM; - } - - len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - kfree(routing_table); - return -1; - } - - dbg("bus dev func slot\n"); - - for (loop = 0; loop < len; ++loop) { - tbus = routing_table->slots[loop].bus; - tdevice = routing_table->slots[loop].devfn; - tslot = routing_table->slots[loop].slot; - dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); - - } - kfree(routing_table); - return 0; -} - - -/* - * get_subsequent_smbios_entry - * - * Gets the first entry if previous == NULL - * Otherwise, returns the next entry - * Uses global SMBIOS Table pointer - * - * @curr: %NULL or pointer to previously returned structure - * - * returns a pointer to an SMBIOS structure or NULL if none found - */ -static void * get_subsequent_smbios_entry(void *smbios_start, void *smbios_table, void *curr) -{ - u8 bail = 0; - u8 previous_byte = 1; - void *p_temp; - void *p_max; - - if (!smbios_table || !curr) - return(NULL); - - // set p_max to the end of the table - p_max = smbios_start + readw(smbios_table + ST_LENGTH); - - p_temp = curr; - p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); - - while ((p_temp < p_max) && !bail) { - // Look for the double NULL terminator - // The first condition is the previous byte and the second is the curr - if (!previous_byte && !(readb(p_temp))) { - bail = 1; - } - - previous_byte = readb(p_temp); - p_temp++; - } - - if (p_temp < p_max) { - return p_temp; - } else { - return NULL; - } -} - - -/** - * get_SMBIOS_entry - * - * @type:SMBIOS structure type to be returned - * @previous: %NULL or pointer to previously returned structure - * - * Gets the first entry of the specified type if previous == NULL - * Otherwise, returns the next entry of the given type. - * Uses global SMBIOS Table pointer - * Uses get_subsequent_smbios_entry - * - * returns a pointer to an SMBIOS structure or %NULL if none found - */ -static void *get_SMBIOS_entry (void *smbios_start, void *smbios_table, u8 type, void * previous) -{ - if (!smbios_table) - return NULL; - - if (!previous) { - previous = smbios_start; - } else { - previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } - - while (previous) { - if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { - previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } else { - break; - } - } - - return previous; -} - - -static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *smbios_table) -{ - struct slot *new_slot; - u8 number_of_slots; - u8 slot_device; - u8 slot_number; - u8 ctrl_slot; - u32 tempdword; - void *slot_entry= NULL; - int result; - - dbg("%s\n", __FUNCTION__); - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!new_slot) - return -ENOMEM; - - memset(new_slot, 0, sizeof(struct slot)); - new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!new_slot->hotplug_slot) { - kfree (new_slot); - return -ENOMEM; - } - memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); - - new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!new_slot->hotplug_slot->info) { - kfree (new_slot->hotplug_slot); - kfree (new_slot); - return -ENOMEM; - } - memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); - new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); - if (!new_slot->hotplug_slot->name) { - kfree (new_slot->hotplug_slot->info); - kfree (new_slot->hotplug_slot); - kfree (new_slot); - return -ENOMEM; - } - - new_slot->magic = SLOT_MAGIC; - new_slot->ctrl = ctrl; - new_slot->bus = ctrl->bus; - new_slot->device = slot_device; - new_slot->number = slot_number; - dbg("slot->number = %d\n",new_slot->number); - - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); - - while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); - } - - new_slot->p_sm_slot = slot_entry; - - init_timer(&new_slot->task_event); - new_slot->task_event.expires = jiffies + 5 * HZ; - new_slot->task_event.function = cpqhp_pushbutton_thread; - - //FIXME: these capabilities aren't used but if they are - // they need to be correctly implemented - new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; - new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; - - if (is_slot64bit(new_slot)) - new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; - if (is_slot66mhz(new_slot)) - new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; - if (ctrl->speed == PCI_SPEED_66MHz) - new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; - - ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); - - // Check presence - new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; - // Check the switch state - new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; - // Check the slot enable - new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; - - /* register this slot with the hotplug pci core */ - new_slot->hotplug_slot->private = new_slot; - make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); - new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - - new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); - new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); - new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); - new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); - - dbg ("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", - new_slot->bus, new_slot->device, new_slot->number, ctrl->slot_device_offset, slot_number); - result = pci_hp_register (new_slot->hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - kfree (new_slot->hotplug_slot->info); - kfree (new_slot->hotplug_slot->name); - kfree (new_slot->hotplug_slot); - kfree (new_slot); - return result; - } - - new_slot->next = ctrl->slot; - ctrl->slot = new_slot; - - number_of_slots--; - slot_device++; - slot_number++; - } - - return(0); -} - - -static int ctrl_slot_cleanup (struct controller * ctrl) -{ - struct slot *old_slot, *next_slot; - - old_slot = ctrl->slot; - ctrl->slot = NULL; - - while (old_slot) { - next_slot = old_slot->next; - pci_hp_deregister (old_slot->hotplug_slot); - kfree(old_slot->hotplug_slot->info); - kfree(old_slot->hotplug_slot->name); - kfree(old_slot->hotplug_slot); - kfree(old_slot); - old_slot = next_slot; - } - - //Free IRQ associated with hot plug device - free_irq(ctrl->interrupt, ctrl); - //Unmap the memory - iounmap(ctrl->hpc_reg); - //Finally reclaim PCI mem - release_mem_region(pci_resource_start(ctrl->pci_dev, 0), - pci_resource_len(ctrl->pci_dev, 0)); - - return(0); -} - - -//============================================================================ -// function: get_slot_mapping -// -// Description: Attempts to determine a logical slot mapping for a PCI -// device. Won't work for more than one PCI-PCI bridge -// in a slot. -// -// Input: u8 bus_num - bus number of PCI device -// u8 dev_num - device number of PCI device -// u8 *slot - Pointer to u8 where slot number will -// be returned -// -// Output: SUCCESS or FAILURE -//============================================================================= -static int get_slot_mapping (struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) -{ - struct irq_routing_table *PCIIRQRoutingInfoLength; - u32 work; - long len; - long loop; - - u8 tbus, tdevice, tslot, bridgeSlot; - - dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot); - - bridgeSlot = 0xFF; - - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); - return -1; - } - - for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; - - if ((tbus == bus_num) && (tdevice == dev_num)) { - *slot = tslot; - - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength); - return 0; - } else { - // Didn't get a match on the target PCI device. Check if the - // current IRQ table entry is a PCI-to-PCI bridge device. If so, - // and it's secondary bus matches the bus number for the target - // device, I need to save the bridge's slot number. If I can't - // find an entry for the target device, I will have to assume it's - // on the other side of the bridge, and assign it the bridge's slot. - bus->number = tbus; - pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_REVISION_ID, &work); - - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); - // See if bridge's secondary bus matches target bus. - if (((work >> 8) & 0x000000FF) == (long) bus_num) { - bridgeSlot = tslot; - } - } - } - - } - - // If we got here, we didn't find an entry in the IRQ mapping table - // for the target PCI device. If we did determine that the target - // device is on the other side of a PCI-to-PCI bridge, return the - // slot number for the bridge. - if (bridgeSlot != 0xFF) { - *slot = bridgeSlot; - if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); - return 0; - } - if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); - // Couldn't find an entry in the routing table for this PCI device - return -1; -} - - -/** - * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off - * - */ -static int cpqhp_set_attention_status (struct controller *ctrl, struct pci_func *func, u32 status) -{ - u8 hp_slot; - - hp_slot = func->device - ctrl->slot_device_offset; - - if (func == NULL) - return(1); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - if (status == 1) { - amber_LED_on (ctrl, hp_slot); - } else if (status == 0) { - amber_LED_off (ctrl, hp_slot); - } else { - // Done with exclusive hardware access - up(&ctrl->crit_sect); - return(1); - } - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - return(0); -} - - -/** - * set_attention_status - Turns the Amber LED for a slot on or off - * - */ -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - struct pci_func *slot_func; - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - u8 bus; - u8 devfn; - u8 device; - u8 function; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) - return -ENODEV; - - device = devfn >> 3; - function = devfn & 0x7; - dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); - - slot_func = cpqhp_slot_find(bus, device, function); - if (!slot_func) { - return -ENODEV; - } - - return cpqhp_set_attention_status(ctrl, slot_func, status); -} - - -static int process_SI (struct hotplug_slot *hotplug_slot) -{ - struct pci_func *slot_func; - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - u8 bus; - u8 devfn; - u8 device; - u8 function; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) - return -ENODEV; - - device = devfn >> 3; - function = devfn & 0x7; - dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); - - slot_func = cpqhp_slot_find(bus, device, function); - if (!slot_func) { - return -ENODEV; - } - - slot_func->bus = bus; - slot_func->device = device; - slot_func->function = function; - slot_func->configured = 0; - dbg("board_added(%p, %p)\n", slot_func, ctrl); - return cpqhp_process_SI(ctrl, slot_func); -} - - -static int process_SS (struct hotplug_slot *hotplug_slot) -{ - struct pci_func *slot_func; - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - u8 bus; - u8 devfn; - u8 device; - u8 function; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) - return -ENODEV; - - device = devfn >> 3; - function = devfn & 0x7; - dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); - - slot_func = cpqhp_slot_find(bus, device, function); - if (!slot_func) { - return -ENODEV; - } - - dbg("In power_down_board, slot_func = %p, ctrl = %p\n", slot_func, ctrl); - return cpqhp_process_SS(ctrl, slot_func); -} - - -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - if (slot == NULL) - return -ENODEV; - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - return cpqhp_hardware_test (ctrl, value); -} - - -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = get_slot_enabled(ctrl, slot); - return 0; -} - -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = cpq_get_attention_status(ctrl, slot); - return 0; -} - -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = cpq_get_latch_status (ctrl, slot); - - return 0; -} - -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = get_presence_status (ctrl, slot); - - return 0; -} - -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = ctrl->speed_capability; - - return 0; -} - -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = ctrl->speed; - - return 0; -} - -static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - u8 num_of_slots = 0; - u8 hp_slot = 0; - u8 device; - u8 rev; - u8 bus_cap; - u16 temp_word; - u16 vendor_id; - u16 subsystem_vid; - u16 subsystem_deviceid; - u32 rc; - struct controller *ctrl; - struct pci_func *func; - - // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery - rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); - if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { - err(msg_HPC_non_compaq_or_intel); - return -ENODEV; - } - dbg("Vendor ID: %x\n", vendor_id); - - rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - dbg("revision: %d\n", rev); - if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { - err(msg_HPC_rev_error); - return -ENODEV; - } - - /* Check for the proper subsytem ID's - * Intel uses a different SSID programming model than Compaq. - * For Intel, each SSID bit identifies a PHP capability. - * Also Intel HPC's may have RID=0. - */ - if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { - // TODO: This code can be made to support non-Compaq or Intel subsystem IDs - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); - if (rc) { - err("%s : pci_read_config_word failed\n", __FUNCTION__); - return rc; - } - dbg("Subsystem Vendor ID: %x\n", subsystem_vid); - if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { - err(msg_HPC_non_compaq_or_intel); - return -ENODEV; - } - - ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); - if (!ctrl) { - err("%s : out of memory\n", __FUNCTION__); - return -ENOMEM; - } - memset(ctrl, 0, sizeof(struct controller)); - - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); - if (rc) { - err("%s : pci_read_config_word failed\n", __FUNCTION__); - goto err_free_ctrl; - } - - info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); - - /* Set Vendor ID, so it can be accessed later from other functions */ - ctrl->vendor_id = vendor_id; - - switch (subsystem_vid) { - case PCI_VENDOR_ID_COMPAQ: - if (rev >= 0x13) { /* CIOBX */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 1; // PCI-X supported - ctrl->pcix_speed_capability = 1; - pci_read_config_byte(pdev, 0x41, &bus_cap); - if (bus_cap & 0x80) { - dbg("bus max supports 133MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; - break; - } - if (bus_cap & 0x40) { - dbg("bus max supports 100MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - break; - } - if (bus_cap & 20) { - dbg("bus max supports 66MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; - break; - } - if (bus_cap & 10) { - dbg("bus max supports 66MHz PCI\n"); - ctrl->speed_capability = PCI_SPEED_66MHz; - break; - } - - break; - } - - switch (subsystem_deviceid) { - case PCI_SUB_HPC_ID: - /* Original 6500/7000 implementation */ - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; // No pushbutton - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID2: - /* First Pushbutton implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID_INTC: - /* Third party (6500/7000) */ - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; // No pushbutton - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID3: - /* First 66 Mhz implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_66MHz; - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID4: - /* First PCI-X implementation, 100MHz */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 1; // PCI-X supported - ctrl->pcix_speed_capability = 0; - break; - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - break; - - case PCI_VENDOR_ID_INTEL: - /* Check for speed capability (0=33, 1=66) */ - if (subsystem_deviceid & 0x0001) { - ctrl->speed_capability = PCI_SPEED_66MHz; - } else { - ctrl->speed_capability = PCI_SPEED_33MHz; - } - - /* Check for push button */ - if (subsystem_deviceid & 0x0002) { - /* no push button */ - ctrl->push_button = 0; - } else { - /* push button supported */ - ctrl->push_button = 1; - } - - /* Check for slot switch type (0=mechanical, 1=not mechanical) */ - if (subsystem_deviceid & 0x0004) { - /* no switch */ - ctrl->slot_switch_type = 0; - } else { - /* switch */ - ctrl->slot_switch_type = 1; - } - - /* PHP Status (0=De-feature PHP, 1=Normal operation) */ - if (subsystem_deviceid & 0x0008) { - ctrl->defeature_PHP = 1; // PHP supported - } else { - ctrl->defeature_PHP = 0; // PHP not supported - } - - /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0010) { - ctrl->alternate_base_address = 1; // supported - } else { - ctrl->alternate_base_address = 0; // not supported - } - - /* PCI Config Space Index (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0020) { - ctrl->pci_config_space = 1; // supported - } else { - ctrl->pci_config_space = 0; // not supported - } - - /* PCI-X support */ - if (subsystem_deviceid & 0x0080) { - /* PCI-X capable */ - ctrl->pcix_support = 1; - /* Frequency of operation in PCI-X mode */ - if (subsystem_deviceid & 0x0040) { - /* 133MHz PCI-X if bit 7 is 1 */ - ctrl->pcix_speed_capability = 1; - } else { - /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ - /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ - ctrl->pcix_speed_capability = 0; - } - } else { - /* Conventional PCI */ - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - } - break; - - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - - } else { - err(msg_HPC_not_supported); - return -ENODEV; - } - - // Tell the user that we found one. - info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); - - dbg ("Hotplug controller capabilities:\n"); - dbg (" speed_capability %d\n", ctrl->speed_capability); - dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); - dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); - dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); - dbg (" pci_config_space %s\n", ctrl->pci_config_space == 0 ? "not supported" : "supported"); - dbg (" pcix_speed_capability %s\n", ctrl->pcix_speed_capability == 0 ? "not supported" : "supported"); - dbg (" pcix_support %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported"); - - ctrl->pci_dev = pdev; - pci_set_drvdata(pdev, ctrl); - - /* make our own copy of the pci bus structure, as we like tweaking it a lot */ - ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); - if (!ctrl->pci_bus) { - err("out of memory\n"); - rc = -ENOMEM; - goto err_free_ctrl; - } - memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); - - ctrl->bus = pdev->bus->number; - ctrl->rev = rev; - dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev); - - init_MUTEX(&ctrl->crit_sect); - init_waitqueue_head(&ctrl->queue); - - /* initialize our threads if they haven't already been started up */ - rc = one_time_init(); - if (rc) { - goto err_free_bus; - } - - dbg("pdev = %p\n", pdev); - dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); - dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); - - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), MY_NAME)) { - err("cannot reserve MMIO region\n"); - rc = -ENOMEM; - goto err_free_bus; - } - - ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - if (!ctrl->hpc_reg) { - err("cannot remap MMIO region %lx @ %lx\n", pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); - rc = -ENODEV; - goto err_free_mem_region; - } - - // Check for 66Mhz operation - ctrl->speed = get_controller_speed(ctrl); - - - //************************************************** - // - // Save configuration headers for this and - // subordinate PCI buses - // - //************************************************** - - // find the physical slot number of the first hot plug slot - - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of a slot. - // CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table) - rc = get_slot_mapping(ctrl->pci_bus, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot)); - dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc); - if (rc) { - err(msg_initialization_err, rc); - goto err_iounmap; - } - - // Store PCI Config Space for all devices on this bus - rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); - if (rc) { - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_iounmap; - } - - /* - * Get IO, memory, and IRQ resources for new devices - */ - // The next line is required for cpqhp_find_available_resources - ctrl->interrupt = pdev->irq; - - ctrl->cfgspc_irq = 0; - pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq); - - rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); - ctrl->add_support = !rc; - if (rc) { - dbg("cpqhp_find_available_resources = 0x%x\n", rc); - err("unable to locate PCI configuration resources for hot plug add.\n"); - goto err_iounmap; - } - - /* - * Finish setting up the hot plug ctrl device - */ - ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - dbg("NumSlots %d \n", ctrl->slot_device_offset); - - ctrl->next_event = 0; - - /* Setup the slot information structures */ - rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table); - if (rc) { - err(msg_initialization_err, 6); - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_iounmap; - } - - /* Mask all general input interrupts */ - writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); - - /* set up the interrupt */ - dbg("HPC interrupt = %d \n", ctrl->interrupt); - if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr, - SA_SHIRQ, MY_NAME, ctrl)) { - err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); - rc = -ENODEV; - goto err_iounmap; - } - - /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ - temp_word = readw(ctrl->hpc_reg + MISC); - temp_word |= 0x4006; - writew(temp_word, ctrl->hpc_reg + MISC); - - // Changed 05/05/97 to clear all interrupts at start - writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); - - ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - writel(0x0L, ctrl->hpc_reg + INT_MASK); - - if (!cpqhp_ctrl_list) { - cpqhp_ctrl_list = ctrl; - ctrl->next = NULL; - } else { - ctrl->next = cpqhp_ctrl_list; - cpqhp_ctrl_list = ctrl; - } - - // turn off empty slots here unless command line option "ON" set - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - - // find first device number for the ctrl - device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - - while (num_of_slots) { - dbg("num_of_slots: %d\n", num_of_slots); - func = cpqhp_slot_find(ctrl->bus, device, 0); - if (!func) - break; - - hp_slot = func->device - ctrl->slot_device_offset; - dbg("hp_slot: %d\n", hp_slot); - - // We have to save the presence info for these slots - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - func->switch_save = 0; - } else { - func->switch_save = 0x10; - } - - if (!power_mode) { - if (!func->is_a_board) { - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - } - } - - device++; - num_of_slots--; - } - - if (!power_mode) { - set_SOGO(ctrl); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - } - - rc = init_SERR(ctrl); - if (rc) { - err("init_SERR failed\n"); - up(&ctrl->crit_sect); - goto err_free_irq; - } - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - cpqhp_create_ctrl_files (ctrl); - - return 0; - -err_free_irq: - free_irq(ctrl->interrupt, ctrl); -err_iounmap: - iounmap(ctrl->hpc_reg); -err_free_mem_region: - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -err_free_bus: - kfree(ctrl->pci_bus); -err_free_ctrl: - kfree(ctrl); - return rc; -} - - -static int one_time_init(void) -{ - int loop; - int retval = 0; - static int initialized = 0; - - if (initialized) - return 0; - - power_mode = 0; - - retval = pci_print_IRQ_route(); - if (retval) - goto error; - - dbg("Initialize + Start the notification mechanism \n"); - - retval = cpqhp_event_start_thread(); - if (retval) - goto error; - - dbg("Initialize slot lists\n"); - for (loop = 0; loop < 256; loop++) { - cpqhp_slot_list[loop] = NULL; - } - - // FIXME: We also need to hook the NMI handler eventually. - // this also needs to be worked with Christoph - // register_NMI_handler(); - - // Map rom address - cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!cpqhp_rom_start) { - err ("Could not ioremap memory region for ROM\n"); - retval = -EIO;; - goto error; - } - - /* Now, map the int15 entry point if we are on compaq specific hardware */ - compaq_nvram_init(cpqhp_rom_start); - - /* Map smbios table entry point structure */ - smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); - if (!smbios_table) { - err ("Could not find the SMBIOS pointer in memory\n"); - retval = -EIO;; - goto error; - } - - smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); - if (!smbios_start) { - err ("Could not ioremap memory region taken from SMBIOS values\n"); - retval = -EIO;; - goto error; - } - - initialized = 1; - - return retval; - -error: - if (cpqhp_rom_start) - iounmap(cpqhp_rom_start); - if (smbios_start) - iounmap(smbios_start); - - return retval; -} - - -static void unload_cpqphpd(void) -{ - struct pci_func *next; - struct pci_func *TempSlot; - int loop; - u32 rc; - struct controller *ctrl; - struct controller *tctrl; - struct pci_resource *res; - struct pci_resource *tres; - - rc = compaq_nvram_store(cpqhp_rom_start); - - ctrl = cpqhp_ctrl_list; - - while (ctrl) { - if (ctrl->hpc_reg) { - u16 misc; - rc = read_slot_enable (ctrl); - - writeb(0, ctrl->hpc_reg + SLOT_SERR); - writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); - - misc = readw(ctrl->hpc_reg + MISC); - misc &= 0xFFFD; - writew(misc, ctrl->hpc_reg + MISC); - } - - ctrl_slot_cleanup(ctrl); - - res = ctrl->io_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = ctrl->mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = ctrl->p_mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = ctrl->bus_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - kfree (ctrl->pci_bus); - - tctrl = ctrl; - ctrl = ctrl->next; - kfree(tctrl); - } - - for (loop = 0; loop < 256; loop++) { - next = cpqhp_slot_list[loop]; - while (next != NULL) { - res = next->io_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = next->mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = next->p_mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = next->bus_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - TempSlot = next; - next = next->next; - kfree(TempSlot); - } - } - - // Stop the notification mechanism - cpqhp_event_stop_thread(); - - //unmap the rom address - if (cpqhp_rom_start) - iounmap(cpqhp_rom_start); - if (smbios_start) - iounmap(smbios_start); -} - - - -static struct pci_device_id hpcd_pci_tbl[] __devinitdata = { - { - /* handle any PCI Hotplug controller */ - .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), - .class_mask = ~0, - - /* no matter who makes it */ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - - }, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); - - - -static struct pci_driver cpqhpc_driver = { - .name = "pci_hotplug", - .id_table = hpcd_pci_tbl, - .probe = cpqhpc_probe, - /* remove: cpqhpc_remove_one, */ -}; - - - -static int __init cpqhpc_init(void) -{ - int result; - - cpqhp_debug = debug; - - result = pci_module_init(&cpqhpc_driver); - dbg("pci_module_init = %d\n", result); - if (result) - return result; - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - return 0; -} - - -static void __exit cpqhpc_cleanup(void) -{ - dbg("unload_cpqphpd()\n"); - unload_cpqphpd(); - - dbg("pci_unregister_driver\n"); - pci_unregister_driver(&cpqhpc_driver); -} - - -module_init(cpqhpc_init); -module_exit(cpqhpc_cleanup); - - diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp_ctrl.c linux-2.5.70-bk10/drivers/hotplug/cpqphp_ctrl.c --- linux-2.5.70-bk9/drivers/hotplug/cpqphp_ctrl.c 2003-05-26 18:00:37.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp_ctrl.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,3084 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpqphp.h" - -static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); -static int configure_new_function(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); -static void interrupt_event_handler(struct controller *ctrl); - -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ - -/* things needed for the long_delay function */ -static struct semaphore delay_sem; -static wait_queue_head_t delay_wait; - -/* delay is in jiffies to wait for */ -static void long_delay (int delay) -{ - DECLARE_WAITQUEUE(wait, current); - - /* only allow 1 customer into the delay queue at once - * yes this makes some people wait even longer, but who really cares? - * this is for _huge_ delays to make the hardware happy as the - * signals bounce around - */ - down (&delay_sem); - - init_waitqueue_head (&delay_wait); - - add_wait_queue(&delay_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(delay); - remove_wait_queue(&delay_wait, &wait); - set_current_state(TASK_RUNNING); - - up (&delay_sem); -} - - -//FIXME: The following line needs to be somewhere else... -#define WRONG_BUS_FREQUENCY 0x07 -static u8 handle_switch_change(u8 change, struct controller * ctrl) -{ - int hp_slot; - u8 rc = 0; - u16 temp_word; - struct pci_func *func; - struct event_info *taskInfo; - - if (!change) - return 0; - - // Switch Change - dbg("cpqsbd: Switch interrupt received.\n"); - - for (hp_slot = 0; hp_slot < 6; hp_slot++) { - if (change & (0x1L << hp_slot)) { - //********************************* - // this one changed. - //********************************* - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - - //this is the structure that tells the worker thread - //what to do - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - //********************************* - // Switch opened - //********************************* - - func->switch_save = 0; - - taskInfo->event_type = INT_SWITCH_OPEN; - } else { - //********************************* - // Switch closed - //********************************* - - func->switch_save = 0x10; - - taskInfo->event_type = INT_SWITCH_CLOSE; - } - } - } - - return rc; -} - - -/* - * cpqhp_find_slot - */ -struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device) -{ - struct slot *slot; - - if (!ctrl) - return NULL; - - slot = ctrl->slot; - - while (slot && (slot->device != device)) { - slot = slot->next; - } - - return slot; -} - - -static u8 handle_presence_change(u16 change, struct controller * ctrl) -{ - int hp_slot; - u8 rc = 0; - u8 temp_byte; - u16 temp_word; - struct pci_func *func; - struct event_info *taskInfo; - struct slot *p_slot; - - if (!change) - return 0; - - //********************************* - // Presence Change - //********************************* - dbg("cpqsbd: Presence/Notify input change.\n"); - dbg(" Changed bits are 0x%4.4x\n", change ); - - for (hp_slot = 0; hp_slot < 6; hp_slot++) { - if (change & (0x0101 << hp_slot)) { - //********************************* - // this one changed. - //********************************* - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - - p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); - if (!p_slot) - return 0; - - // If the switch closed, must be a button - // If not in button mode, nevermind - if (func->switch_save && (ctrl->push_button == 1)) { - temp_word = ctrl->ctrl_int_comp >> 16; - temp_byte = (temp_word >> hp_slot) & 0x01; - temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (temp_byte != func->presence_save) { - //********************************* - // button Pressed (doesn't do anything) - //********************************* - dbg("hp_slot %d button pressed\n", hp_slot); - taskInfo->event_type = INT_BUTTON_PRESS; - } else { - //********************************* - // button Released - TAKE ACTION!!!! - //********************************* - dbg("hp_slot %d button released\n", hp_slot); - taskInfo->event_type = INT_BUTTON_RELEASE; - - // Cancel if we are still blinking - if ((p_slot->state == BLINKINGON_STATE) - || (p_slot->state == BLINKINGOFF_STATE)) { - taskInfo->event_type = INT_BUTTON_CANCEL; - dbg("hp_slot %d button cancel\n", hp_slot); - } else if ((p_slot->state == POWERON_STATE) - || (p_slot->state == POWEROFF_STATE)) { - //info(msg_button_ignore, p_slot->number); - taskInfo->event_type = INT_BUTTON_IGNORE; - dbg("hp_slot %d button ignore\n", hp_slot); - } - } - } else { - // Switch is open, assume a presence change - // Save the presence state - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) || - (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) { - //********************************* - // Present - //********************************* - taskInfo->event_type = INT_PRESENCE_ON; - } else { - //********************************* - // Not Present - //********************************* - taskInfo->event_type = INT_PRESENCE_OFF; - } - } - } - } - - return rc; -} - - -static u8 handle_power_fault(u8 change, struct controller * ctrl) -{ - int hp_slot; - u8 rc = 0; - struct pci_func *func; - struct event_info *taskInfo; - - if (!change) - return 0; - - //********************************* - // power fault - //********************************* - - info("power fault interrupt\n"); - - for (hp_slot = 0; hp_slot < 6; hp_slot++) { - if (change & (0x01 << hp_slot)) { - //********************************* - // this one changed. - //********************************* - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - - if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { - //********************************* - // power fault Cleared - //********************************* - func->status = 0x00; - - taskInfo->event_type = INT_POWER_FAULT_CLEAR; - } else { - //********************************* - // power fault - //********************************* - taskInfo->event_type = INT_POWER_FAULT; - - if (ctrl->rev < 4) { - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - set_SOGO (ctrl); - - // this is a fatal condition, we want to crash the - // machine to protect from data corruption - // simulated_NMI shouldn't ever return - //FIXME - //simulated_NMI(hp_slot, ctrl); - - //The following code causes a software crash just in - //case simulated_NMI did return - //FIXME - //panic(msg_power_fault); - } else { - // set power fault status for this board - func->status = 0xFF; - info("power fault bit %x set\n", hp_slot); - } - } - } - } - - return rc; -} - - -/* - * sort_by_size - * - * Sorts nodes on the list by their length. - * Smallest first. - * - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - // Special case for swapping list head - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } // End of out_of_order loop - - return(0); -} - - -/* - * sort_by_max_size - * - * Sorts nodes on the list by their length. - * Largest first. - * - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - // Special case for swapping list head - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } // End of out_of_order loop - - return(0); -} - - -/* - * do_pre_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - struct pci_resource *split_node; - u32 rc; - u32 temp_dword; - dbg("do_pre_bridge_resource_split\n"); - - if (!(*head) || !(*orig_head)) - return(NULL); - - rc = cpqhp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - if ((*head)->base != (*orig_head)->base) - return(NULL); - - if ((*head)->length == (*orig_head)->length) - return(NULL); - - - // If we got here, there the bridge requires some of the resource, but - // we may be able to split some off of the front - - node = *head; - - if (node->length & (alignment -1)) { - // this one isn't an aligned length, so we'll make a new entry - // and split it up. - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - temp_dword = (node->length | (alignment-1)) + 1 - alignment; - - split_node->base = node->base; - split_node->length = temp_dword; - - node->length -= temp_dword; - node->base += split_node->length; - - // Put it in the list - *head = split_node; - split_node->next = node; - } - - if (node->length < alignment) { - return(NULL); - } - - // Now unlink it - if (*head == node) { - *head = node->next; - node->next = NULL; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - node->next = NULL; - } - - return(node); -} - - -/* - * do_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - u32 rc; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - rc = cpqhp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - node = *head; - - while (node->next) { - prevnode = node; - node = node->next; - kfree(prevnode); - } - - if (node->length < alignment) { - kfree(node); - return(NULL); - } - - if (node->base & (alignment - 1)) { - // Short circuit if adjusted size is too small - temp_dword = (node->base | (alignment-1)) + 1; - if ((node->length - (temp_dword - node->base)) < alignment) { - kfree(node); - return(NULL); - } - - node->length -= (temp_dword - node->base); - node->base = temp_dword; - } - - if (node->length & (alignment - 1)) { - // There's stuff in use after this node - kfree(node); - return(NULL); - } - - return(node); -} - - -/* - * get_io_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( cpqhp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - // this one isn't base aligned properly - // so we'll make a new entry and split it up - temp_dword = (node->base | (size-1)) + 1; - - // Short circuit if adjusted size is too small - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of non-aligned base - - // Don't need to check if too small since we already did - if (node->length > size) { - // this one is longer than we need - // so we'll make a new entry and split it up - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of too big on top end - - // For IO make sure it's not in the ISA aliasing space - if (node->base & 0x300L) - continue; - - // If we got here, then it is the right size - // Now take it out of the list - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - // Stop looping - break; - } - - return(node); -} - - -/* - * get_max_resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - */ -static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if (cpqhp_resource_sort_and_combine(head)) - return(NULL); - - if (sort_by_max_size(head)) - return(NULL); - - for (max = *head;max; max = max->next) { - - // If not big enough we could probably just bail, - // instead we'll continue to the next. - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - // this one isn't base aligned properly - // so we'll make a new entry and split it up - temp_dword = (max->base | (size-1)) + 1; - - // Short circuit if adjusted size is too small - if ((max->length - (temp_dword - max->base)) < size) - continue; - - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = max->base; - split_node->length = temp_dword - max->base; - max->base = temp_dword; - max->length -= split_node->length; - - // Put it next in the list - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - // this one isn't end aligned properly at the top - // so we'll make a new entry and split it up - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - temp_dword = ((max->base + max->length) & ~(size - 1)); - split_node->base = temp_dword; - split_node->length = max->length + max->base - - split_node->base; - max->length -= split_node->length; - - // Put it in the list - split_node->next = max->next; - max->next = split_node; - } - - // Make sure it didn't shrink too much when we aligned it - if (max->length < size) - continue; - - // Now take it out of the list - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return(max); - } - - // If we get here, we couldn't find one - return(NULL); -} - - -/* - * get_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( cpqhp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - // this one isn't base aligned properly - // so we'll make a new entry and split it up - temp_dword = (node->base | (size-1)) + 1; - - // Short circuit if adjusted size is too small - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of non-aligned base - - // Don't need to check if too small since we already did - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - // this one is longer than we need - // so we'll make a new entry and split it up - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of too big on top end - - dbg("%s: got one!!!\n", __FUNCTION__); - // If we got here, then it is the right size - // Now take it out of the list - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - // Stop looping - break; - } - return(node); -} - - -/* - * cpqhp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int cpqhp_resource_sort_and_combine(struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); - - if (!(*head)) - return(1); - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return(0); /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(*head)->base); - dbg("*head->next->base = 0x%x\n",(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - // Special case for swapping list head - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } // End of out_of_order loop - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - // Combine - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return(0); -} - - -irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) -{ - struct controller *ctrl = data; - u8 schedule_flag = 0; - u8 reset; - u16 misc; - u32 Diff; - u32 temp_dword; - - - misc = readw(ctrl->hpc_reg + MISC); - //********************************* - // Check to see if it was our interrupt - //********************************* - if (!(misc & 0x000C)) { - return IRQ_NONE; - } - - if (misc & 0x0004) { - //********************************* - // Serial Output interrupt Pending - //********************************* - - // Clear the interrupt - misc |= 0x0004; - writew(misc, ctrl->hpc_reg + MISC); - - // Read to clear posted writes - misc = readw(ctrl->hpc_reg + MISC); - - dbg ("%s - waking up\n", __FUNCTION__); - wake_up_interruptible(&ctrl->queue); - } - - if (misc & 0x0008) { - // General-interrupt-input interrupt Pending - Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp; - - ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - // Clear the interrupt - writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR); - - // Read it back to clear any posted writes - temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - if (!Diff) { - // Clear all interrupts - writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR); - } - - schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl); - schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl); - schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); - } - - reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); - if (reset & 0x40) { - /* Bus reset has completed */ - reset &= 0xCF; - writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE); - reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); - wake_up_interruptible(&ctrl->queue); - } - - if (schedule_flag) { - up(&event_semaphore); - dbg("Signal event_semaphore\n"); - } - return IRQ_HANDLED; -} - - -/** - * cpqhp_slot_create - Creates a node and adds it to the proper bus. - * @busnumber - bus where new node is to be located - * - * Returns pointer to the new node or NULL if unsuccessful - */ -struct pci_func *cpqhp_slot_create(u8 busnumber) -{ - struct pci_func *new_slot; - struct pci_func *next; - - new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); - - if (new_slot == NULL) { - // I'm not dead yet! - // You will be. - return(new_slot); - } - - memset(new_slot, 0, sizeof(struct pci_func)); - - new_slot->next = NULL; - new_slot->configured = 1; - - if (cpqhp_slot_list[busnumber] == NULL) { - cpqhp_slot_list[busnumber] = new_slot; - } else { - next = cpqhp_slot_list[busnumber]; - while (next->next != NULL) - next = next->next; - next->next = new_slot; - } - return(new_slot); -} - - -/* - * slot_remove - Removes a node from the linked list of slots. - * @old_slot: slot to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int slot_remove(struct pci_func * old_slot) -{ - struct pci_func *next; - - if (old_slot == NULL) - return(1); - - next = cpqhp_slot_list[old_slot->bus]; - - if (next == NULL) { - return(1); - } - - if (next == old_slot) { - cpqhp_slot_list[old_slot->bus] = old_slot->next; - cpqhp_destroy_board_resources(old_slot); - kfree(old_slot); - return(0); - } - - while ((next->next != old_slot) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == old_slot) { - next->next = old_slot->next; - cpqhp_destroy_board_resources(old_slot); - kfree(old_slot); - return(0); - } else - return(2); -} - - -/** - * bridge_slot_remove - Removes a node from the linked list of slots. - * @bridge: bridge to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int bridge_slot_remove(struct pci_func *bridge) -{ - u8 subordinateBus, secondaryBus; - u8 tempBus; - struct pci_func *next; - - if (bridge == NULL) - return(1); - - secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; - subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; - - for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { - next = cpqhp_slot_list[tempBus]; - - while (!slot_remove(next)) { - next = cpqhp_slot_list[tempBus]; - } - } - - next = cpqhp_slot_list[bridge->bus]; - - if (next == NULL) { - return(1); - } - - if (next == bridge) { - cpqhp_slot_list[bridge->bus] = bridge->next; - kfree(bridge); - return(0); - } - - while ((next->next != bridge) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == bridge) { - next->next = bridge->next; - kfree(bridge); - return(0); - } else - return(2); -} - - -/** - * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed - * @bus: bus to find - * @device: device to find - * @index: is 0 for first function found, 1 for the second... - * - * Returns pointer to the node if successful, %NULL otherwise. - */ -struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) -{ - int found = -1; - struct pci_func *func; - - func = cpqhp_slot_list[bus]; - - if ((func == NULL) || ((func->device == device) && (index == 0))) - return(func); - - if (func->device == device) - found++; - - while (func->next != NULL) { - func = func->next; - - if (func->device == device) - found++; - - if (found == index) - return(func); - } - - return(NULL); -} - - -// DJZ: I don't think is_bridge will work as is. -//FIXME -static int is_bridge(struct pci_func * func) -{ - // Check the header type - if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) - return 1; - else - return 0; -} - - -/* the following routines constitute the bulk of the - hotplug controller logic - */ - - -/** - * board_replaced - Called after a board has been replaced in the system. - * - * This is only used if we don't have resources for hot add - * Turns power on for the board - * Checks to see if board is the same - * If board is same, reconfigures it - * If board isn't same, turns it back off. - * - */ -static u32 board_replaced(struct pci_func * func, struct controller * ctrl) -{ - u8 hp_slot; - u8 temp_byte; - u8 adapter_speed; - u32 index; - u32 rc = 0; - u32 src = 8; - - hp_slot = func->device - ctrl->slot_device_offset; - - if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { - //********************************* - // The switch is open. - //********************************* - rc = INTERLOCK_OPEN; - } else if (is_slot_enabled (ctrl, hp_slot)) { - //********************************* - // The board is already on - //********************************* - rc = CARD_FUNCTIONING; - } else { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - // turn on board without attaching to the bus - enable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Change bits in slot power register to force another shift out - // NOTE: this is to work around the timer bug - temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); - writeb(0x00, ctrl->hpc_reg + SLOT_POWER); - writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - adapter_speed = get_adapter_speed(ctrl, hp_slot); - if (ctrl->speed != adapter_speed) - if (set_controller_speed(ctrl, adapter_speed, hp_slot)) - rc = WRONG_BUS_FREQUENCY; - - // turn off board without attaching to the bus - disable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (rc) - return(rc); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - slot_enable (ctrl, hp_slot); - green_LED_blink (ctrl, hp_slot); - - amber_LED_off (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - // Wait for ~1 second because of hot plug spec - long_delay(1*HZ); - - // Check for a power fault - if (func->status == 0xFF) { - // power fault occurred, but it was benign - rc = POWER_FAILURE; - func->status = 0; - } else - rc = cpqhp_valid_replace(ctrl, func); - - if (!rc) { - // It must be the same board - - rc = cpqhp_configure_board(ctrl, func); - - if (rc || src) { - // If configuration fails, turn it off - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of an adapter. - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (rc) - return(rc); - else - return(1); - } - - func->status = 0; - func->switch_save = 0x10; - - index = 1; - while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { - rc |= cpqhp_configure_board(ctrl, func); - index++; - } - - if (rc) { - // If configuration fails, turn it off - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of an adapter. - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - return(rc); - } - // Done configuring so turn LED on full time - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - rc = 0; - } else { - // Something is wrong - - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of an adapter. - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - } - - } - return(rc); - -} - - -/** - * board_added - Called after a board has been added to the system. - * - * Turns power on for the board - * Configures board - * - */ -static u32 board_added(struct pci_func * func, struct controller * ctrl) -{ - u8 hp_slot; - u8 temp_byte; - u8 adapter_speed; - int index; - u32 temp_register = 0xFFFFFFFF; - u32 rc = 0; - struct pci_func *new_slot = NULL; - struct slot *p_slot; - struct resource_lists res_lists; - - hp_slot = func->device - ctrl->slot_device_offset; - dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", - __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - // turn on board without attaching to the bus - enable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Change bits in slot power register to force another shift out - // NOTE: this is to work around the timer bug - temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); - writeb(0x00, ctrl->hpc_reg + SLOT_POWER); - writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - adapter_speed = get_adapter_speed(ctrl, hp_slot); - if (ctrl->speed != adapter_speed) - if (set_controller_speed(ctrl, adapter_speed, hp_slot)) - rc = WRONG_BUS_FREQUENCY; - - // turn off board without attaching to the bus - disable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (rc) - return(rc); - - p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - // turn on board and blink green LED - - // Wait for exclusive access to hardware - dbg("%s: before down\n", __FUNCTION__); - down(&ctrl->crit_sect); - dbg("%s: after down\n", __FUNCTION__); - - dbg("%s: before slot_enable\n", __FUNCTION__); - slot_enable (ctrl, hp_slot); - - dbg("%s: before green_LED_blink\n", __FUNCTION__); - green_LED_blink (ctrl, hp_slot); - - dbg("%s: before amber_LED_blink\n", __FUNCTION__); - amber_LED_off (ctrl, hp_slot); - - dbg("%s: before set_SOGO\n", __FUNCTION__); - set_SOGO(ctrl); - - // Wait for SOBS to be unset - dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__); - wait_for_ctrl_irq (ctrl); - dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__); - - // Done with exclusive hardware access - dbg("%s: before up\n", __FUNCTION__); - up(&ctrl->crit_sect); - dbg("%s: after up\n", __FUNCTION__); - - // Wait for ~1 second because of hot plug spec - dbg("%s: before long_delay\n", __FUNCTION__); - long_delay(1*HZ); - dbg("%s: after long_delay\n", __FUNCTION__); - - dbg("%s: func status = %x\n", __FUNCTION__, func->status); - // Check for a power fault - if (func->status == 0xFF) { - // power fault occurred, but it was benign - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); - rc = POWER_FAILURE; - func->status = 0; - } else { - // Get vendor/device ID u32 - ctrl->pci_bus->number = func->bus; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); - - if (rc != 0) { - // Something's wrong here - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); - } - // Preset return code. It will be changed later if things go okay. - rc = NO_ADAPTER_PRESENT; - } - - // All F's is an empty slot or an invalid board - if (temp_register != 0xFFFFFFFF) { // Check for a board in the slot - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - res_lists.irqs = NULL; - - rc = configure_new_device(ctrl, func, 0, &res_lists); - - dbg("%s: back from configure_new_device\n", __FUNCTION__); - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - return(rc); - } else { - cpqhp_save_slot_config(ctrl, func); - } - - - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; - - //next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present) - dbg("%s: configure linux pci_dev structure\n", __FUNCTION__); - index = 0; - do { - new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); - if (new_slot && !new_slot->pci_dev) { - cpqhp_configure_device(ctrl, new_slot); - } - } while (new_slot); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - } else { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - return(rc); - } - return 0; -} - - -/** - * remove_board - Turns off slot and LED's - * - */ -static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) -{ - int index; - u8 skip = 0; - u8 device; - u8 hp_slot; - u8 temp_byte; - u32 rc; - struct resource_lists res_lists; - struct pci_func *temp_func; - - if (func == NULL) - return(1); - - if (cpqhp_unconfigure_device(func)) - return(1); - - device = func->device; - - hp_slot = func->device - ctrl->slot_device_offset; - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - - // When we get here, it is safe to change base Address Registers. - // We will attempt to save the base Address Register Lengths - if (replace_flag || !ctrl->add_support) - rc = cpqhp_save_base_addr_length(ctrl, func); - else if (!func->bus_head && !func->mem_head && - !func->p_mem_head && !func->io_head) { - // Here we check to see if we've saved any of the board's - // resources already. If so, we'll skip the attempt to - // determine what's being used. - index = 0; - temp_func = cpqhp_slot_find(func->bus, func->device, index++); - while (temp_func) { - if (temp_func->bus_head || temp_func->mem_head - || temp_func->p_mem_head || temp_func->io_head) { - skip = 1; - break; - } - temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++); - } - - if (!skip) - rc = cpqhp_save_used_resources(ctrl, func); - } - // Change status to shutdown - if (func->is_a_board) - func->status = 0x01; - func->configured = 0; - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // turn off SERR for slot - temp_byte = readb(ctrl->hpc_reg + SLOT_SERR); - temp_byte &= ~(0x01 << hp_slot); - writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (!replace_flag && ctrl->add_support) { - while (func) { - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - - cpqhp_return_board_resources(func, &res_lists); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (is_bridge(func)) { - bridge_slot_remove(func); - } else - slot_remove(func); - - func = cpqhp_slot_find(ctrl->bus, device, 0); - } - - // Setup slot structure with entry for empty slot - func = cpqhp_slot_create(ctrl->bus); - - if (func == NULL) { - // Out of memory - return(1); - } - - func->bus = ctrl->bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->switch_save = 0x10; - func->is_a_board = 0; - func->p_task_event = NULL; - } - - return 0; -} - - -static void pushbutton_helper_thread (unsigned long data) -{ - pushbutton_pending = data; - up(&event_semaphore); -} - - -// this is the main worker thread -static int event_thread(void* data) -{ - struct controller *ctrl; - lock_kernel(); - daemonize("phpd_event"); - - unlock_kernel(); - - while (1) { - dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished) break; - /* Do stuff here */ - if (pushbutton_pending) - cpqhp_pushbutton_thread(pushbutton_pending); - else - for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next) - interrupt_event_handler(ctrl); - } - dbg("event_thread signals exit\n"); - up(&event_exit); - return 0; -} - - -int cpqhp_event_start_thread (void) -{ - int pid; - - /* initialize our semaphores */ - init_MUTEX(&delay_sem); - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - pid = kernel_thread(event_thread, 0, 0); - if (pid < 0) { - err ("Can't start up our event thread\n"); - return -1; - } - dbg("Our event thread pid = %d\n", pid); - return 0; -} - - -void cpqhp_event_stop_thread (void) -{ - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); -} - - -static int update_slot_info (struct controller *ctrl, struct slot *slot) -{ - struct hotplug_slot_info *info; - int result; - - info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->power_status = get_slot_enabled(ctrl, slot); - info->attention_status = cpq_get_attention_status(ctrl, slot); - info->latch_status = cpq_get_latch_status(ctrl, slot); - info->adapter_status = get_presence_status(ctrl, slot); - result = pci_hp_change_slot_info(slot->hotplug_slot, info); - kfree (info); - return result; -} - -static void interrupt_event_handler(struct controller *ctrl) -{ - int loop = 0; - int change = 1; - struct pci_func *func; - u8 hp_slot; - struct slot *p_slot; - - while (change) { - change = 0; - - for (loop = 0; loop < 10; loop++) { - //dbg("loop %d\n", loop); - if (ctrl->event_queue[loop].event_type != 0) { - hp_slot = ctrl->event_queue[loop].hp_slot; - - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - if (!func) - return; - - p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - if (!p_slot) - return; - - dbg("hp_slot %d, func %p, p_slot %p\n", - hp_slot, func, p_slot); - - if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { - dbg("button pressed\n"); - } else if (ctrl->event_queue[loop].event_type == - INT_BUTTON_CANCEL) { - dbg("button cancel\n"); - del_timer(&p_slot->task_event); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - if (p_slot->state == BLINKINGOFF_STATE) { - // slot is on - // turn on green LED - dbg("turn on green LED\n"); - green_LED_on (ctrl, hp_slot); - } else if (p_slot->state == BLINKINGON_STATE) { - // slot is off - // turn off green LED - dbg("turn off green LED\n"); - green_LED_off (ctrl, hp_slot); - } - - info(msg_button_cancel, p_slot->number); - - p_slot->state = STATIC_STATE; - - amber_LED_off (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - } - // ***********button Released (No action on press...) - else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { - dbg("button release\n"); - - if (is_slot_enabled (ctrl, hp_slot)) { - // slot is on - dbg("slot is on\n"); - p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); - } else { - // slot is off - dbg("slot is off\n"); - p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); - } - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - dbg("blink green LED and turn off amber\n"); - - amber_LED_off (ctrl, hp_slot); - green_LED_blink (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - init_timer(&p_slot->task_event); - p_slot->hp_slot = hp_slot; - p_slot->ctrl = ctrl; -// p_slot->physical_slot = physical_slot; - p_slot->task_event.expires = jiffies + 5 * HZ; // 5 second delay - p_slot->task_event.function = pushbutton_helper_thread; - p_slot->task_event.data = (u32) p_slot; - - dbg("add_timer p_slot = %p\n", p_slot); - add_timer(&p_slot->task_event); - } - // ***********POWER FAULT - else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { - dbg("power fault\n"); - } else { - /* refresh notification */ - if (p_slot) - update_slot_info(ctrl, p_slot); - } - - ctrl->event_queue[loop].event_type = 0; - - change = 1; - } - } // End of FOR loop - } - - return; -} - - -/** - * cpqhp_pushbutton_thread - * - * Scheduled procedure to handle blocking stuff for the pushbuttons - * Handles all pending events and exits. - * - */ -void cpqhp_pushbutton_thread (unsigned long slot) -{ - u8 hp_slot; - u8 device; - struct pci_func *func; - struct slot *p_slot = (struct slot *) slot; - struct controller *ctrl = (struct controller *) p_slot->ctrl; - - pushbutton_pending = 0; - hp_slot = p_slot->hp_slot; - - device = p_slot->device; - - if (is_slot_enabled (ctrl, hp_slot)) { - p_slot->state = POWEROFF_STATE; - // power Down board - func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); - dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); - if (!func) { - dbg("Error! func NULL in %s\n", __FUNCTION__); - return ; - } - - if (func != NULL && ctrl != NULL) { - if (cpqhp_process_SS(ctrl, func) != 0) { - amber_LED_on (ctrl, hp_slot); - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - } - } - - p_slot->state = STATIC_STATE; - } else { - p_slot->state = POWERON_STATE; - // slot is off - - func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); - dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); - if (!func) { - dbg("Error! func NULL in %s\n", __FUNCTION__); - return ; - } - - if (func != NULL && ctrl != NULL) { - if (cpqhp_process_SI(ctrl, func) != 0) { - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - } - } - - p_slot->state = STATIC_STATE; - } - - return; -} - - -int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func) -{ - u8 device, hp_slot; - u16 temp_word; - u32 tempdword; - int rc; - struct slot* p_slot; - int physical_slot = 0; - - if (!ctrl) - return(1); - - tempdword = 0; - - device = func->device; - hp_slot = device - ctrl->slot_device_offset; - p_slot = cpqhp_find_slot(ctrl, device); - if (p_slot) { - physical_slot = p_slot->number; - } - - // Check to see if the interlock is closed - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - if (tempdword & (0x01 << hp_slot)) { - return(1); - } - - if (func->is_a_board) { - rc = board_replaced(func, ctrl); - } else { - // add board - slot_remove(func); - - func = cpqhp_slot_create(ctrl->bus); - if (func == NULL) { - return(1); - } - - func->bus = ctrl->bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; - - // We have to save the presence info for these slots - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - func->switch_save = 0; - } else { - func->switch_save = 0x10; - } - - rc = board_added(func, ctrl); - if (rc) { - if (is_bridge(func)) { - bridge_slot_remove(func); - } else - slot_remove(func); - - // Setup slot structure with entry for empty slot - func = cpqhp_slot_create(ctrl->bus); - - if (func == NULL) { - // Out of memory - return(1); - } - - func->bus = ctrl->bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->is_a_board = 0; - - // We have to save the presence info for these slots - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= - (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - func->switch_save = 0; - } else { - func->switch_save = 0x10; - } - } - } - - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - } - - if (p_slot) - update_slot_info(ctrl, p_slot); - - return rc; -} - - -int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func) -{ - u8 device, class_code, header_type, BCR; - u8 index = 0; - u8 replace_flag; - u32 rc = 0; - unsigned int devfn; - struct slot* p_slot; - struct pci_bus *pci_bus = ctrl->pci_bus; - int physical_slot=0; - - device = func->device; - func = cpqhp_slot_find(ctrl->bus, device, index++); - p_slot = cpqhp_find_slot(ctrl, device); - if (p_slot) { - physical_slot = p_slot->number; - } - - // Make sure there are no video controllers here - while (func && !rc) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Check the Class Code - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (rc) - return rc; - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - /* Display/Video adapter (not supported) */ - rc = REMOVE_NOT_SUPPORTED; - } else { - // See if it's a bridge - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - // If it's a bridge, check the VGA Enable bit - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); - if (rc) - return rc; - - // If the VGA Enable bit is set, remove isn't supported - if (BCR & PCI_BRIDGE_CTL_VGA) { - rc = REMOVE_NOT_SUPPORTED; - } - } - } - - func = cpqhp_slot_find(ctrl->bus, device, index++); - } - - func = cpqhp_slot_find(ctrl->bus, device, 0); - if ((func != NULL) && !rc) { - //FIXME: Replace flag should be passed into process_SS - replace_flag = !(ctrl->add_support); - rc = remove_board(func, replace_flag, ctrl); - } else if (!rc) { - rc = 1; - } - - if (p_slot) - update_slot_info(ctrl, p_slot); - - return(rc); -} - - - -/** - * hardware_test - runs hardware tests - * - * For hot plug ctrl folks to play with. - * test_num is the number entered in the GUI - * - */ -int cpqhp_hardware_test(struct controller *ctrl, int test_num) -{ - u32 save_LED; - u32 work_LED; - int loop; - int num_of_slots; - - num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; - - switch (test_num) { - case 1: - // Do stuff here! - - // Do that funky LED thing - save_LED = readl(ctrl->hpc_reg + LED_CONTROL); // so we can restore them later - work_LED = 0x01010101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - work_LED = 0x00000101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((3*HZ)/10); - work_LED = work_LED >> 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((3*HZ)/10); - work_LED = work_LED << 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - } - - writel (save_LED, ctrl->hpc_reg + LED_CONTROL); // put it back the way it was - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - break; - case 2: - // Do other stuff here! - break; - case 3: - // and more... - break; - } - return 0; -} - - -/** - * configure_new_device - Configures the PCI header information of one board. - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Returns 0 if success - * - */ -static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources) -{ - u8 temp_byte, function, max_functions, stop_it; - int rc; - u32 ID; - struct pci_func *new_slot; - int index; - - new_slot = func; - - dbg("%s\n", __FUNCTION__); - // Check for Multi-function device - ctrl->pci_bus->number = func->bus; - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - return rc; - } - - if (temp_byte & 0x80) // Multi-function device - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - rc = configure_new_function(ctrl, new_slot, behind_bridge, resources); - - if (rc) { - dbg("configure_new_function failed %d\n",rc); - index = 0; - - while (new_slot) { - new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++); - - if (new_slot) - cpqhp_return_board_resources(new_slot, resources); - } - - return(rc); - } - - function++; - - stop_it = 0; - - // The following loop skips to the next present function - // and creates a board structure - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - - if (ID == 0xFFFFFFFF) { // There's nothing there. - function++; - } else { // There's something there - // Setup slot structure. - new_slot = cpqhp_slot_create(func->bus); - - if (new_slot == NULL) { - // Out of memory - return(1); - } - - new_slot->bus = func->bus; - new_slot->device = func->device; - new_slot->function = function; - new_slot->is_a_board = 1; - new_slot->status = 0; - - stop_it++; - } - } - - } while (function < max_functions); - dbg("returning from configure_new_device\n"); - - return 0; -} - - -/* - Configuration logic that involves the hotplug data structures and - their bookkeeping - */ - - -/** - * configure_new_function - Configures the PCI header information of one device - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Calls itself recursively for bridged devices. - * Returns 0 if success - * - */ -static int configure_new_function (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources) -{ - int cloop; - u8 IRQ; - u8 temp_byte; - u8 device; - u8 class_code; - u16 command; - u16 temp_word; - u32 temp_dword; - u32 rc; - u32 temp_register; - u32 base; - u32 ID; - unsigned int devfn; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_resource *hold_mem_node; - struct pci_resource *hold_p_mem_node; - struct pci_resource *hold_IO_node; - struct pci_resource *hold_bus_node; - struct irq_mapping irqs; - struct pci_func *new_slot; - struct pci_bus *pci_bus; - struct resource_lists temp_resources; - - pci_bus = ctrl->pci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Check for Bridge - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); - if (rc) - return rc; - - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // set Primary bus - dbg("set Primary bus = %d\n", func->bus); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); - if (rc) - return rc; - - // find range of busses to use - dbg("find ranges of buses to use\n"); - bus_node = get_max_resource(&resources->bus_head, 1); - - // If we don't have any busses to allocate, we can't continue - if (!bus_node) - return -ENOMEM; - - // set Secondary bus - temp_byte = bus_node->base; - dbg("set Secondary bus = %d\n", bus_node->base); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); - if (rc) - return rc; - - // set subordinate bus - temp_byte = bus_node->base + bus_node->length - 1; - dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - if (rc) - return rc; - - // set subordinate Latency Timer and base Latency Timer - temp_byte = 0x40; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - if (rc) - return rc; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - if (rc) - return rc; - - // set Cache Line size - temp_byte = 0x08; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - if (rc) - return rc; - - // Setup the IO, memory, and prefetchable windows - - io_node = get_max_resource(&(resources->io_head), 0x1000); - if (!io_node) - return -ENOMEM; - mem_node = get_max_resource(&(resources->mem_head), 0x100000); - if (!mem_node) - return -ENOMEM; - p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000); - if (!p_mem_node) - return -ENOMEM; - dbg("Setup the IO, memory, and prefetchable windows\n"); - dbg("io_node\n"); - dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); - dbg("mem_node\n"); - dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); - dbg("p_mem_node\n"); - dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); - - // set up the IRQ info - if (!resources->irqs) { - irqs.barber_pole = 0; - irqs.interrupt[0] = 0; - irqs.interrupt[1] = 0; - irqs.interrupt[2] = 0; - irqs.interrupt[3] = 0; - irqs.valid_INT = 0; - } else { - irqs.barber_pole = resources->irqs->barber_pole; - irqs.interrupt[0] = resources->irqs->interrupt[0]; - irqs.interrupt[1] = resources->irqs->interrupt[1]; - irqs.interrupt[2] = resources->irqs->interrupt[2]; - irqs.interrupt[3] = resources->irqs->interrupt[3]; - irqs.valid_INT = resources->irqs->valid_INT; - } - - // set up resource lists that are now aligned on top and bottom - // for anything behind the bridge. - temp_resources.bus_head = bus_node; - temp_resources.io_head = io_node; - temp_resources.mem_head = mem_node; - temp_resources.p_mem_head = p_mem_node; - temp_resources.irqs = &irqs; - - // Make copies of the nodes we are going to pass down so that - // if there is a problem,we can just use these to free resources - hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { - if (hold_bus_node) - kfree(hold_bus_node); - if (hold_IO_node) - kfree(hold_IO_node); - if (hold_mem_node) - kfree(hold_mem_node); - if (hold_p_mem_node) - kfree(hold_p_mem_node); - - return(1); - } - - memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); - - bus_node->base += 1; - bus_node->length -= 1; - bus_node->next = NULL; - - // If we have IO resources copy them and fill in the bridge's - // IO range registers - if (io_node) { - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; - - // set IO base and Limit registers - temp_byte = io_node->base >> 8; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - temp_byte = (io_node->base + io_node->length - 1) >> 8; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - } else { - kfree(hold_IO_node); - hold_IO_node = NULL; - } - - // If we have memory resources copy them and fill in the bridge's - // memory range registers. Otherwise, fill in the range - // registers with values that disable them. - if (mem_node) { - memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; - - // set Mem base and Limit registers - temp_word = mem_node->base >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = (mem_node->base + mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - kfree(hold_mem_node); - hold_mem_node = NULL; - } - - // If we have prefetchable memory resources copy them and - // fill in the bridge's memory range registers. Otherwise, - // fill in the range registers with values that disable them. - if (p_mem_node) { - memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); - p_mem_node->next = NULL; - - // set Pre Mem base and Limit registers - temp_word = p_mem_node->base >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - kfree(hold_p_mem_node); - hold_p_mem_node = NULL; - } - - // Adjust this to compensate for extra adjustment in first loop - irqs.barber_pole--; - - rc = 0; - - // Here we actually find the devices and configure them - for (device = 0; (device <= 0x1F) && !rc; device++) { - irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; - - ID = 0xFFFFFFFF; - pci_bus->number = hold_bus_node->base; - pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), 0x00, &ID); - pci_bus->number = func->bus; - - if (ID != 0xFFFFFFFF) { // device Present - // Setup slot structure. - new_slot = cpqhp_slot_create(hold_bus_node->base); - - if (new_slot == NULL) { - // Out of memory - rc = -ENOMEM; - continue; - } - - new_slot->bus = hold_bus_node->base; - new_slot->device = device; - new_slot->function = 0; - new_slot->is_a_board = 1; - new_slot->status = 0; - - rc = configure_new_device(ctrl, new_slot, 1, &temp_resources); - dbg("configure_new_device rc=0x%x\n",rc); - } // End of IF (device in slot?) - } // End of FOR loop - - if (rc) { - cpqhp_destroy_resource_list(&temp_resources); - - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return(rc); - } - // save the interrupt routing information - if (resources->irqs) { - resources->irqs->interrupt[0] = irqs.interrupt[0]; - resources->irqs->interrupt[1] = irqs.interrupt[1]; - resources->irqs->interrupt[2] = irqs.interrupt[2]; - resources->irqs->interrupt[3] = irqs.interrupt[3]; - resources->irqs->valid_INT = irqs.valid_INT; - } else if (!behind_bridge) { - // We need to hook up the interrupts here - for (cloop = 0; cloop < 4; cloop++) { - if (irqs.valid_INT & (0x01 << cloop)) { - rc = cpqhp_set_irq(func->bus, func->device, - 0x0A + cloop, irqs.interrupt[cloop]); - if (rc) { - cpqhp_destroy_resource_list (&temp_resources); - - return_resource(&(resources-> bus_head), hold_bus_node); - return_resource(&(resources-> io_head), hold_IO_node); - return_resource(&(resources-> mem_head), hold_mem_node); - return_resource(&(resources-> p_mem_head), hold_p_mem_node); - return rc; - } - } - } // end of for loop - } - // Return unused bus resources - // First use the temporary node to store information for the board - if (hold_bus_node && bus_node && temp_resources.bus_head) { - hold_bus_node->length = bus_node->base - hold_bus_node->base; - - hold_bus_node->next = func->bus_head; - func->bus_head = hold_bus_node; - - temp_byte = temp_resources.bus_head->base - 1; - - // set subordinate bus - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - - if (temp_resources.bus_head->length == 0) { - kfree(temp_resources.bus_head); - temp_resources.bus_head = NULL; - } else { - return_resource(&(resources->bus_head), temp_resources.bus_head); - } - } - - // If we have IO space available and there is some left, - // return the unused portion - if (hold_IO_node && temp_resources.io_head) { - io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), - &hold_IO_node, 0x1000); - - // Check if we were able to split something off - if (io_node) { - hold_IO_node->base = io_node->base + io_node->length; - - temp_byte = (hold_IO_node->base) >> 8; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - return_resource(&(resources->io_head), io_node); - } - - io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); - - // Check if we were able to split something off - if (io_node) { - // First use the temporary node to store information for the board - hold_IO_node->length = io_node->base - hold_IO_node->base; - - // If we used any, add it to the board's list - if (hold_IO_node->length) { - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - - temp_byte = (io_node->base - 1) >> 8; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - } else { - // it doesn't need any IO - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_LIMIT, temp_word); - - return_resource(&(resources->io_head), io_node); - kfree(hold_IO_node); - } - } else { - // it used most of the range - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - } else if (hold_IO_node) { - // it used the whole range - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - // If we have memory space available and there is some left, - // return the unused portion - if (hold_mem_node && temp_resources.mem_head) { - mem_node = do_pre_bridge_resource_split(&(temp_resources. mem_head), - &hold_mem_node, 0x100000); - - // Check if we were able to split something off - if (mem_node) { - hold_mem_node->base = mem_node->base + mem_node->length; - - temp_word = (hold_mem_node->base) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - return_resource(&(resources->mem_head), mem_node); - } - - mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000); - - // Check if we were able to split something off - if (mem_node) { - // First use the temporary node to store information for the board - hold_mem_node->length = mem_node->base - hold_mem_node->base; - - if (hold_mem_node->length) { - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - - // configure end address - temp_word = (mem_node->base - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - // Return unused resources to the pool - return_resource(&(resources->mem_head), mem_node); - } else { - // it doesn't need any Mem - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->mem_head), mem_node); - kfree(hold_mem_node); - } - } else { - // it used most of the range - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - } else if (hold_mem_node) { - // it used the whole range - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - // If we have prefetchable memory space available and there is some - // left at the end, return the unused portion - if (hold_p_mem_node && temp_resources.p_mem_head) { - p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), - &hold_p_mem_node, 0x100000); - - // Check if we were able to split something off - if (p_mem_node) { - hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; - - temp_word = (hold_p_mem_node->base) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } - - p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000); - - // Check if we were able to split something off - if (p_mem_node) { - // First use the temporary node to store information for the board - hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; - - // If we used any, add it to the board's list - if (hold_p_mem_node->length) { - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - - temp_word = (p_mem_node->base - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } else { - // it doesn't need any PMem - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - kfree(hold_p_mem_node); - } - } else { - // it used the most of the range - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - } else if (hold_p_mem_node) { - // it used the whole range - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - // We should be configuring an IRQ and the bridge's base address - // registers if it needs them. Although we have never seen such - // a device - - // enable card - command = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); - - // set Bridge Control Register - command = 0x07; // = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Standard device - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - // Display (video) adapter (not supported) - return(DEVICE_TYPE_NOT_SUPPORTED); - } - // Figure out IO and memory needs - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - temp_register = 0xFFFFFFFF; - - dbg("CND: bus=%d, devfn=%d, offset=%d\n", pci_bus->number, devfn, cloop); - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - - rc = pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register); - dbg("CND: base = 0x%x\n", temp_register); - - if (temp_register) { // If this register is implemented - if ((temp_register & 0x03L) == 0x01) { - // Map IO - - // set base = amount of IO space - base = temp_register & 0xFFFFFFFC; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - io_node = get_io_resource(&(resources->io_head), base); - dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n", - io_node->base, io_node->length, io_node->next); - dbg("func (%p) io_head (%p)\n", func, func->io_head); - - // allocate the resource to the board - if (io_node) { - base = io_node->base; - - io_node->next = func->io_head; - func->io_head = io_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x08) { - // Map prefetchable memory - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - p_mem_node = get_resource(&(resources->p_mem_head), base); - - // allocate the resource to the board - if (p_mem_node) { - base = p_mem_node->base; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x00) { - // Map memory - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - mem_node = get_resource(&(resources->mem_head), base); - - // allocate the resource to the board - if (mem_node) { - base = mem_node->base; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x04) { - // Map memory - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - mem_node = get_resource(&(resources->mem_head), base); - - // allocate the resource to the board - if (mem_node) { - base = mem_node->base; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x06) { - // Those bits are reserved, we can't handle this - return(1); - } else { - // Requesting space below 1M - return(NOT_ENOUGH_RESOURCES); - } - - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); - - // Check for 64-bit base - if ((temp_register & 0x07L) == 0x04) { - cloop += 4; - - // Upper 32 bits of address always zero on today's systems - // FIXME this is probably not true on Alpha and ia64??? - base = 0; - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); - } - } - } // End of base register loop - - // Figure out which interrupt pin this function uses - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); - - // If this function needs an interrupt and we are behind a bridge - // and the pin is tied to something that's alread mapped, - // set this one the same - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & - (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { - // We have to share with something already set up - IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; - } else { - // Program IRQ based on card type - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_STORAGE) { - IRQ = cpqhp_disk_irq; - } else { - IRQ = cpqhp_nic_irq; - } - } - - // IRQ Line - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); - - if (!behind_bridge) { - rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); - if (rc) - return(1); - } else { - //TBD - this code may also belong in the other clause of this If statement - resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; - resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; - } - - // Latency Timer - temp_byte = 0x40; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - - // Cache Line size - temp_byte = 0x08; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - - // disable ROM base Address - temp_dword = 0x00L; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_dword); - - // enable card - temp_word = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, temp_word); - } // End of Not-A-Bridge else - else { - // It's some strange type of PCI adapter (Cardbus?) - return(DEVICE_TYPE_NOT_SUPPORTED); - } - - func->configured = 1; - - return 0; -} - diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp_nvram.c linux-2.5.70-bk10/drivers/hotplug/cpqphp_nvram.c --- linux-2.5.70-bk9/drivers/hotplug/cpqphp_nvram.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp_nvram.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,667 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpqphp.h" -#include "cpqphp_nvram.h" - - -#define ROM_INT15_PHY_ADDR 0x0FF859 -#define READ_EV 0xD8A4 -#define WRITE_EV 0xD8A5 - -struct register_foo { - union { - unsigned long lword; /* eax */ - unsigned short word; /* ax */ - - struct { - unsigned char low; /* al */ - unsigned char high; /* ah */ - } byte; - } data; - - unsigned char opcode; /* see below */ - unsigned long length; /* if the reg. is a pointer, how much data */ -} __attribute__ ((packed)); - -struct all_reg { - struct register_foo eax_reg; - struct register_foo ebx_reg; - struct register_foo ecx_reg; - struct register_foo edx_reg; - struct register_foo edi_reg; - struct register_foo esi_reg; - struct register_foo eflags_reg; -} __attribute__ ((packed)); - - -struct ev_hrt_header { - u8 Version; - u8 num_of_ctrl; - u8 next; -}; - -struct ev_hrt_ctrl { - u8 bus; - u8 device; - u8 function; - u8 mem_avail; - u8 p_mem_avail; - u8 io_avail; - u8 bus_avail; - u8 next; -}; - - -static u8 evbuffer_init; -static u8 evbuffer_length; -static u8 evbuffer[1024]; - -static void *compaq_int15_entry_point; - -static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ - - -/* This is a series of function that deals with - setting & getting the hotplug resource table in some environment variable. -*/ - -/* - * We really shouldn't be doing this unless there is a _very_ good reason to!!! - * greg k-h - */ - - -static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) -{ - u8 **tByte; - - if ((*used + 1) > *avail) - return(1); - - *((u8*)*p_buffer) = value; - tByte = (u8**)p_buffer; - (*tByte)++; - *used+=1; - return(0); -} - - -static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) -{ - if ((*used + 4) > *avail) - return(1); - - **p_buffer = value; - (*p_buffer)++; - *used+=4; - return(0); -} - - -/* - * check_for_compaq_ROM - * - * this routine verifies that the ROM OEM string is 'COMPAQ' - * - * returns 0 for non-Compaq ROM, 1 for Compaq ROM - */ -static int check_for_compaq_ROM (void *rom_start) -{ - u8 temp1, temp2, temp3, temp4, temp5, temp6; - int result = 0; - - temp1 = readb(rom_start + 0xffea + 0); - temp2 = readb(rom_start + 0xffea + 1); - temp3 = readb(rom_start + 0xffea + 2); - temp4 = readb(rom_start + 0xffea + 3); - temp5 = readb(rom_start + 0xffea + 4); - temp6 = readb(rom_start + 0xffea + 5); - if ((temp1 == 'C') && - (temp2 == 'O') && - (temp3 == 'M') && - (temp4 == 'P') && - (temp5 == 'A') && - (temp6 == 'Q')) { - result = 1; - } - dbg ("%s - returned %d\n", __FUNCTION__, result); - return result; -} - - -static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) -{ - unsigned long flags; - int op = operation; - int ret_val; - - if (!compaq_int15_entry_point) - return -ENODEV; - - spin_lock_irqsave(&int15_lock, flags); - __asm__ ( - "xorl %%ebx,%%ebx\n" \ - "xorl %%edx,%%edx\n" \ - "pushf\n" \ - "push %%cs\n" \ - "cli\n" \ - "call *%6\n" - : "=c" (*buf_size), "=a" (ret_val) - : "a" (op), "c" (*buf_size), "S" (ev_name), - "D" (buffer), "m" (compaq_int15_entry_point) - : "%ebx", "%edx"); - spin_unlock_irqrestore(&int15_lock, flags); - - return((ret_val & 0xFF00) >> 8); -} - - -/* - * load_HRT - * - * Read the hot plug Resource Table from NVRAM - */ -static int load_HRT (void *rom_start) -{ - u32 available; - u32 temp_dword; - u8 temp_byte = 0xFF; - u32 rc; - - if (!check_for_compaq_ROM(rom_start)) { - return -ENODEV; - } - - available = 1024; - - // Now load the EV - temp_dword = available; - - rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); - - evbuffer_length = temp_dword; - - // We're maintaining the resource lists so write FF to invalidate old info - temp_dword = 1; - - rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); - - return rc; -} - - -/* - * store_HRT - * - * Save the hot plug Resource Table in NVRAM - */ -static u32 store_HRT (void *rom_start) -{ - u32 *buffer; - u32 *pFill; - u32 usedbytes; - u32 available; - u32 temp_dword; - u32 rc; - u8 loop; - u8 numCtrl = 0; - struct controller *ctrl; - struct pci_resource *resNode; - struct ev_hrt_header *p_EV_header; - struct ev_hrt_ctrl *p_ev_ctrl; - - available = 1024; - - if (!check_for_compaq_ROM(rom_start)) { - return(1); - } - - buffer = (u32*) evbuffer; - - if (!buffer) - return(1); - - pFill = buffer; - usedbytes = 0; - - p_EV_header = (struct ev_hrt_header *) pFill; - - ctrl = cpqhp_ctrl_list; - - // The revision of this structure - rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); - if (rc) - return(rc); - - // The number of controllers - rc = add_byte( &pFill, 1, &usedbytes, &available); - if (rc) - return(rc); - - while (ctrl) { - p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; - - numCtrl++; - - // The bus number - rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); - if (rc) - return(rc); - - // The device Number - rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); - if (rc) - return(rc); - - // The function Number - rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); - if (rc) - return(rc); - - // Skip the number of available entries - rc = add_dword( &pFill, 0, &usedbytes, &available); - if (rc) - return(rc); - - // Figure out memory Available - - resNode = ctrl->mem_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->mem_avail = loop; - - // Figure out prefetchable memory Available - - resNode = ctrl->p_mem_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->p_mem_avail = loop; - - // Figure out IO Available - - resNode = ctrl->io_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->io_avail = loop; - - // Figure out bus Available - - resNode = ctrl->bus_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->bus_avail = loop; - - ctrl = ctrl->next; - } - - p_EV_header->num_of_ctrl = numCtrl; - - // Now store the EV - - temp_dword = usedbytes; - - rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword); - - dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); - - evbuffer_length = temp_dword; - - if (rc) { - err(msg_unable_to_save); - return(1); - } - - return(0); -} - - -void compaq_nvram_init (void *rom_start) -{ - if (rom_start) { - compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); - } - dbg("int15 entry = %p\n", compaq_int15_entry_point); - - /* initialize our int15 lock */ - spin_lock_init(&int15_lock); -} - - -int compaq_nvram_load (void *rom_start, struct controller *ctrl) -{ - u8 bus, device, function; - u8 nummem, numpmem, numio, numbus; - u32 rc; - u8 *p_byte; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct ev_hrt_ctrl *p_ev_ctrl; - struct ev_hrt_header *p_EV_header; - - if (!evbuffer_init) { - // Read the resource list information in from NVRAM - if (load_HRT(rom_start)) - memset (evbuffer, 0, 1024); - - evbuffer_init = 1; - } - - // If we saved information in NVRAM, use it now - p_EV_header = (struct ev_hrt_header *) evbuffer; - - // The following code is for systems where version 1.0 of this - // driver has been loaded, but doesn't support the hardware. - // In that case, the driver would incorrectly store something - // in NVRAM. - if ((p_EV_header->Version == 2) || - ((p_EV_header->Version == 1) && !ctrl->push_flag)) { - p_byte = &(p_EV_header->next); - - p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); - - p_byte += 3; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - bus = p_ev_ctrl->bus; - device = p_ev_ctrl->device; - function = p_ev_ctrl->function; - - while ((bus != ctrl->bus) || - (device != PCI_SLOT(ctrl->pci_dev->devfn)) || - (function != PCI_FUNC(ctrl->pci_dev->devfn))) { - nummem = p_ev_ctrl->mem_avail; - numpmem = p_ev_ctrl->p_mem_avail; - numio = p_ev_ctrl->io_avail; - numbus = p_ev_ctrl->bus_avail; - - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - // Skip forward to the next entry - p_byte += (nummem + numpmem + numio + numbus) * 8; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; - - p_byte += 3; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - bus = p_ev_ctrl->bus; - device = p_ev_ctrl->device; - function = p_ev_ctrl->function; - } - - nummem = p_ev_ctrl->mem_avail; - numpmem = p_ev_ctrl->p_mem_avail; - numio = p_ev_ctrl->io_avail; - numbus = p_ev_ctrl->bus_avail; - - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - while (nummem--) { - mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!mem_node) - break; - - mem_node->base = *(u32*)p_byte; - dbg("mem base = %8.8x\n",mem_node->base); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(mem_node); - return 2; - } - - mem_node->length = *(u32*)p_byte; - dbg("mem length = %8.8x\n",mem_node->length); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(mem_node); - return 2; - } - - mem_node->next = ctrl->mem_head; - ctrl->mem_head = mem_node; - } - - while (numpmem--) { - p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!p_mem_node) - break; - - p_mem_node->base = *(u32*)p_byte; - dbg("pre-mem base = %8.8x\n",p_mem_node->base); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(p_mem_node); - return 2; - } - - p_mem_node->length = *(u32*)p_byte; - dbg("pre-mem length = %8.8x\n",p_mem_node->length); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(p_mem_node); - return 2; - } - - p_mem_node->next = ctrl->p_mem_head; - ctrl->p_mem_head = p_mem_node; - } - - while (numio--) { - io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!io_node) - break; - - io_node->base = *(u32*)p_byte; - dbg("io base = %8.8x\n",io_node->base); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(io_node); - return 2; - } - - io_node->length = *(u32*)p_byte; - dbg("io length = %8.8x\n",io_node->length); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(io_node); - return 2; - } - - io_node->next = ctrl->io_head; - ctrl->io_head = io_node; - } - - while (numbus--) { - bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!bus_node) - break; - - bus_node->base = *(u32*)p_byte; - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(bus_node); - return 2; - } - - bus_node->length = *(u32*)p_byte; - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(bus_node); - return 2; - } - - bus_node->next = ctrl->bus_head; - ctrl->bus_head = bus_node; - } - - // If all of the following fail, we don't have any resources for - // hot plug add - rc = 1; - rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) - return(rc); - } else { - if ((evbuffer[0] != 0) && (!ctrl->push_flag)) - return 1; - } - - return 0; -} - - -int compaq_nvram_store (void *rom_start) -{ - int rc = 1; - - if (rom_start == NULL) - return -ENODEV; - - if (evbuffer_init) { - rc = store_HRT(rom_start); - if (rc) { - err(msg_unable_to_save); - } - } - return rc; -} - diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp_nvram.h linux-2.5.70-bk10/drivers/hotplug/cpqphp_nvram.h --- linux-2.5.70-bk9/drivers/hotplug/cpqphp_nvram.h 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp_nvram.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,57 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#ifndef _CPQPHP_NVRAM_H -#define _CPQPHP_NVRAM_H - -#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM - -static inline void compaq_nvram_init (void *rom_start) -{ - return; -} - -static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl) -{ - return 0; -} - -static inline int compaq_nvram_store (void *rom_start) -{ - return 0; -} - -#else - -extern void compaq_nvram_init (void *rom_start); -extern int compaq_nvram_load (void *rom_start, struct controller *ctrl); -extern int compaq_nvram_store (void *rom_start); - -#endif - -#endif - diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp_pci.c linux-2.5.70-bk10/drivers/hotplug/cpqphp_pci.c --- linux-2.5.70-bk9/drivers/hotplug/cpqphp_pci.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp_pci.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1548 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpqphp.h" -#include "cpqphp_nvram.h" -#include "../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ - - -u8 cpqhp_nic_irq; -u8 cpqhp_disk_irq; - -static u16 unused_IRQ; - -/* - * detect_HRT_floating_pointer - * - * find the Hot Plug Resource Table in the specified region of memory. - * - */ -static void *detect_HRT_floating_pointer(void *begin, void *end) -{ - void *fp; - void *endp; - u8 temp1, temp2, temp3, temp4; - int status = 0; - - endp = (end - sizeof(struct hrt) + 1); - - for (fp = begin; fp <= endp; fp += 16) { - temp1 = readb(fp + SIG0); - temp2 = readb(fp + SIG1); - temp3 = readb(fp + SIG2); - temp4 = readb(fp + SIG3); - if (temp1 == '$' && - temp2 == 'H' && - temp3 == 'R' && - temp4 == 'T') { - status = 1; - break; - } - } - - if (!status) - fp = NULL; - - dbg("Discovered Hotplug Resource Table at %p\n", fp); - return fp; -} - - -int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) -{ - unsigned char bus; - struct pci_bus *child; - int num; - - if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - - /* No pci device, we need to create it then */ - if (func->pci_dev == NULL) { - dbg("INFO: pci_dev still null\n"); - - num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function)); - if (num) - pci_bus_add_devices(ctrl->pci_dev->bus); - - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - if (func->pci_dev == NULL) { - dbg("ERROR: pci_dev still null\n"); - return 0; - } - } - - if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); - } - - return 0; -} - - -int cpqhp_unconfigure_device(struct pci_func* func) -{ - int j; - - dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); - - for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); - if (temp) - pci_remove_bus_device(temp); - } - return 0; -} - -static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value) -{ - u32 vendID = 0; - - if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1) - return -1; - if (vendID == 0xffffffff) - return -1; - return pci_bus_read_config_dword (bus, devfn, offset, value); -} - - -/* - * cpqhp_set_irq - * - * @bus_num: bus number of PCI device - * @dev_num: device number of PCI device - * @slot: pointer to u8 where slot number will be returned - */ -int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) -{ - int rc; - u16 temp_word; - struct pci_dev fakedev; - struct pci_bus fakebus; - - fakedev.devfn = dev_num << 3; - fakedev.bus = &fakebus; - fakebus.number = bus_num; - dbg("%s: dev %d, bus %d, pin %d, num %d\n", - __FUNCTION__, dev_num, bus_num, int_pin, irq_num); - rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); - dbg("%s: rc %d\n", __FUNCTION__, rc); - if (!rc) - return !rc; - - // set the Edge Level Control Register (ELCR) - temp_word = inb(0x4d0); - temp_word |= inb(0x4d1) << 8; - - temp_word |= 0x01 << irq_num; - - // This should only be for x86 as it sets the Edge Level Control Register - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); - - return 0; -} - - -/* - * WTF??? This function isn't in the code, yet a function calls it, but the - * compiler optimizes it away? strange. Here as a placeholder to keep the - * compiler happy. - */ -static int PCI_ScanBusNonBridge (u8 bus, u8 device) -{ - return 0; -} - -static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) -{ - u8 tdevice; - u32 work; - u8 tbus; - - ctrl->pci_bus->number = bus_num; - - for (tdevice = 0; tdevice < 0x100; tdevice++) { - //Scan for access first - if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) - continue; - dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. Not a bridge ? - if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { - *dev_num = tdevice; - dbg("found it !\n"); - return 0; - } - } - for (tdevice = 0; tdevice < 0x100; tdevice++) { - //Scan for access first - if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) - continue; - dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. bridge ? - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); - dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); - if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) - return 0; - } - } - - return -1; -} - - -static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) -{ - struct irq_routing_table *PCIIRQRoutingInfoLength; - long len; - long loop; - u32 work; - - u8 tbus, tdevice, tslot; - - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return -1; - } - - for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; - - if (tslot == slot) { - *bus_num = tbus; - *dev_num = tdevice; - ctrl->pci_bus->number = tbus; - pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); - if (!nobridge || (work == 0xffffffff)) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return 0; - } - - dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); - pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); - dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); - - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus); - dbg("Scan bus for Non Bridge: bus %d\n", tbus); - if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { - *bus_num = tbus; - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return 0; - } - } else { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return 0; - } - - } - } - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return -1; -} - - -int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) -{ - return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) -} - - -/* More PCI configuration routines; this time centered around hotplug controller */ - - -/* - * cpqhp_save_config - * - * Reads configuration for all slots in a PCI bus and saves info. - * - * Note: For non-hot plug busses, the slot # saved is the device # - * - * returns 0 if success - */ -int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) -{ - long rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - struct pci_func *new_slot; - int sub_bus; - int FirstSupported; - int LastSupported; - int max_functions; - int function; - u8 DevError; - int device = 0; - int cloop = 0; - int stop_it; - int index; - - // Decide which slots are supported - - if (is_hot_plug) { - //********************************* - // is_hot_plug is the slot mask - //********************************* - FirstSupported = is_hot_plug >> 4; - LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; - } else { - FirstSupported = 0; - LastSupported = 0x1F; - } - - // Save PCI configuration space for all devices in supported slots - ctrl->pci_bus->number = busnumber; - for (device = FirstSupported; device <= LastSupported; device++) { - ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { // device in slot - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - // If multi-function device, set max_functions to 8 - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge - // Recurse the subordinate bus - // get the subordinate bus number - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - // Save secondary bus cfg spc - // with this recursive call. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return rc; - ctrl->pci_bus->number = busnumber; - } - } - - index = 0; - new_slot = cpqhp_slot_find(busnumber, device, index++); - while (new_slot && - (new_slot->function != (u8) function)) - new_slot = cpqhp_slot_find(busnumber, device, index++); - - if (!new_slot) { - // Setup slot structure. - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - // In case of unsupported board - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); - - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - if (rc) - return rc; - } - - function++; - - stop_it = 0; - - // this loop skips to the next present function - // reading in Class Code and Header type. - - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - stop_it++; - } - } - - } while (function < max_functions); - } // End of IF (device in slot?) - else if (is_hot_plug) { - // Setup slot structure with entry for empty slot - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } - } // End of FOR loop - - return(0); -} - - -/* - * cpqhp_save_slot_config - * - * Saves configuration info for all PCI devices in a given slot - * including subordinate busses. - * - * returns 0 if success - */ -int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) -{ - long rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - int sub_bus; - int max_functions; - int function; - int cloop = 0; - int stop_it; - - ID = 0xFFFFFFFF; - - ctrl->pci_bus->number = new_slot->bus; - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { // device in slot - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) // Multi-function device - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Recurse the subordinate bus - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - // Save the config headers for the secondary bus. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return(rc); - ctrl->pci_bus->number = new_slot->bus; - - } // End of IF - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - } - - function++; - - stop_it = 0; - - // this loop skips to the next present function - // reading in the Class Code and the Header type. - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); - - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); - - stop_it++; - } - } - - } while (function < max_functions); - } // End of IF (device in slot?) - else { - return(2); - } - - return(0); -} - - -/* - * cpqhp_save_base_addr_length - * - * Saves the length of all base address registers for the - * specified slot. this is for hot plug REPLACE - * - * returns 0 if success - */ -int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 type; - int sub_bus; - u32 temp_register; - u32 base; - u32 rc; - struct pci_func *next; - int index = 0; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while (func != NULL) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Check for Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - // PCI-PCI Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - next = cpqhp_slot_list[sub_bus]; - - while (next != NULL) { - rc = cpqhp_save_base_addr_length(ctrl, next); - - if (rc) - return(rc); - - next = next->next; - } - pci_bus->number = func->bus; - - //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x14; cloop += 4) { - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented - if (base & 0x01L) { - // IO base - // set base = amount of IO space requested - base = base & 0xFFFFFFFE; - base = (~base) + 1; - - type = 1; - } else { - // memory base - base = base & 0xFFFFFFF0; - base = (~base) + 1; - - type = 0; - } - } else { - base = 0x0L; - type = 0; - } - - // Save information in slot structure - func->base_length[(cloop - 0x10) >> 2] = - base; - func->base_type[(cloop - 0x10) >> 2] = type; - - } // End of base register loop - - - } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented - if (base & 0x01L) { - // IO base - // base = amount of IO space requested - base = base & 0xFFFFFFFE; - base = (~base) + 1; - - type = 1; - } else { - // memory base - // base = amount of memory space requested - base = base & 0xFFFFFFF0; - base = (~base) + 1; - - type = 0; - } - } else { - base = 0x0L; - type = 0; - } - - // Save information in slot structure - func->base_length[(cloop - 0x10) >> 2] = base; - func->base_type[(cloop - 0x10) >> 2] = type; - - } // End of base register loop - - } else { // Some other unknown header type - } - - // find the next device in this slot - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - return(0); -} - - -/* - * cpqhp_save_used_resources - * - * Stores used resource information for existing boards. this is - * for boards that were in the system when this driver was loaded. - * this function is for hot plug ADD - * - * returns 0 if success - */ -int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 temp_byte; - u8 b_base; - u8 b_length; - u16 command; - u16 save_command; - u16 w_base; - u16 w_length; - u32 temp_register; - u32 save_base; - u32 base; - int index = 0; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while ((func != NULL) && func->is_a_board) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Save the command register - pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command); - - // disable card - command = 0x00; - pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); - - // Check for Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Clear Bridge Control Register - command = 0x00; - pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); - - bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = secondary_bus; - bus_node->length = temp_byte - secondary_bus + 1; - - bus_node->next = func->bus_head; - func->bus_head = bus_node; - - // Save IO base and Limit registers - pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &b_base); - pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &b_length); - - if ((b_base <= b_length) && (save_command & 0x01)) { - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (b_base & 0xF0) << 8; - io_node->length = (b_length - b_base + 0x10) << 8; - - io_node->next = func->io_head; - func->io_head = io_node; - } - - // Save memory base and Limit registers - pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base); - pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (save_command & 0x02)) { - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = w_base << 16; - mem_node->length = (w_length - w_base + 0x10) << 16; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - - // Save prefetchable memory base and Limit registers - pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); - pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (save_command & 0x02)) { - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = w_base << 16; - p_mem_node->length = (w_length - w_base + 0x10) << 16; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x14; cloop += 4) { - pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - temp_register = base; - - if (base) { // If this register is implemented - if (((base & 0x03L) == 0x01) - && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested - temp_register = base & 0xFFFFFFFE; - temp_register = (~temp_register) + 1; - - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = - save_base & (~0x03L); - io_node->length = temp_register; - - io_node->next = func->io_head; - func->io_head = io_node; - } else - if (((base & 0x0BL) == 0x08) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = save_base & (~0x0FL); - p_mem_node->length = temp_register; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else - if (((base & 0x0BL) == 0x00) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = save_base & (~0x0FL); - mem_node->length = temp_register; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return(1); - } - } // End of base register loop - } else if ((header_type & 0x7F) == 0x00) { // Standard header - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - temp_register = base; - - if (base) { // If this register is implemented - if (((base & 0x03L) == 0x01) - && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested - temp_register = base & 0xFFFFFFFE; - temp_register = (~temp_register) + 1; - - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = save_base & (~0x01L); - io_node->length = temp_register; - - io_node->next = func->io_head; - func->io_head = io_node; - } else - if (((base & 0x0BL) == 0x08) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = save_base & (~0x0FL); - p_mem_node->length = temp_register; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else - if (((base & 0x0BL) == 0x00) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = save_base & (~0x0FL); - mem_node->length = temp_register; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return(1); - } - } // End of base register loop - } else { // Some other unknown header type - } - - // find the next device in this slot - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - return(0); -} - - -/* - * cpqhp_configure_board - * - * Copies saved configuration information to one slot. - * this is called recursively for bridge devices. - * this is for hot plug REPLACE! - * - * returns 0 if success - */ -int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) -{ - int cloop; - u8 header_type; - u8 secondary_bus; - int sub_bus; - struct pci_func *next; - u32 temp; - u32 rc; - int index = 0; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while (func != NULL) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Start at the top of config space so that the control - // registers are programmed last - for (cloop = 0x3C; cloop > 0; cloop -= 4) { - pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); - } - - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - // If this is a bridge device, restore subordinate devices - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - next = cpqhp_slot_list[sub_bus]; - - while (next != NULL) { - rc = cpqhp_configure_board(ctrl, next); - - if (rc) - return rc; - - next = next->next; - } - } else { - - // Check all the base Address Registers to make sure - // they are the same. If not, the board is different. - - for (cloop = 16; cloop < 40; cloop += 4) { - pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); - - if (temp != func->config_space[cloop >> 2]) { - dbg("Config space compare failure!!! offset = %x\n", cloop); - dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); - dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]); - return 1; - } - } - } - - func->configured = 1; - - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - return 0; -} - - -/* - * cpqhp_valid_replace - * - * this function checks to see if a board is the same as the - * one it is replacing. this check will detect if the device's - * vendor or device id's are the same - * - * returns 0 if the board is the same nonzero otherwise - */ -int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 type; - u32 temp_register = 0; - u32 base; - u32 rc; - struct pci_func *next; - int index = 0; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - if (!func->is_a_board) - return(ADD_NOT_SUPPORTED); - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while (func != NULL) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); - - // No adapter present - if (temp_register == 0xFFFFFFFF) - return(NO_ADAPTER_PRESENT); - - if (temp_register != func->config_space[0]) - return(ADAPTER_NOT_SAME); - - // Check for same revision number and class code - pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); - - // Adapter not the same - if (temp_register != func->config_space[0x08 >> 2]) - return(ADAPTER_NOT_SAME); - - // Check for Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // In order to continue checking, we must program the - // bus registers in the bridge to respond to accesses - // for it's subordinate bus(es) - - temp_register = func->config_space[0x18 >> 2]; - pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); - - secondary_bus = (temp_register >> 8) & 0xFF; - - next = cpqhp_slot_list[secondary_bus]; - - while (next != NULL) { - rc = cpqhp_valid_replace(ctrl, next); - - if (rc) - return(rc); - - next = next->next; - } - - } - // Check to see if it is a standard config header - else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Check subsystem vendor and ID - pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); - - if (temp_register != func->config_space[0x2C >> 2]) { - // If it's a SMART-2 and the register isn't filled - // in, ignore the difference because - // they just have an old rev of the firmware - - if (!((func->config_space[0] == 0xAE100E11) - && (temp_register == 0x00L))) - return(ADAPTER_NOT_SAME); - } - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented - if (base & 0x01L) { - // IO base - // set base = amount of IO space requested - base = base & 0xFFFFFFFE; - base = (~base) + 1; - - type = 1; - } else { - // memory base - base = base & 0xFFFFFFF0; - base = (~base) + 1; - - type = 0; - } - } else { - base = 0x0L; - type = 0; - } - - // Check information in slot structure - if (func->base_length[(cloop - 0x10) >> 2] != base) - return(ADAPTER_NOT_SAME); - - if (func->base_type[(cloop - 0x10) >> 2] != type) - return(ADAPTER_NOT_SAME); - - } // End of base register loop - - } // End of (type 0 config space) else - else { - // this is not a type 0 or 1 config space header so - // we don't know how to do it - return(DEVICE_TYPE_NOT_SUPPORTED); - } - - // Get the next function - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - - return(0); -} - - -/* - * cpqhp_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start) -{ - u8 temp; - u8 populated_slot; - u8 bridged_slot; - void *one_slot; - struct pci_func *func = NULL; - int i = 10, index; - u32 temp_dword, rc; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - void *rom_resource_table; - - rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); - dbg("rom_resource_table = %p\n", rom_resource_table); - - if (rom_resource_table == NULL) { - return -ENODEV; - } - // Sum all resources and setup resource maps - unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); - dbg("unused_IRQ = %x\n", unused_IRQ); - - temp = 0; - while (unused_IRQ) { - if (unused_IRQ & 1) { - cpqhp_disk_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); - unused_IRQ = unused_IRQ >> 1; - temp++; - - while (unused_IRQ) { - if (unused_IRQ & 1) { - cpqhp_nic_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); - unused_IRQ = readl(rom_resource_table + PCIIRQ); - - temp = 0; - - if (!cpqhp_nic_irq) { - cpqhp_nic_irq = ctrl->cfgspc_irq; - } - - if (!cpqhp_disk_irq) { - cpqhp_disk_irq = ctrl->cfgspc_irq; - } - - dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); - - rc = compaq_nvram_load(rom_start, ctrl); - if (rc) - return rc; - - one_slot = rom_resource_table + sizeof (struct hrt); - - i = readb(rom_resource_table + NUMBER_OF_ENTRIES); - dbg("number_of_entries = %d\n", i); - - if (!readb(one_slot + SECONDARY_BUS)) { - return(1); - } - - dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); - - while (i && readb(one_slot + SECONDARY_BUS)) { - u8 dev_func = readb(one_slot + DEV_FUNC); - u8 primary_bus = readb(one_slot + PRIMARY_BUS); - u8 secondary_bus = readb(one_slot + SECONDARY_BUS); - u8 max_bus = readb(one_slot + MAX_BUS); - u16 io_base = readw(one_slot + IO_BASE); - u16 io_length = readw(one_slot + IO_LENGTH); - u16 mem_base = readw(one_slot + MEM_BASE); - u16 mem_length = readw(one_slot + MEM_LENGTH); - u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); - u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); - - dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", - dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, - primary_bus, secondary_bus, max_bus); - - // If this entry isn't for our controller's bus, ignore it - if (primary_bus != ctrl->bus) { - i--; - one_slot += sizeof (struct slot_rt); - continue; - } - // find out if this entry is for an occupied slot - ctrl->pci_bus->number = primary_bus; - pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); - dbg("temp_D_word = %x\n", temp_dword); - - if (temp_dword != 0xFFFFFFFF) { - index = 0; - func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); - - while (func && (func->function != (dev_func & 0x07))) { - dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); - func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); - } - - // If we can't find a match, skip this table entry - if (!func) { - i--; - one_slot += sizeof (struct slot_rt); - continue; - } - // this may not work and shouldn't be used - if (secondary_bus != primary_bus) - bridged_slot = 1; - else - bridged_slot = 0; - - populated_slot = 1; - } else { - populated_slot = 0; - bridged_slot = 0; - } - - - // If we've got a valid IO base, use it - - temp_dword = io_base + io_length; - - if ((io_base) && (temp_dword < 0x10000)) { - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = io_base; - io_node->length = io_length; - - dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); - dbg("populated slot =%d \n", populated_slot); - if (!populated_slot) { - io_node->next = ctrl->io_head; - ctrl->io_head = io_node; - } else { - io_node->next = func->io_head; - func->io_head = io_node; - } - } - - // If we've got a valid memory base, use it - temp_dword = mem_base + mem_length; - if ((mem_base) && (temp_dword < 0x10000)) { - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = mem_base << 16; - - mem_node->length = mem_length << 16; - - dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); - dbg("populated slot =%d \n", populated_slot); - if (!populated_slot) { - mem_node->next = ctrl->mem_head; - ctrl->mem_head = mem_node; - } else { - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - } - - // If we've got a valid prefetchable memory base, and - // the base + length isn't greater than 0xFFFF - temp_dword = pre_mem_base + pre_mem_length; - if ((pre_mem_base) && (temp_dword < 0x10000)) { - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = pre_mem_base << 16; - - p_mem_node->length = pre_mem_length << 16; - dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); - dbg("populated slot =%d \n", populated_slot); - - if (!populated_slot) { - p_mem_node->next = ctrl->p_mem_head; - ctrl->p_mem_head = p_mem_node; - } else { - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - } - - // If we've got a valid bus number, use it - // The second condition is to ignore bus numbers on - // populated slots that don't have PCI-PCI bridges - if (secondary_bus && (secondary_bus != primary_bus)) { - bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = secondary_bus; - bus_node->length = max_bus - secondary_bus + 1; - dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); - dbg("populated slot =%d \n", populated_slot); - if (!populated_slot) { - bus_node->next = ctrl->bus_head; - ctrl->bus_head = bus_node; - } else { - bus_node->next = func->bus_head; - func->bus_head = bus_node; - } - } - - i--; - one_slot += sizeof (struct slot_rt); - } - - // If all of the following fail, we don't have any resources for - // hot plug add - rc = 1; - rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - return(rc); -} - - -/* - * cpqhp_return_board_resources - * - * this routine returns all resources allocated to a board to - * the available pool. - * - * returns 0 if success - */ -int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) -{ - int rc = 0; - struct pci_resource *node; - struct pci_resource *t_node; - dbg("%s\n", __FUNCTION__); - - if (!func) - return(1); - - node = func->io_head; - func->io_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->io_head), node); - node = t_node; - } - - node = func->mem_head; - func->mem_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->mem_head), node); - node = t_node; - } - - node = func->p_mem_head; - func->p_mem_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->p_mem_head), node); - node = t_node; - } - - node = func->bus_head; - func->bus_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->bus_head), node); - node = t_node; - } - - rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); - rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); - rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); - rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); - - return(rc); -} - - -/* - * cpqhp_destroy_resource_list - * - * Puts node back in the resource list pointed to by head - */ -void cpqhp_destroy_resource_list (struct resource_lists * resources) -{ - struct pci_resource *res, *tres; - - res = resources->io_head; - resources->io_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = resources->mem_head; - resources->mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = resources->p_mem_head; - resources->p_mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = resources->bus_head; - resources->bus_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - - -/* - * cpqhp_destroy_board_resources - * - * Puts node back in the resource list pointed to by head - */ -void cpqhp_destroy_board_resources (struct pci_func * func) -{ - struct pci_resource *res, *tres; - - res = func->io_head; - func->io_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = func->mem_head; - func->mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = func->p_mem_head; - func->p_mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = func->bus_head; - func->bus_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - diff -urN linux-2.5.70-bk9/drivers/hotplug/cpqphp_sysfs.c linux-2.5.70-bk10/drivers/hotplug/cpqphp_sysfs.c --- linux-2.5.70-bk9/drivers/hotplug/cpqphp_sysfs.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/cpqphp_sysfs.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,143 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "cpqphp.h" - - -/* A few routines that create sysfs entries for the hot plug controller */ - -static int show_ctrl (struct device *dev, char *buf) -{ - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; - int index; - struct pci_resource *res; - - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - - out += sprintf(buf, "Free resources: memory\n"); - index = 11; - res = ctrl->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "Free resources: prefetchable memory\n"); - index = 11; - res = ctrl->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "Free resources: IO\n"); - index = 11; - res = ctrl->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "Free resources: bus numbers\n"); - index = 11; - res = ctrl->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - - return out - buf; -} -static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); - -static int show_dev (struct device *dev, char *buf) -{ - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; - int index; - struct pci_resource *res; - struct pci_func *new_slot; - struct slot *slot; - - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - - slot=ctrl->slot; - - while (slot) { - new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); - if (!new_slot) - break; - out += sprintf(out, "assigned resources: memory\n"); - index = 11; - res = new_slot->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: prefetchable memory\n"); - index = 11; - res = new_slot->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: IO\n"); - index = 11; - res = new_slot->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: bus numbers\n"); - index = 11; - res = new_slot->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - slot=slot->next; - } - - return out - buf; -} -static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); - -void cpqhp_create_ctrl_files (struct controller *ctrl) -{ - device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); - device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); -} diff -urN linux-2.5.70-bk9/drivers/hotplug/ibmphp.h linux-2.5.70-bk10/drivers/hotplug/ibmphp.h --- linux-2.5.70-bk9/drivers/hotplug/ibmphp.h 2003-05-26 18:00:23.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/ibmphp.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,772 +0,0 @@ -#ifndef __IBMPHP_H -#define __IBMPHP_H - -/* - * IBM Hot Plug Controller Driver - * - * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include "pci_hotplug.h" - -extern int ibmphp_debug; - -#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE) - #define MY_NAME "ibmphpd" -#else - #define MY_NAME THIS_MODULE->name -#endif -#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) -#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) - - -/* EBDA stuff */ - -/*********************************************************** -* SLOT CAPABILITY * -***********************************************************/ - -#define EBDA_SLOT_133_MAX 0x20 -#define EBDA_SLOT_100_MAX 0x10 -#define EBDA_SLOT_66_MAX 0x02 -#define EBDA_SLOT_PCIX_CAP 0x08 - - -/************************************************************ -* RESOURE TYPE * -************************************************************/ - -#define EBDA_RSRC_TYPE_MASK 0x03 -#define EBDA_IO_RSRC_TYPE 0x00 -#define EBDA_MEM_RSRC_TYPE 0x01 -#define EBDA_PFM_RSRC_TYPE 0x03 -#define EBDA_RES_RSRC_TYPE 0x02 - - -/************************************************************* -* IO RESTRICTION TYPE * -*************************************************************/ - -#define EBDA_IO_RESTRI_MASK 0x0c -#define EBDA_NO_RESTRI 0x00 -#define EBDA_AVO_VGA_ADDR 0x04 -#define EBDA_AVO_VGA_ADDR_AND_ALIA 0x08 -#define EBDA_AVO_ISA_ADDR 0x0c - - -/************************************************************** -* DEVICE TYPE DEF * -**************************************************************/ - -#define EBDA_DEV_TYPE_MASK 0x10 -#define EBDA_PCI_DEV 0x10 -#define EBDA_NON_PCI_DEV 0x00 - - -/*************************************************************** -* PRIMARY DEF DEFINITION * -***************************************************************/ - -#define EBDA_PRI_DEF_MASK 0x20 -#define EBDA_PRI_PCI_BUS_INFO 0x20 -#define EBDA_NORM_DEV_RSRC_INFO 0x00 - - -//-------------------------------------------------------------- -// RIO TABLE DATA STRUCTURE -//-------------------------------------------------------------- - -struct rio_table_hdr { - u8 ver_num; - u8 scal_count; - u8 riodev_count; - u16 offset; -}; - -//------------------------------------------------------------- -// SCALABILITY DETAIL -//------------------------------------------------------------- - -struct scal_detail { - u8 node_id; - u32 cbar; - u8 port0_node_connect; - u8 port0_port_connect; - u8 port1_node_connect; - u8 port1_port_connect; - u8 port2_node_connect; - u8 port2_port_connect; - u8 chassis_num; -// struct list_head scal_detail_list; -}; - -//-------------------------------------------------------------- -// RIO DETAIL -//-------------------------------------------------------------- - -struct rio_detail { - u8 rio_node_id; - u32 bbar; - u8 rio_type; - u8 owner_id; - u8 port0_node_connect; - u8 port0_port_connect; - u8 port1_node_connect; - u8 port1_port_connect; - u8 first_slot_num; - u8 status; - u8 wpindex; - u8 chassis_num; - struct list_head rio_detail_list; -}; - -struct opt_rio { - u8 rio_type; - u8 chassis_num; - u8 first_slot_num; - u8 middle_num; - struct list_head opt_rio_list; -}; - -struct opt_rio_lo { - u8 rio_type; - u8 chassis_num; - u8 first_slot_num; - u8 middle_num; - u8 pack_count; - struct list_head opt_rio_lo_list; -}; - -/**************************************************************** -* HPC DESCRIPTOR NODE * -****************************************************************/ - -struct ebda_hpc_list { - u8 format; - u16 num_ctlrs; - short phys_addr; -// struct list_head ebda_hpc_list; -}; -/***************************************************************** -* IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS * -* STRUCTURE * -*****************************************************************/ - -struct ebda_hpc_slot { - u8 slot_num; - u32 slot_bus_num; - u8 ctl_index; - u8 slot_cap; -}; - -struct ebda_hpc_bus { - u32 bus_num; - u8 slots_at_33_conv; - u8 slots_at_66_conv; - u8 slots_at_66_pcix; - u8 slots_at_100_pcix; - u8 slots_at_133_pcix; -}; - - -/******************************************************************** -* THREE TYPE OF HOT PLUG CONTROLER * -********************************************************************/ - -struct isa_ctlr_access { - u16 io_start; - u16 io_end; -}; - -struct pci_ctlr_access { - u8 bus; - u8 dev_fun; -}; - -struct wpeg_i2c_ctlr_access { - ulong wpegbbar; - u8 i2c_addr; -}; - -#define HPC_DEVICE_ID 0x0246 -#define HPC_SUBSYSTEM_ID 0x0247 -#define HPC_PCI_OFFSET 0x40 -/************************************************************************* -* RSTC DESCRIPTOR NODE * -*************************************************************************/ - -struct ebda_rsrc_list { - u8 format; - u16 num_entries; - u16 phys_addr; - struct ebda_rsrc_list *next; -}; - - -/*************************************************************************** -* PCI RSRC NODE * -***************************************************************************/ - -struct ebda_pci_rsrc { - u8 rsrc_type; - u8 bus_num; - u8 dev_fun; - u32 start_addr; - u32 end_addr; - u8 marked; /* for NVRAM */ - struct list_head ebda_pci_rsrc_list; -}; - - -/*********************************************************** -* BUS_INFO DATE STRUCTURE * -***********************************************************/ - -struct bus_info { - u8 slot_min; - u8 slot_max; - u8 slot_count; - u8 busno; - u8 controller_id; - u8 current_speed; - u8 current_bus_mode; - u8 index; - u8 slots_at_33_conv; - u8 slots_at_66_conv; - u8 slots_at_66_pcix; - u8 slots_at_100_pcix; - u8 slots_at_133_pcix; - struct list_head bus_info_list; -}; - - -/*********************************************************** -* GLOBAL VARIABLES * -***********************************************************/ -extern struct list_head ibmphp_ebda_pci_rsrc_head; -extern struct list_head ibmphp_slot_head; -extern struct list_head ibmphp_res_head; -/*********************************************************** -* FUNCTION PROTOTYPES * -***********************************************************/ - -extern void ibmphp_free_ebda_hpc_queue (void); -extern int ibmphp_access_ebda (void); -extern struct slot *ibmphp_get_slot_from_physical_num (u8); -extern int ibmphp_get_total_hp_slots (void); -extern void ibmphp_free_ibm_slot (struct slot *); -extern void ibmphp_free_bus_info_queue (void); -extern void ibmphp_free_ebda_pci_rsrc_queue (void); -extern struct bus_info *ibmphp_find_same_bus_num (u32); -extern int ibmphp_get_bus_index (u8); -extern u16 ibmphp_get_total_controllers (void); -extern int ibmphp_register_pci (void); - -/* passed parameters */ -#define MEM 0 -#define IO 1 -#define PFMEM 2 - -/* bit masks */ -#define RESTYPE 0x03 -#define IOMASK 0x00 /* will need to take its complement */ -#define MMASK 0x01 -#define PFMASK 0x03 -#define PCIDEVMASK 0x10 /* we should always have PCI devices */ -#define PRIMARYBUSMASK 0x20 - -/* pci specific defines */ -#define PCI_VENDOR_ID_NOTVALID 0xFFFF -#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 -#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 - -#define LATENCY 0x64 -#define CACHE 64 -#define DEVICEENABLE 0x015F /* CPQ has 0x0157 */ - -#define IOBRIDGE 0x1000 /* 4k */ -#define MEMBRIDGE 0x100000 /* 1M */ - -/* irqs */ -#define SCSI_IRQ 0x09 -#define LAN_IRQ 0x0A -#define OTHER_IRQ 0x0B - -/* Data Structures */ - -/* type is of the form x x xx xx - * | | | |_ 00 - I/O, 01 - Memory, 11 - PFMemory - * | | - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid - * | | VGA and their aliases, 11 - Avoid ISA - * | - 1 - PCI device, 0 - non pci device - * - 1 - Primary PCI Bus Information (0 if Normal device) - * the IO restrictions [2:3] are only for primary buses - */ - - -/* we need this struct because there could be several resource blocks - * allocated per primary bus in the EBDA - */ -struct range_node { - int rangeno; - u32 start; - u32 end; - struct range_node *next; -}; - -struct bus_node { - u8 busno; - int noIORanges; - struct range_node *rangeIO; - int noMemRanges; - struct range_node *rangeMem; - int noPFMemRanges; - struct range_node *rangePFMem; - int needIOUpdate; - int needMemUpdate; - int needPFMemUpdate; - struct resource_node *firstIO; /* first IO resource on the Bus */ - struct resource_node *firstMem; /* first memory resource on the Bus */ - struct resource_node *firstPFMem; /* first prefetchable memory resource on the Bus */ - struct resource_node *firstPFMemFromMem; /* when run out of pfmem available, taking from Mem */ - struct list_head bus_list; -}; - -struct resource_node { - int rangeno; - u8 busno; - u8 devfunc; - u32 start; - u32 end; - u32 len; - int type; /* MEM, IO, PFMEM */ - u8 fromMem; /* this is to indicate that the range is from - * from the Memory bucket rather than from PFMem */ - struct resource_node *next; - struct resource_node *nextRange; /* for the other mem range on bus */ -}; - -struct res_needed { - u32 mem; - u32 pfmem; - u32 io; - u8 not_correct; /* needed for return */ - int devices[32]; /* for device numbers behind this bridge */ -}; - -/* functions */ - -extern int ibmphp_rsrc_init (void); -extern int ibmphp_add_resource (struct resource_node *); -extern int ibmphp_remove_resource (struct resource_node *); -extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); -extern int ibmphp_check_resource (struct resource_node *, u8); -extern int ibmphp_remove_bus (struct bus_node *, u8); -extern void ibmphp_free_resources (void); -extern int ibmphp_add_pfmem_from_mem (struct resource_node *); -extern struct bus_node *ibmphp_find_res_bus (u8); -extern void ibmphp_print_test (void); /* for debugging purposes */ - -extern void ibmphp_hpc_initvars (void); -extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); -extern int ibmphp_hpc_writeslot (struct slot *, u8); -extern void ibmphp_lock_operations (void); -extern void ibmphp_unlock_operations (void); -extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *); -extern int ibmphp_hpc_start_poll_thread (void); -extern void ibmphp_hpc_stop_poll_thread (void); - -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -// HPC return codes -//---------------------------------------------------------------------------- -#define FALSE 0x00 -#define TRUE 0x01 -#define HPC_ERROR 0xFF - -//----------------------------------------------------------------------------- -// BUS INFO -//----------------------------------------------------------------------------- -#define BUS_SPEED 0x30 -#define BUS_MODE 0x40 -#define BUS_MODE_PCIX 0x01 -#define BUS_MODE_PCI 0x00 -#define BUS_SPEED_2 0x20 -#define BUS_SPEED_1 0x10 -#define BUS_SPEED_33 0x00 -#define BUS_SPEED_66 0x01 -#define BUS_SPEED_100 0x02 -#define BUS_SPEED_133 0x03 -#define BUS_SPEED_66PCIX 0x04 -#define BUS_SPEED_66UNKNOWN 0x05 -#define BUS_STATUS_AVAILABLE 0x01 -#define BUS_CONTROL_AVAILABLE 0x02 -#define SLOT_LATCH_REGS_SUPPORTED 0x10 - -#define PRGM_MODEL_REV_LEVEL 0xF0 -#define MAX_ADAPTER_NONE 0x09 - -//---------------------------------------------------------------------------- -// HPC 'write' operations/commands -//---------------------------------------------------------------------------- -// Command Code State Write to reg -// Machine at index -//------------------------- ---- ------- ------------ -#define HPC_CTLR_ENABLEIRQ 0x00 // N 15 -#define HPC_CTLR_DISABLEIRQ 0x01 // N 15 -#define HPC_SLOT_OFF 0x02 // Y 0-14 -#define HPC_SLOT_ON 0x03 // Y 0-14 -#define HPC_SLOT_ATTNOFF 0x04 // N 0-14 -#define HPC_SLOT_ATTNON 0x05 // N 0-14 -#define HPC_CTLR_CLEARIRQ 0x06 // N 15 -#define HPC_CTLR_RESET 0x07 // Y 15 -#define HPC_CTLR_IRQSTEER 0x08 // N 15 -#define HPC_BUS_33CONVMODE 0x09 // Y 31-34 -#define HPC_BUS_66CONVMODE 0x0A // Y 31-34 -#define HPC_BUS_66PCIXMODE 0x0B // Y 31-34 -#define HPC_BUS_100PCIXMODE 0x0C // Y 31-34 -#define HPC_BUS_133PCIXMODE 0x0D // Y 31-34 -#define HPC_ALLSLOT_OFF 0x11 // Y 15 -#define HPC_ALLSLOT_ON 0x12 // Y 15 -#define HPC_SLOT_BLINKLED 0x13 // N 0-14 - -//---------------------------------------------------------------------------- -// read commands -//---------------------------------------------------------------------------- -#define READ_SLOTSTATUS 0x01 -#define READ_EXTSLOTSTATUS 0x02 -#define READ_BUSSTATUS 0x03 -#define READ_CTLRSTATUS 0x04 -#define READ_ALLSTAT 0x05 -#define READ_ALLSLOT 0x06 -#define READ_SLOTLATCHLOWREG 0x07 -#define READ_REVLEVEL 0x08 -#define READ_HPCOPTIONS 0x09 -//---------------------------------------------------------------------------- -// slot status -//---------------------------------------------------------------------------- -#define HPC_SLOT_POWER 0x01 -#define HPC_SLOT_CONNECT 0x02 -#define HPC_SLOT_ATTN 0x04 -#define HPC_SLOT_PRSNT2 0x08 -#define HPC_SLOT_PRSNT1 0x10 -#define HPC_SLOT_PWRGD 0x20 -#define HPC_SLOT_BUS_SPEED 0x40 -#define HPC_SLOT_LATCH 0x80 - -//---------------------------------------------------------------------------- -// HPC_SLOT_POWER status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_POWER_OFF 0x00 -#define HPC_SLOT_POWER_ON 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_CONNECT status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_CONNECTED 0x00 -#define HPC_SLOT_DISCONNECTED 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_ATTN status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_ATTN_OFF 0x00 -#define HPC_SLOT_ATTN_ON 0x01 -#define HPC_SLOT_ATTN_BLINK 0x02 - -//---------------------------------------------------------------------------- -// HPC_SLOT_PRSNT status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_EMPTY 0x00 -#define HPC_SLOT_PRSNT_7 0x01 -#define HPC_SLOT_PRSNT_15 0x02 -#define HPC_SLOT_PRSNT_25 0x03 - -//---------------------------------------------------------------------------- -// HPC_SLOT_PWRGD status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_PWRGD_FAULT_NONE 0x00 -#define HPC_SLOT_PWRGD_GOOD 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_BUS_SPEED status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_BUS_SPEED_OK 0x00 -#define HPC_SLOT_BUS_SPEED_MISM 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_LATCH status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_LATCH_OPEN 0x01 // NOTE : in PCI spec bit off = open -#define HPC_SLOT_LATCH_CLOSED 0x00 // NOTE : in PCI spec bit on = closed - - -//---------------------------------------------------------------------------- -// extended slot status -//---------------------------------------------------------------------------- -#define HPC_SLOT_PCIX 0x01 -#define HPC_SLOT_SPEED1 0x02 -#define HPC_SLOT_SPEED2 0x04 -#define HPC_SLOT_BLINK_ATTN 0x08 -#define HPC_SLOT_RSRVD1 0x10 -#define HPC_SLOT_RSRVD2 0x20 -#define HPC_SLOT_BUS_MODE 0x40 -#define HPC_SLOT_RSRVD3 0x80 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_PCIX_CAP status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_PCIX_NO 0x00 -#define HPC_SLOT_PCIX_YES 0x01 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_SPEED status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_SPEED_33 0x00 -#define HPC_SLOT_SPEED_66 0x01 -#define HPC_SLOT_SPEED_133 0x02 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_ATTN_BLINK status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_ATTN_BLINK_OFF 0x00 -#define HPC_SLOT_ATTN_BLINK_ON 0x01 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_BUS_MODE status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_BUS_MODE_OK 0x00 -#define HPC_SLOT_BUS_MODE_MISM 0x01 - -//---------------------------------------------------------------------------- -// Controller status -//---------------------------------------------------------------------------- -#define HPC_CTLR_WORKING 0x01 -#define HPC_CTLR_FINISHED 0x02 -#define HPC_CTLR_RESULT0 0x04 -#define HPC_CTLR_RESULT1 0x08 -#define HPC_CTLR_RESULE2 0x10 -#define HPC_CTLR_RESULT3 0x20 -#define HPC_CTLR_IRQ_ROUTG 0x40 -#define HPC_CTLR_IRQ_PENDG 0x80 - -//---------------------------------------------------------------------------- -// HPC_CTLR_WROKING status return codes -//---------------------------------------------------------------------------- -#define HPC_CTLR_WORKING_NO 0x00 -#define HPC_CTLR_WORKING_YES 0x01 - -//---------------------------------------------------------------------------- -// HPC_CTLR_FINISHED status return codes -//---------------------------------------------------------------------------- -#define HPC_CTLR_FINISHED_NO 0x00 -#define HPC_CTLR_FINISHED_YES 0x01 - -//---------------------------------------------------------------------------- -// HPC_CTLR_RESULT status return codes -//---------------------------------------------------------------------------- -#define HPC_CTLR_RESULT_SUCCESS 0x00 -#define HPC_CTLR_RESULT_FAILED 0x01 -#define HPC_CTLR_RESULT_RSVD 0x02 -#define HPC_CTLR_RESULT_NORESP 0x03 - - -//---------------------------------------------------------------------------- -// macro for slot info -//---------------------------------------------------------------------------- -#define SLOT_POWER(s) ((u8) ((s & HPC_SLOT_POWER) \ - ? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF)) - -#define SLOT_CONNECT(s) ((u8) ((s & HPC_SLOT_CONNECT) \ - ? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED)) - -#define SLOT_ATTN(s,es) ((u8) ((es & HPC_SLOT_BLINK_ATTN) \ - ? HPC_SLOT_ATTN_BLINK \ - : ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF))) - -#define SLOT_PRESENT(s) ((u8) ((s & HPC_SLOT_PRSNT1) \ - ? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \ - : ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7))) - -#define SLOT_PWRGD(s) ((u8) ((s & HPC_SLOT_PWRGD) \ - ? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE)) - -#define SLOT_BUS_SPEED(s) ((u8) ((s & HPC_SLOT_BUS_SPEED) \ - ? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK)) - -#define SLOT_LATCH(s) ((u8) ((s & HPC_SLOT_LATCH) \ - ? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN)) - -#define SLOT_PCIX(es) ((u8) ((es & HPC_SLOT_PCIX) \ - ? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO)) - -#define SLOT_SPEED(es) ((u8) ((es & HPC_SLOT_SPEED2) \ - ? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133 \ - : HPC_SLOT_SPEED_66) \ - : HPC_SLOT_SPEED_33)) - -#define SLOT_BUS_MODE(es) ((u8) ((es & HPC_SLOT_BUS_MODE) \ - ? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK)) - -//-------------------------------------------------------------------------- -// macro for bus info -//--------------------------------------------------------------------------- -#define CURRENT_BUS_SPEED(s) ((u8) (s & BUS_SPEED_2) \ - ? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \ - : ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33)) - -#define CURRENT_BUS_MODE(s) ((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI) - -#define READ_BUS_STATUS(s) ((u8) (s->options & BUS_STATUS_AVAILABLE)) - -#define READ_BUS_MODE(s) ((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20) - -#define SET_BUS_STATUS(s) ((u8) (s->options & BUS_CONTROL_AVAILABLE)) - -#define READ_SLOT_LATCH(s) ((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED)) - -//---------------------------------------------------------------------------- -// macro for controller info -//---------------------------------------------------------------------------- -#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \ - ? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO)) -#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \ - ? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO)) -#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1) \ - ? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \ - : HPC_CTLR_RESULT_RSVD) \ - : ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \ - : HPC_CTLR_RESULT_SUCCESS))) - -// command that affect the state machine of HPC -#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF) || \ - (c == HPC_SLOT_ON) || \ - (c == HPC_CTLR_RESET) || \ - (c == HPC_BUS_33CONVMODE) || \ - (c == HPC_BUS_66CONVMODE) || \ - (c == HPC_BUS_66PCIXMODE) || \ - (c == HPC_BUS_100PCIXMODE) || \ - (c == HPC_BUS_133PCIXMODE) || \ - (c == HPC_ALLSLOT_OFF) || \ - (c == HPC_ALLSLOT_ON)) - - -/* Core part of the driver */ - -#define ENABLE 1 -#define DISABLE 0 - -#define CARD_INFO 0x07 -#define PCIX133 0x07 -#define PCIX66 0x05 -#define PCI66 0x04 - -extern struct pci_bus *ibmphp_pci_bus; - -/* Variables */ - -struct pci_func { - struct pci_dev *dev; /* from the OS */ - u8 busno; - u8 device; - u8 function; - struct resource_node *io[6]; - struct resource_node *mem[6]; - struct resource_node *pfmem[6]; - struct pci_func *next; - int devices[32]; /* for bridge config */ - u8 irq[4]; /* for interrupt config */ - u8 bus; /* flag for unconfiguring, to say if PPB */ -}; - -struct slot { - u8 bus; - u8 device; - u8 number; - u8 real_physical_slot_num; - char name[100]; - u32 capabilities; - u8 supported_speed; - u8 supported_bus_mode; - struct hotplug_slot *hotplug_slot; - struct controller *ctrl; - struct pci_func *func; - u8 irq[4]; - u8 flag; /* this is for disable slot and polling */ - int bit_mode; /* 0 = 32, 1 = 64 */ - u8 ctlr_index; - struct bus_info *bus_on; - struct list_head ibm_slot_list; - u8 status; - u8 ext_status; - u8 busstatus; -}; - -struct controller { - struct ebda_hpc_slot *slots; - struct ebda_hpc_bus *buses; - struct pci_dev *ctrl_dev; /* in case where controller is PCI */ - u8 starting_slot_num; /* starting and ending slot #'s this ctrl controls*/ - u8 ending_slot_num; - u8 revision; - u8 options; /* which options HPC supports */ - u8 status; - u8 ctlr_id; - u8 slot_count; - u8 bus_count; - u8 ctlr_relative_id; - u32 irq; - union { - struct isa_ctlr_access isa_ctlr; - struct pci_ctlr_access pci_ctlr; - struct wpeg_i2c_ctlr_access wpeg_ctlr; - } u; - u8 ctlr_type; - struct list_head ebda_hpc_list; -}; - -/* Functions */ - -extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ -extern int ibmphp_disable_slot (struct hotplug_slot *); /* This function is called from HPC, so we need it to not be static */ -extern int ibmphp_do_disable_slot (struct slot *slot_cur); -extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ -extern int ibmphp_configure_card (struct pci_func *, u8); -extern int ibmphp_unconfigure_card (struct slot **, int); -extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; - -static inline void long_delay (int delay) -{ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (delay); -} - -#endif //__IBMPHP_H - diff -urN linux-2.5.70-bk9/drivers/hotplug/ibmphp_core.c linux-2.5.70-bk10/drivers/hotplug/ibmphp_core.c --- linux-2.5.70-bk9/drivers/hotplug/ibmphp_core.c 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/ibmphp_core.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1439 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ -#include "ibmphp.h" - -#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) -#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF) -#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED) -#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) -#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) - -#define DRIVER_VERSION "0.6" -#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" - -int ibmphp_debug; - -static int debug; -MODULE_PARM (debug, "i"); -MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); -MODULE_LICENSE ("GPL"); -MODULE_DESCRIPTION (DRIVER_DESC); - -struct pci_bus *ibmphp_pci_bus; -static int max_slots; - -static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */ - -static int init_flag; - -/* -static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8); - -static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) -{ - return get_max_adapter_speed_1 (hs, value, 1); -} -*/ -static inline int get_cur_bus_info (struct slot **sl) -{ - int rc = 1; - struct slot * slot_cur = *sl; - - debug ("options = %x\n", slot_cur->ctrl->options); - debug ("revision = %x\n", slot_cur->ctrl->revision); - - if (READ_BUS_STATUS (slot_cur->ctrl)) - rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL); - - if (rc) - return rc; - - slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus); - if (READ_BUS_MODE (slot_cur->ctrl)) - slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus); - else - slot_cur->bus_on->current_bus_mode = 0xFF; - - debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); - - *sl = slot_cur; - return 0; -} - -static inline int slot_update (struct slot **sl) -{ - int rc; - rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); - if (rc) - return rc; - if (!init_flag) - return get_cur_bus_info (sl); - return rc; -} - -static int __init get_max_slots (void) -{ - struct slot * slot_cur; - struct list_head * tmp; - u8 slot_count = 0; - - list_for_each (tmp, &ibmphp_slot_head) { - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - /* sometimes the hot-pluggable slots start with 4 (not always from 1 */ - slot_count = max (slot_count, slot_cur->number); - } - return slot_count; -} - -/* This routine will put the correct slot->device information per slot. It's - * called from initialization of the slot structures. It will also assign - * interrupt numbers per each slot. - * Parameters: struct slot - * Returns 0 or errors - */ -int ibmphp_init_devno (struct slot **cur_slot) -{ - struct irq_routing_table *rtable; - int len; - int loop; - int i; - - rtable = pcibios_get_irq_routing_table (); - if (!rtable) { - err ("no BIOS routing table...\n"); - return -ENOMEM; - } - - len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); - - if (!len) - return -1; - for (loop = 0; loop < len; loop++) { - if ((*cur_slot)->number == rtable->slots[loop].slot) { - if ((*cur_slot)->bus == rtable->slots[loop].bus) { - (*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn); - for (i = 0; i < 4; i++) - (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); - - debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); - debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); - debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); - debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); - - debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); - debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); - debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); - debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); - debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); - - debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link); - debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); - debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); - debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); - debug ("end of init_devno\n"); - return 0; - } - } - } - - return -1; -} - -static inline int power_on (struct slot *slot_cur) -{ - u8 cmd = HPC_SLOT_ON; - int retval; - - retval = ibmphp_hpc_writeslot (slot_cur, cmd); - if (retval) { - err ("power on failed\n"); - return retval; - } - if (CTLR_RESULT (slot_cur->ctrl->status)) { - err ("command not completed successfully in power_on \n"); - return -EIO; - } - long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ - return 0; -} - -static inline int power_off (struct slot *slot_cur) -{ - u8 cmd = HPC_SLOT_OFF; - int retval; - - retval = ibmphp_hpc_writeslot (slot_cur, cmd); - if (retval) { - err ("power off failed \n"); - return retval; - } - if (CTLR_RESULT (slot_cur->ctrl->status)) { - err ("command not completed successfully in power_off \n"); - return -EIO; - } - return 0; -} - -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) -{ - int rc = 0; - struct slot *pslot; - u8 cmd; - int hpcrc = 0; - - debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); - ibmphp_lock_operations (); - cmd = 0x00; // avoid compiler warning - - if (hotplug_slot) { - switch (value) { - case HPC_SLOT_ATTN_OFF: - cmd = HPC_SLOT_ATTNOFF; - break; - case HPC_SLOT_ATTN_ON: - cmd = HPC_SLOT_ATTNON; - break; - case HPC_SLOT_ATTN_BLINK: - cmd = HPC_SLOT_BLINKLED; - break; - default: - rc = -ENODEV; - err ("set_attention_status - Error : invalid input [%x]\n", value); - break; - } - if (rc == 0) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) - hpcrc = ibmphp_hpc_writeslot (pslot, cmd); - else - rc = -ENODEV; - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - - debug ("set_attention_status - Exit rc[%d]\n", rc); - return rc; -} - -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) - hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); - if (!hpcrc) { - *value = SLOT_ATTN (myslot.status, myslot.ext_status); - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) { - *value = SLOT_LATCH (myslot.status); - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - - -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) { - *value = SLOT_PWRGD (myslot.status); - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 present; - int hpcrc = 0; - struct slot myslot; - - debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) { - present = SLOT_PRESENT (myslot.status); - if (present == HPC_SLOT_EMPTY) - *value = 0; - else - *value = 1; - rc = 0; - } - } - } else - rc = -ENODEV; - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 mode = 0; - - debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, - hotplug_slot, value); - - ibmphp_lock_operations (); - - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - rc = 0; - mode = pslot->supported_bus_mode; - *value = pslot->supported_speed; - switch (*value) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - *value += 0x01; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - *value = pslot->supported_speed + 0x01; - break; - default: - /* Note (will need to change): there would be soon 256, 512 also */ - rc = -ENODEV; - } - } - } else - rc = -ENODEV; - - ibmphp_unlock_operations (); - debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); - return rc; -} - -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 mode = 0; - - debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, - hotplug_slot, value); - - ibmphp_lock_operations (); - - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - rc = get_cur_bus_info (&pslot); - if (!rc) { - mode = pslot->bus_on->current_bus_mode; - *value = pslot->bus_on->current_speed; - switch (*value) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - *value += 0x01; - else if (mode == BUS_MODE_PCI) - ; - else - *value = PCI_SPEED_UNKNOWN; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - *value += 0x01; - break; - default: - /* Note of change: there would also be 256, 512 soon */ - rc = -ENODEV; - } - } - } - } else - rc = -ENODEV; - - ibmphp_unlock_operations (); - debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); - return rc; -} -/* -static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); - - if (flag) - ibmphp_lock_operations (); - - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - - if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) { - hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); - if (!hpcrc) { - *value = SLOT_SPEED (myslot.ext_status); - rc = 0; - } - } else { - *value = MAX_ADAPTER_NONE; - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - if (flag) - ibmphp_unlock_operations (); - - debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value) -{ - int rc = -ENODEV; - struct slot *pslot = NULL; - - debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot); - - ibmphp_lock_operations (); - - if (hotplug_slot) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - rc = 0; - snprintf (value, 100, "Bus %x", pslot->bus); - } - } else - rc = -ENODEV; - - ibmphp_unlock_operations (); - debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value); - return rc; -} -*/ - -/******************************************************************************* - * This routine will initialize the ops data structure used in the validate - * function. It will also power off empty slots that are powered on since BIOS - * leaves those on, albeit disconnected - ******************************************************************************/ -static int __init init_ops (void) -{ - struct slot *slot_cur; - struct list_head *tmp; - int retval; - int rc; - - list_for_each (tmp, &ibmphp_slot_head) { - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - - if (!slot_cur) - return -ENODEV; - - debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); - if (slot_cur->ctrl->revision == 0xFF) - if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision)) - return -1; - - if (slot_cur->bus_on->current_speed == 0xFF) - if (get_cur_bus_info (&slot_cur)) - return -1; - - if (slot_cur->ctrl->options == 0xFF) - if (get_hpc_options (slot_cur, &slot_cur->ctrl->options)) - return -1; - - retval = slot_update (&slot_cur); - if (retval) - return retval; - - debug ("status = %x\n", slot_cur->status); - debug ("ext_status = %x\n", slot_cur->ext_status); - debug ("SLOT_POWER = %x\n", SLOT_POWER (slot_cur->status)); - debug ("SLOT_PRESENT = %x\n", SLOT_PRESENT (slot_cur->status)); - debug ("SLOT_LATCH = %x\n", SLOT_LATCH (slot_cur->status)); - - if ((SLOT_PWRGD (slot_cur->status)) && - !(SLOT_PRESENT (slot_cur->status)) && - !(SLOT_LATCH (slot_cur->status))) { - debug ("BEFORE POWER OFF COMMAND\n"); - rc = power_off (slot_cur); - if (rc) - return rc; - - /* retval = slot_update (&slot_cur); - * if (retval) - * return retval; - * ibmphp_update_slot_info (slot_cur); - */ - } - } - init_flag = 0; - return 0; -} - -/* This operation will check whether the slot is within the bounds and - * the operation is valid to perform on that slot - * Parameters: slot, operation - * Returns: 0 or error codes - */ -static int validate (struct slot *slot_cur, int opn) -{ - int number; - int retval; - - if (!slot_cur) - return -ENODEV; - number = slot_cur->number; - if ((number > max_slots) || (number < 0)) - return -EBADSLT; - debug ("slot_number in validate is %d\n", slot_cur->number); - - retval = slot_update (&slot_cur); - if (retval) - return retval; - - switch (opn) { - case ENABLE: - if (!(SLOT_PWRGD (slot_cur->status)) && - (SLOT_PRESENT (slot_cur->status)) && - !(SLOT_LATCH (slot_cur->status))) - return 0; - break; - case DISABLE: - if ((SLOT_PWRGD (slot_cur->status)) && - (SLOT_PRESENT (slot_cur->status)) && - !(SLOT_LATCH (slot_cur->status))) - return 0; - break; - default: - break; - } - err ("validate failed....\n"); - return -EINVAL; -} - -/******************************************************************************** - * This routine is for updating the data structures in the hotplug core - * Parameters: struct slot - * Returns: 0 or error - *******************************************************************************/ -int ibmphp_update_slot_info (struct slot *slot_cur) -{ - struct hotplug_slot_info *info; - int rc; - u8 bus_speed; - u8 mode; - - info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) { - err ("out of system memory \n"); - return -ENOMEM; - } - - info->power_status = SLOT_PWRGD (slot_cur->status); - info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status); - info->latch_status = SLOT_LATCH (slot_cur->status); - if (!SLOT_PRESENT (slot_cur->status)) { - info->adapter_status = 0; -// info->max_adapter_speed_status = MAX_ADAPTER_NONE; - } else { - info->adapter_status = 1; -// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0); - } - - bus_speed = slot_cur->bus_on->current_speed; - mode = slot_cur->bus_on->current_bus_mode; - - switch (bus_speed) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - bus_speed += 0x01; - else if (mode == BUS_MODE_PCI) - ; - else - bus_speed = PCI_SPEED_UNKNOWN; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - bus_speed += 0x01; - break; - default: - bus_speed = PCI_SPEED_UNKNOWN; - } - - info->cur_bus_speed = bus_speed; - info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed; - // To do: bus_names - - rc = pci_hp_change_slot_info (slot_cur->hotplug_slot, info); - kfree (info); - return rc; -} - - -/****************************************************************************** - * This function will return the pci_func, given bus and devfunc, or NULL. It - * is called from visit routines - ******************************************************************************/ - -static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) -{ - struct pci_func *func_cur; - struct slot *slot_cur; - struct list_head * tmp; - list_for_each (tmp, &ibmphp_slot_head) { - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - if (slot_cur->func) { - func_cur = slot_cur->func; - while (func_cur) { - if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function)) - return func_cur; - func_cur = func_cur->next; - } - } - } - return NULL; -} - -/* This routine is to find the pci_bus from kernel structures. - * Parameters: bus number - * Returns : pci_bus * or NULL if not found - */ -static struct pci_bus *ibmphp_find_bus (u8 busno) -{ - const struct list_head *tmp; - struct pci_bus *bus; - debug ("inside %s, busno = %x \n", __FUNCTION__, busno); - - list_for_each (tmp, &pci_root_buses) { - bus = (struct pci_bus *) pci_bus_b (tmp); - if (bus) - if (bus->number == busno) - return bus; - } - return NULL; -} - -/************************************************************* - * This routine frees up memory used by struct slot, including - * the pointers to pci_func, bus, hotplug_slot, controller, - * and deregistering from the hotplug core - *************************************************************/ -static void free_slots (void) -{ - struct slot *slot_cur; - struct list_head * tmp; - struct list_head * next; - - debug ("%s -- enter\n", __FUNCTION__); - - list_for_each_safe (tmp, next, &ibmphp_slot_head) { - - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - - pci_hp_deregister (slot_cur->hotplug_slot); - - if (slot_cur->hotplug_slot) { - kfree (slot_cur->hotplug_slot); - slot_cur->hotplug_slot = NULL; - } - - if (slot_cur->ctrl) - slot_cur->ctrl = NULL; - - if (slot_cur->bus_on) - slot_cur->bus_on = NULL; - - ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */ - - kfree (slot_cur); - slot_cur = NULL; - } - debug ("%s -- exit\n", __FUNCTION__); -} - -static int ibm_unconfigure_device (struct pci_func *func) -{ - struct pci_dev *temp; - u8 j; - - debug ("inside %s\n", __FUNCTION__); - debug ("func->device = %x, func->function = %x\n", func->device, func->function); - debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); - - for (j = 0; j < 0x08; j++) { - temp = pci_find_slot (func->busno, (func->device << 3) | j); - if (temp) - pci_remove_bus_device(temp); - } - return 0; -} - -/* - * The following function is to fix kernel bug regarding - * getting bus entries, here we manually add those primary - * bus entries to kernel bus structure whenever apply - */ - -static u8 bus_structure_fixup (u8 busno) -{ - struct pci_bus *bus; - struct pci_dev *dev; - u16 l; - - if (ibmphp_find_bus (busno) || !(ibmphp_find_same_bus_num (busno))) - return 1; - - bus = kmalloc (sizeof (*bus), GFP_KERNEL); - if (!bus) { - err ("%s - out of memory\n", __FUNCTION__); - return 1; - } - dev = kmalloc (sizeof (*dev), GFP_KERNEL); - if (!dev) { - kfree (bus); - err ("%s - out of memory\n", __FUNCTION__); - return 1; - } - - bus->number = busno; - bus->ops = ibmphp_pci_bus->ops; - dev->bus = bus; - for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) { - if (!pci_read_config_word (dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { - debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__); - pci_scan_bus (busno, ibmphp_pci_bus->ops, NULL); - break; - } - } - - kfree (dev); - kfree (bus); - - return 0; -} - -static int ibm_configure_device (struct pci_func *func) -{ - unsigned char bus; - struct pci_bus *child; - int num; - int flag = 0; /* this is to make sure we don't double scan the bus, for bridged devices primarily */ - - if (!(bus_structure_fixup (func->busno))) - flag = 1; - if (func->dev == NULL) - func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function)); - - if (func->dev == NULL) { - struct pci_bus *bus = ibmphp_find_bus (func->busno); - if (!bus) - return 0; - - num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function)); - if (num) - pci_bus_add_devices(bus); - - func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function)); - if (func->dev == NULL) { - err ("ERROR... : pci_dev still NULL \n"); - return 0; - } - } - if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { - pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus); - pci_do_scan_bus (child); - } - - return 0; -} - -/******************************************************* - * Returns whether the bus is empty or not - *******************************************************/ -static int is_bus_empty (struct slot * slot_cur) -{ - int rc; - struct slot * tmp_slot; - u8 i = slot_cur->bus_on->slot_min; - - while (i <= slot_cur->bus_on->slot_max) { - if (i == slot_cur->number) { - i++; - continue; - } - tmp_slot = ibmphp_get_slot_from_physical_num (i); - if (!tmp_slot) - return 0; - rc = slot_update (&tmp_slot); - if (rc) - return 0; - if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status)) - return 0; - i++; - } - return 1; -} - -/*********************************************************** - * If the HPC permits and the bus currently empty, tries to set the - * bus speed and mode at the maximum card and bus capability - * Parameters: slot - * Returns: bus is set (0) or error code - ***********************************************************/ -static int set_bus (struct slot * slot_cur) -{ - int rc; - u8 speed; - u8 cmd = 0x0; - const struct list_head *tmp; - struct pci_dev * dev; - int retval; - - debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number); - if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) { - rc = slot_update (&slot_cur); - if (rc) - return rc; - speed = SLOT_SPEED (slot_cur->ext_status); - debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); - switch (speed) { - case HPC_SLOT_SPEED_33: - cmd = HPC_BUS_33CONVMODE; - break; - case HPC_SLOT_SPEED_66: - if (SLOT_PCIX (slot_cur->ext_status)) { - if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX)) - cmd = HPC_BUS_66PCIXMODE; - else if (!SLOT_BUS_MODE (slot_cur->ext_status)) - /* if max slot/bus capability is 66 pci - and there's no bus mode mismatch, then - the adapter supports 66 pci */ - cmd = HPC_BUS_66CONVMODE; - else - cmd = HPC_BUS_33CONVMODE; - } else { - if (slot_cur->supported_speed >= BUS_SPEED_66) - cmd = HPC_BUS_66CONVMODE; - else - cmd = HPC_BUS_33CONVMODE; - } - break; - case HPC_SLOT_SPEED_133: - switch (slot_cur->supported_speed) { - case BUS_SPEED_33: - cmd = HPC_BUS_33CONVMODE; - break; - case BUS_SPEED_66: - if (slot_cur->supported_bus_mode == BUS_MODE_PCIX) - cmd = HPC_BUS_66PCIXMODE; - else - cmd = HPC_BUS_66CONVMODE; - break; - case BUS_SPEED_100: - cmd = HPC_BUS_100PCIXMODE; - break; - case BUS_SPEED_133: - /* This is to take care of the bug in CIOBX chip*/ - list_for_each (tmp, &pci_devices) { - dev = (struct pci_dev *) pci_dev_g (tmp); - if (dev) { - if ((dev->vendor == 0x1166) && (dev->device == 0x0101)) - ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE); - } - } - cmd = HPC_BUS_133PCIXMODE; - break; - default: - err ("Wrong bus speed \n"); - return -ENODEV; - } - break; - default: - err ("wrong slot speed \n"); - return -ENODEV; - } - debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd); - retval = ibmphp_hpc_writeslot (slot_cur, cmd); - if (retval) { - err ("setting bus speed failed\n"); - return retval; - } - if (CTLR_RESULT (slot_cur->ctrl->status)) { - err ("command not completed successfully in set_bus \n"); - return -EIO; - } - } - /* This is for x440, once Brandon fixes the firmware, - will not need this delay */ - long_delay (1 * HZ); - debug ("%s -Exit \n", __FUNCTION__); - return 0; -} - -/* This routine checks the bus limitations that the slot is on from the BIOS. - * This is used in deciding whether or not to power up the slot. - * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on - * same bus) - * Parameters: slot - * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus - */ -static int check_limitations (struct slot *slot_cur) -{ - u8 i; - struct slot * tmp_slot; - u8 count = 0; - u8 limitation = 0; - - for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) { - tmp_slot = ibmphp_get_slot_from_physical_num (i); - if (!tmp_slot) - return -ENODEV; - if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) - count++; - } - get_cur_bus_info (&slot_cur); - switch (slot_cur->bus_on->current_speed) { - case BUS_SPEED_33: - limitation = slot_cur->bus_on->slots_at_33_conv; - break; - case BUS_SPEED_66: - if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX) - limitation = slot_cur->bus_on->slots_at_66_pcix; - else - limitation = slot_cur->bus_on->slots_at_66_conv; - break; - case BUS_SPEED_100: - limitation = slot_cur->bus_on->slots_at_100_pcix; - break; - case BUS_SPEED_133: - limitation = slot_cur->bus_on->slots_at_133_pcix; - break; - } - - if ((count + 1) > limitation) - return -EINVAL; - return 0; -} - -static inline void print_card_capability (struct slot *slot_cur) -{ - info ("capability of the card is "); - if ((slot_cur->ext_status & CARD_INFO) == PCIX133) - info (" 133 MHz PCI-X \n"); - else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) - info (" 66 MHz PCI-X \n"); - else if ((slot_cur->ext_status & CARD_INFO) == PCI66) - info (" 66 MHz PCI \n"); - else - info (" 33 MHz PCI \n"); - -} - -/* This routine will power on the slot, configure the device(s) and find the - * drivers for them. - * Parameters: hotplug_slot - * Returns: 0 or failure codes - */ -static int enable_slot (struct hotplug_slot *hs) -{ - int rc, i, rcpr; - struct slot *slot_cur; - u8 function; - struct pci_func *tmp_func; - - ibmphp_lock_operations (); - - debug ("ENABLING SLOT........ \n"); - slot_cur = (struct slot *) hs->private; - - if ((rc = validate (slot_cur, ENABLE))) { - err ("validate function failed \n"); - goto error_nopower; - } - - attn_LED_blink (slot_cur); - - rc = set_bus (slot_cur); - if (rc) { - err ("was not able to set the bus \n"); - goto error_nopower; - } - - /*-----------------debugging------------------------------*/ - get_cur_bus_info (&slot_cur); - debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); - /*----------------------------------------------------------*/ - - rc = check_limitations (slot_cur); - if (rc) { - err ("Adding this card exceeds the limitations of this bus.\n"); - err ("(i.e., >1 133MHz cards running on same bus, or " - ">2 66 PCI cards running on same bus\n."); - err ("Try hot-adding into another bus \n"); - rc = -EINVAL; - goto error_nopower; - } - - rc = power_on (slot_cur); - - if (rc) { - err ("something wrong when powering up... please see below for details\n"); - /* need to turn off before on, otherwise, blinking overwrites */ - attn_off(slot_cur); - attn_on (slot_cur); - if (slot_update (&slot_cur)) { - attn_off (slot_cur); - attn_on (slot_cur); - rc = -ENODEV; - goto exit; - } - /* Check to see the error of why it failed */ - if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status))) - err ("power fault occurred trying to power up \n"); - else if (SLOT_BUS_SPEED (slot_cur->status)) { - err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); - print_card_capability (slot_cur); - } else if (SLOT_BUS_MODE (slot_cur->ext_status)) { - err ("bus mode mismatch occurred. please check current bus mode and card capability \n"); - print_card_capability (slot_cur); - } - ibmphp_update_slot_info (slot_cur); - goto exit; - } - debug ("after power_on\n"); - /*-----------------------debugging---------------------------*/ - get_cur_bus_info (&slot_cur); - debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed); - /*----------------------------------------------------------*/ - - rc = slot_update (&slot_cur); - if (rc) - goto error_power; - - rc = -EINVAL; - if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) { - err ("power fault occurred trying to power up... \n"); - goto error_power; - } - if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) { - err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); - print_card_capability (slot_cur); - goto error_power; - } - /* Don't think this case will happen after above checks... but just in case, for paranoia sake */ - if (!(SLOT_POWER (slot_cur->status))) { - err ("power on failed... \n"); - goto error_power; - } - - slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!slot_cur->func) { - /* We cannot do update_slot_info here, since no memory for - * kmalloc n.e.ways, and update_slot_info allocates some */ - err ("out of system memory \n"); - rc = -ENOMEM; - goto error_power; - } - memset (slot_cur->func, 0, sizeof (struct pci_func)); - slot_cur->func->busno = slot_cur->bus; - slot_cur->func->device = slot_cur->device; - for (i = 0; i < 4; i++) - slot_cur->func->irq[i] = slot_cur->irq[i]; - - debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device); - - if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) { - err ("configure_card was unsuccessful... \n"); - ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */ - debug ("after unconfigure_card\n"); - slot_cur->func = NULL; - rc = -ENOMEM; - goto error_power; - } - - function = 0x00; - do { - tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++); - if (tmp_func && !(tmp_func->dev)) - ibm_configure_device (tmp_func); - } while (tmp_func); - - attn_off (slot_cur); - if (slot_update (&slot_cur)) { - rc = -EFAULT; - goto exit; - } - ibmphp_print_test (); - rc = ibmphp_update_slot_info (slot_cur); -exit: - ibmphp_unlock_operations(); - return rc; - -error_nopower: - attn_off (slot_cur); /* need to turn off if was blinking b4 */ - attn_on (slot_cur); -error_cont: - rcpr = slot_update (&slot_cur); - if (rcpr) { - rc = rcpr; - goto exit; - } - ibmphp_update_slot_info (slot_cur); - goto exit; - -error_power: - attn_off (slot_cur); /* need to turn off if was blinking b4 */ - attn_on (slot_cur); - rcpr = power_off (slot_cur); - if (rcpr) { - rc = rcpr; - goto exit; - } - goto error_cont; -} - -/************************************************************** -* HOT REMOVING ADAPTER CARD * -* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * -* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * - DISABLE POWER , * -**************************************************************/ -int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = hotplug_slot->private; - int rc; - - ibmphp_lock_operations(); - rc = ibmphp_do_disable_slot(slot); - ibmphp_unlock_operations(); - return rc; -} - -int ibmphp_do_disable_slot (struct slot *slot_cur) -{ - int rc; - u8 flag; - int parm = 0; - - debug ("DISABLING SLOT... \n"); - - if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) { - return -ENODEV; - } - - flag = slot_cur->flag; - slot_cur->flag = TRUE; - - if (flag == TRUE) { - rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */ - if (rc) - goto error; - } - attn_LED_blink (slot_cur); - - if (slot_cur->func == NULL) { - /* We need this for fncs's that were there on bootup */ - slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!slot_cur->func) { - err ("out of system memory \n"); - rc = -ENOMEM; - goto error; - } - memset (slot_cur->func, 0, sizeof (struct pci_func)); - slot_cur->func->busno = slot_cur->bus; - slot_cur->func->device = slot_cur->device; - } - - if ((rc = ibm_unconfigure_device (slot_cur->func))) { - err ("removing from kernel failed... \n"); - err ("Please check to see if it was statically linked or is " - "in use otherwise. (perhaps the driver is not 'hot-removable')\n"); - goto error; - } - - /* If we got here from latch suddenly opening on operating card or - a power fault, there's no power to the card, so cannot - read from it to determine what resources it occupied. This operation - is forbidden anyhow. The best we can do is remove it from kernel - lists at least */ - - if (!flag) { - attn_off (slot_cur); - return 0; - } - - rc = ibmphp_unconfigure_card (&slot_cur, parm); - slot_cur->func = NULL; - debug ("in disable_slot. after unconfigure_card\n"); - if (rc) { - err ("could not unconfigure card.\n"); - goto error; - } - - rc = ibmphp_hpc_writeslot (slot_cur, HPC_SLOT_OFF); - if (rc) - goto error; - - attn_off (slot_cur); - rc = slot_update (&slot_cur); - if (rc) - goto exit; - - rc = ibmphp_update_slot_info (slot_cur); - ibmphp_print_test (); -exit: - return rc; - -error: - /* Need to turn off if was blinking b4 */ - attn_off (slot_cur); - attn_on (slot_cur); - if (slot_update (&slot_cur)) { - rc = -EFAULT; - goto exit; - } - if (flag) - ibmphp_update_slot_info (slot_cur); - goto exit; -} - -struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = enable_slot, - .disable_slot = ibmphp_disable_slot, - .hardware_test = NULL, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_present, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -/* .get_max_adapter_speed = get_max_adapter_speed, - .get_bus_name_status = get_bus_name, -*/ -}; - -static void ibmphp_unload (void) -{ - free_slots (); - debug ("after slots \n"); - ibmphp_free_resources (); - debug ("after resources \n"); - ibmphp_free_bus_info_queue (); - debug ("after bus info \n"); - ibmphp_free_ebda_hpc_queue (); - debug ("after ebda hpc \n"); - ibmphp_free_ebda_pci_rsrc_queue (); - debug ("after ebda pci rsrc \n"); - kfree (ibmphp_pci_bus); -} - -static int __init ibmphp_init (void) -{ - struct pci_bus *bus; - int i = 0; - int rc = 0; - - init_flag = 1; - - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - - ibmphp_pci_bus = kmalloc (sizeof (*ibmphp_pci_bus), GFP_KERNEL); - if (!ibmphp_pci_bus) { - err ("out of memory\n"); - rc = -ENOMEM; - goto exit; - } - - bus = ibmphp_find_bus (0); - if (!bus) { - err ("Can't find the root pci bus, can not continue\n"); - rc = -ENODEV; - goto error; - } - memcpy (ibmphp_pci_bus, bus, sizeof (*ibmphp_pci_bus)); - - ibmphp_debug = debug; - - ibmphp_hpc_initvars (); - - for (i = 0; i < 16; i++) - irqs[i] = 0; - - if ((rc = ibmphp_access_ebda ())) - goto error; - debug ("after ibmphp_access_ebda ()\n"); - - if ((rc = ibmphp_rsrc_init ())) - goto error; - debug ("AFTER Resource & EBDA INITIALIZATIONS\n"); - - max_slots = get_max_slots (); - - if ((rc = ibmphp_register_pci ())) - goto error; - - if (init_ops ()) { - rc = -ENODEV; - goto error; - } - - ibmphp_print_test (); - if ((rc = ibmphp_hpc_start_poll_thread ())) { - goto error; - } - - /* lock ourselves into memory with a module - * count of -1 so that no one can unload us. */ - module_put(THIS_MODULE); - -exit: - return rc; - -error: - ibmphp_unload (); - goto exit; -} - -static void __exit ibmphp_exit (void) -{ - ibmphp_hpc_stop_poll_thread (); - debug ("after polling\n"); - ibmphp_unload (); - debug ("done\n"); -} - -module_init (ibmphp_init); -module_exit (ibmphp_exit); diff -urN linux-2.5.70-bk9/drivers/hotplug/ibmphp_ebda.c linux-2.5.70-bk10/drivers/hotplug/ibmphp_ebda.c --- linux-2.5.70-bk9/drivers/hotplug/ibmphp_ebda.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/ibmphp_ebda.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1228 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Tong Yu, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ibmphp.h" - -/* - * POST builds data blocks(in this data block definition, a char-1 - * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended - * BIOS Data Area which describe the configuration of the hot-plug - * controllers and resources used by the PCI Hot-Plug devices. - * - * This file walks EBDA, maps data block from physical addr, - * reconstruct linked lists about all system resource(MEM, PFM, IO) - * already assigned by POST, as well as linked lists about hot plug - * controllers (ctlr#, slot#, bus&slot features...) - */ - -/* Global lists */ -LIST_HEAD (ibmphp_ebda_pci_rsrc_head); -LIST_HEAD (ibmphp_slot_head); - -/* Local variables */ -static struct ebda_hpc_list *hpc_list_ptr; -static struct ebda_rsrc_list *rsrc_list_ptr; -static struct rio_table_hdr *rio_table_ptr = NULL; -static LIST_HEAD (ebda_hpc_head); -static LIST_HEAD (bus_info_head); -static LIST_HEAD (rio_vg_head); -static LIST_HEAD (rio_lo_head); -static LIST_HEAD (opt_vg_head); -static LIST_HEAD (opt_lo_head); -static void *io_mem; - -/* Local functions */ -static int ebda_rsrc_controller (void); -static int ebda_rsrc_rsrc (void); -static int ebda_rio_table (void); - -static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void) -{ - struct ebda_hpc_list *list; - - list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); - if (!list) - return NULL; - memset (list, 0, sizeof (*list)); - return list; -} - -static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) -{ - struct controller *controller; - struct ebda_hpc_slot *slots; - struct ebda_hpc_bus *buses; - - controller = kmalloc (sizeof (struct controller), GFP_KERNEL); - if (!controller) - return NULL; - memset (controller, 0, sizeof (*controller)); - - slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); - if (!slots) { - kfree (controller); - return NULL; - } - memset (slots, 0, sizeof (*slots) * slot_count); - controller->slots = slots; - - buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); - if (!buses) { - kfree (controller->slots); - kfree (controller); - return NULL; - } - memset (buses, 0, sizeof (*buses) * bus_count); - controller->buses = buses; - - return controller; -} - -static void free_ebda_hpc (struct controller *controller) -{ - kfree (controller->slots); - controller->slots = NULL; - kfree (controller->buses); - controller->buses = NULL; - controller->ctrl_dev = NULL; - kfree (controller); -} - -static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void) -{ - struct ebda_rsrc_list *list; - - list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); - if (!list) - return NULL; - memset (list, 0, sizeof (*list)); - return list; -} - -static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) -{ - struct ebda_pci_rsrc *resource; - - resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); - if (!resource) - return NULL; - memset (resource, 0, sizeof (*resource)); - return resource; -} - -static void __init print_bus_info (void) -{ - struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); - debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); - debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); - debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); - debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); - debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); - - debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv); - debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv); - debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix); - debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix); - debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix); - - } -} - -static void print_lo_info (void) -{ - struct rio_detail *ptr; - struct list_head *ptr1; - debug ("print_lo_info ---- \n"); - list_for_each (ptr1, &rio_lo_head) { - ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); - debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); - debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); - debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); - debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); - - } -} - -static void print_vg_info (void) -{ - struct rio_detail *ptr; - struct list_head *ptr1; - debug ("%s --- \n", __FUNCTION__); - list_for_each (ptr1, &rio_vg_head) { - ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); - debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); - debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); - debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); - debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); - - } -} - -static void __init print_ebda_pci_rsrc (void) -{ - struct ebda_pci_rsrc *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { - ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); - } -} - -static void __init print_ibm_slot (void) -{ - struct slot *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &ibmphp_slot_head) { - ptr = list_entry (ptr1, struct slot, ibm_slot_list); - debug ("%s - slot_number: %x \n", __FUNCTION__, ptr->number); - } -} - -static void __init print_opt_vg (void) -{ - struct opt_rio *ptr; - struct list_head *ptr1; - debug ("%s --- \n", __FUNCTION__); - list_for_each (ptr1, &opt_vg_head) { - ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); - debug ("%s - rio_type %x \n", __FUNCTION__, ptr->rio_type); - debug ("%s - chassis_num: %x \n", __FUNCTION__, ptr->chassis_num); - debug ("%s - first_slot_num: %x \n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - middle_num: %x \n", __FUNCTION__, ptr->middle_num); - } -} - -static void __init print_ebda_hpc (void) -{ - struct controller *hpc_ptr; - struct list_head *ptr1; - u16 index; - - list_for_each (ptr1, &ebda_hpc_head) { - - hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); - - for (index = 0; index < hpc_ptr->slot_count; index++) { - debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); - debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); - debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); - debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); - } - - for (index = 0; index < hpc_ptr->bus_count; index++) { - debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); - } - - debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); - switch (hpc_ptr->ctlr_type) { - case 1: - debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); - debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); - break; - - case 0: - debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); - debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); - break; - - case 2: - case 4: - debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); - debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); - break; - } - } -} - -int __init ibmphp_access_ebda (void) -{ - u8 format, num_ctlrs, rio_complete, hs_complete; - u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; - - - rio_complete = 0; - hs_complete = 0; - - io_mem = ioremap ((0x40 << 4) + 0x0e, 2); - if (!io_mem ) - return -ENOMEM; - ebda_seg = readw (io_mem); - iounmap (io_mem); - debug ("returned ebda segment: %x\n", ebda_seg); - - io_mem = ioremap (ebda_seg<<4, 65000); - if (!io_mem ) - return -ENOMEM; - next_offset = 0x180; - - for (;;) { - offset = next_offset; - next_offset = readw (io_mem + offset); /* offset of next blk */ - - offset += 2; - if (next_offset == 0) /* 0 indicate it's last blk */ - break; - blk_id = readw (io_mem + offset); /* this blk id */ - - offset += 2; - /* check if it is hot swap block or rio block */ - if (blk_id != 0x4853 && blk_id != 0x4752) - continue; - /* found hs table */ - if (blk_id == 0x4853) { - debug ("now enter hot swap block---\n"); - debug ("hot blk id: %x\n", blk_id); - format = readb (io_mem + offset); - - offset += 1; - if (format != 4) { - iounmap (io_mem); - return -ENODEV; - } - debug ("hot blk format: %x\n", format); - /* hot swap sub blk */ - base = offset; - - sub_addr = base; - re = readw (io_mem + sub_addr); /* next sub blk */ - - sub_addr += 2; - rc_id = readw (io_mem + sub_addr); /* sub blk id */ - - sub_addr += 2; - if (rc_id != 0x5243) { - iounmap (io_mem); - return -ENODEV; - } - /* rc sub blk signature */ - num_ctlrs = readb (io_mem + sub_addr); - - sub_addr += 1; - hpc_list_ptr = alloc_ebda_hpc_list (); - if (!hpc_list_ptr) { - iounmap (io_mem); - return -ENOMEM; - } - hpc_list_ptr->format = format; - hpc_list_ptr->num_ctlrs = num_ctlrs; - hpc_list_ptr->phys_addr = sub_addr; /* offset of RSRC_CONTROLLER blk */ - debug ("info about hpc descriptor---\n"); - debug ("hot blk format: %x\n", format); - debug ("num of controller: %x\n", num_ctlrs); - debug ("offset of hpc data structure enteries: %x\n ", sub_addr); - - sub_addr = base + re; /* re sub blk */ - rc = readw (io_mem + sub_addr); /* next sub blk */ - - sub_addr += 2; - re_id = readw (io_mem + sub_addr); /* sub blk id */ - - sub_addr += 2; - if (re_id != 0x5245) { - iounmap (io_mem); - return -ENODEV; - } - - /* signature of re */ - num_entries = readw (io_mem + sub_addr); - - sub_addr += 2; /* offset of RSRC_ENTRIES blk */ - rsrc_list_ptr = alloc_ebda_rsrc_list (); - if (!rsrc_list_ptr ) { - iounmap (io_mem); - return -ENOMEM; - } - rsrc_list_ptr->format = format; - rsrc_list_ptr->num_entries = num_entries; - rsrc_list_ptr->phys_addr = sub_addr; - - debug ("info about rsrc descriptor---\n"); - debug ("format: %x\n", format); - debug ("num of rsrc: %x\n", num_entries); - debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); - - hs_complete = 1; - } - /* found rio table */ - else if (blk_id == 0x4752) { - debug ("now enter io table ---\n"); - debug ("rio blk id: %x\n", blk_id); - - rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); - if (!rio_table_ptr) - return -ENOMEM; - memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); - rio_table_ptr->ver_num = readb (io_mem + offset); - rio_table_ptr->scal_count = readb (io_mem + offset + 1); - rio_table_ptr->riodev_count = readb (io_mem + offset + 2); - rio_table_ptr->offset = offset +3 ; - - debug ("info about rio table hdr ---\n"); - debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset); - - rio_complete = 1; - } - } - - if (!hs_complete && !rio_complete) { - iounmap (io_mem); - return -ENODEV; - } - - if (rio_table_ptr) { - if (rio_complete == 1 && rio_table_ptr->ver_num == 3) { - rc = ebda_rio_table (); - if (rc) { - iounmap (io_mem); - return rc; - } - } - } - rc = ebda_rsrc_controller (); - if (rc) { - iounmap (io_mem); - return rc; - } - - rc = ebda_rsrc_rsrc (); - if (rc) { - iounmap (io_mem); - return rc; - } - - iounmap (io_mem); - return 0; -} - -/* - * map info of scalability details and rio details from physical address - */ -static int __init ebda_rio_table (void) -{ - u16 offset; - u8 i; - struct rio_detail *rio_detail_ptr; - - offset = rio_table_ptr->offset; - offset += 12 * rio_table_ptr->scal_count; - - // we do concern about rio details - for (i = 0; i < rio_table_ptr->riodev_count; i++) { - rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL); - if (!rio_detail_ptr) - return -ENOMEM; - memset (rio_detail_ptr, 0, sizeof (struct rio_detail)); - rio_detail_ptr->rio_node_id = readb (io_mem + offset); - rio_detail_ptr->bbar = readl (io_mem + offset + 1); - rio_detail_ptr->rio_type = readb (io_mem + offset + 5); - rio_detail_ptr->owner_id = readb (io_mem + offset + 6); - rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7); - rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8); - rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9); - rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10); - rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11); - rio_detail_ptr->status = readb (io_mem + offset + 12); - rio_detail_ptr->wpindex = readb (io_mem + offset + 13); - rio_detail_ptr->chassis_num = readb (io_mem + offset + 14); -// debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); - //create linked list of chassis - if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) - list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head); - //create linked list of expansion box - else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) - list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head); - else - // not in my concern - kfree (rio_detail_ptr); - offset += 15; - } - print_lo_info (); - print_vg_info (); - return 0; -} - -/* - * reorganizing linked list of chassis - */ -static struct opt_rio *search_opt_vg (u8 chassis_num) -{ - struct opt_rio *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &opt_vg_head) { - ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); - if (ptr->chassis_num == chassis_num) - return ptr; - } - return NULL; -} - -static int __init combine_wpg_for_chassis (void) -{ - struct opt_rio *opt_rio_ptr = NULL; - struct rio_detail *rio_detail_ptr = NULL; - struct list_head *list_head_ptr = NULL; - - list_for_each (list_head_ptr, &rio_vg_head) { - rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); - opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num); - if (!opt_rio_ptr) { - opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL); - if (!opt_rio_ptr) - return -ENOMEM; - memset (opt_rio_ptr, 0, sizeof (struct opt_rio)); - opt_rio_ptr->rio_type = rio_detail_ptr->rio_type; - opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num; - opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num; - opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num; - list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head); - } else { - opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num); - opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num); - } - } - print_opt_vg (); - return 0; -} - -/* - * reorgnizing linked list of expansion box - */ -static struct opt_rio_lo *search_opt_lo (u8 chassis_num) -{ - struct opt_rio_lo *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &opt_lo_head) { - ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list); - if (ptr->chassis_num == chassis_num) - return ptr; - } - return NULL; -} - -static int combine_wpg_for_expansion (void) -{ - struct opt_rio_lo *opt_rio_lo_ptr = NULL; - struct rio_detail *rio_detail_ptr = NULL; - struct list_head *list_head_ptr = NULL; - - list_for_each (list_head_ptr, &rio_lo_head) { - rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); - opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num); - if (!opt_rio_lo_ptr) { - opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL); - if (!opt_rio_lo_ptr) - return -ENOMEM; - memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo)); - opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type; - opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num; - opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num; - opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num; - opt_rio_lo_ptr->pack_count = 1; - - list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head); - } else { - opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num); - opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num); - opt_rio_lo_ptr->pack_count = 2; - } - } - return 0; -} - - -/* Since we don't know the max slot number per each chassis, hence go - * through the list of all chassis to find out the range - * Arguments: slot_num, 1st slot number of the chassis we think we are on, - * var (0 = chassis, 1 = expansion box) - */ -static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) -{ - struct opt_rio *opt_vg_ptr = NULL; - struct opt_rio_lo *opt_lo_ptr = NULL; - struct list_head *ptr = NULL; - int rc = 0; - - if (!var) { - list_for_each (ptr, &opt_vg_head) { - opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); - if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { - rc = -ENODEV; - break; - } - } - } else { - list_for_each (ptr, &opt_lo_head) { - opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); - if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) { - rc = -ENODEV; - break; - } - } - } - return rc; -} - -static struct opt_rio_lo * find_rxe_num (u8 slot_num) -{ - struct opt_rio_lo *opt_lo_ptr; - struct list_head *ptr; - - list_for_each (ptr, &opt_lo_head) { - opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); - //check to see if this slot_num belongs to expansion box - if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) - return opt_lo_ptr; - } - return NULL; -} - -static struct opt_rio * find_chassis_num (u8 slot_num) -{ - struct opt_rio *opt_vg_ptr; - struct list_head *ptr; - - list_for_each (ptr, &opt_vg_head) { - opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); - //check to see if this slot_num belongs to chassis - if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) - return opt_vg_ptr; - } - return NULL; -} - -/* This routine will find out how many slots are in the chassis, so that - * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc - */ -static u8 calculate_first_slot (u8 slot_num) -{ - u8 first_slot = 1; - struct list_head * list; - struct slot * slot_cur; - - list_for_each (list, &ibmphp_slot_head) { - slot_cur = list_entry (list, struct slot, ibm_slot_list); - if (slot_cur->ctrl) { - if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) - first_slot = slot_cur->ctrl->ending_slot_num; - } - } - return first_slot + 1; - -} -static char *create_file_name (struct slot * slot_cur) -{ - struct opt_rio *opt_vg_ptr = NULL; - struct opt_rio_lo *opt_lo_ptr = NULL; - static char str[30]; - int which = 0; /* rxe = 1, chassis = 0 */ - u8 number = 1; /* either chassis or rxe # */ - u8 first_slot = 1; - u8 slot_num; - u8 flag = 0; - - if (!slot_cur) { - err ("Structure passed is empty \n"); - return NULL; - } - - slot_num = slot_cur->number; - - memset (str, 0, sizeof(str)); - - if (rio_table_ptr) { - if (rio_table_ptr->ver_num == 3) { - opt_vg_ptr = find_chassis_num (slot_num); - opt_lo_ptr = find_rxe_num (slot_num); - } - } - if (opt_vg_ptr) { - if (opt_lo_ptr) { - if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) { - number = opt_lo_ptr->chassis_num; - first_slot = opt_lo_ptr->first_slot_num; - which = 1; /* it is RXE */ - } else { - first_slot = opt_vg_ptr->first_slot_num; - number = opt_vg_ptr->chassis_num; - which = 0; - } - } else { - first_slot = opt_vg_ptr->first_slot_num; - number = opt_vg_ptr->chassis_num; - which = 0; - } - ++flag; - } else if (opt_lo_ptr) { - number = opt_lo_ptr->chassis_num; - first_slot = opt_lo_ptr->first_slot_num; - which = 1; - ++flag; - } else if (rio_table_ptr) { - if (rio_table_ptr->ver_num == 3) { - /* if both NULL and we DO have correct RIO table in BIOS */ - return NULL; - } - } - if (!flag) { - if (slot_cur->ctrl->ctlr_type == 4) { - first_slot = calculate_first_slot (slot_num); - which = 1; - } else { - which = 0; - } - } - - sprintf(str, "%s%dslot%d", - which == 0 ? "chassis" : "rxe", - number, slot_num - first_slot + 1); - return str; -} - -static struct pci_driver ibmphp_driver; - -/* - * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of - * each hpc from physical address to a list of hot plug controllers based on - * hpc descriptors. - */ -static int __init ebda_rsrc_controller (void) -{ - u16 addr, addr_slot, addr_bus; - u8 ctlr_id, temp, bus_index; - u16 ctlr, slot, bus; - u16 slot_num, bus_num, index; - struct hotplug_slot *hp_slot_ptr; - struct controller *hpc_ptr; - struct ebda_hpc_bus *bus_ptr; - struct ebda_hpc_slot *slot_ptr; - struct bus_info *bus_info_ptr1, *bus_info_ptr2; - int rc; - struct slot *tmp_slot; - struct list_head *list; - - addr = hpc_list_ptr->phys_addr; - for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { - bus_index = 1; - ctlr_id = readb (io_mem + addr); - addr += 1; - slot_num = readb (io_mem + addr); - - addr += 1; - addr_slot = addr; /* offset of slot structure */ - addr += (slot_num * 4); - - bus_num = readb (io_mem + addr); - - addr += 1; - addr_bus = addr; /* offset of bus */ - addr += (bus_num * 9); /* offset of ctlr_type */ - temp = readb (io_mem + addr); - - addr += 1; - /* init hpc structure */ - hpc_ptr = alloc_ebda_hpc (slot_num, bus_num); - if (!hpc_ptr ) { - rc = -ENOMEM; - goto error_no_hpc; - } - hpc_ptr->ctlr_id = ctlr_id; - hpc_ptr->ctlr_relative_id = ctlr; - hpc_ptr->slot_count = slot_num; - hpc_ptr->bus_count = bus_num; - debug ("now enter ctlr data struture ---\n"); - debug ("ctlr id: %x\n", ctlr_id); - debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); - debug ("count of slots controlled by this ctlr: %x\n", slot_num); - debug ("count of buses controlled by this ctlr: %x\n", bus_num); - - /* init slot structure, fetch slot, bus, cap... */ - slot_ptr = hpc_ptr->slots; - for (slot = 0; slot < slot_num; slot++) { - slot_ptr->slot_num = readb (io_mem + addr_slot); - slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num); - slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); - slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); - - // create bus_info lined list --- if only one slot per bus: slot_min = slot_max - - bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); - if (!bus_info_ptr2) { - bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); - if (!bus_info_ptr1) { - rc = -ENOMEM; - goto error_no_hp_slot; - } - memset (bus_info_ptr1, 0, sizeof (struct bus_info)); - bus_info_ptr1->slot_min = slot_ptr->slot_num; - bus_info_ptr1->slot_max = slot_ptr->slot_num; - bus_info_ptr1->slot_count += 1; - bus_info_ptr1->busno = slot_ptr->slot_bus_num; - bus_info_ptr1->index = bus_index++; - bus_info_ptr1->current_speed = 0xff; - bus_info_ptr1->current_bus_mode = 0xff; - - bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; - - list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); - - } else { - bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num); - bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num); - bus_info_ptr2->slot_count += 1; - - } - - // end of creating the bus_info linked list - - slot_ptr++; - addr_slot += 1; - } - - /* init bus structure */ - bus_ptr = hpc_ptr->buses; - for (bus = 0; bus < bus_num; bus++) { - bus_ptr->bus_num = readb (io_mem + addr_bus + bus); - bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus); - bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1); - - bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2); - - bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3); - - bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4); - - bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num); - if (bus_info_ptr2) { - bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv; - bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv; - bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix; - bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix; - bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; - } - bus_ptr++; - } - - hpc_ptr->ctlr_type = temp; - - switch (hpc_ptr->ctlr_type) { - case 1: - hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr); - hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); - hpc_ptr->irq = readb (io_mem + addr + 2); - addr += 3; - debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", - hpc_ptr->u.pci_ctlr.bus, - hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq); - break; - - case 0: - hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr); - hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2); - if (!request_region (hpc_ptr->u.isa_ctlr.io_start, - (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), - "ibmphp")) { - rc = -ENODEV; - goto error_no_hp_slot; - } - hpc_ptr->irq = readb (io_mem + addr + 4); - addr += 5; - break; - - case 2: - case 4: - hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); - hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); - hpc_ptr->irq = readb (io_mem + addr + 5); - addr += 6; - break; - default: - rc = -ENODEV; - goto error_no_hp_slot; - } - - //reorganize chassis' linked list - combine_wpg_for_chassis (); - combine_wpg_for_expansion (); - hpc_ptr->revision = 0xff; - hpc_ptr->options = 0xff; - hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num; - hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num; - - // register slots with hpc core as well as create linked list of ibm slot - for (index = 0; index < hpc_ptr->slot_count; index++) { - - hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!hp_slot_ptr) { - rc = -ENOMEM; - goto error_no_hp_slot; - } - memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot)); - - hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!hp_slot_ptr->info) { - rc = -ENOMEM; - goto error_no_hp_info; - } - memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info)); - - hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL); - if (!hp_slot_ptr->name) { - rc = -ENOMEM; - goto error_no_hp_name; - } - - tmp_slot = kmalloc (sizeof (struct slot), GFP_KERNEL); - if (!tmp_slot) { - rc = -ENOMEM; - goto error_no_slot; - } - memset (tmp_slot, 0, sizeof (*tmp_slot)); - - tmp_slot->flag = TRUE; - - tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap; - if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX) - tmp_slot->supported_speed = 3; - else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX) - tmp_slot->supported_speed = 2; - else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX) - tmp_slot->supported_speed = 1; - - if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP) - tmp_slot->supported_bus_mode = 1; - else - tmp_slot->supported_bus_mode = 0; - - - tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num; - - bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); - if (!bus_info_ptr1) { - rc = -ENODEV; - goto error; - } - tmp_slot->bus_on = bus_info_ptr1; - bus_info_ptr1 = NULL; - tmp_slot->ctrl = hpc_ptr; - - tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index; - tmp_slot->number = hpc_ptr->slots[index].slot_num; - tmp_slot->hotplug_slot = hp_slot_ptr; - - hp_slot_ptr->private = tmp_slot; - - rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr); - if (rc) - goto error; - - rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private); - if (rc) - goto error; - hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; - - // end of registering ibm slot with hotplug core - - list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); - } - - print_bus_info (); - list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head ); - - } /* each hpc */ - - list_for_each (list, &ibmphp_slot_head) { - tmp_slot = list_entry (list, struct slot, ibm_slot_list); - - snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); - pci_hp_register (tmp_slot->hotplug_slot); - } - - print_ebda_hpc (); - print_ibm_slot (); - return 0; - -error: - kfree (hp_slot_ptr->private); -error_no_slot: - kfree (hp_slot_ptr->name); -error_no_hp_name: - kfree (hp_slot_ptr->info); -error_no_hp_info: - kfree (hp_slot_ptr); -error_no_hp_slot: - free_ebda_hpc (hpc_ptr); -error_no_hpc: - iounmap (io_mem); - return rc; -} - -/* - * map info (bus, devfun, start addr, end addr..) of i/o, memory, - * pfm from the physical addr to a list of resource. - */ -static int __init ebda_rsrc_rsrc (void) -{ - u16 addr; - short rsrc; - u8 type, rsrc_type; - struct ebda_pci_rsrc *rsrc_ptr; - - addr = rsrc_list_ptr->phys_addr; - debug ("now entering rsrc land\n"); - debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr); - - for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) { - type = readb (io_mem + addr); - - addr += 1; - rsrc_type = type & EBDA_RSRC_TYPE_MASK; - - if (rsrc_type == EBDA_IO_RSRC_TYPE) { - rsrc_ptr = alloc_ebda_pci_rsrc (); - if (!rsrc_ptr) { - iounmap (io_mem); - return -ENOMEM; - } - rsrc_ptr->rsrc_type = type; - - rsrc_ptr->bus_num = readb (io_mem + addr); - rsrc_ptr->dev_fun = readb (io_mem + addr + 1); - rsrc_ptr->start_addr = readw (io_mem + addr + 2); - rsrc_ptr->end_addr = readw (io_mem + addr + 4); - addr += 6; - - debug ("rsrc from io type ----\n"); - debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); - - list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); - } - - if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) { - rsrc_ptr = alloc_ebda_pci_rsrc (); - if (!rsrc_ptr ) { - iounmap (io_mem); - return -ENOMEM; - } - rsrc_ptr->rsrc_type = type; - - rsrc_ptr->bus_num = readb (io_mem + addr); - rsrc_ptr->dev_fun = readb (io_mem + addr + 1); - rsrc_ptr->start_addr = readl (io_mem + addr + 2); - rsrc_ptr->end_addr = readl (io_mem + addr + 6); - addr += 10; - - debug ("rsrc from mem or pfm ---\n"); - debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); - - list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); - } - } - kfree (rsrc_list_ptr); - rsrc_list_ptr = NULL; - print_ebda_pci_rsrc (); - return 0; -} - -u16 ibmphp_get_total_controllers (void) -{ - return hpc_list_ptr->num_ctlrs; -} - -struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) -{ - struct slot *slot; - struct list_head *list; - - list_for_each (list, &ibmphp_slot_head) { - slot = list_entry (list, struct slot, ibm_slot_list); - if (slot->number == physical_num) - return slot; - } - return NULL; -} - -/* To find: - * - the smallest slot number - * - the largest slot number - * - the total number of the slots based on each bus - * (if only one slot per bus slot_min = slot_max ) - */ -struct bus_info *ibmphp_find_same_bus_num (u32 num) -{ - struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - if (ptr->busno == num) - return ptr; - } - return NULL; -} - -/* Finding relative bus number, in order to map corresponding - * bus register - */ -int ibmphp_get_bus_index (u8 num) -{ - struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - if (ptr->busno == num) - return ptr->index; - } - return -ENODEV; -} - -void ibmphp_free_bus_info_queue (void) -{ - struct bus_info *bus_info; - struct list_head *list; - struct list_head *next; - - list_for_each_safe (list, next, &bus_info_head ) { - bus_info = list_entry (list, struct bus_info, bus_info_list); - kfree (bus_info); - } -} - -void ibmphp_free_ebda_hpc_queue (void) -{ - struct controller *controller = NULL; - struct list_head *list; - struct list_head *next; - int pci_flag = 0; - - list_for_each_safe (list, next, &ebda_hpc_head) { - controller = list_entry (list, struct controller, ebda_hpc_list); - if (controller->ctlr_type == 0) - release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1)); - else if ((controller->ctlr_type == 1) && (!pci_flag)) { - ++pci_flag; - pci_unregister_driver (&ibmphp_driver); - } - free_ebda_hpc (controller); - } -} - -void ibmphp_free_ebda_pci_rsrc_queue (void) -{ - struct ebda_pci_rsrc *resource; - struct list_head *list; - struct list_head *next; - - list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) { - resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - kfree (resource); - resource = NULL; - } -} - -static struct pci_device_id id_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_IBM, - .device = HPC_DEVICE_ID, - .subvendor = PCI_VENDOR_ID_IBM, - .subdevice = HPC_SUBSYSTEM_ID, - .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), - }, {} -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *); -static struct pci_driver ibmphp_driver = { - .name = "ibmphp", - .id_table = id_table, - .probe = ibmphp_probe, -}; - -int ibmphp_register_pci (void) -{ - struct controller *ctrl; - struct list_head *tmp; - int rc = 0; - - list_for_each (tmp, &ebda_hpc_head) { - ctrl = list_entry (tmp, struct controller, ebda_hpc_list); - if (ctrl->ctlr_type == 1) { - rc = pci_module_init (&ibmphp_driver); - break; - } - } - return rc; -} -static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) -{ - struct controller *ctrl; - struct list_head *tmp; - - debug ("inside ibmphp_probe \n"); - - list_for_each (tmp, &ebda_hpc_head) { - ctrl = list_entry (tmp, struct controller, ebda_hpc_list); - if (ctrl->ctlr_type == 1) { - if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) { - ctrl->ctrl_dev = dev; - debug ("found device!!! \n"); - debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device); - return 0; - } - } - } - return -ENODEV; -} - diff -urN linux-2.5.70-bk9/drivers/hotplug/ibmphp_hpc.c linux-2.5.70-bk10/drivers/hotplug/ibmphp_hpc.c --- linux-2.5.70-bk9/drivers/hotplug/ibmphp_hpc.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/ibmphp_hpc.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1228 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Jyoti Shah, IBM Corporation - * - * Copyright (c) 2001-2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - * - */ - -#include -#include -#include -#include -#include -#include -#include "ibmphp.h" - -static int to_debug = FALSE; -#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) - -//---------------------------------------------------------------------------- -// timeout values -//---------------------------------------------------------------------------- -#define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd -#define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd -#define HPC_GETACCESS_TIMEOUT 60 // seconds -#define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds -#define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots - -//---------------------------------------------------------------------------- -// Winnipeg Architected Register Offsets -//---------------------------------------------------------------------------- -#define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low -#define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg -#define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register -#define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register -#define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register - -//---------------------------------------------------------------------------- -// Winnipeg Store Type commands (Add this commands to the register offset) -//---------------------------------------------------------------------------- -#define WPG_I2C_AND 0x1000 // I2C AND operation -#define WPG_I2C_OR 0x2000 // I2C OR operation - -//---------------------------------------------------------------------------- -// Command set for I2C Master Operation Setup Regisetr -//---------------------------------------------------------------------------- -#define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index -#define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index -#define WPG_READDIRECT_MASK 0x10010000 -#define WPG_WRITEDIRECT_MASK 0x60010000 - - -//---------------------------------------------------------------------------- -// bit masks for I2C Master Control Register -//---------------------------------------------------------------------------- -#define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation - -//---------------------------------------------------------------------------- -// -//---------------------------------------------------------------------------- -#define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval - -//---------------------------------------------------------------------------- -// command index -//---------------------------------------------------------------------------- -#define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr -#define WPG_CTLR_INDEX 0x0F // index - ctlr -#define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr -#define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr - -//---------------------------------------------------------------------------- -// macro utilities -//---------------------------------------------------------------------------- -// if bits 20,22,25,26,27,29,30 are OFF return TRUE -#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) - -//---------------------------------------------------------------------------- -// global variables -//---------------------------------------------------------------------------- -static int ibmphp_shutdown; -static int tid_poll; -static struct semaphore sem_hpcaccess; // lock access to HPC -static struct semaphore semOperations; // lock all operations and - // access to data structures -static struct semaphore sem_exit; // make sure polling thread goes away -//---------------------------------------------------------------------------- -// local function prototypes -//---------------------------------------------------------------------------- -static u8 i2c_ctrl_read (struct controller *, void *, u8); -static u8 i2c_ctrl_write (struct controller *, void *, u8, u8); -static u8 hpc_writecmdtoindex (u8, u8); -static u8 hpc_readcmdtoindex (u8, u8); -static void get_hpc_access (void); -static void free_hpc_access (void); -static void poll_hpc (void); -static int update_slot (struct slot *, u8); -static int process_changeinstatus (struct slot *, struct slot *); -static int process_changeinlatch (u8, u8, struct controller *); -static int hpc_poll_thread (void *); -static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); -//---------------------------------------------------------------------------- - - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_initvars -* -* Action: initialize semaphores and variables -*---------------------------------------------------------------------*/ -void __init ibmphp_hpc_initvars (void) -{ - debug ("%s - Entry\n", __FUNCTION__); - - init_MUTEX (&sem_hpcaccess); - init_MUTEX (&semOperations); - init_MUTEX_LOCKED (&sem_exit); - to_debug = FALSE; - ibmphp_shutdown = FALSE; - tid_poll = 0; - - debug ("%s - Exit\n", __FUNCTION__); -} - -/*---------------------------------------------------------------------- -* Name: i2c_ctrl_read -* -* Action: read from HPC over I2C -* -*---------------------------------------------------------------------*/ -static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) -{ - u8 status; - int i; - void *wpg_addr; // base addr + offset - ulong wpg_data, // data to/from WPG LOHI format - ultemp, data; // actual data HILO format - - - debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index); - - //-------------------------------------------------------------------- - // READ - step 1 - // read at address, byte length, I2C address (shifted), index - // or read direct, byte length, index - if (ctlr_ptr->ctlr_type == 0x02) { - data = WPG_READATADDR_MASK; - // fill in I2C address - ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; - ultemp = ultemp >> 1; - data |= (ultemp << 8); - - // fill in index - data |= (ulong) index; - } else if (ctlr_ptr->ctlr_type == 0x04) { - data = WPG_READDIRECT_MASK; - - // fill in index - ultemp = (ulong) index; - ultemp = ultemp << 8; - data |= ultemp; - } else { - err ("this controller type is not supported \n"); - return HPC_ERROR; - } - - wpg_data = swab32 (data); // swap data before writing - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // READ - step 2 : clear the message buffer - data = 0x00000000; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // READ - step 3 : issue start operation, I2C master control bit 30:ON - // 2020 : [20] OR operation at [20] offset 0x20 - data = WPG_I2CMCNTL_STARTOP_MASK; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // READ - step 4 : wait until start operation bit clears - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) - break; - i--; - } - if (i == 0) { - debug ("%s - Error : WPG timeout\n", __FUNCTION__); - return HPC_ERROR; - } - //-------------------------------------------------------------------- - // READ - step 5 : read I2C status register - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (HPC_I2CSTATUS_CHECK (data)) - break; - i--; - } - if (i == 0) { - debug ("ctrl_read - Exit Error:I2C timeout\n"); - return HPC_ERROR; - } - - //-------------------------------------------------------------------- - // READ - step 6 : get DATA - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - - status = (u8) data; - - debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); - - return (status); -} - -/*---------------------------------------------------------------------- -* Name: i2c_ctrl_write -* -* Action: write to HPC over I2C -* -* Return 0 or error codes -*---------------------------------------------------------------------*/ -static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd) -{ - u8 rc; - void *wpg_addr; // base addr + offset - ulong wpg_data, // data to/from WPG LOHI format - ultemp, data; // actual data HILO format - int i; - - - debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd); - - rc = 0; - //-------------------------------------------------------------------- - // WRITE - step 1 - // write at address, byte length, I2C address (shifted), index - // or write direct, byte length, index - data = 0x00000000; - - if (ctlr_ptr->ctlr_type == 0x02) { - data = WPG_WRITEATADDR_MASK; - // fill in I2C address - ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; - ultemp = ultemp >> 1; - data |= (ultemp << 8); - - // fill in index - data |= (ulong) index; - } else if (ctlr_ptr->ctlr_type == 0x04) { - data = WPG_WRITEDIRECT_MASK; - - // fill in index - ultemp = (ulong) index; - ultemp = ultemp << 8; - data |= ultemp; - } else { - err ("this controller type is not supported \n"); - return HPC_ERROR; - } - - wpg_data = swab32 (data); // swap data before writing - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // WRITE - step 2 : clear the message buffer - data = 0x00000000 | (ulong) cmd; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // WRITE - step 3 : issue start operation,I2C master control bit 30:ON - // 2020 : [20] OR operation at [20] offset 0x20 - data = WPG_I2CMCNTL_STARTOP_MASK; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // WRITE - step 4 : wait until start operation bit clears - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) - break; - i--; - } - if (i == 0) { - debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); - rc = HPC_ERROR; - } - - //-------------------------------------------------------------------- - // WRITE - step 5 : read I2C status register - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (HPC_I2CSTATUS_CHECK (data)) - break; - i--; - } - if (i == 0) { - debug ("ctrl_read - Error : I2C timeout\n"); - rc = HPC_ERROR; - } - - debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); - return (rc); -} - -//------------------------------------------------------------ -// Read from ISA type HPC -//------------------------------------------------------------ -static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset) -{ - u16 start_address; - u16 end_address; - u8 data; - - start_address = ctlr_ptr->u.isa_ctlr.io_start; - end_address = ctlr_ptr->u.isa_ctlr.io_end; - data = inb (start_address + offset); - return data; -} - -//-------------------------------------------------------------- -// Write to ISA type HPC -//-------------------------------------------------------------- -static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data) -{ - u16 start_address; - u16 port_address; - - start_address = ctlr_ptr->u.isa_ctlr.io_start; - port_address = start_address + (u16) offset; - outb (data, port_address); -} - -static u8 pci_ctrl_read (struct controller *ctrl, u8 offset) -{ - u8 data = 0x00; - debug ("inside pci_ctrl_read\n"); - if (ctrl->ctrl_dev) - pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data); - return data; -} - -static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data) -{ - u8 rc = -ENODEV; - debug ("inside pci_ctrl_write\n"); - if (ctrl->ctrl_dev) { - pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data); - rc = 0; - } - return rc; -} - -static u8 ctrl_read (struct controller *ctlr, void *base, u8 offset) -{ - u8 rc; - switch (ctlr->ctlr_type) { - case 0: - rc = isa_ctrl_read (ctlr, offset); - break; - case 1: - rc = pci_ctrl_read (ctlr, offset); - break; - case 2: - case 4: - rc = i2c_ctrl_read (ctlr, base, offset); - break; - default: - return -ENODEV; - } - return rc; -} - -static u8 ctrl_write (struct controller *ctlr, void *base, u8 offset, u8 data) -{ - u8 rc = 0; - switch (ctlr->ctlr_type) { - case 0: - isa_ctrl_write(ctlr, offset, data); - break; - case 1: - rc = pci_ctrl_write (ctlr, offset, data); - break; - case 2: - case 4: - rc = i2c_ctrl_write(ctlr, base, offset, data); - break; - default: - return -ENODEV; - } - return rc; -} -/*---------------------------------------------------------------------- -* Name: hpc_writecmdtoindex() -* -* Action: convert a write command to proper index within a controller -* -* Return index, HPC_ERROR -*---------------------------------------------------------------------*/ -static u8 hpc_writecmdtoindex (u8 cmd, u8 index) -{ - u8 rc; - - switch (cmd) { - case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 - case HPC_CTLR_CLEARIRQ: // 0x06.N.15 - case HPC_CTLR_RESET: // 0x07.N.15 - case HPC_CTLR_IRQSTEER: // 0x08.N.15 - case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 - case HPC_ALLSLOT_ON: // 0x11.N.15 - case HPC_ALLSLOT_OFF: // 0x12.N.15 - rc = 0x0F; - break; - - case HPC_SLOT_OFF: // 0x02.Y.0-14 - case HPC_SLOT_ON: // 0x03.Y.0-14 - case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 - case HPC_SLOT_ATTNON: // 0x05.N.0-14 - case HPC_SLOT_BLINKLED: // 0x13.N.0-14 - rc = index; - break; - - case HPC_BUS_33CONVMODE: - case HPC_BUS_66CONVMODE: - case HPC_BUS_66PCIXMODE: - case HPC_BUS_100PCIXMODE: - case HPC_BUS_133PCIXMODE: - rc = index + WPG_1ST_BUS_INDEX - 1; - break; - - default: - err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); - rc = HPC_ERROR; - } - - return rc; -} - -/*---------------------------------------------------------------------- -* Name: hpc_readcmdtoindex() -* -* Action: convert a read command to proper index within a controller -* -* Return index, HPC_ERROR -*---------------------------------------------------------------------*/ -static u8 hpc_readcmdtoindex (u8 cmd, u8 index) -{ - u8 rc; - - switch (cmd) { - case READ_CTLRSTATUS: - rc = 0x0F; - break; - case READ_SLOTSTATUS: - case READ_ALLSTAT: - rc = index; - break; - case READ_EXTSLOTSTATUS: - rc = index + WPG_1ST_EXTSLOT_INDEX; - break; - case READ_BUSSTATUS: - rc = index + WPG_1ST_BUS_INDEX - 1; - break; - case READ_SLOTLATCHLOWREG: - rc = 0x28; - break; - case READ_REVLEVEL: - rc = 0x25; - break; - case READ_HPCOPTIONS: - rc = 0x27; - break; - default: - rc = HPC_ERROR; - } - return rc; -} - -/*---------------------------------------------------------------------- -* Name: HPCreadslot() -* -* Action: issue a READ command to HPC -* -* Input: pslot - can not be NULL for READ_ALLSTAT -* pstatus - can be NULL for READ_ALLSTAT -* -* Return 0 or error codes -*---------------------------------------------------------------------*/ -int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) -{ - void *wpg_bbar = NULL; - struct controller *ctlr_ptr; - struct list_head *pslotlist; - u8 index, status; - int rc = 0; - int busindex; - - debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus); - - if ((pslot == NULL) - || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { - rc = -EINVAL; - err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - if (cmd == READ_BUSSTATUS) { - busindex = ibmphp_get_bus_index (pslot->bus); - if (busindex < 0) { - rc = -EINVAL; - err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); - return rc; - } else - index = (u8) busindex; - } else - index = pslot->ctlr_index; - - index = hpc_readcmdtoindex (cmd, index); - - if (index == HPC_ERROR) { - rc = -EINVAL; - err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - ctlr_ptr = pslot->ctrl; - - get_hpc_access (); - - //-------------------------------------------------------------------- - // map physical address to logical address - //-------------------------------------------------------------------- - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) - wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); - - //-------------------------------------------------------------------- - // check controller status before reading - //-------------------------------------------------------------------- - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); - if (!rc) { - switch (cmd) { - case READ_ALLSTAT: - // update the slot structure - pslot->ctrl->status = status; - pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, - &status); - if (!rc) - pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); - - break; - - case READ_SLOTSTATUS: - // DO NOT update the slot structure - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - - case READ_EXTSLOTSTATUS: - // DO NOT update the slot structure - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - - case READ_CTLRSTATUS: - // DO NOT update the slot structure - *pstatus = status; - break; - - case READ_BUSSTATUS: - pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - case READ_REVLEVEL: - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - case READ_HPCOPTIONS: - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - case READ_SLOTLATCHLOWREG: - // DO NOT update the slot structure - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - - // Not used - case READ_ALLSLOT: - list_for_each (pslotlist, &ibmphp_slot_head) { - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - index = pslot->ctlr_index; - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, - wpg_bbar, &status); - if (!rc) { - pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, - ctlr_ptr, wpg_bbar, &status); - if (!rc) - pslot->ext_status = - ctrl_read (ctlr_ptr, wpg_bbar, - index + WPG_1ST_EXTSLOT_INDEX); - } else { - err ("%s - Error ctrl_read failed\n", __FUNCTION__); - rc = -EINVAL; - break; - } - } - break; - default: - rc = -EINVAL; - break; - } - } - //-------------------------------------------------------------------- - // cleanup - //-------------------------------------------------------------------- - - // remove physical to logical address mapping - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) - iounmap (wpg_bbar); - - free_hpc_access (); - - debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_writeslot() -* -* Action: issue a WRITE command to HPC -*---------------------------------------------------------------------*/ -int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) -{ - void *wpg_bbar = NULL; - struct controller *ctlr_ptr; - u8 index, status; - int busindex; - u8 done; - int rc = 0; - int timeout; - - debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd); - if (pslot == NULL) { - rc = -EINVAL; - err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) || - (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) || - (cmd == HPC_BUS_133PCIXMODE)) { - busindex = ibmphp_get_bus_index (pslot->bus); - if (busindex < 0) { - rc = -EINVAL; - err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); - return rc; - } else - index = (u8) busindex; - } else - index = pslot->ctlr_index; - - index = hpc_writecmdtoindex (cmd, index); - - if (index == HPC_ERROR) { - rc = -EINVAL; - err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - ctlr_ptr = pslot->ctrl; - - get_hpc_access (); - - //-------------------------------------------------------------------- - // map physical address to logical address - //-------------------------------------------------------------------- - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) { - wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); - - debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, - ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, - ctlr_ptr->u.wpeg_ctlr.i2c_addr); - } - //-------------------------------------------------------------------- - // check controller status before writing - //-------------------------------------------------------------------- - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); - if (!rc) { - - ctrl_write (ctlr_ptr, wpg_bbar, index, cmd); - - //-------------------------------------------------------------------- - // check controller is still not working on the command - //-------------------------------------------------------------------- - timeout = CMD_COMPLETE_TOUT_SEC; - done = FALSE; - while (!done) { - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, - &status); - if (!rc) { - if (NEEDTOCHECK_CMDSTATUS (cmd)) { - if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) - done = TRUE; - } else - done = TRUE; - } - if (!done) { - long_delay (1 * HZ); - if (timeout < 1) { - done = TRUE; - err ("%s - Error command complete timeout\n", __FUNCTION__); - rc = -EFAULT; - } else - timeout--; - } - } - ctlr_ptr->status = status; - } - // cleanup - - // remove physical to logical address mapping - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) - iounmap (wpg_bbar); - free_hpc_access (); - - debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: get_hpc_access() -* -* Action: make sure only one process can access HPC at one time -*---------------------------------------------------------------------*/ -static void get_hpc_access (void) -{ - down (&sem_hpcaccess); -} - -/*---------------------------------------------------------------------- -* Name: free_hpc_access() -*---------------------------------------------------------------------*/ -void free_hpc_access (void) -{ - up (&sem_hpcaccess); -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_lock_operations() -* -* Action: make sure only one process can change the data structure -*---------------------------------------------------------------------*/ -void ibmphp_lock_operations (void) -{ - down (&semOperations); - to_debug = TRUE; -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_unlock_operations() -*---------------------------------------------------------------------*/ -void ibmphp_unlock_operations (void) -{ - debug ("%s - Entry\n", __FUNCTION__); - up (&semOperations); - to_debug = FALSE; - debug ("%s - Exit\n", __FUNCTION__); -} - -/*---------------------------------------------------------------------- -* Name: poll_hpc() -*---------------------------------------------------------------------*/ -#define POLL_LATCH_REGISTER 0 -#define POLL_SLOTS 1 -#define POLL_SLEEP 2 -static void poll_hpc (void) -{ - struct slot myslot; - struct slot *pslot = NULL; - struct list_head *pslotlist; - int rc; - int poll_state = POLL_LATCH_REGISTER; - u8 oldlatchlow = 0x00; - u8 curlatchlow = 0x00; - int poll_count = 0; - u8 ctrl_count = 0x00; - - debug ("%s - Entry\n", __FUNCTION__); - - while (!ibmphp_shutdown) { - if (ibmphp_shutdown) - break; - - /* try to get the lock to do some kind of harware access */ - down (&semOperations); - - switch (poll_state) { - case POLL_LATCH_REGISTER: - oldlatchlow = curlatchlow; - ctrl_count = 0x00; - list_for_each (pslotlist, &ibmphp_slot_head) { - if (ctrl_count >= ibmphp_get_total_controllers()) - break; - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - if (pslot->ctrl->ctlr_relative_id == ctrl_count) { - ctrl_count++; - if (READ_SLOT_LATCH (pslot->ctrl)) { - rc = ibmphp_hpc_readslot (pslot, - READ_SLOTLATCHLOWREG, - &curlatchlow); - if (oldlatchlow != curlatchlow) - process_changeinlatch (oldlatchlow, - curlatchlow, - pslot->ctrl); - } - } - } - ++poll_count; - poll_state = POLL_SLEEP; - break; - case POLL_SLOTS: - list_for_each (pslotlist, &ibmphp_slot_head) { - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - // make a copy of the old status - memcpy ((void *) &myslot, (void *) pslot, - sizeof (struct slot)); - rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - if ((myslot.status != pslot->status) - || (myslot.ext_status != pslot->ext_status)) - process_changeinstatus (pslot, &myslot); - } - ctrl_count = 0x00; - list_for_each (pslotlist, &ibmphp_slot_head) { - if (ctrl_count >= ibmphp_get_total_controllers()) - break; - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - if (pslot->ctrl->ctlr_relative_id == ctrl_count) { - ctrl_count++; - if (READ_SLOT_LATCH (pslot->ctrl)) - rc = ibmphp_hpc_readslot (pslot, - READ_SLOTLATCHLOWREG, - &curlatchlow); - } - } - ++poll_count; - poll_state = POLL_SLEEP; - break; - case POLL_SLEEP: - /* don't sleep with a lock on the hardware */ - up (&semOperations); - long_delay (POLL_INTERVAL_SEC * HZ); - - if (ibmphp_shutdown) - break; - - down (&semOperations); - - if (poll_count >= POLL_LATCH_CNT) { - poll_count = 0; - poll_state = POLL_SLOTS; - } else - poll_state = POLL_LATCH_REGISTER; - break; - } - /* give up the harware semaphore */ - up (&semOperations); - /* sleep for a short time just for good measure */ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (HZ/10); - } - up (&sem_exit); - debug ("%s - Exit\n", __FUNCTION__); -} - - -/* ---------------------------------------------------------------------- - * Name: ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot) - * - * Action: fill out the hotplug_slot info - * - * Input: pointer to hotplug_slot - * - * Return - * Value: 0 or error codes - *-----------------------------------------------------------------------*/ -int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot) -{ - int rc = 0; - struct slot *pslot; - - if (phpslot && phpslot->private) { - pslot = (struct slot *) phpslot->private; - rc = update_slot (pslot, (u8) TRUE); - if (!rc) { - - // power - enabled:1 not:0 - phpslot->info->power_status = SLOT_POWER (pslot->status); - - // attention - off:0, on:1, blinking:2 - phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status); - - // latch - open:1 closed:0 - phpslot->info->latch_status = SLOT_LATCH (pslot->status); - - // pci board - present:1 not:0 - if (SLOT_PRESENT (pslot->status)) - phpslot->info->adapter_status = 1; - else - phpslot->info->adapter_status = 0; -/* - if (pslot->bus_on->supported_bus_mode - && (pslot->bus_on->supported_speed == BUS_SPEED_66)) - phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX; - else - phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed; -*/ } else - rc = -EINVAL; - } else - rc = -EINVAL; - - return rc; -} - -/*---------------------------------------------------------------------- -* Name: update_slot -* -* Action: fill out slot status and extended status, controller status -* -* Input: pointer to slot struct -*---------------------------------------------------------------------*/ -static int update_slot (struct slot *pslot, u8 update) -{ - int rc = 0; - - debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot); - rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: process_changeinstatus -* -* Action: compare old and new slot status, process the change in status -* -* Input: pointer to slot struct, old slot struct -* -* Return 0 or error codes -* Value: -* -* Side -* Effects: None. -* -* Notes: -*---------------------------------------------------------------------*/ -static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) -{ - u8 status; - int rc = 0; - u8 disable = FALSE; - u8 update = FALSE; - - debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot, - (ulong) poldslot); - - // bit 0 - HPC_SLOT_POWER - if ((pslot->status & 0x01) != (poldslot->status & 0x01)) - update = TRUE; - - // bit 1 - HPC_SLOT_CONNECT - // ignore - - // bit 2 - HPC_SLOT_ATTN - if ((pslot->status & 0x04) != (poldslot->status & 0x04)) - update = TRUE; - - // bit 3 - HPC_SLOT_PRSNT2 - // bit 4 - HPC_SLOT_PRSNT1 - if (((pslot->status & 0x08) != (poldslot->status & 0x08)) - || ((pslot->status & 0x10) != (poldslot->status & 0x10))) - update = TRUE; - - // bit 5 - HPC_SLOT_PWRGD - if ((pslot->status & 0x20) != (poldslot->status & 0x20)) - // OFF -> ON: ignore, ON -> OFF: disable slot - if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) - disable = TRUE; - - // bit 6 - HPC_SLOT_BUS_SPEED - // ignore - - // bit 7 - HPC_SLOT_LATCH - if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { - update = TRUE; - // OPEN -> CLOSE - if (pslot->status & 0x80) { - if (SLOT_PWRGD (pslot->status)) { - // power goes on and off after closing latch - // check again to make sure power is still ON - long_delay (1 * HZ); - rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); - if (SLOT_PWRGD (status)) - update = TRUE; - else // overwrite power in pslot to OFF - pslot->status &= ~HPC_SLOT_POWER; - } - } - // CLOSE -> OPEN - else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD) - && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) { - disable = TRUE; - } - // else - ignore - } - // bit 4 - HPC_SLOT_BLINK_ATTN - if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) - update = TRUE; - - if (disable) { - debug ("process_changeinstatus - disable slot\n"); - pslot->flag = FALSE; - rc = ibmphp_do_disable_slot (pslot); - } - - if (update || disable) { - ibmphp_update_slot_info (pslot); - } - - debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); - - return rc; -} - -/*---------------------------------------------------------------------- -* Name: process_changeinlatch -* -* Action: compare old and new latch reg status, process the change -* -* Input: old and current latch register status -* -* Return 0 or error codes -* Value: -*---------------------------------------------------------------------*/ -static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) -{ - struct slot myslot, *pslot; - u8 i; - u8 mask; - int rc = 0; - - debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); - // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots - - for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) { - mask = 0x01 << i; - if ((mask & old) != (mask & new)) { - pslot = ibmphp_get_slot_from_physical_num (i); - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); - process_changeinstatus (pslot, &myslot); - } else { - rc = -EINVAL; - err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); - } - } - } - debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: hpc_poll_thread -* -* Action: polling -* -* Return 0 -* Value: -*---------------------------------------------------------------------*/ -static int hpc_poll_thread (void *data) -{ - debug ("%s - Entry\n", __FUNCTION__); - - daemonize("hpc_poll"); - allow_signal(SIGKILL); - - poll_hpc (); - - tid_poll = 0; - debug ("%s - Exit\n", __FUNCTION__); - return 0; -} - - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_start_poll_thread -* -* Action: start polling thread -*---------------------------------------------------------------------*/ -int __init ibmphp_hpc_start_poll_thread (void) -{ - int rc = 0; - - debug ("%s - Entry\n", __FUNCTION__); - - tid_poll = kernel_thread (hpc_poll_thread, 0, 0); - if (tid_poll < 0) { - err ("%s - Error, thread not started\n", __FUNCTION__); - rc = -1; - } - - debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_stop_poll_thread -* -* Action: stop polling thread and cleanup -*---------------------------------------------------------------------*/ -void __exit ibmphp_hpc_stop_poll_thread (void) -{ - debug ("%s - Entry\n", __FUNCTION__); - - ibmphp_shutdown = TRUE; - debug ("before locking operations \n"); - ibmphp_lock_operations (); - debug ("after locking operations \n"); - - // wait for poll thread to exit - debug ("before sem_exit down \n"); - down (&sem_exit); - debug ("after sem_exit down \n"); - - // cleanup - debug ("before free_hpc_access \n"); - free_hpc_access (); - debug ("after free_hpc_access \n"); - ibmphp_unlock_operations (); - debug ("after unlock operations \n"); - up (&sem_exit); - debug ("after sem exit up\n"); - - debug ("%s - Exit\n", __FUNCTION__); -} - -/*---------------------------------------------------------------------- -* Name: hpc_wait_ctlr_notworking -* -* Action: wait until the controller is in a not working state -* -* Return 0, HPC_ERROR -* Value: -*---------------------------------------------------------------------*/ -static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar, - u8 * pstatus) -{ - int rc = 0; - u8 done = FALSE; - - debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); - - while (!done) { - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); - if (*pstatus == HPC_ERROR) { - rc = HPC_ERROR; - done = TRUE; - } - if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) - done = TRUE; - if (!done) { - long_delay (1 * HZ); - if (timeout < 1) { - done = TRUE; - err ("HPCreadslot - Error ctlr timeout\n"); - rc = HPC_ERROR; - } else - timeout--; - } - } - debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); - return rc; -} diff -urN linux-2.5.70-bk9/drivers/hotplug/ibmphp_pci.c linux-2.5.70-bk10/drivers/hotplug/ibmphp_pci.c --- linux-2.5.70-bk9/drivers/hotplug/ibmphp_pci.c 2003-05-26 18:00:19.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/ibmphp_pci.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1758 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include "ibmphp.h" - - -static int configure_device(struct pci_func *); -static int configure_bridge(struct pci_func **, u8); -static struct res_needed *scan_behind_bridge(struct pci_func *, u8); -static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); -static u8 find_sec_number (u8 primary_busno, u8 slotno); - -/* - * NOTE..... If BIOS doesn't provide default routing, we assign: - * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. - * If adapter is bridged, then we assign 11 to it and devices behind it. - * We also assign the same irq numbers for multi function devices. - * These are PIC mode, so shouldn't matter n.e.ways (hopefully) - */ -static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) -{ - int j = 0; - for (j = 0; j < 4; j++) { - if (cur_func->irq[j] == 0xff) { - switch (class_code) { - case PCI_BASE_CLASS_STORAGE: - cur_func->irq[j] = SCSI_IRQ; - break; - case PCI_BASE_CLASS_NETWORK: - cur_func->irq[j] = LAN_IRQ; - break; - default: - cur_func->irq[j] = OTHER_IRQ; - break; - } - } - } -} - -/* - * Configures the device to be added (will allocate needed resources if it - * can), the device can be a bridge or a regular pci device, can also be - * multi-functional - * - * Input: function to be added - * - * TO DO: The error case with Multifunction device or multi function bridge, - * if there is an error, will need to go through all previous functions and - * unconfigure....or can add some code into unconfigure_card.... - */ -int ibmphp_configure_card (struct pci_func *func, u8 slotno) -{ - u16 vendor_id; - u32 class; - u8 class_code; - u8 hdr_type, device, sec_number; - u8 function; - struct pci_func *newfunc; /* for multi devices */ - struct pci_func *cur_func, *prev_func; - int rc, i, j; - int cleanup_count; - u8 flag; - u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ - - debug ("inside configure_card, func->busno = %x \n", func->busno); - - device = func->device; - cur_func = func; - - /* We only get bus and device from IRQ routing table. So at this point, - * func->busno is correct, and func->device contains only device (at the 5 - * highest bits) - */ - - /* For every function on the card */ - for (function = 0x00; function < 0x08; function++) { - unsigned int devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = cur_func->busno; - - cur_func->function = function; - - debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", - cur_func->busno, cur_func->device, cur_func->function); - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - debug ("vendor_id is %x\n", vendor_id); - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - debug ("found valid device, vendor_id = %x\n", vendor_id); - - ++valid_device; - - /* header: x x x x x x x x - * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge - * |_=> 0 = single function device, 1 = multi-function device - */ - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); - - class_code = class >> 24; - debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code); - class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ - if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x is VGA compatible and as is not supported for hot plugging. " - "Please choose another device.\n", cur_func->device); - return -ENODEV; - } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", cur_func->device); - return -ENODEV; - } - switch (hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); - assign_alt_irq (cur_func, class_code); - if ((rc = configure_device (cur_func)) < 0) { - /* We need to do this in case some other BARs were properly inserted */ - err ("was not able to configure devfunc %x on bus %x. \n", - cur_func->device, cur_func->busno); - cleanup_count = 6; - goto error; - } - cur_func->next = NULL; - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIDEVICE: - assign_alt_irq (cur_func, class_code); - if ((rc = configure_device (cur_func)) < 0) { - /* We need to do this in case some other BARs were properly inserted */ - err ("was not able to configure devfunc %x on bus %x...bailing out\n", - cur_func->device, cur_func->busno); - cleanup_count = 6; - goto error; - } - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = cur_func->busno; - newfunc->device = device; - cur_func->next = newfunc; - cur_func = newfunc; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - break; - case PCI_HEADER_TYPE_MULTIBRIDGE: - class >>= 8; - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); - return -ENODEV; - } - assign_alt_irq (cur_func, class_code); - rc = configure_bridge (&cur_func, slotno); - if (rc == -ENODEV) { - err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); - err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); - return rc; - } - if (rc) { - /* We need to do this in case some other BARs were properly inserted */ - err ("was not able to hot-add PPB properly.\n"); - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - cleanup_count = 2; - goto error; - } - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - flag = FALSE; - for (i = 0; i < 32; i++) { - if (func->devices[i]) { - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = sec_number; - newfunc->device = (u8) i; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - - if (flag) { - for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; - prev_func->next = newfunc; - } else - cur_func->next = newfunc; - - rc = ibmphp_configure_card (newfunc, slotno); - /* This could only happen if kmalloc failed */ - if (rc) { - /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - cleanup_count = 2; - goto error; - } - flag = TRUE; - } - } - - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = cur_func->busno; - newfunc->device = device; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; - prev_func->next = newfunc; - cur_func = newfunc; - break; - case PCI_HEADER_TYPE_BRIDGE: - class >>= 8; - debug ("class now is %x\n", class); - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); - return -ENODEV; - } - - assign_alt_irq (cur_func, class_code); - - debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); - rc = configure_bridge (&cur_func, slotno); - if (rc == -ENODEV) { - err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); - err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); - return rc; - } - if (rc) { - /* We need to do this in case some other BARs were properly inserted */ - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - err ("was not able to hot-add PPB properly.\n"); - cleanup_count = 2; - goto error; - } - debug ("cur_func->busno = %x, device = %x, function = %x\n", - cur_func->busno, device, function); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - debug ("after configuring bridge..., sec_number = %x\n", sec_number); - flag = FALSE; - for (i = 0; i < 32; i++) { - if (func->devices[i]) { - debug ("inside for loop, device is %x\n", i); - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err (" out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = sec_number; - newfunc->device = (u8) i; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - - if (flag) { - for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; - prev_func->next = newfunc; - } else - cur_func->next = newfunc; - - rc = ibmphp_configure_card (newfunc, slotno); - - /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ - if (rc) { - /* We need to do this in case some other BARs were properly inserted */ - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - cleanup_count = 2; - goto error; - } - flag = TRUE; - } - } - - function = 0x8; - break; - default: - err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); - return -ENXIO; - break; - } /* end of switch */ - } /* end of valid device */ - } /* end of for */ - - if (!valid_device) { - err ("Cannot find any valid devices on the card. Or unable to read from card.\n"); - return -ENODEV; - } - - return 0; - -error: - for (i = 0; i < cleanup_count; i++) { - if (cur_func->io[i]) { - ibmphp_remove_resource (cur_func->io[i]); - cur_func->io[i] = NULL; - } else if (cur_func->pfmem[i]) { - ibmphp_remove_resource (cur_func->pfmem[i]); - cur_func->pfmem[i] = NULL; - } else if (cur_func->mem[i]) { - ibmphp_remove_resource (cur_func->mem[i]); - cur_func->mem[i] = NULL; - } - } - return rc; -} - -/* - * This function configures the pci BARs of a single device. - * Input: pointer to the pci_func - * Output: configured PCI, 0, or error - */ -static int configure_device (struct pci_func *func) -{ - u32 bar[6]; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - u8 irq; - int count; - int len[6]; - struct resource_node *io[6]; - struct resource_node *mem[6]; - struct resource_node *mem_tmp; - struct resource_node *pfmem[6]; - unsigned int devfn; - - debug ("%s - inside\n", __FUNCTION__); - - devfn = PCI_DEVFN(func->device, func->function); - ibmphp_pci_bus->number = func->busno; - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - - /* not sure if i need this. per scott, said maybe need smth like this - if devices don't adhere 100% to the spec, so don't want to write - to the reserved bits - - pcibios_read_config_byte(cur_func->busno, cur_func->device, - PCI_BASE_ADDRESS_0 + 4 * count, &tmp); - if (tmp & 0x01) // IO - pcibios_write_config_dword(cur_func->busno, cur_func->device, - PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); - else // Memory - pcibios_write_config_dword(cur_func->busno, cur_func->device, - PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); - */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - - if (!bar[count]) /* This BAR is not implemented */ - continue; - - debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]); - - if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - debug ("inside IO SPACE\n"); - - len[count] = bar[count] & 0xFFFFFFFC; - len[count] = ~len[count] + 1; - - debug ("len[count] in IO %x, count %d\n", len[count], count); - - io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - - if (!io[count]) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (io[count], 0, sizeof (struct resource_node)); - io[count]->type = IO; - io[count]->busno = func->busno; - io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - io[count]->len = len[count]; - if (ibmphp_check_resource(io[count], 0) == 0) { - ibmphp_add_resource (io[count]); - func->io[count] = io[count]; - } else { - err ("cannot allocate requested io for bus %x device %x function %x len %x\n", - func->busno, func->device, func->function, len[count]); - kfree (io[count]); - return -EIO; - } - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); - - /* _______________This is for debugging purposes only_____________________ */ - debug ("b4 writing, the IO address is %x\n", func->io[count]->start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - debug ("after writing.... the start address is %x\n", bar[count]); - /* _________________________________________________________________________*/ - - } else { - /* This is Memory */ - if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - debug ("PFMEM SPACE\n"); - - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in PFMEM %x, count %d\n", len[count], count); - - pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!pfmem[count]) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (pfmem[count], 0, sizeof (struct resource_node)); - pfmem[count]->type = PFMEM; - pfmem[count]->busno = func->busno; - pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - pfmem[count]->len = len[count]; - pfmem[count]->fromMem = FALSE; - if (ibmphp_check_resource (pfmem[count], 0) == 0) { - ibmphp_add_resource (pfmem[count]); - func->pfmem[count] = pfmem[count]; - } else { - mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem_tmp) { - err ("out of system memory \n"); - kfree (pfmem[count]); - return -ENOMEM; - } - memset (mem_tmp, 0, sizeof (struct resource_node)); - mem_tmp->type = MEM; - mem_tmp->busno = pfmem[count]->busno; - mem_tmp->devfunc = pfmem[count]->devfunc; - mem_tmp->len = pfmem[count]->len; - debug ("there's no pfmem... going into mem.\n"); - if (ibmphp_check_resource (mem_tmp, 0) == 0) { - ibmphp_add_resource (mem_tmp); - pfmem[count]->fromMem = TRUE; - pfmem[count]->rangeno = mem_tmp->rangeno; - pfmem[count]->start = mem_tmp->start; - pfmem[count]->end = mem_tmp->end; - ibmphp_add_pfmem_from_mem (pfmem[count]); - func->pfmem[count] = pfmem[count]; - } else { - err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (mem_tmp); - kfree (pfmem[count]); - return -EIO; - } - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); - - /*_______________This is for debugging purposes only______________________________*/ - debug ("b4 writing, start address is %x\n", func->pfmem[count]->start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - debug ("after writing, start address is %x\n", bar[count]); - /*_________________________________________________________________________________*/ - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - debug ("inside the mem 64 case, count %d\n", count); - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - } - } else { - /* regular memory */ - debug ("REGULAR MEM SPACE\n"); - - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in Mem %x, count %d\n", len[count], count); - - mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem[count]) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem[count], 0, sizeof (struct resource_node)); - mem[count]->type = MEM; - mem[count]->busno = func->busno; - mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - mem[count]->len = len[count]; - if (ibmphp_check_resource (mem[count], 0) == 0) { - ibmphp_add_resource (mem[count]); - func->mem[count] = mem[count]; - } else { - err ("cannot allocate requested mem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (mem[count]); - return -EIO; - } - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); - /* _______________________This is for debugging purposes only _______________________*/ - debug ("b4 writing, start address is %x\n", func->mem[count]->start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - debug ("after writing, the address is %x\n", bar[count]); - /* __________________________________________________________________________________*/ - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - debug ("inside mem 64 case, reg. mem, count %d\n", count); - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - } - } - } /* end of mem */ - } /* end of for */ - - func->bus = 0; /* To indicate that this is not a PPB */ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); - if ((irq > 0x00) && (irq < 0x05)) - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); - - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); - - return 0; -} - -/****************************************************************************** - * This routine configures a PCI-2-PCI bridge and the functions behind it - * Parameters: pci_func - * Returns: - ******************************************************************************/ -static int configure_bridge (struct pci_func **func_passed, u8 slotno) -{ - int count; - int i; - int rc; - u8 sec_number; - u8 io_base; - u16 pfmem_base; - u32 bar[2]; - u32 len[2]; - u8 flag_io = FALSE; - u8 flag_mem = FALSE; - u8 flag_pfmem = FALSE; - u8 need_io_upper = FALSE; - u8 need_pfmem_upper = FALSE; - struct res_needed *amount_needed = NULL; - struct resource_node *io = NULL; - struct resource_node *bus_io[2] = {NULL, NULL}; - struct resource_node *mem = NULL; - struct resource_node *bus_mem[2] = {NULL, NULL}; - struct resource_node *mem_tmp = NULL; - struct resource_node *pfmem = NULL; - struct resource_node *bus_pfmem[2] = {NULL, NULL}; - struct bus_node *bus; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - 0 - }; - struct pci_func *func = *func_passed; - unsigned int devfn; - u8 irq; - int retval; - - debug ("%s - enter\n", __FUNCTION__); - - devfn = PCI_DEVFN(func->function, func->device); - ibmphp_pci_bus->number = func->busno; - - /* Configuring necessary info for the bridge so that we could see the devices - * behind it - */ - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno); - - /* _____________________For debugging purposes only __________________________ - pci_bus_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); - debug ("primary # written into the bridge is %x\n", pri_number); - ___________________________________________________________________________*/ - - /* in EBDA, only get allocated 1 additional bus # per slot */ - sec_number = find_sec_number (func->busno, slotno); - if (sec_number == 0xff) { - err ("cannot allocate secondary bus number for the bridged device \n"); - return -EINVAL; - } - - debug ("after find_sec_number, the number we got is %x\n", sec_number); - debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number); - - /* __________________For debugging purposes only __________________________________ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - debug ("sec_number after write/read is %x\n", sec_number); - ________________________________________________________________________________*/ - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number); - - /* __________________For debugging purposes only ____________________________________ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number); - debug ("subordinate number after write/read is %x\n", sec_number); - __________________________________________________________________________________*/ - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY); - - debug ("func->busno is %x\n", func->busno); - debug ("sec_number after writing is %x\n", sec_number); - - - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ - - - /* First we need to allocate mem/io for the bridge itself in case it needs it */ - for (count = 0; address[count]; count++) { /* for 2 BARs */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - - if (!bar[count]) { - /* This BAR is not implemented */ - debug ("so we come here then, eh?, count = %d\n", count); - continue; - } - // tmp_bar = bar[count]; - - debug ("Bar %d wants %x\n", count, bar[count]); - - if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - len[count] = bar[count] & 0xFFFFFFFC; - len[count] = ~len[count] + 1; - - debug ("len[count] in IO = %x\n", len[count]); - - bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - - if (!bus_io[count]) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus_io[count], 0, sizeof (struct resource_node)); - bus_io[count]->type = IO; - bus_io[count]->busno = func->busno; - bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - bus_io[count]->len = len[count]; - if (ibmphp_check_resource (bus_io[count], 0) == 0) { - ibmphp_add_resource (bus_io[count]); - func->io[count] = bus_io[count]; - } else { - err ("cannot allocate requested io for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (bus_io[count]); - return -EIO; - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); - - } else { - /* This is Memory */ - if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in PFMEM = %x\n", len[count]); - - bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!bus_pfmem[count]) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus_pfmem[count], 0, sizeof (struct resource_node)); - bus_pfmem[count]->type = PFMEM; - bus_pfmem[count]->busno = func->busno; - bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - bus_pfmem[count]->len = len[count]; - bus_pfmem[count]->fromMem = FALSE; - if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { - ibmphp_add_resource (bus_pfmem[count]); - func->pfmem[count] = bus_pfmem[count]; - } else { - mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem_tmp) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (mem_tmp, 0, sizeof (struct resource_node)); - mem_tmp->type = MEM; - mem_tmp->busno = bus_pfmem[count]->busno; - mem_tmp->devfunc = bus_pfmem[count]->devfunc; - mem_tmp->len = bus_pfmem[count]->len; - if (ibmphp_check_resource (mem_tmp, 0) == 0) { - ibmphp_add_resource (mem_tmp); - bus_pfmem[count]->fromMem = TRUE; - bus_pfmem[count]->rangeno = mem_tmp->rangeno; - ibmphp_add_pfmem_from_mem (bus_pfmem[count]); - func->pfmem[count] = bus_pfmem[count]; - } else { - err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (mem_tmp); - kfree (bus_pfmem[count]); - return -EIO; - } - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - - } - } else { - /* regular memory */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in Memory is %x\n", len[count]); - - bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!bus_mem[count]) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus_mem[count], 0, sizeof (struct resource_node)); - bus_mem[count]->type = MEM; - bus_mem[count]->busno = func->busno; - bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - bus_mem[count]->len = len[count]; - if (ibmphp_check_resource (bus_mem[count], 0) == 0) { - ibmphp_add_resource (bus_mem[count]); - func->mem[count] = bus_mem[count]; - } else { - err ("cannot allocate requested mem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (bus_mem[count]); - return -EIO; - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - - } - } - } /* end of mem */ - } /* end of for */ - - /* Now need to see how much space the devices behind the bridge needed */ - amount_needed = scan_behind_bridge (func, sec_number); - if (amount_needed == NULL) - return -ENOMEM; - - ibmphp_pci_bus->number = func->busno; - debug ("after coming back from scan_behind_bridge\n"); - debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct); - debug ("amount_needed->io = %x\n", amount_needed->io); - debug ("amount_needed->mem = %x\n", amount_needed->mem); - debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); - - if (amount_needed->not_correct) { - debug ("amount_needed is not correct \n"); - for (count = 0; address[count]; count++) { - /* for 2 BARs */ - if (bus_io[count]) { - ibmphp_remove_resource (bus_io[count]); - func->io[count] = NULL; - } else if (bus_pfmem[count]) { - ibmphp_remove_resource (bus_pfmem[count]); - func->pfmem[count] = NULL; - } else if (bus_mem[count]) { - ibmphp_remove_resource (bus_mem[count]); - func->mem[count] = NULL; - } - } - kfree (amount_needed); - return -ENODEV; - } - - if (!amount_needed->io) { - debug ("it doesn't want IO?\n"); - flag_io = TRUE; - } else { - debug ("it wants %x IO behind the bridge \n", amount_needed->io); - io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - - if (!io) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (io, 0, sizeof (struct resource_node)); - io->type = IO; - io->busno = func->busno; - io->devfunc = ((func->device << 3) | (func->function & 0x7)); - io->len = amount_needed->io; - if (ibmphp_check_resource (io, 1) == 0) { - debug ("were we able to add io\n"); - ibmphp_add_resource (io); - flag_io = TRUE; - } - } - - if (!amount_needed->mem) { - debug ("it doesn't want n.e.memory?\n"); - flag_mem = TRUE; - } else { - debug ("it wants %x memory behind the bridge\n", amount_needed->mem); - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (mem, 0, sizeof (struct resource_node)); - mem->type = MEM; - mem->busno = func->busno; - mem->devfunc = ((func->device << 3) | (func->function & 0x7)); - mem->len = amount_needed->mem; - if (ibmphp_check_resource (mem, 1) == 0) { - ibmphp_add_resource (mem); - flag_mem = TRUE; - debug ("were we able to add mem\n"); - } - } - - if (!amount_needed->pfmem) { - debug ("it doesn't want n.e.pfmem mem?\n"); - flag_pfmem = TRUE; - } else { - debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); - pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!pfmem) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (pfmem, 0, sizeof (struct resource_node)); - pfmem->type = PFMEM; - pfmem->busno = func->busno; - pfmem->devfunc = ((func->device << 3) | (func->function & 0x7)); - pfmem->len = amount_needed->pfmem; - pfmem->fromMem = FALSE; - if (ibmphp_check_resource (pfmem, 1) == 0) { - ibmphp_add_resource (pfmem); - flag_pfmem = TRUE; - } else { - mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem_tmp) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (mem_tmp, 0, sizeof (struct resource_node)); - mem_tmp->type = MEM; - mem_tmp->busno = pfmem->busno; - mem_tmp->devfunc = pfmem->devfunc; - mem_tmp->len = pfmem->len; - if (ibmphp_check_resource (mem_tmp, 1) == 0) { - ibmphp_add_resource (mem_tmp); - pfmem->fromMem = TRUE; - pfmem->rangeno = mem_tmp->rangeno; - ibmphp_add_pfmem_from_mem (pfmem); - flag_pfmem = TRUE; - } - } - } - - debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n"); - debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem); - - if (flag_io && flag_mem && flag_pfmem) { - /* If on bootup, there was a bridged card in this slot, - * then card was removed and ibmphp got unloaded and loaded - * back again, there's no way for us to remove the bus - * struct, so no need to kmalloc, can use existing node - */ - bus = ibmphp_find_res_bus (sec_number); - if (!bus) { - bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); - if (!bus) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus, 0, sizeof (struct bus_node)); - bus->busno = sec_number; - debug ("b4 adding new bus\n"); - rc = add_new_bus (bus, io, mem, pfmem, func->busno); - } else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem)) - rc = add_new_bus (bus, io, mem, pfmem, 0xFF); - else { - err ("expected bus structure not empty? \n"); - retval = -EIO; - goto error; - } - if (rc) { - if (rc == -ENOMEM) { - ibmphp_remove_bus (bus, func->busno); - kfree (amount_needed); - return rc; - } - retval = rc; - goto error; - } - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base); - - if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { - debug ("io 32\n"); - need_io_upper = TRUE; - } - if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { - debug ("pfmem 64\n"); - need_pfmem_upper = TRUE; - } - - if (bus->noIORanges) { - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); - - /* _______________This is for debugging purposes only ____________________ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp); - debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp); - debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); - ________________________________________________________________________*/ - - if (need_io_upper) { /* since can't support n.e.ways */ - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000); - } - } else { - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00); - } - - if (bus->noMemRanges) { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); - - /* ____________________This is for debugging purposes only ________________________ - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp); - debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp); - debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - __________________________________________________________________________________*/ - - } else { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000); - } - if (bus->noPFMemRanges) { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16); - - /* __________________________This is for debugging purposes only _______________________ - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp); - debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp); - debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - ______________________________________________________________________________________*/ - - if (need_pfmem_upper) { /* since can't support n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000); - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000); - } - } else { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000); - } - - debug ("b4 writing control information\n"); - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); - if ((irq > 0x00) && (irq < 0x05)) - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); - /* - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); - */ - - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07); - for (i = 0; i < 32; i++) { - if (amount_needed->devices[i]) { - debug ("device where devices[i] is 1 = %x\n", i); - func->devices[i] = 1; - } - } - func->bus = 1; /* For unconfiguring, to indicate it's PPB */ - func_passed = &func; - debug ("func->busno b4 returning is %x\n", func->busno); - debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno); - kfree (amount_needed); - return 0; - } else { - err ("Configuring bridge was unsuccessful... \n"); - mem_tmp = NULL; - retval = -EIO; - goto error; - } - -error: - if (amount_needed) - kfree (amount_needed); - if (pfmem) - ibmphp_remove_resource (pfmem); - if (io) - ibmphp_remove_resource (io); - if (mem) - ibmphp_remove_resource (mem); - for (i = 0; i < 2; i++) { /* for 2 BARs */ - if (bus_io[i]) { - ibmphp_remove_resource (bus_io[i]); - func->io[i] = NULL; - } else if (bus_pfmem[i]) { - ibmphp_remove_resource (bus_pfmem[i]); - func->pfmem[i] = NULL; - } else if (bus_mem[i]) { - ibmphp_remove_resource (bus_mem[i]); - func->mem[i] = NULL; - } - } - return retval; -} - -/***************************************************************************** - * This function adds up the amount of resources needed behind the PPB bridge - * and passes it to the configure_bridge function - * Input: bridge function - * Ouput: amount of resources needed - *****************************************************************************/ -static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) -{ - int count, len[6]; - u16 vendor_id; - u8 hdr_type; - u8 device, function; - unsigned int devfn; - int howmany = 0; /*this is to see if there are any devices behind the bridge */ - - u32 bar[6], class; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - struct res_needed *amount; - - amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL); - if (amount == NULL) - return NULL; - memset (amount, 0, sizeof (struct res_needed)); - - ibmphp_pci_bus->number = busno; - - debug ("the bus_no behind the bridge is %x\n", busno); - debug ("scanning devices behind the bridge...\n"); - for (device = 0; device < 32; device++) { - amount->devices[device] = 0; - for (function = 0; function < 8; function++) { - devfn = PCI_DEVFN(device, function); - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - howmany++; - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); - - debug ("hdr_type behind the bridge is %x\n", hdr_type); - if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { - err ("embedded bridges not supported for hot-plugging.\n"); - amount->not_correct = TRUE; - return amount; - } - - class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ - if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x is VGA compatible and as is not supported for hot plugging. " - "Please choose another device.\n", device); - amount->not_correct = TRUE; - return amount; - } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", device); - amount->not_correct = TRUE; - return amount; - } - - amount->devices[device] = 1; - - for (count = 0; address[count]; count++) { - /* for 6 BARs */ - /* - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, address[count], &tmp); - if (tmp & 0x01) // IO - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD); - else // MEMORY - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - - debug ("what is bar[count]? %x, count = %d\n", bar[count], count); - - if (!bar[count]) /* This BAR is not implemented */ - continue; - - //tmp_bar = bar[count]; - - debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]); - - if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - len[count] = bar[count] & 0xFFFFFFFC; - len[count] = ~len[count] + 1; - amount->io += len[count]; - } else { - /* This is Memory */ - if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - amount->pfmem += len[count]; - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) - /* takes up another dword */ - count += 1; - - } else { - /* regular memory */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - amount->mem += len[count]; - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - } - } - } /* end for */ - } /* end if (valid) */ - } /* end for */ - } /* end for */ - - if (!howmany) - amount->not_correct = TRUE; - else - amount->not_correct = FALSE; - if ((amount->io) && (amount->io < IOBRIDGE)) - amount->io = IOBRIDGE; - if ((amount->mem) && (amount->mem < MEMBRIDGE)) - amount->mem = MEMBRIDGE; - if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE)) - amount->pfmem = MEMBRIDGE; - return amount; -} - -/* The following 3 unconfigure_boot_ routines deal with the case when we had the card - * upon bootup in the system, since we don't allocate func to such case, we need to read - * the start addresses from pci config space and then find the corresponding entries in - * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) - * Change: we also call these functions even if we configured the card ourselves (i.e., not - * the bootup case), since it should work same way - */ -static int unconfigure_boot_device (u8 busno, u8 device, u8 function) -{ - u32 start_address; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct resource_node *io; - struct resource_node *mem; - struct resource_node *pfmem; - struct bus_node *bus; - u32 end_address; - u32 temp_end; - u32 size; - u32 tmp_address; - unsigned int devfn; - - debug ("%s - enter\n", __FUNCTION__); - - bus = ibmphp_find_res_bus (busno); - if (!bus) { - debug ("cannot find corresponding bus.\n"); - return -EINVAL; - } - - devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = busno; - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); - - /* We can do this here, b/c by that time the device driver of the card has been stopped */ - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &size); - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], start_address); - - debug ("start_address is %x\n", start_address); - debug ("busno, device, function %x %x %x\n", busno, device, function); - if (!size) { - /* This BAR is not implemented */ - debug ("is this bar no implemented?, count = %d\n", count); - continue; - } - tmp_address = start_address; - if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - start_address &= PCI_BASE_ADDRESS_IO_MASK; - size = size & 0xFFFFFFFC; - size = ~size + 1; - end_address = start_address + size - 1; - if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { - err ("cannot find corresponding IO resource to remove\n"); - return -EIO; - } - debug ("io->start = %x\n", io->start); - temp_end = io->end; - start_address = io->end + 1; - ibmphp_remove_resource (io); - /* This is needed b/c of the old I/O restrictions in the BIOS */ - while (temp_end < end_address) { - if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { - err ("cannot find corresponding IO resource to remove\n"); - return -EIO; - } - debug ("io->start = %x\n", io->start); - temp_end = io->end; - start_address = io->end + 1; - ibmphp_remove_resource (io); - } - - /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ - } else { - /* This is Memory */ - if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - debug ("start address of pfmem is %x\n", start_address); - - if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { - err ("cannot find corresponding PFMEM resource to remove\n"); - return -EIO; - } - if (pfmem) - debug ("pfmem->start = %x\n", pfmem->start); - - ibmphp_remove_resource (pfmem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - - } else { - /* regular memory */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - debug ("start address of mem is %x\n", start_address); - if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { - err ("cannot find corresponding MEM resource to remove\n"); - return -EIO; - } - if (mem) - debug ("mem->start = %x\n", mem->start); - - ibmphp_remove_resource (mem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - } - } /* end of mem */ - } /* end of for */ - - return 0; -} - -static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) -{ - int count; - int bus_no, pri_no, sub_no, sec_no = 0; - u32 start_address, tmp_address; - u8 sec_number, sub_number, pri_number; - struct resource_node *io = NULL; - struct resource_node *mem = NULL; - struct resource_node *pfmem = NULL; - struct bus_node *bus; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - 0 - }; - unsigned int devfn; - - devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = busno; - bus_no = (int) busno; - debug ("busno is %x\n", busno); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); - debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - debug ("sec_number is %x\n", sec_number); - sec_no = (int) sec_number; - pri_no = (int) pri_number; - if (pri_no != bus_no) { - err ("primary numbers in our structures and pci config space don't match.\n"); - return -EINVAL; - } - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - sec_no = (int) sec_no; - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number); - sub_no = (int) sub_number; - debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); - if (sec_no != sub_number) { - err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); - return -ENODEV; - } - - bus = ibmphp_find_res_bus (sec_number); - debug ("bus->busno is %x\n", bus->busno); - debug ("sec_number is %x\n", sec_number); - if (!bus) { - err ("cannot find Bus structure for the bridged device\n"); - return -EINVAL; - } - - ibmphp_remove_bus (bus, busno); - - for (count = 0; address[count]; count++) { - /* for 2 BARs */ - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); - - if (!start_address) { - /* This BAR is not implemented */ - continue; - } - - tmp_address = start_address; - - if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - start_address &= PCI_BASE_ADDRESS_IO_MASK; - if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { - err ("cannot find corresponding IO resource to remove\n"); - return -EIO; - } - if (io) - debug ("io->start = %x\n", io->start); - - ibmphp_remove_resource (io); - - /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ - } else { - /* This is Memory */ - if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { - err ("cannot find corresponding PFMEM resource to remove\n"); - return -EINVAL; - } - if (pfmem) - debug ("pfmem->start = %x\n", pfmem->start); - - ibmphp_remove_resource (pfmem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - - } else { - /* regular memory */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { - err ("cannot find corresponding MEM resource to remove\n"); - return -EINVAL; - } - if (mem) - debug ("mem->start = %x\n", mem->start); - - ibmphp_remove_resource (mem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - } - } /* end of mem */ - } /* end of for */ - debug ("%s - exiting, returning success\n", __FUNCTION__); - return 0; -} - -static int unconfigure_boot_card (struct slot *slot_cur) -{ - u16 vendor_id; - u32 class; - u8 hdr_type; - u8 device; - u8 busno; - u8 function; - int rc; - unsigned int devfn; - u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ - - debug ("%s - enter\n", __FUNCTION__); - - device = slot_cur->device; - busno = slot_cur->bus; - - debug ("b4 for loop, device is %x\n", device); - /* For every function on the card */ - for (function = 0x0; function < 0x08; function++) { - devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = busno; - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - ++valid_device; - - debug ("%s - found correct device\n", __FUNCTION__); - - /* header: x x x x x x x x - * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge - * |_=> 0 = single function device, 1 = multi-function device - */ - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); - - debug ("hdr_type %x, class %x\n", hdr_type, class); - class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ - if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x function %x is VGA compatible and is not supported for hot removing. " - "Please choose another device.\n", device, function); - return -ENODEV; - } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x function %x is not supported for hot removing. " - "Please choose another device.\n", device, function); - return -ENODEV; - } - - switch (hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - rc = unconfigure_boot_device (busno, device, function); - if (rc) { - err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", - device, function, busno); - return rc; - } - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIDEVICE: - rc = unconfigure_boot_device (busno, device, function); - if (rc) { - err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", - device, function, busno); - return rc; - } - break; - case PCI_HEADER_TYPE_BRIDGE: - class >>= 8; - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); - return -ENODEV; - } - rc = unconfigure_boot_bridge (busno, device, function); - if (rc != 0) { - err ("was not able to hot-remove PPB properly.\n"); - return rc; - } - - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIBRIDGE: - class >>= 8; - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); - return -ENODEV; - } - rc = unconfigure_boot_bridge (busno, device, function); - if (rc != 0) { - err ("was not able to hot-remove PPB properly.\n"); - return rc; - } - break; - default: - err ("MAJOR PROBLEM!!!! Cannot read device's header \n"); - return -1; - break; - } /* end of switch */ - } /* end of valid device */ - } /* end of for */ - - if (!valid_device) { - err ("Could not find device to unconfigure. Or could not read the card. \n"); - return -1; - } - return 0; -} - -/* - * free the resources of the card (multi, single, or bridged) - * Parameters: slot, flag to say if this is for removing entire module or just - * unconfiguring the device - * TO DO: will probably need to add some code in case there was some resource, - * to remove it... this is from when we have errors in the configure_card... - * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! - * Returns: 0, -1, -ENODEV - */ -int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) -{ - int i; - int count; - int rc; - struct slot *sl = *slot_cur; - struct pci_func *cur_func = NULL; - struct pci_func *temp_func; - - debug ("%s - enter\n", __FUNCTION__); - - if (!the_end) { - /* Need to unconfigure the card */ - rc = unconfigure_boot_card (sl); - if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { - /* In all other cases, will still need to get rid of func structure if it exists */ - return rc; - } - } - - if (sl->func) { - cur_func = sl->func; - while (cur_func) { - /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ - if (cur_func->bus) { - /* in other words, it's a PPB */ - count = 2; - } else { - count = 6; - } - - for (i = 0; i < count; i++) { - if (cur_func->io[i]) { - debug ("io[%d] exists \n", i); - if (the_end > 0) - ibmphp_remove_resource (cur_func->io[i]); - cur_func->io[i] = NULL; - } - if (cur_func->mem[i]) { - debug ("mem[%d] exists \n", i); - if (the_end > 0) - ibmphp_remove_resource (cur_func->mem[i]); - cur_func->mem[i] = NULL; - } - if (cur_func->pfmem[i]) { - debug ("pfmem[%d] exists \n", i); - if (the_end > 0) - ibmphp_remove_resource (cur_func->pfmem[i]); - cur_func->pfmem[i] = NULL; - } - } - - temp_func = cur_func->next; - kfree (cur_func); - cur_func = temp_func; - } - } - - sl->func = NULL; - *slot_cur = sl; - debug ("%s - exit\n", __FUNCTION__); - return 0; -} - -/* - * add a new bus resulting from hot-plugging a PPB bridge with devices - * - * Input: bus and the amount of resources needed (we know we can assign those, - * since they've been checked already - * Output: bus added to the correct spot - * 0, -1, error - */ -static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) -{ - struct range_node *io_range = NULL; - struct range_node *mem_range = NULL; - struct range_node *pfmem_range = NULL; - struct bus_node *cur_bus = NULL; - - /* Trying to find the parent bus number */ - if (parent_busno != 0xFF) { - cur_bus = ibmphp_find_res_bus (parent_busno); - if (!cur_bus) { - err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); - return -ENODEV; - } - - list_add (&bus->bus_list, &cur_bus->bus_list); - } - if (io) { - io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!io_range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (io_range, 0, sizeof (struct range_node)); - io_range->start = io->start; - io_range->end = io->end; - io_range->rangeno = 1; - bus->noIORanges = 1; - bus->rangeIO = io_range; - } - if (mem) { - mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!mem_range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem_range, 0, sizeof (struct range_node)); - mem_range->start = mem->start; - mem_range->end = mem->end; - mem_range->rangeno = 1; - bus->noMemRanges = 1; - bus->rangeMem = mem_range; - } - if (pfmem) { - pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!pfmem_range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (pfmem_range, 0, sizeof (struct range_node)); - pfmem_range->start = pfmem->start; - pfmem_range->end = pfmem->end; - pfmem_range->rangeno = 1; - bus->noPFMemRanges = 1; - bus->rangePFMem = pfmem_range; - } - return 0; -} - -/* - * find the 1st available bus number for PPB to set as its secondary bus - * Parameters: bus_number of the primary bus - * Returns: bus_number of the secondary bus or 0xff in case of failure - */ -static u8 find_sec_number (u8 primary_busno, u8 slotno) -{ - int min, max; - u8 busno; - struct bus_info *bus; - struct bus_node *bus_cur; - - bus = ibmphp_find_same_bus_num (primary_busno); - if (!bus) { - err ("cannot get slot range of the bus from the BIOS\n"); - return 0xff; - } - max = bus->slot_max; - min = bus->slot_min; - if ((slotno > max) || (slotno < min)) { - err ("got the wrong range\n"); - return 0xff; - } - busno = (u8) (slotno - (u8) min); - busno += primary_busno + 0x01; - bus_cur = ibmphp_find_res_bus (busno); - /* either there is no such bus number, or there are no ranges, which - * can only happen if we removed the bridged device in previous load - * of the driver, and now only have the skeleton bus struct - */ - if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem))) - return busno; - return 0xff; -} - diff -urN linux-2.5.70-bk9/drivers/hotplug/ibmphp_res.c linux-2.5.70-bk10/drivers/hotplug/ibmphp_res.c --- linux-2.5.70-bk9/drivers/hotplug/ibmphp_res.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/ibmphp_res.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,2157 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include "ibmphp.h" - -static int flags = 0; /* for testing */ - -static void update_resources (struct bus_node *bus_cur, int type, int rangeno); -static int once_over (void); -static int remove_ranges (struct bus_node *, struct bus_node *); -static int update_bridge_ranges (struct bus_node **); -static int add_range (int type, struct range_node *, struct bus_node *); -static void fix_resources (struct bus_node *); -static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); - -static LIST_HEAD(gbuses); -LIST_HEAD(ibmphp_res_head); - -static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag) -{ - struct bus_node * newbus; - - if (!(curr) && !(flag)) { - err ("NULL pointer passed \n"); - return NULL; - } - - newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); - if (!newbus) { - err ("out of system memory \n"); - return NULL; - } - - memset (newbus, 0, sizeof (struct bus_node)); - if (flag) - newbus->busno = busno; - else - newbus->busno = curr->bus_num; - list_add_tail (&newbus->bus_list, &gbuses); - return newbus; -} - -static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr) -{ - struct resource_node *rs; - - if (!curr) { - err ("NULL passed to allocate \n"); - return NULL; - } - - rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!rs) { - err ("out of system memory \n"); - return NULL; - } - memset (rs, 0, sizeof (struct resource_node)); - rs->busno = curr->bus_num; - rs->devfunc = curr->dev_fun; - rs->start = curr->start_addr; - rs->end = curr->end_addr; - rs->len = curr->end_addr - curr->start_addr + 1; - return rs; -} - -static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) -{ - struct bus_node * newbus; - struct range_node *newrange; - u8 num_ranges = 0; - - if (first_bus) { - newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); - if (!newbus) { - err ("out of system memory. \n"); - return -ENOMEM; - } - memset (newbus, 0, sizeof (struct bus_node)); - newbus->busno = curr->bus_num; - } else { - newbus = *new_bus; - switch (flag) { - case MEM: - num_ranges = newbus->noMemRanges; - break; - case PFMEM: - num_ranges = newbus->noPFMemRanges; - break; - case IO: - num_ranges = newbus->noIORanges; - break; - } - } - - newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!newrange) { - if (first_bus) - kfree (newbus); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newrange, 0, sizeof (struct range_node)); - newrange->start = curr->start_addr; - newrange->end = curr->end_addr; - - if (first_bus || (!num_ranges)) - newrange->rangeno = 1; - else { - /* need to insert our range */ - add_range (flag, newrange, newbus); - debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); - } - - switch (flag) { - case MEM: - newbus->rangeMem = newrange; - if (first_bus) - newbus->noMemRanges = 1; - else { - debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - ++newbus->noMemRanges; - fix_resources (newbus); - } - break; - case IO: - newbus->rangeIO = newrange; - if (first_bus) - newbus->noIORanges = 1; - else { - debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - ++newbus->noIORanges; - fix_resources (newbus); - } - break; - case PFMEM: - newbus->rangePFMem = newrange; - if (first_bus) - newbus->noPFMemRanges = 1; - else { - debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - ++newbus->noPFMemRanges; - fix_resources (newbus); - } - - break; - } - - *new_bus = newbus; - *new_range = newrange; - return 0; -} - - -/* Notes: - * 1. The ranges are ordered. The buses are not ordered. (First come) - * - * 2. If cannot allocate out of PFMem range, allocate from Mem ranges. PFmemFromMem - * are not sorted. (no need since use mem node). To not change the entire code, we - * also add mem node whenever this case happens so as not to change - * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) - */ - -/***************************************************************************** - * This is the Resource Management initialization function. It will go through - * the Resource list taken from EBDA and fill in this module's data structures - * - * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, - * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW - * - * Input: ptr to the head of the resource list from EBDA - * Output: 0, -1 or error codes - ***************************************************************************/ -int __init ibmphp_rsrc_init (void) -{ - struct ebda_pci_rsrc *curr; - struct range_node *newrange = NULL; - struct bus_node *newbus = NULL; - struct bus_node *bus_cur; - struct bus_node *bus_prev; - struct list_head *tmp; - struct resource_node *new_io = NULL; - struct resource_node *new_mem = NULL; - struct resource_node *new_pfmem = NULL; - int rc; - struct list_head *tmp_ebda; - - list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) { - curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - if (!(curr->rsrc_type & PCIDEVMASK)) { - /* EBDA still lists non PCI devices, so ignore... */ - debug ("this is not a PCI DEVICE in rsrc_init, please take care\n"); - // continue; - } - - /* this is a primary bus resource */ - if (curr->rsrc_type & PRIMARYBUSMASK) { - /* memory */ - if ((curr->rsrc_type & RESTYPE) == MMASK) { - /* no bus structure exists in place yet */ - if (list_empty (&gbuses)) { - if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } else { - bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); - /* found our bus */ - if (bus_cur) { - rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0); - if (rc) - return rc; - } else { - /* went through all the buses and didn't find ours, need to create a new bus node */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) - return rc; - - list_add_tail (&newbus->bus_list, &gbuses); - debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } - } - } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { - /* prefetchable memory */ - if (list_empty (&gbuses)) { - /* no bus structure exists in place yet */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } else { - bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); - if (bus_cur) { - /* found our bus */ - rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0); - if (rc) - return rc; - } else { - /* went through all the buses and didn't find ours, need to create a new bus node */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } - } - } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { - /* IO */ - if (list_empty (&gbuses)) { - /* no bus structure exists in place yet */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } else { - bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); - if (bus_cur) { - rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0); - if (rc) - return rc; - } else { - /* went through all the buses and didn't find ours, need to create a new bus node */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } - } - - } else { - ; /* type is reserved WHAT TO DO IN THIS CASE??? - NOTHING TO DO??? */ - } - } else { - /* regular pci device resource */ - if ((curr->rsrc_type & RESTYPE) == MMASK) { - /* Memory resource */ - new_mem = alloc_resources (curr); - if (!new_mem) - return -ENOMEM; - new_mem->type = MEM; - /* - * if it didn't find the bus, means PCI dev - * came b4 the Primary Bus info, so need to - * create a bus rangeno becomes a problem... - * assign a -1 and then update once the range - * actually appears... - */ - if (ibmphp_add_resource (new_mem) < 0) { - newbus = alloc_error_bus (curr, 0, 0); - if (!newbus) - return -ENOMEM; - newbus->firstMem = new_mem; - ++newbus->needMemUpdate; - new_mem->rangeno = -1; - } - debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end); - - } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { - /* PFMemory resource */ - new_pfmem = alloc_resources (curr); - if (!new_pfmem) - return -ENOMEM; - new_pfmem->type = PFMEM; - new_pfmem->fromMem = FALSE; - if (ibmphp_add_resource (new_pfmem) < 0) { - newbus = alloc_error_bus (curr, 0, 0); - if (!newbus) - return -ENOMEM; - newbus->firstPFMem = new_pfmem; - ++newbus->needPFMemUpdate; - new_pfmem->rangeno = -1; - } - - debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end); - } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { - /* IO resource */ - new_io = alloc_resources (curr); - if (!new_io) - return -ENOMEM; - new_io->type = IO; - - /* - * if it didn't find the bus, means PCI dev - * came b4 the Primary Bus info, so need to - * create a bus rangeno becomes a problem... - * Can assign a -1 and then update once the - * range actually appears... - */ - if (ibmphp_add_resource (new_io) < 0) { - newbus = alloc_error_bus (curr, 0, 0); - if (!newbus) - return -ENOMEM; - newbus->firstIO = new_io; - ++newbus->needIOUpdate; - new_io->rangeno = -1; - } - debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end); - } - } - } - - list_for_each (tmp, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */ - rc = update_bridge_ranges (&bus_cur); - if (rc) - return rc; - } - rc = once_over (); /* This is to align ranges (so no -1) */ - if (rc) - return rc; - return 0; -} - -/******************************************************************************** - * This function adds a range into a sorted list of ranges per bus for a particular - * range type, it then calls another routine to update the range numbers on the - * pci devices' resources for the appropriate resource - * - * Input: type of the resource, range to add, current bus - * Output: 0 or -1, bus and range ptrs - ********************************************************************************/ -static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) -{ - struct range_node *range_cur = NULL; - struct range_node *range_prev; - int count = 0, i_init; - int noRanges = 0; - - switch (type) { - case MEM: - range_cur = bus_cur->rangeMem; - noRanges = bus_cur->noMemRanges; - break; - case PFMEM: - range_cur = bus_cur->rangePFMem; - noRanges = bus_cur->noPFMemRanges; - break; - case IO: - range_cur = bus_cur->rangeIO; - noRanges = bus_cur->noIORanges; - break; - } - - range_prev = NULL; - while (range_cur) { - if (range->start < range_cur->start) - break; - range_prev = range_cur; - range_cur = range_cur->next; - count = count + 1; - } - if (!count) { - /* our range will go at the beginning of the list */ - switch (type) { - case MEM: - bus_cur->rangeMem = range; - break; - case PFMEM: - bus_cur->rangePFMem = range; - break; - case IO: - bus_cur->rangeIO = range; - break; - } - range->next = range_cur; - range->rangeno = 1; - i_init = 0; - } else if (!range_cur) { - /* our range will go at the end of the list */ - range->next = NULL; - range_prev->next = range; - range->rangeno = range_prev->rangeno + 1; - return 0; - } else { - /* the range is in the middle */ - range_prev->next = range; - range->next = range_cur; - range->rangeno = range_cur->rangeno; - i_init = range_prev->rangeno; - } - - for (count = i_init; count < noRanges; ++count) { - ++range_cur->rangeno; - range_cur = range_cur->next; - } - - update_resources (bus_cur, type, i_init + 1); - return 0; -} - -/******************************************************************************* - * This routine goes through the list of resources of type 'type' and updates - * the range numbers that they correspond to. It was called from add_range fnc - * - * Input: bus, type of the resource, the rangeno starting from which to update - ******************************************************************************/ -static void update_resources (struct bus_node *bus_cur, int type, int rangeno) -{ - struct resource_node *res = NULL; - u8 eol = FALSE; /* end of list indicator */ - - switch (type) { - case MEM: - if (bus_cur->firstMem) - res = bus_cur->firstMem; - break; - case PFMEM: - if (bus_cur->firstPFMem) - res = bus_cur->firstPFMem; - break; - case IO: - if (bus_cur->firstIO) - res = bus_cur->firstIO; - break; - } - - if (res) { - while (res) { - if (res->rangeno == rangeno) - break; - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else { - eol = TRUE; - break; - } - } - - if (!eol) { - /* found the range */ - while (res) { - ++res->rangeno; - res = res->next; - } - } - } -} - -static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range) -{ - char * str = ""; - switch (res->type) { - case IO: - str = "io"; - break; - case MEM: - str = "mem"; - break; - case PFMEM: - str = "pfmem"; - break; - } - - while (res) { - if (res->rangeno == -1) { - while (range) { - if ((res->start >= range->start) && (res->end <= range->end)) { - res->rangeno = range->rangeno; - debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno); - switch (res->type) { - case IO: - --bus_cur->needIOUpdate; - break; - case MEM: - --bus_cur->needMemUpdate; - break; - case PFMEM: - --bus_cur->needPFMemUpdate; - break; - } - break; - } - range = range->next; - } - } - if (res->next) - res = res->next; - else - res = res->nextRange; - } - -} - -/***************************************************************************** - * This routine reassigns the range numbers to the resources that had a -1 - * This case can happen only if upon initialization, resources taken by pci dev - * appear in EBDA before the resources allocated for that bus, since we don't - * know the range, we assign -1, and this routine is called after a new range - * is assigned to see the resources with unknown range belong to the added range - * - * Input: current bus - * Output: none, list of resources for that bus are fixed if can be - *******************************************************************************/ -static void fix_resources (struct bus_node *bus_cur) -{ - struct range_node *range; - struct resource_node *res; - - debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); - - if (bus_cur->needIOUpdate) { - res = bus_cur->firstIO; - range = bus_cur->rangeIO; - fix_me (res, bus_cur, range); - } - if (bus_cur->needMemUpdate) { - res = bus_cur->firstMem; - range = bus_cur->rangeMem; - fix_me (res, bus_cur, range); - } - if (bus_cur->needPFMemUpdate) { - res = bus_cur->firstPFMem; - range = bus_cur->rangePFMem; - fix_me (res, bus_cur, range); - } -} - -/******************************************************************************* - * This routine adds a resource to the list of resources to the appropriate bus - * based on their resource type and sorted by their starting addresses. It assigns - * the ptrs to next and nextRange if needed. - * - * Input: resource ptr - * Output: ptrs assigned (to the node) - * 0 or -1 - *******************************************************************************/ -int ibmphp_add_resource (struct resource_node *res) -{ - struct resource_node *res_cur; - struct resource_node *res_prev; - struct bus_node *bus_cur; - struct range_node *range_cur = NULL; - struct resource_node *res_start = NULL; - - debug ("%s - enter\n", __FUNCTION__); - - if (!res) { - err ("NULL passed to add \n"); - return -ENODEV; - } - - bus_cur = find_bus_wprev (res->busno, NULL, 0); - - if (!bus_cur) { - /* didn't find a bus, smth's wrong!!! */ - debug ("no bus in the system, either pci_dev's wrong or allocation failed\n"); - return -ENODEV; - } - - /* Normal case */ - switch (res->type) { - case IO: - range_cur = bus_cur->rangeIO; - res_start = bus_cur->firstIO; - break; - case MEM: - range_cur = bus_cur->rangeMem; - res_start = bus_cur->firstMem; - break; - case PFMEM: - range_cur = bus_cur->rangePFMem; - res_start = bus_cur->firstPFMem; - break; - default: - err ("cannot read the type of the resource to add... problem \n"); - return -EINVAL; - } - while (range_cur) { - if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) { - res->rangeno = range_cur->rangeno; - break; - } - range_cur = range_cur->next; - } - - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * this is again the case of rangeno = -1 - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - */ - - if (!range_cur) { - switch (res->type) { - case IO: - ++bus_cur->needIOUpdate; - break; - case MEM: - ++bus_cur->needMemUpdate; - break; - case PFMEM: - ++bus_cur->needPFMemUpdate; - break; - } - res->rangeno = -1; - } - - debug ("The range is %d\n", res->rangeno); - if (!res_start) { - /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ - switch (res->type) { - case IO: - bus_cur->firstIO = res; - break; - case MEM: - bus_cur->firstMem = res; - break; - case PFMEM: - bus_cur->firstPFMem = res; - break; - } - res->next = NULL; - res->nextRange = NULL; - } else { - res_cur = res_start; - res_prev = NULL; - - debug ("res_cur->rangeno is %d\n", res_cur->rangeno); - - while (res_cur) { - if (res_cur->rangeno >= res->rangeno) - break; - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - - if (!res_cur) { - /* at the end of the resource list */ - debug ("i should be here, [%x - %x]\n", res->start, res->end); - res_prev->nextRange = res; - res->next = NULL; - res->nextRange = NULL; - } else if (res_cur->rangeno == res->rangeno) { - /* in the same range */ - while (res_cur) { - if (res->start < res_cur->start) - break; - res_prev = res_cur; - res_cur = res_cur->next; - } - if (!res_cur) { - /* the last resource in this range */ - res_prev->next = res; - res->next = NULL; - res->nextRange = res_prev->nextRange; - res_prev->nextRange = NULL; - } else if (res->start < res_cur->start) { - /* at the beginning or middle of the range */ - if (!res_prev) { - switch (res->type) { - case IO: - bus_cur->firstIO = res; - break; - case MEM: - bus_cur->firstMem = res; - break; - case PFMEM: - bus_cur->firstPFMem = res; - break; - } - } else if (res_prev->rangeno == res_cur->rangeno) - res_prev->next = res; - else - res_prev->nextRange = res; - - res->next = res_cur; - res->nextRange = NULL; - } - } else { - /* this is the case where it is 1st occurrence of the range */ - if (!res_prev) { - /* at the beginning of the resource list */ - res->next = NULL; - switch (res->type) { - case IO: - res->nextRange = bus_cur->firstIO; - bus_cur->firstIO = res; - break; - case MEM: - res->nextRange = bus_cur->firstMem; - bus_cur->firstMem = res; - break; - case PFMEM: - res->nextRange = bus_cur->firstPFMem; - bus_cur->firstPFMem = res; - break; - } - } else if (res_cur->rangeno > res->rangeno) { - /* in the middle of the resource list */ - res_prev->nextRange = res; - res->next = NULL; - res->nextRange = res_cur; - } - } - } - - debug ("%s - exit\n", __FUNCTION__); - return 0; -} - -/**************************************************************************** - * This routine will remove the resource from the list of resources - * - * Input: io, mem, and/or pfmem resource to be deleted - * Ouput: modified resource list - * 0 or error code - ****************************************************************************/ -int ibmphp_remove_resource (struct resource_node *res) -{ - struct bus_node *bus_cur; - struct resource_node *res_cur = NULL; - struct resource_node *res_prev; - struct resource_node *mem_cur; - char * type = ""; - - if (!res) { - err ("resource to remove is NULL \n"); - return -ENODEV; - } - - bus_cur = find_bus_wprev (res->busno, NULL, 0); - - if (!bus_cur) { - err ("cannot find corresponding bus of the io resource to remove " - "bailing out...\n"); - return -ENODEV; - } - - switch (res->type) { - case IO: - res_cur = bus_cur->firstIO; - type = "io"; - break; - case MEM: - res_cur = bus_cur->firstMem; - type = "mem"; - break; - case PFMEM: - res_cur = bus_cur->firstPFMem; - type = "pfmem"; - break; - default: - err ("unknown type for resource to remove \n"); - return -EINVAL; - } - res_prev = NULL; - - while (res_cur) { - if ((res_cur->start == res->start) && (res_cur->end == res->end)) - break; - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - - if (!res_cur) { - if (res->type == PFMEM) { - /* - * case where pfmem might be in the PFMemFromMem list - * so will also need to remove the corresponding mem - * entry - */ - res_cur = bus_cur->firstPFMemFromMem; - res_prev = NULL; - - while (res_cur) { - if ((res_cur->start == res->start) && (res_cur->end == res->end)) { - mem_cur = bus_cur->firstMem; - while (mem_cur) { - if ((mem_cur->start == res_cur->start) - && (mem_cur->end == res_cur->end)) - break; - if (mem_cur->next) - mem_cur = mem_cur->next; - else - mem_cur = mem_cur->nextRange; - } - if (!mem_cur) { - err ("cannot find corresponding mem node for pfmem...\n"); - return -EINVAL; - } - - ibmphp_remove_resource (mem_cur); - if (!res_prev) - bus_cur->firstPFMemFromMem = res_cur->next; - else - res_prev->next = res_cur->next; - kfree (res_cur); - return 0; - } - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - if (!res_cur) { - err ("cannot find pfmem to delete...\n"); - return -EINVAL; - } - } else { - err ("the %s resource is not in the list to be deleted...\n", type); - return -EINVAL; - } - } - if (!res_prev) { - /* first device to be deleted */ - if (res_cur->next) { - switch (res->type) { - case IO: - bus_cur->firstIO = res_cur->next; - break; - case MEM: - bus_cur->firstMem = res_cur->next; - break; - case PFMEM: - bus_cur->firstPFMem = res_cur->next; - break; - } - } else if (res_cur->nextRange) { - switch (res->type) { - case IO: - bus_cur->firstIO = res_cur->nextRange; - break; - case MEM: - bus_cur->firstMem = res_cur->nextRange; - break; - case PFMEM: - bus_cur->firstPFMem = res_cur->nextRange; - break; - } - } else { - switch (res->type) { - case IO: - bus_cur->firstIO = NULL; - break; - case MEM: - bus_cur->firstMem = NULL; - break; - case PFMEM: - bus_cur->firstPFMem = NULL; - break; - } - } - kfree (res_cur); - return 0; - } else { - if (res_cur->next) { - if (res_prev->rangeno == res_cur->rangeno) - res_prev->next = res_cur->next; - else - res_prev->nextRange = res_cur->next; - } else if (res_cur->nextRange) { - res_prev->next = NULL; - res_prev->nextRange = res_cur->nextRange; - } else { - res_prev->next = NULL; - res_prev->nextRange = NULL; - } - kfree (res_cur); - return 0; - } - - return 0; -} - -static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) -{ - struct range_node * range = NULL; - - switch (res->type) { - case IO: - range = bus_cur->rangeIO; - break; - case MEM: - range = bus_cur->rangeMem; - break; - case PFMEM: - range = bus_cur->rangePFMem; - break; - default: - err ("cannot read resource type in find_range \n"); - } - - while (range) { - if (res->rangeno == range->rangeno) - break; - range = range->next; - } - return range; -} - -/***************************************************************************** - * This routine will check to make sure the io/mem/pfmem->len that the device asked for - * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, - * otherwise, returns 0 - * - * Input: resource - * Ouput: the correct start and end address are inputted into the resource node, - * 0 or -EINVAL - *****************************************************************************/ -int ibmphp_check_resource (struct resource_node *res, u8 bridge) -{ - struct bus_node *bus_cur; - struct range_node *range = NULL; - struct resource_node *res_prev; - struct resource_node *res_cur = NULL; - u32 len_cur = 0, start_cur = 0, len_tmp = 0; - int noranges = 0; - u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ - u32 tmp_divide; - u8 flag = FALSE; - - if (!res) - return -EINVAL; - - if (bridge) { - /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/ - if (res->type == IO) - tmp_divide = IOBRIDGE; - else - tmp_divide = MEMBRIDGE; - } else - tmp_divide = res->len; - - bus_cur = find_bus_wprev (res->busno, NULL, 0); - - if (!bus_cur) { - /* didn't find a bus, smth's wrong!!! */ - debug ("no bus in the system, either pci_dev's wrong or allocation failed \n"); - return -EINVAL; - } - - debug ("%s - enter\n", __FUNCTION__); - debug ("bus_cur->busno is %d\n", bus_cur->busno); - - /* This is a quick fix to not mess up with the code very much. i.e., - * 2000-2fff, len = 1000, but when we compare, we need it to be fff */ - res->len -= 1; - - switch (res->type) { - case IO: - res_cur = bus_cur->firstIO; - noranges = bus_cur->noIORanges; - break; - case MEM: - res_cur = bus_cur->firstMem; - noranges = bus_cur->noMemRanges; - break; - case PFMEM: - res_cur = bus_cur->firstPFMem; - noranges = bus_cur->noPFMemRanges; - break; - default: - err ("wrong type of resource to check \n"); - return -EINVAL; - } - res_prev = NULL; - - while (res_cur) { - range = find_range (bus_cur, res_cur); - debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); - - if (!range) { - err ("no range for the device exists... bailing out...\n"); - return -EINVAL; - } - - /* found our range */ - if (!res_prev) { - /* first time in the loop */ - if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { - debug ("len_tmp = %x\n", len_tmp); - - if ((len_tmp < len_cur) || (len_cur == 0)) { - - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address is divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= res_cur->start - 1) - break; - } - } - - if (flag && len_cur == res->len) { - debug ("but we are not here, right?\n"); - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } - if (!res_cur->next) { - /* last device on the range */ - if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { - debug ("len_tmp = %x\n", len_tmp); - if ((len_tmp < len_cur) || (len_cur == 0)) { - - if (((res_cur->end + 1) % tmp_divide) == 0) { - /* just perfect, starting address is divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = res_cur->end + 1; - } else { - /* Needs adjusting */ - tmp_start = res_cur->end + 1; - flag = FALSE; - - while ((len_tmp = range->end - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= range->end) - break; - } - } - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } - - if (res_prev) { - if (res_prev->rangeno != res_cur->rangeno) { - /* 1st device on this range */ - if ((res_cur->start != range->start) && - ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address is divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= res_cur->start - 1) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } else { - /* in the same range */ - if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if (((res_prev->end + 1) % tmp_divide) == 0) { - /* just perfect, starting address's divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = res_prev->end + 1; - } else { - /* Needs adjusting */ - tmp_start = res_prev->end + 1; - flag = FALSE; - - while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= res_cur->start - 1) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } - } - /* end if (res_prev) */ - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } /* end of while */ - - - if (!res_prev) { - /* 1st device ever */ - /* need to find appropriate range */ - switch (res->type) { - case IO: - range = bus_cur->rangeIO; - break; - case MEM: - range = bus_cur->rangeMem; - break; - case PFMEM: - range = bus_cur->rangePFMem; - break; - } - while (range) { - if ((len_tmp = range->end - range->start) >= res->len) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address's divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = range->end - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= range->end) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - range = range->next; - } /* end of while */ - - if ((!range) && (len_cur == 0)) { - /* have gone through the list of devices and ranges and haven't found n.e.thing */ - err ("no appropriate range.. bailing out...\n"); - return -EINVAL; - } else if (len_cur) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - - if (!res_cur) { - debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); - if (res_prev->rangeno < noranges) { - /* if there're more ranges out there to check */ - switch (res->type) { - case IO: - range = bus_cur->rangeIO; - break; - case MEM: - range = bus_cur->rangeMem; - break; - case PFMEM: - range = bus_cur->rangePFMem; - break; - } - while (range) { - if ((len_tmp = range->end - range->start) >= res->len) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address's divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = range->end - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= range->end) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - range = range->next; - } /* end of while */ - - if ((!range) && (len_cur == 0)) { - /* have gone through the list of devices and ranges and haven't found n.e.thing */ - err ("no appropriate range.. bailing out...\n"); - return -EINVAL; - } else if (len_cur) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } else { - /* no more ranges to check on */ - if (len_cur) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } else { - /* have gone through the list of devices and haven't found n.e.thing */ - err ("no appropriate range.. bailing out...\n"); - return -EINVAL; - } - } - } /* end if(!res_cur) */ - return -EINVAL; -} - -/******************************************************************************** - * This routine is called from remove_card if the card contained PPB. - * It will remove all the resources on the bus as well as the bus itself - * Input: Bus - * Ouput: 0, -ENODEV - ********************************************************************************/ -int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) -{ - struct resource_node *res_cur; - struct resource_node *res_tmp; - struct bus_node *prev_bus; - int rc; - - prev_bus = find_bus_wprev (parent_busno, NULL, 0); - - if (!prev_bus) { - debug ("something terribly wrong. Cannot find parent bus to the one to remove\n"); - return -ENODEV; - } - - debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); - - rc = remove_ranges (bus, prev_bus); - if (rc) - return rc; - - if (bus->firstIO) { - res_cur = bus->firstIO; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstIO = NULL; - } - if (bus->firstMem) { - res_cur = bus->firstMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstMem = NULL; - } - if (bus->firstPFMem) { - res_cur = bus->firstPFMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstPFMem = NULL; - } - - if (bus->firstPFMemFromMem) { - res_cur = bus->firstPFMemFromMem; - while (res_cur) { - res_tmp = res_cur; - res_cur = res_cur->next; - - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstPFMemFromMem = NULL; - } - - list_del (&bus->bus_list); - kfree (bus); - return 0; -} - -/****************************************************************************** - * This routine deletes the ranges from a given bus, and the entries from the - * parent's bus in the resources - * Input: current bus, previous bus - * Output: 0, -EINVAL - ******************************************************************************/ -static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) -{ - struct range_node *range_cur; - struct range_node *range_tmp; - int i; - struct resource_node *res = NULL; - - if (bus_cur->noIORanges) { - range_cur = bus_cur->rangeIO; - for (i = 0; i < bus_cur->noIORanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) - return -EINVAL; - ibmphp_remove_resource (res); - - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - bus_cur->rangeIO = NULL; - } - if (bus_cur->noMemRanges) { - range_cur = bus_cur->rangeMem; - for (i = 0; i < bus_cur->noMemRanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) - return -EINVAL; - - ibmphp_remove_resource (res); - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - bus_cur->rangeMem = NULL; - } - if (bus_cur->noPFMemRanges) { - range_cur = bus_cur->rangePFMem; - for (i = 0; i < bus_cur->noPFMemRanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) - return -EINVAL; - - ibmphp_remove_resource (res); - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - bus_cur->rangePFMem = NULL; - } - return 0; -} - -/* - * find the resource node in the bus - * Input: Resource needed, start address of the resource, type of resource - */ -int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) -{ - struct resource_node *res_cur = NULL; - char * type = ""; - - if (!bus) { - err ("The bus passed in NULL to find resource \n"); - return -ENODEV; - } - - switch (flag) { - case IO: - res_cur = bus->firstIO; - type = "io"; - break; - case MEM: - res_cur = bus->firstMem; - type = "mem"; - break; - case PFMEM: - res_cur = bus->firstPFMem; - type = "pfmem"; - break; - default: - err ("wrong type of flag \n"); - return -EINVAL; - } - - while (res_cur) { - if (res_cur->start == start_address) { - *res = res_cur; - break; - } - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - - if (!res_cur) { - if (flag == PFMEM) { - res_cur = bus->firstPFMemFromMem; - while (res_cur) { - if (res_cur->start == start_address) { - *res = res_cur; - break; - } - res_cur = res_cur->next; - } - if (!res_cur) { - debug ("SOS...cannot find %s resource in the bus. \n", type); - return -EINVAL; - } - } else { - debug ("SOS... cannot find %s resource in the bus. \n", type); - return -EINVAL; - } - } - - if (*res) - debug ("*res->start = %x \n", (*res)->start); - - return 0; -} - -/*********************************************************************** - * This routine will free the resource structures used by the - * system. It is called from cleanup routine for the module - * Parameters: none - * Returns: none - ***********************************************************************/ -void ibmphp_free_resources (void) -{ - struct bus_node *bus_cur = NULL; - struct bus_node *bus_tmp; - struct range_node *range_cur; - struct range_node *range_tmp; - struct resource_node *res_cur; - struct resource_node *res_tmp; - struct list_head *tmp; - struct list_head *next; - int i = 0; - flags = 1; - - list_for_each_safe (tmp, next, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - if (bus_cur->noIORanges) { - range_cur = bus_cur->rangeIO; - for (i = 0; i < bus_cur->noIORanges; i++) { - if (!range_cur) - break; - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - } - if (bus_cur->noMemRanges) { - range_cur = bus_cur->rangeMem; - for (i = 0; i < bus_cur->noMemRanges; i++) { - if (!range_cur) - break; - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - } - if (bus_cur->noPFMemRanges) { - range_cur = bus_cur->rangePFMem; - for (i = 0; i < bus_cur->noPFMemRanges; i++) { - if (!range_cur) - break; - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - } - - if (bus_cur->firstIO) { - res_cur = bus_cur->firstIO; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstIO = NULL; - } - if (bus_cur->firstMem) { - res_cur = bus_cur->firstMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstMem = NULL; - } - if (bus_cur->firstPFMem) { - res_cur = bus_cur->firstPFMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstPFMem = NULL; - } - - if (bus_cur->firstPFMemFromMem) { - res_cur = bus_cur->firstPFMemFromMem; - while (res_cur) { - res_tmp = res_cur; - res_cur = res_cur->next; - - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstPFMemFromMem = NULL; - } - - bus_tmp = bus_cur; - list_del (&bus_cur->bus_list); - kfree (bus_tmp); - bus_tmp = NULL; - } -} - -/********************************************************************************* - * This function will go over the PFmem resources to check if the EBDA allocated - * pfmem out of memory buckets of the bus. If so, it will change the range numbers - * and a flag to indicate that this resource is out of memory. It will also move the - * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create - * a new Mem node - * This routine is called right after initialization - *******************************************************************************/ -static int __init once_over (void) -{ - struct resource_node *pfmem_cur; - struct resource_node *pfmem_prev; - struct resource_node *mem; - struct bus_node *bus_cur; - struct list_head *tmp; - - list_for_each (tmp, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { - for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { - pfmem_cur->fromMem = TRUE; - if (pfmem_prev) - pfmem_prev->next = pfmem_cur->next; - else - bus_cur->firstPFMem = pfmem_cur->next; - - if (!bus_cur->firstPFMemFromMem) - pfmem_cur->next = NULL; - else - /* we don't need to sort PFMemFromMem since we're using mem node for - all the real work anyways, so just insert at the beginning of the - list - */ - pfmem_cur->next = bus_cur->firstPFMemFromMem; - - bus_cur->firstPFMemFromMem = pfmem_cur; - - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem, 0, sizeof (struct resource_node)); - mem->type = MEM; - mem->busno = pfmem_cur->busno; - mem->devfunc = pfmem_cur->devfunc; - mem->start = pfmem_cur->start; - mem->end = pfmem_cur->end; - mem->len = pfmem_cur->len; - if (ibmphp_add_resource (mem) < 0) - err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); - pfmem_cur->rangeno = mem->rangeno; - } /* end for pfmem */ - } /* end if */ - } /* end list_for_each bus */ - return 0; -} - -int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) -{ - struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); - - if (!bus_cur) { - err ("cannot find bus of pfmem to add...\n"); - return -ENODEV; - } - - if (bus_cur->firstPFMemFromMem) - pfmem->next = bus_cur->firstPFMemFromMem; - else - pfmem->next = NULL; - - bus_cur->firstPFMemFromMem = pfmem; - - return 0; -} - -/* This routine just goes through the buses to see if the bus already exists. - * It is called from ibmphp_find_sec_number, to find out a secondary bus number for - * bridged cards - * Parameters: bus_number - * Returns: Bus pointer or NULL - */ -struct bus_node *ibmphp_find_res_bus (u8 bus_number) -{ - return find_bus_wprev (bus_number, NULL, 0); -} - -static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) -{ - struct bus_node *bus_cur; - struct list_head *tmp; - struct list_head *tmp_prev; - - list_for_each (tmp, &gbuses) { - tmp_prev = tmp->prev; - bus_cur = list_entry (tmp, struct bus_node, bus_list); - if (flag) - *prev = list_entry (tmp_prev, struct bus_node, bus_list); - if (bus_cur->busno == bus_number) - return bus_cur; - } - - return NULL; -} - -void ibmphp_print_test (void) -{ - int i = 0; - struct bus_node *bus_cur = NULL; - struct range_node *range; - struct resource_node *res; - struct list_head *tmp; - - debug_pci ("*****************START**********************\n"); - - if ((!list_empty(&gbuses)) && flags) { - err ("The GBUSES is not NULL?!?!?!?!?\n"); - return; - } - - list_for_each (tmp, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - debug_pci ("This is bus # %d. There are \n", bus_cur->busno); - debug_pci ("IORanges = %d\t", bus_cur->noIORanges); - debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges); - debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); - debug_pci ("The IO Ranges are as follows:\n"); - if (bus_cur->rangeIO) { - range = bus_cur->rangeIO; - for (i = 0; i < bus_cur->noIORanges; i++) { - debug_pci ("rangeno is %d\n", range->rangeno); - debug_pci ("[%x - %x]\n", range->start, range->end); - range = range->next; - } - } - - debug_pci ("The Mem Ranges are as follows:\n"); - if (bus_cur->rangeMem) { - range = bus_cur->rangeMem; - for (i = 0; i < bus_cur->noMemRanges; i++) { - debug_pci ("rangeno is %d\n", range->rangeno); - debug_pci ("[%x - %x]\n", range->start, range->end); - range = range->next; - } - } - - debug_pci ("The PFMem Ranges are as follows:\n"); - - if (bus_cur->rangePFMem) { - range = bus_cur->rangePFMem; - for (i = 0; i < bus_cur->noPFMemRanges; i++) { - debug_pci ("rangeno is %d\n", range->rangeno); - debug_pci ("[%x - %x]\n", range->start, range->end); - range = range->next; - } - } - - debug_pci ("The resources on this bus are as follows\n"); - - debug_pci ("IO...\n"); - if (bus_cur->firstIO) { - res = bus_cur->firstIO; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else - break; - } - } - debug_pci ("Mem...\n"); - if (bus_cur->firstMem) { - res = bus_cur->firstMem; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else - break; - } - } - debug_pci ("PFMem...\n"); - if (bus_cur->firstPFMem) { - res = bus_cur->firstPFMem; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else - break; - } - } - - debug_pci ("PFMemFromMem...\n"); - if (bus_cur->firstPFMemFromMem) { - res = bus_cur->firstPFMemFromMem; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - res = res->next; - } - } - } - debug_pci ("***********************END***********************\n"); -} - -static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type) -{ - struct range_node * range_cur = NULL; - switch (type) { - case IO: - range_cur = bus_cur->rangeIO; - break; - case MEM: - range_cur = bus_cur->rangeMem; - break; - case PFMEM: - range_cur = bus_cur->rangePFMem; - break; - default: - err ("wrong type passed to find out if range already exists \n"); - return -ENODEV; - } - - while (range_cur) { - if ((range_cur->start == range->start) && (range_cur->end == range->end)) - return 1; - range_cur = range_cur->next; - } - - return 0; -} - -/* This routine will read the windows for any PPB we have and update the - * range info for the secondary bus, and will also input this info into - * primary bus, since BIOS doesn't. This is for PPB that are in the system - * on bootup. For bridged cards that were added during previous load of the - * driver, only the ranges and the bus structure are added, the devices are - * added from NVRAM - * Input: primary busno - * Returns: none - * Note: this function doesn't take into account IO restrictions etc, - * so will only work for bridges with no video/ISA devices behind them It - * also will not work for onboard PPB's that can have more than 1 *bus - * behind them All these are TO DO. - * Also need to add more error checkings... (from fnc returns etc) - */ -static int __init update_bridge_ranges (struct bus_node **bus) -{ - u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address; - u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; - u32 start_address, end_address, upper_start, upper_end; - struct bus_node *bus_sec; - struct bus_node *bus_cur; - struct resource_node *io; - struct resource_node *mem; - struct resource_node *pfmem; - struct range_node *range; - unsigned int devfn; - - bus_cur = *bus; - if (!bus_cur) - return -ENODEV; - ibmphp_pci_bus->number = bus_cur->busno; - - debug ("inside %s \n", __FUNCTION__); - debug ("bus_cur->busno = %x\n", bus_cur->busno); - - for (device = 0; device < 32; device++) { - for (function = 0x00; function < 0x08; function++) { - devfn = PCI_DEVFN(device, function); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - - switch (hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIDEVICE: - break; - case PCI_HEADER_TYPE_BRIDGE: - function = 0x8; - case PCI_HEADER_TYPE_MULTIBRIDGE: - /* We assume here that only 1 bus behind the bridge - TO DO: add functionality for several: - temp = secondary; - while (temp < subordinate) { - ... - temp++; - } - */ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno); - bus_sec = find_bus_wprev (sec_busno, NULL, 0); - /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */ - if (!bus_sec) { - bus_sec = alloc_error_bus (NULL, sec_busno, 1); - /* the rest will be populated during NVRAM call */ - return 0; - } - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end); - start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; - start_address |= (upper_io_start << 16); - end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; - end_address |= (upper_io_end << 16); - - if ((start_address) && (start_address <= end_address)) { - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (range, 0, sizeof (struct range_node)); - range->start = start_address; - range->end = end_address + 0xfff; - - if (bus_sec->noIORanges > 0) { - if (!range_exists_already (range, bus_sec, IO)) { - add_range (IO, range, bus_sec); - ++bus_sec->noIORanges; - } else { - kfree (range); - range = NULL; - } - } else { - /* 1st IO Range on the bus */ - range->rangeno = 1; - bus_sec->rangeIO = range; - ++bus_sec->noIORanges; - } - fix_resources (bus_sec); - - if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) { - io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!io) { - kfree (range); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (io, 0, sizeof (struct resource_node)); - io->type = IO; - io->busno = bus_cur->busno; - io->devfunc = ((device << 3) | (function & 0x7)); - io->start = start_address; - io->end = end_address + 0xfff; - io->len = io->end - io->start + 1; - ibmphp_add_resource (io); - } - } - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address); - - start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; - end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; - - if ((start_address) && (start_address <= end_address)) { - - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (range, 0, sizeof (struct range_node)); - range->start = start_address; - range->end = end_address + 0xfffff; - - if (bus_sec->noMemRanges > 0) { - if (!range_exists_already (range, bus_sec, MEM)) { - add_range (MEM, range, bus_sec); - ++bus_sec->noMemRanges; - } else { - kfree (range); - range = NULL; - } - } else { - /* 1st Mem Range on the bus */ - range->rangeno = 1; - bus_sec->rangeMem = range; - ++bus_sec->noMemRanges; - } - - fix_resources (bus_sec); - - if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) { - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem) { - kfree (range); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem, 0, sizeof (struct resource_node)); - mem->type = MEM; - mem->busno = bus_cur->busno; - mem->devfunc = ((device << 3) | (function & 0x7)); - mem->start = start_address; - mem->end = end_address + 0xfffff; - mem->len = mem->end - mem->start + 1; - ibmphp_add_resource (mem); - } - } - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end); - start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; - end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; -#if BITS_PER_LONG == 64 - start_address |= ((long) upper_start) << 32; - end_address |= ((long) upper_end) << 32; -#endif - - if ((start_address) && (start_address <= end_address)) { - - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (range, 0, sizeof (struct range_node)); - range->start = start_address; - range->end = end_address + 0xfffff; - - if (bus_sec->noPFMemRanges > 0) { - if (!range_exists_already (range, bus_sec, PFMEM)) { - add_range (PFMEM, range, bus_sec); - ++bus_sec->noPFMemRanges; - } else { - kfree (range); - range = NULL; - } - } else { - /* 1st PFMem Range on the bus */ - range->rangeno = 1; - bus_sec->rangePFMem = range; - ++bus_sec->noPFMemRanges; - } - - fix_resources (bus_sec); - if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) { - pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!pfmem) { - kfree (range); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (pfmem, 0, sizeof (struct resource_node)); - pfmem->type = PFMEM; - pfmem->busno = bus_cur->busno; - pfmem->devfunc = ((device << 3) | (function & 0x7)); - pfmem->start = start_address; - pfmem->end = end_address + 0xfffff; - pfmem->len = pfmem->end - pfmem->start + 1; - pfmem->fromMem = FALSE; - - ibmphp_add_resource (pfmem); - } - } - break; - } /* end of switch */ - } /* end if vendor */ - } /* end for function */ - } /* end for device */ - - bus = &bus_cur; - return 0; -} diff -urN linux-2.5.70-bk9/drivers/hotplug/pci_hotplug.h linux-2.5.70-bk10/drivers/hotplug/pci_hotplug.h --- linux-2.5.70-bk9/drivers/hotplug/pci_hotplug.h 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/pci_hotplug.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,146 +0,0 @@ -/* - * PCI HotPlug Core Functions - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - */ -#ifndef _PCI_HOTPLUG_H -#define _PCI_HOTPLUG_H - - -/* These values come from the PCI Hotplug Spec */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0X12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCI_SPEED_UNKNOWN = 0xff, -}; - -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -/** - * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @enable_slot: Called when the user wants to enable a specific pci slot - * @disable_slot: Called when the user wants to disable a specific pci slot - * @set_attention_status: Called to set the specific slot's attention LED to - * the specified value - * @hardware_test: Called to run a specified hardware test on the specified - * slot. - * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_max_bus_speed: Called to get the max bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_cur_bus_speed: Called to get the current bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * - * The table of function pointers that is passed to the hotplug pci core by a - * hotplug pci driver. These functions are called by the hotplug pci core when - * the user wants to do something to a specific slot (query it for information, - * set an LED, enable / disable power, etc.) - */ -struct hotplug_slot_ops { - struct module *owner; - int (*enable_slot) (struct hotplug_slot *slot); - int (*disable_slot) (struct hotplug_slot *slot); - int (*set_attention_status) (struct hotplug_slot *slot, u8 value); - int (*hardware_test) (struct hotplug_slot *slot, u32 value); - int (*get_power_status) (struct hotplug_slot *slot, u8 *value); - int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); - int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); - int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); - int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); - int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); -}; - -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_present: if there is a pci board present in the slot or not (1/0) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; - enum pci_bus_speed max_bus_speed; - enum pci_bus_speed cur_bus_speed; -}; - -/** - * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. - * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the inital values for - * this slot. - * @private: used by the hotplug pci controller driver to store whatever it - * needs. - */ -struct hotplug_slot { - char *name; - struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; - void *private; - - /* Variables below this are for use only by the hotplug pci core. */ - struct list_head slot_list; - struct kobject kobj; -}; - -extern int pci_hp_register (struct hotplug_slot *slot); -extern int pci_hp_deregister (struct hotplug_slot *slot); -extern int pci_hp_change_slot_info (struct hotplug_slot *slot, - struct hotplug_slot_info *info); - -#endif - diff -urN linux-2.5.70-bk9/drivers/hotplug/pci_hotplug_core.c linux-2.5.70-bk10/drivers/hotplug/pci_hotplug_core.c --- linux-2.5.70-bk9/drivers/hotplug/pci_hotplug_core.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/pci_hotplug_core.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,666 +0,0 @@ -/* - * PCI HotPlug Controller Core - * - * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001-2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - * - * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci_hotplug.h" - - -#if !defined(CONFIG_HOTPLUG_PCI_MODULE) - #define MY_NAME "pci_hotplug" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) - - -/* local variables */ -static int debug; - -#define DRIVER_VERSION "0.5" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Scott Murray " -#define DRIVER_DESC "PCI Hot Plug PCI Core" - - -////////////////////////////////////////////////////////////////// - -static LIST_HEAD(pci_hotplug_slot_list); - -static struct subsystem hotplug_slots_subsys; - -static ssize_t hotplug_slot_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct hotplug_slot *slot=container_of(kobj, - struct hotplug_slot,kobj); - struct hotplug_slot_attribute *attribute = - container_of(attr, struct hotplug_slot_attribute, attr); - return attribute->show ? attribute->show(slot, buf) : 0; -} - -static ssize_t hotplug_slot_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t len) -{ - struct hotplug_slot *slot=container_of(kobj, - struct hotplug_slot,kobj); - struct hotplug_slot_attribute *attribute = - container_of(attr, struct hotplug_slot_attribute, attr); - return attribute->store ? attribute->store(slot, buf, len) : 0; -} - -static struct sysfs_ops hotplug_slot_sysfs_ops = { - .show = hotplug_slot_attr_show, - .store = hotplug_slot_attr_store, -}; - -static struct kobj_type hotplug_slot_ktype = { - .sysfs_ops = &hotplug_slot_sysfs_ops -}; - -static decl_subsys(hotplug_slots, &hotplug_slot_ktype, NULL); - - -/* these strings match up with the values in pci_bus_speed */ -static char *pci_bus_speed_strings[] = { - "33 MHz PCI", /* 0x00 */ - "66 MHz PCI", /* 0x01 */ - "66 MHz PCIX", /* 0x02 */ - "100 MHz PCIX", /* 0x03 */ - "133 MHz PCIX", /* 0x04 */ - NULL, /* 0x05 */ - NULL, /* 0x06 */ - NULL, /* 0x07 */ - NULL, /* 0x08 */ - "66 MHz PCIX 266", /* 0x09 */ - "100 MHz PCIX 266", /* 0x0a */ - "133 MHz PCIX 266", /* 0x0b */ - NULL, /* 0x0c */ - NULL, /* 0x0d */ - NULL, /* 0x0e */ - NULL, /* 0x0f */ - NULL, /* 0x10 */ - "66 MHz PCIX 533", /* 0x11 */ - "100 MHz PCIX 533", /* 0x12 */ - "133 MHz PCIX 533", /* 0x13 */ -}; - -#ifdef CONFIG_HOTPLUG_PCI_CPCI -extern int cpci_hotplug_init(int debug); -extern void cpci_hotplug_exit(void); -#else -static inline int cpci_hotplug_init(int debug) { return 0; } -static inline void cpci_hotplug_exit(void) { } -#endif - -/* Weee, fun with macros... */ -#define GET_STATUS(name,type) \ -static int get_##name (struct hotplug_slot *slot, type *value) \ -{ \ - struct hotplug_slot_ops *ops = slot->ops; \ - int retval = 0; \ - if (try_module_get(ops->owner)) { \ - if (ops->get_##name) \ - retval = ops->get_##name (slot, value); \ - else \ - *value = slot->info->name; \ - module_put(ops->owner); \ - } \ - return retval; \ -} - -GET_STATUS(power_status, u8) -GET_STATUS(attention_status, u8) -GET_STATUS(latch_status, u8) -GET_STATUS(adapter_status, u8) -GET_STATUS(max_bus_speed, enum pci_bus_speed) -GET_STATUS(cur_bus_speed, enum pci_bus_speed) - -static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_power_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); -exit: - return retval; -} - -static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) -{ - unsigned long lpower; - u8 power; - int retval = 0; - - lpower = simple_strtoul (buf, NULL, 10); - power = (u8)(lpower & 0xff); - dbg ("power = %d\n", power); - - if (!try_module_get(slot->ops->owner)) { - retval = -ENODEV; - goto exit; - } - switch (power) { - case 0: - if (slot->ops->disable_slot) - retval = slot->ops->disable_slot(slot); - break; - - case 1: - if (slot->ops->enable_slot) - retval = slot->ops->enable_slot(slot); - break; - - default: - err ("Illegal value specified for power\n"); - retval = -EINVAL; - } - module_put(slot->ops->owner); - -exit: - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_power = { - .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = power_read_file, - .store = power_write_file -}; - -static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_attention_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); - -exit: - return retval; -} - -static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) -{ - unsigned long lattention; - u8 attention; - int retval = 0; - - lattention = simple_strtoul (buf, NULL, 10); - attention = (u8)(lattention & 0xff); - dbg (" - attention = %d\n", attention); - - if (!try_module_get(slot->ops->owner)) { - retval = -ENODEV; - goto exit; - } - if (slot->ops->set_attention_status) - retval = slot->ops->set_attention_status(slot, attention); - module_put(slot->ops->owner); - -exit: - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_attention = { - .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = attention_read_file, - .store = attention_write_file -}; - -static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_latch_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_latch = { - .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = latch_read_file, -}; - -static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_adapter_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_presence = { - .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = presence_read_file, -}; - -static char *unknown_speed = "Unknown bus speed"; - -static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) -{ - char *speed_string; - int retval; - enum pci_bus_speed value; - - retval = get_max_bus_speed (slot, &value); - if (retval) - goto exit; - - if (value == PCI_SPEED_UNKNOWN) - speed_string = unknown_speed; - else - speed_string = pci_bus_speed_strings[value]; - - retval = sprintf (buf, "%s\n", speed_string); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { - .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = max_bus_speed_read_file, -}; - -static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) -{ - char *speed_string; - int retval; - enum pci_bus_speed value; - - retval = get_cur_bus_speed (slot, &value); - if (retval) - goto exit; - - if (value == PCI_SPEED_UNKNOWN) - speed_string = unknown_speed; - else - speed_string = pci_bus_speed_strings[value]; - - retval = sprintf (buf, "%s\n", speed_string); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { - .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = cur_bus_speed_read_file, -}; - -static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) -{ - unsigned long ltest; - u32 test; - int retval = 0; - - ltest = simple_strtoul (buf, NULL, 10); - test = (u32)(ltest & 0xffffffff); - dbg ("test = %d\n", test); - - if (!try_module_get(slot->ops->owner)) { - retval = -ENODEV; - goto exit; - } - if (slot->ops->hardware_test) - retval = slot->ops->hardware_test(slot, test); - module_put(slot->ops->owner); - -exit: - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_test = { - .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .store = test_write_file -}; - -static int has_power_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if ((slot->ops->enable_slot) || - (slot->ops->disable_slot) || - (slot->ops->get_power_status)) - return 0; - return -ENOENT; -} - -static int has_attention_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if ((slot->ops->set_attention_status) || - (slot->ops->get_attention_status)) - return 0; - return -ENOENT; -} - -static int has_latch_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_latch_status) - return 0; - return -ENOENT; -} - -static int has_adapter_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_adapter_status) - return 0; - return -ENOENT; -} - -static int has_max_bus_speed_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_max_bus_speed) - return 0; - return -ENOENT; -} - -static int has_cur_bus_speed_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_cur_bus_speed) - return 0; - return -ENOENT; -} - -static int has_test_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->hardware_test) - return 0; - return -ENOENT; -} - -static int fs_add_slot (struct hotplug_slot *slot) -{ - if (has_power_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if (has_attention_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if (has_latch_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if (has_adapter_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if (has_max_bus_speed_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if (has_cur_bus_speed_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - if (has_test_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); - - return 0; -} - -static void fs_remove_slot (struct hotplug_slot *slot) -{ - if (has_power_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if (has_latch_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - if (has_test_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); -} - -static struct hotplug_slot *get_slot_from_name (const char *name) -{ - struct hotplug_slot *slot; - struct list_head *tmp; - - list_for_each (tmp, &pci_hotplug_slot_list) { - slot = list_entry (tmp, struct hotplug_slot, slot_list); - if (strcmp(slot->name, name) == 0) - return slot; - } - return NULL; -} - -/** - * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem - * @slot: pointer to the &struct hotplug_slot to register - * - * Registers a hotplug slot with the pci hotplug subsystem, which will allow - * userspace interaction to the slot. - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_register (struct hotplug_slot *slot) -{ - int result; - - if (slot == NULL) - return -ENODEV; - if ((slot->info == NULL) || (slot->ops == NULL)) - return -EINVAL; - - strlcpy(slot->kobj.name, slot->name, KOBJ_NAME_LEN); - kobj_set_kset_s(slot, hotplug_slots_subsys); - - /* this can fail if we have already registered a slot with the same name */ - if (kobject_register(&slot->kobj)) { - err("Unable to register kobject"); - return -EINVAL; - } - - list_add (&slot->slot_list, &pci_hotplug_slot_list); - - result = fs_add_slot (slot); - dbg ("Added slot %s to the list\n", slot->name); - return result; -} - -/** - * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem - * @slot: pointer to the &struct hotplug_slot to deregister - * - * The @slot must have been registered with the pci hotplug subsystem - * previously with a call to pci_hp_register(). - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_deregister (struct hotplug_slot *slot) -{ - struct hotplug_slot *temp; - - if (slot == NULL) - return -ENODEV; - - temp = get_slot_from_name (slot->name); - if (temp != slot) { - return -ENODEV; - } - list_del (&slot->slot_list); - - fs_remove_slot (slot); - dbg ("Removed slot %s from the list\n", slot->name); - kobject_unregister(&slot->kobj); - return 0; -} - -/** - * pci_hp_change_slot_info - changes the slot's information structure in the core - * @slot: pointer to the slot whose info has changed - * @info: pointer to the info copy into the slot's info structure - * - * @slot must have been registered with the pci - * hotplug subsystem previously with a call to pci_hp_register(). - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) -{ - if ((slot == NULL) || (info == NULL)) - return -ENODEV; - - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); - - return 0; -} - -static int __init pci_hotplug_init (void) -{ - int result; - - kset_set_kset_s(&hotplug_slots_subsys, pci_bus_type.subsys); - result = subsystem_register(&hotplug_slots_subsys); - if (result) { - err("Register subsys with error %d\n", result); - goto exit; - } - result = cpci_hotplug_init(debug); - if (result) { - err ("cpci_hotplug_init with error %d\n", result); - goto err_subsys; - } - - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - goto exit; - -err_subsys: - subsystem_unregister(&hotplug_slots_subsys); -exit: - return result; -} - -static void __exit pci_hotplug_exit (void) -{ - cpci_hotplug_exit(); - subsystem_unregister(&hotplug_slots_subsys); -} - -module_init(pci_hotplug_init); -module_exit(pci_hotplug_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -EXPORT_SYMBOL_GPL(pci_hp_register); -EXPORT_SYMBOL_GPL(pci_hp_deregister); -EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff -urN linux-2.5.70-bk9/drivers/hotplug/pcihp_skeleton.c linux-2.5.70-bk10/drivers/hotplug/pcihp_skeleton.c --- linux-2.5.70-bk9/drivers/hotplug/pcihp_skeleton.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/drivers/hotplug/pcihp_skeleton.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,432 +0,0 @@ -/* - * PCI Hot Plug Controller Skeleton Driver - 0.1 - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This driver is to be used as a skeleton driver to be show how to interface - * with the pci hotplug core easily. - * - * Send feedback to - * - */ - -#include -#include -#include -#include -#include -#include -#include "pci_hotplug.h" - - -#define SLOT_MAGIC 0x67267322 -struct slot { - u32 magic; - u8 number; - struct hotplug_slot *hotplug_slot; - struct list_head slot_list; -}; - -static LIST_HEAD(slot_list); - -#if !defined(CONFIG_HOTPLUG_PCI_SKELETON_MODULE) - #define MY_NAME "pcihp_skeleton" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if (debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - - - -/* local variables */ -static int debug; -static int num_slots; - -#define DRIVER_VERSION "0.1" -#define DRIVER_AUTHOR "Greg Kroah-Hartman " -#define DRIVER_DESC "Hot Plug PCI Controller Skeleton Driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -static int enable_slot (struct hotplug_slot *slot); -static int disable_slot (struct hotplug_slot *slot); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); - -static struct hotplug_slot_ops skel_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, -}; - - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check (slot, function)) - return NULL; - return slot; -} - - -static int enable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* - * Fill in code here to enable the specified slot - */ - - return retval; -} - - -static int disable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* - * Fill in code here to disable the specified slot - */ - - return retval; -} - -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - switch (status) { - case 0: - /* - * Fill in code here to turn light off - */ - break; - - case 1: - default: - /* - * Fill in code here to turn light on - */ - break; - } - - return retval; -} - -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - err ("No hardware tests are defined for this driver"); - retval = -ENODEV; - - /* Or you can specify a test if you want to */ - - return retval; -} - -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current power status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current attention status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current latch status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current adapter status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -#define SLOT_NAME_SIZE 10 -static void make_slot_name (struct slot *slot) -{ - /* - * Stupid way to make a filename out of the slot name. - * replace this if your hardware provides a better way to name slots. - */ - snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number); -} - -static int init_slots (void) -{ - struct slot *slot; - struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; - char *name; - int retval = 0; - int i; - - /* - * Create a structure for each slot, and register that slot - * with the pci_hotplug subsystem. - */ - for (i = 0; i < num_slots; ++i) { - slot = kmalloc (sizeof (struct slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - memset(slot, 0, sizeof(struct slot)); - - hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!hotplug_slot) { - kfree (slot); - return -ENOMEM; - } - memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); - slot->hotplug_slot = hotplug_slot; - - info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) { - kfree (hotplug_slot); - kfree (slot); - return -ENOMEM; - } - memset(info, 0, sizeof (struct hotplug_slot_info)); - hotplug_slot->info = info; - - name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); - if (!name) { - kfree (info); - kfree (hotplug_slot); - kfree (slot); - return -ENOMEM; - } - hotplug_slot->name = name; - - slot->magic = SLOT_MAGIC; - slot->number = i; - - hotplug_slot->private = slot; - make_slot_name (slot); - hotplug_slot->ops = &skel_hotplug_slot_ops; - - /* - * Initilize the slot info structure with some known - * good values. - */ - info->power_status = get_skel_power_status(slot); - info->attention_status = get_skel_attention_status(slot); - info->latch_status = get_skel_latch_status(slot); - info->adapter_status = get_skel_adapter_status(slot); - - dbg ("registering slot %d\n", i); - retval = pci_hp_register (slot->hotplug_slot); - if (retval) { - err ("pci_hp_register failed with error %d\n", retval); - kfree (info); - kfree (name); - kfree (hotplug_slot); - kfree (slot); - return retval; - } - - /* add slot to our internal list */ - list_add (&slot->slot_list, &slot_list); - } - - return retval; -} - -static void cleanup_slots (void) -{ - struct list_head *tmp; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem, - * and free up all memory that we had allocated. - */ - list_for_each (tmp, &slot_list) { - slot = list_entry (tmp, struct slot, slot_list); - list_del (&slot->slot_list); - pci_hp_deregister (slot->hotplug_slot); - kfree (slot->hotplug_slot->info); - kfree (slot->hotplug_slot->name); - kfree (slot->hotplug_slot); - kfree (slot); - } - - return; -} - -static int __init pcihp_skel_init(void) -{ - int retval; - - /* - * Do specific initialization stuff for your driver here - * Like initilizing your controller hardware (if any) and - * determining the number of slots you have in the system - * right now. - */ - num_slots = 5; - - retval = init_slots(); - if (retval) - return retval; - - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - return 0; -} - -static void __exit pcihp_skel_exit(void) -{ - /* - * Clean everything up. - */ - cleanup_slots(); -} - -module_init(pcihp_skel_init); -module_exit(pcihp_skel_exit); - diff -urN linux-2.5.70-bk9/drivers/ide/pci/cs5530.c linux-2.5.70-bk10/drivers/ide/pci/cs5530.c --- linux-2.5.70-bk9/drivers/ide/pci/cs5530.c 2003-05-26 18:00:37.000000000 -0700 +++ linux-2.5.70-bk10/drivers/ide/pci/cs5530.c 2003-06-05 04:41:36.000000000 -0700 @@ -281,16 +281,15 @@ } #endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ - pci_for_each_dev (dev) { - if (dev->vendor == PCI_VENDOR_ID_CYRIX) { - switch (dev->device) { - case PCI_DEVICE_ID_CYRIX_PCI_MASTER: - master_0 = dev; - break; - case PCI_DEVICE_ID_CYRIX_5530_LEGACY: - cs5530_0 = dev; - break; - } + dev = NULL; + while ((dev = pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { + switch (dev->device) { + case PCI_DEVICE_ID_CYRIX_PCI_MASTER: + master_0 = dev; + break; + case PCI_DEVICE_ID_CYRIX_5530_LEGACY: + cs5530_0 = dev; + break; } } if (!master_0) { diff -urN linux-2.5.70-bk9/drivers/ide/pci/hpt366.c linux-2.5.70-bk10/drivers/ide/pci/hpt366.c --- linux-2.5.70-bk9/drivers/ide/pci/hpt366.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/drivers/ide/pci/hpt366.c 2003-06-05 04:41:36.000000000 -0700 @@ -1100,7 +1100,7 @@ if (PCI_FUNC(dev->devfn) & 1) return; - pci_for_each_dev(findev) { + while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && ((findev->devfn - dev->devfn) == 1) && @@ -1150,7 +1150,7 @@ d->channels = 1; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - pci_for_each_dev(findev) { + while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && ((findev->devfn - dev->devfn) == 1) && diff -urN linux-2.5.70-bk9/drivers/ide/pci/pdc202xx_new.c linux-2.5.70-bk10/drivers/ide/pci/pdc202xx_new.c --- linux-2.5.70-bk9/drivers/ide/pci/pdc202xx_new.c 2003-05-26 18:00:45.000000000 -0700 +++ linux-2.5.70-bk10/drivers/ide/pci/pdc202xx_new.c 2003-06-05 04:41:36.000000000 -0700 @@ -579,7 +579,7 @@ static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev; + struct pci_dev *findev = NULL; if ((dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && @@ -588,7 +588,7 @@ return; } d->extra = 0; - pci_for_each_dev(findev) { + while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && (PCI_SLOT(findev->devfn) & 2)) { diff -urN linux-2.5.70-bk9/drivers/ide/setup-pci.c linux-2.5.70-bk10/drivers/ide/setup-pci.c --- linux-2.5.70-bk9/drivers/ide/setup-pci.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/drivers/ide/setup-pci.c 2003-06-05 04:41:36.000000000 -0700 @@ -870,13 +870,13 @@ void __init ide_scan_pcibus (int scan_direction) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct pci_driver *d; struct list_head *l, *n; pre_init = 0; if (!scan_direction) { - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ide_scan_pcidev(dev); } } else { diff -urN linux-2.5.70-bk9/drivers/macintosh/via-pmu.c linux-2.5.70-bk10/drivers/macintosh/via-pmu.c --- linux-2.5.70-bk9/drivers/macintosh/via-pmu.c 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk10/drivers/macintosh/via-pmu.c 2003-06-05 04:41:36.000000000 -0700 @@ -1713,10 +1713,10 @@ pbook_alloc_pci_save(void) { int npci; - struct pci_dev *pd; + struct pci_dev *pd = NULL; npci = 0; - pci_for_each_dev(pd) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { ++npci; } if (npci == 0) @@ -1740,13 +1740,13 @@ pbook_pci_save(void) { struct pci_save *ps = pbook_pci_saves; - struct pci_dev *pd; + struct pci_dev *pd = NULL; int npci = pbook_npci_saves; if (ps == NULL) return; - pci_for_each_dev(pd) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { if (npci-- == 0) return; #ifndef HACKED_PCI_SAVE @@ -1772,11 +1772,11 @@ { u16 cmd; struct pci_save *ps = pbook_pci_saves - 1; - struct pci_dev *pd; + struct pci_dev *pd = NULL; int npci = pbook_npci_saves; int j; - pci_for_each_dev(pd) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { #ifdef HACKED_PCI_SAVE int i; if (npci-- == 0) diff -urN linux-2.5.70-bk9/drivers/md/md.c linux-2.5.70-bk10/drivers/md/md.c --- linux-2.5.70-bk9/drivers/md/md.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/drivers/md/md.c 2003-06-05 04:41:36.000000000 -0700 @@ -2860,7 +2860,7 @@ loff_t l = *pos; mddev_t *mddev; - if (l > 0x10000) + if (l >= 0x10000) return NULL; if (!l--) /* header */ @@ -2875,7 +2875,9 @@ return mddev; } spin_unlock(&all_mddevs_lock); - return (void*)2;/* tail */ + if (!l--) + return (void*)2;/* tail */ + return NULL; } static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos) diff -urN linux-2.5.70-bk9/drivers/md/raid0.c linux-2.5.70-bk10/drivers/md/raid0.c --- linux-2.5.70-bk9/drivers/md/raid0.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/drivers/md/raid0.c 2003-06-05 04:41:36.000000000 -0700 @@ -85,10 +85,8 @@ conf->devlist = kmalloc(sizeof(mdk_rdev_t*)* conf->nr_strip_zones*mddev->raid_disks, GFP_KERNEL); - if (!conf->devlist) { - kfree(conf); + if (!conf->devlist) return 1; - } memset(conf->strip_zone, 0,sizeof(struct strip_zone)* conf->nr_strip_zones); @@ -193,8 +191,6 @@ printk("raid0: done.\n"); return 0; abort: - kfree(conf->devlist); - kfree(conf->strip_zone); return 1; } @@ -235,6 +231,8 @@ goto out; mddev->private = (void *)conf; + conf->strip_zone = NULL; + conf->devlist = NULL; if (create_strip_zones (mddev)) goto out_free_conf; @@ -273,7 +271,7 @@ nb_zone*sizeof(struct strip_zone*)); conf->hash_table = kmalloc (sizeof (struct strip_zone *)*nb_zone, GFP_KERNEL); if (!conf->hash_table) - goto out_free_zone_conf; + goto out_free_conf; size = conf->strip_zone[cur].size; for (i=0; i< nb_zone; i++) { @@ -296,12 +294,11 @@ blk_queue_merge_bvec(&mddev->queue, raid0_mergeable_bvec); return 0; -out_free_zone_conf: - kfree(conf->strip_zone); - conf->strip_zone = NULL; - out_free_conf: - kfree (conf->devlist); + if (conf->strip_zone) + kfree(conf->strip_zone); + if (conf->devlist) + kfree (conf->devlist); kfree(conf); mddev->private = NULL; out: diff -urN linux-2.5.70-bk9/drivers/md/raid1.c linux-2.5.70-bk10/drivers/md/raid1.c --- linux-2.5.70-bk9/drivers/md/raid1.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/drivers/md/raid1.c 2003-06-05 04:41:36.000000000 -0700 @@ -462,7 +462,7 @@ mirror_info_t *mirror; r1bio_t *r1_bio; struct bio *read_bio; - int i, sum_bios = 0, disks = conf->raid_disks; + int i, disks = conf->raid_disks; /* * Register the new request and wait if the reconstruction @@ -525,6 +525,9 @@ r1_bio->write_bios[i] = NULL; } spin_unlock_irq(&conf->device_lock); + + atomic_set(&r1_bio->remaining, 1); + md_write_start(mddev); for (i = 0; i < disks; i++) { struct bio *mbio; if (!r1_bio->write_bios[i]) @@ -539,37 +542,7 @@ mbio->bi_rw = r1_bio->cmd; mbio->bi_private = r1_bio; - sum_bios++; - } - if (!sum_bios) { - /* - * If all mirrors are non-operational - * then return an IO error: - */ - md_write_end(mddev); - raid_end_bio_io(r1_bio); - return 0; - } - atomic_set(&r1_bio->remaining, sum_bios+1); - - /* - * We have to be a bit careful about the semaphore above, thats - * why we start the requests separately. Since generic_make_request() - * can sleep, this is the safer solution. Imagine, raid1_end_request - * decreasing the semaphore before we could have set it up ... - * We could play tricks with the semaphore (presetting it and - * correcting at the end if sum_bios is not 'n' but we have to - * do raid1_end_request by hand if all requests finish until we had a - * chance to set up the semaphore correctly ... lots of races). - */ - - md_write_start(mddev); - for (i=disks; i--; ) { - struct bio *mbio; - mbio = r1_bio->write_bios[i]; - if (!mbio) - continue; - + atomic_inc(&r1_bio->remaining); generic_make_request(mbio); } @@ -802,7 +775,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) { conf_t *conf = mddev_to_conf(mddev); - int i, sum_bios = 0; + int i; int disks = conf->raid_disks; struct bio *bio, *mbio; @@ -849,7 +822,8 @@ } spin_unlock_irq(&conf->device_lock); - for (i = 0; i < disks ; i++) { + atomic_set(&r1_bio->remaining, 1); + for (i = disks; i-- ; ) { if (!r1_bio->write_bios[i]) continue; mbio = bio_clone(bio, GFP_NOIO); @@ -860,32 +834,14 @@ mbio->bi_rw = WRITE; mbio->bi_private = r1_bio; - sum_bios++; + atomic_inc(&r1_bio->remaining); + md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9); + generic_make_request(mbio); } - if (i != disks) - BUG(); - atomic_set(&r1_bio->remaining, sum_bios); - - if (!sum_bios) { - /* - * Nowhere to write this to... I guess we - * must be done - */ - printk(KERN_ALERT "raid1: sync aborting as there is nowhere" - " to write sector %llu\n", - (unsigned long long)r1_bio->sector); + if (atomic_dec_and_test(&r1_bio->remaining)) { md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); put_buf(r1_bio); - return; - } - for (i = 0; i < disks ; i++) { - mbio = r1_bio->write_bios[i]; - if (!mbio) - continue; - - md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9); - generic_make_request(mbio); } } diff -urN linux-2.5.70-bk9/drivers/md/raid5.c linux-2.5.70-bk10/drivers/md/raid5.c --- linux-2.5.70-bk9/drivers/md/raid5.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/drivers/md/raid5.c 2003-06-05 04:41:36.000000000 -0700 @@ -940,7 +940,7 @@ /* and fail all 'written' */ bi = sh->dev[i].written; sh->dev[i].written = NULL; - while (bi && bi->bi_sector < dev->sector + STRIPE_SECTORS) { + while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = bi->bi_next; clear_bit(BIO_UPTODATE, &bi->bi_flags); if (--bi->bi_phys_segments == 0) { diff -urN linux-2.5.70-bk9/drivers/media/radio/radio-cadet.c linux-2.5.70-bk10/drivers/media/radio/radio-cadet.c --- linux-2.5.70-bk9/drivers/media/radio/radio-cadet.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/drivers/media/radio/radio-cadet.c 2003-06-05 04:41:36.000000000 -0700 @@ -389,9 +389,6 @@ v->flags|=VIDEO_TUNER_STEREO_ON; } v->flags|=cadet_getrds(); - if(copy_to_user(arg,&v, sizeof(v))) { - return -EFAULT; - } break; case 1: strcpy(v->name,"AM"); @@ -402,9 +399,6 @@ v->mode=0; v->mode|=VIDEO_MODE_AUTO; v->signal=sigstrength; - if(copy_to_user(arg,&v, sizeof(v))) { - return -EFAULT; - } break; } return 0; diff -urN linux-2.5.70-bk9/drivers/media/video/bw-qcam.c linux-2.5.70-bk10/drivers/media/video/bw-qcam.c --- linux-2.5.70-bk9/drivers/media/video/bw-qcam.c 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk10/drivers/media/video/bw-qcam.c 2003-06-05 04:41:36.000000000 -0700 @@ -723,8 +723,6 @@ /* Good question.. its composite or SVHS so.. */ v->type = VIDEO_TYPE_CAMERA; strcpy(v->name, "Camera"); - if(copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; return 0; } case VIDIOCSCHAN: diff -urN linux-2.5.70-bk9/drivers/media/video/zr36120.c linux-2.5.70-bk10/drivers/media/video/zr36120.c --- linux-2.5.70-bk9/drivers/media/video/zr36120.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/drivers/media/video/zr36120.c 2003-06-05 04:41:36.000000000 -0700 @@ -1693,12 +1693,12 @@ for (x=0; optr+1w; x++) { unsigned char a = iptr[x*2]; - *optr++ = a; - *optr++ = a; + __put_user(a, optr++); + __put_user(a, optr++); } /* and clear the rest of the line */ for (x*=2; optrbpl; x++) - *optr++ = 0; + __put_user(0, optr++); /* next line */ iptr += done->bpl; } @@ -1715,10 +1715,10 @@ { /* copy to doubled data to userland */ for (x=0; optrw; x++) - *optr++ = iptr[x*2]; + __put_user(iptr[x*2], optr++); /* and clear the rest of the line */ for (;optrbpl; x++) - *optr++ = 0; + __put_user(0, optr++); /* next line */ iptr += done->bpl; } @@ -1727,7 +1727,7 @@ /* API compliance: * place the framenumber (half fieldnr) in the last long */ - ((ulong*)eptr)[-1] = done->fieldnr/2; + __put_user(done->fieldnr/2, ((ulong*)eptr)[-1]); } /* keep the engine running */ diff -urN linux-2.5.70-bk9/drivers/message/fusion/mptbase.c linux-2.5.70-bk10/drivers/message/fusion/mptbase.c --- linux-2.5.70-bk9/drivers/message/fusion/mptbase.c 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk10/drivers/message/fusion/mptbase.c 2003-06-05 04:41:36.000000000 -0700 @@ -1152,7 +1152,7 @@ static int __init mpt_pci_scan(void) { - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct pci_dev *pdev2; int found = 0; int count = 0; @@ -1164,11 +1164,8 @@ * NOTE: The 929, 929X, 1030 and 1035 will appear as 2 separate PCI devices, * one for each channel. */ - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_VENDOR_ID_LSI_LOGIC, PCI_ANY_ID, pdev)) != NULL) { pdev2 = NULL; - if (pdev->vendor != 0x1000) - continue; - if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) && diff -urN linux-2.5.70-bk9/drivers/message/i2o/i2o_core.c linux-2.5.70-bk10/drivers/message/i2o/i2o_core.c --- linux-2.5.70-bk9/drivers/message/i2o/i2o_core.c 2003-06-05 04:41:31.000000000 -0700 +++ linux-2.5.70-bk10/drivers/message/i2o/i2o_core.c 2003-06-05 04:41:36.000000000 -0700 @@ -3645,12 +3645,12 @@ int __init i2o_pci_scan(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int count=0; printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); - pci_for_each_dev(dev) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) continue; diff -urN linux-2.5.70-bk9/drivers/net/3c509.c linux-2.5.70-bk10/drivers/net/3c509.c --- linux-2.5.70-bk9/drivers/net/3c509.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/3c509.c 2003-06-05 04:41:36.000000000 -0700 @@ -300,17 +300,11 @@ * * Both call el3_common_init/el3_common_remove. */ -static int __init el3_common_init (struct net_device *dev) +static void __init el3_common_init(struct net_device *dev) { struct el3_private *lp = dev->priv; short i; - el3_cards++; - if (!lp->dev) /* probed devices are not chained */ - { - lp->next_dev = el3_root_dev; - el3_root_dev = dev; - } spin_lock_init(&lp->lock); if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ @@ -343,8 +337,6 @@ dev->tx_timeout = el3_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->do_ioctl = netdev_ioctl; - - return 0; } static void el3_common_remove (struct net_device *dev) @@ -374,6 +366,7 @@ int ioaddr, irq, if_port; u16 phys_addr[3]; static int current_tag; + int err = -ENODEV; #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) static int pnp_cards; struct pnp_dev *idev = NULL; @@ -413,7 +406,8 @@ phys_addr[j] = htons(read_eeprom(ioaddr, j)); if_port = read_eeprom(ioaddr, 8) >> 14; - if (!(dev = init_etherdev(NULL, sizeof(struct el3_private)))) { + dev = alloc_etherdev(sizeof (struct el3_private)); + if (!dev) { release_region(ioaddr, EL3_IO_EXTENT); pnp_device_detach(idev); return -ENOMEM; @@ -421,6 +415,8 @@ SET_MODULE_OWNER(dev); pnp_cards++; + + netdev_boot_setup_check(dev); goto found; } } @@ -514,28 +510,29 @@ irq = 13; #endif - if (!(dev = init_etherdev(NULL, sizeof(struct el3_private)))) - return -ENOMEM; + dev = alloc_etherdev(sizeof (struct el3_private)); + if (!dev) + return -ENOMEM; SET_MODULE_OWNER(dev); + + netdev_boot_setup_check(dev); /* Set passed-in IRQ or I/O Addr. */ if (dev->irq > 1 && dev->irq < 16) irq = dev->irq; if (dev->base_addr) { - if (dev->mem_end == 0x3c509 /* Magic key */ - && dev->base_addr >= 0x200 && dev->base_addr <= 0x3e0) - ioaddr = dev->base_addr & 0x3f0; - else if (dev->base_addr != ioaddr) { - unregister_netdev (dev); - return -ENODEV; - } + if (dev->mem_end == 0x3c509 /* Magic key */ + && dev->base_addr >= 0x200 && dev->base_addr <= 0x3e0) + ioaddr = dev->base_addr & 0x3f0; + else if (dev->base_addr != ioaddr) + goto out; } if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509")) { - unregister_netdev (dev); - return -EBUSY; + err = -EBUSY; + goto out; } /* Set the adaptor tag so that the next card can be found. */ @@ -549,11 +546,8 @@ #endif EL3WINDOW(0); - if (inw(ioaddr) != 0x6d50) { - unregister_netdev (dev); - release_region(ioaddr, EL3_IO_EXTENT); - return -ENODEV; - } + if (inw(ioaddr) != 0x6d50) + goto out1; /* Free the interrupt so that some other card can use it. */ outw(0x0f00, ioaddr + WN0_IRQ); @@ -570,6 +564,11 @@ #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) lp->dev = &idev->dev; #endif + el3_common_init(dev); + + err = register_netdev(dev); + if (err) + goto out1; #ifdef CONFIG_PM /* register power management */ @@ -581,7 +580,22 @@ } #endif - return el3_common_init (dev); + el3_cards++; +#if !defined(__ISAPNP__) || defined(CONFIG_X86_PC9800) + lp->next_dev = el3_root_dev; + el3_root_dev = dev; +#endif + return 0; + +out1: + release_region(ioaddr, EL3_IO_EXTENT); +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) + if (idev) + pnp_device_detach(idev); +#endif +out: + kfree(dev); + return err; } #ifdef CONFIG_MCA @@ -602,6 +616,7 @@ u_char pos4, pos5; struct mca_device *mdev = to_mca_device(device); int slot = mdev->slot; + int err; pos4 = mca_device_read_stored_pos(mdev, 4); pos5 = mca_device_read_stored_pos(mdev, 5); @@ -630,13 +645,14 @@ phys_addr[i] = htons(read_eeprom(ioaddr, i)); } - dev = init_etherdev(NULL, sizeof(struct el3_private)); + dev = alloc_etherdev(sizeof (struct el3_private)); if (dev == NULL) { release_region(ioaddr, EL3_IO_EXTENT); return -ENOMEM; } SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; @@ -646,8 +662,16 @@ lp->dev = device; lp->type = EL3_MCA; device->driver_data = dev; + el3_common_init(dev); + + err = register_netdev(dev); + if (err) { + release_region(ioaddr, EL3_IO_EXTENT); + return -ENOMEM; + } - return el3_common_init (dev); + el3_cards++; + return 0; } #endif /* CONFIG_MCA */ @@ -661,6 +685,7 @@ u16 phys_addr[3]; struct net_device *dev = NULL; struct eisa_device *edev; + int err; /* Yeepee, The driver framework is calling us ! */ edev = to_eisa_device (device); @@ -680,7 +705,7 @@ /* Restore the "Product ID" to the EEPROM read register. */ read_eeprom(ioaddr, 3); - dev = init_etherdev(NULL, sizeof(struct el3_private)); + dev = alloc_etherdev(sizeof (struct el3_private)); if (dev == NULL) { release_region(ioaddr, EL3_IO_EXTENT); return -ENOMEM; @@ -688,6 +713,8 @@ SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); + memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; @@ -696,8 +723,16 @@ lp->dev = device; lp->type = EL3_EISA; eisa_set_drvdata (edev, dev); + el3_common_init(dev); + + err = register_netdev(dev); + if (err) { + release_region(ioaddr, EL3_IO_EXTENT); + return err; + } - return el3_common_init (dev); + el3_cards++; + return 0; } #endif diff -urN linux-2.5.70-bk9/drivers/net/e100/e100_main.c linux-2.5.70-bk10/drivers/net/e100/e100_main.c --- linux-2.5.70-bk9/drivers/net/e100/e100_main.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/e100/e100_main.c 2003-06-05 04:41:36.000000000 -0700 @@ -4272,13 +4272,13 @@ static int e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) { - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; switch(event) { case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if(pci_dev_driver(pdev) == &e100_driver) { /* If net_device struct is allocated? */ if (pci_get_drvdata(pdev)) diff -urN linux-2.5.70-bk9/drivers/net/e1000/e1000_main.c linux-2.5.70-bk10/drivers/net/e1000/e1000_main.c --- linux-2.5.70-bk9/drivers/net/e1000/e1000_main.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/e1000/e1000_main.c 2003-06-05 04:41:36.000000000 -0700 @@ -2649,7 +2649,7 @@ case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if(pci_dev_driver(pdev) == &e1000_driver) e1000_suspend(pdev, 3); } diff -urN linux-2.5.70-bk9/drivers/net/hamradio/dmascc.c linux-2.5.70-bk10/drivers/net/hamradio/dmascc.c --- linux-2.5.70-bk9/drivers/net/hamradio/dmascc.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/hamradio/dmascc.c 2003-06-05 04:41:36.000000000 -0700 @@ -250,8 +250,6 @@ /* Function declarations */ - -int dmascc_init(void) __init; static int setup_adapter(int card_base, int type, int n) __init; static void write_scc(struct scc_priv *priv, int reg, int val); @@ -299,23 +297,12 @@ static unsigned long rand; -/* Module functions */ - -#ifdef MODULE - - MODULE_AUTHOR("Klaus Kudielka"); MODULE_DESCRIPTION("Driver for high-speed SCC boards"); MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); MODULE_LICENSE("GPL"); - -int init_module(void) { - return dmascc_init(); -} - - -void cleanup_module(void) { +static void __exit dmascc_exit(void) { int i; struct scc_info *info; @@ -341,24 +328,16 @@ } } - -#else - - +#ifndef MODULE void __init dmascc_setup(char *str, int *ints) { int i; for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) io[i] = ints[i+1]; } - - #endif - -/* Initialization functions */ - -int __init dmascc_init(void) { +static int __init dmascc_init(void) { int h, i, j, n; int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], t1[MAX_NUM_DEVS]; @@ -461,6 +440,9 @@ return -EIO; } +module_init(dmascc_init); +module_exit(dmascc_exit); + int __init setup_adapter(int card_base, int type, int n) { int i, irq, chip; @@ -580,6 +562,7 @@ if (sizeof(dev->name) == sizeof(char *)) dev->name = priv->name; #endif sprintf(dev->name, "dmascc%i", 2*n+i); + SET_MODULE_OWNER(dev); dev->base_addr = card_base; dev->irq = irq; dev->open = scc_open; @@ -707,12 +690,9 @@ struct scc_info *info = priv->info; int card_base = priv->card_base; - MOD_INC_USE_COUNT; - /* Request IRQ if not already used by other channel */ if (!info->irq_used) { if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) { - MOD_DEC_USE_COUNT; return -EAGAIN; } } @@ -722,7 +702,6 @@ if (priv->param.dma >= 0) { if (request_dma(priv->param.dma, "dmascc")) { if (--info->irq_used == 0) free_irq(dev->irq, info); - MOD_DEC_USE_COUNT; return -EAGAIN; } else { unsigned long flags = claim_dma_lock(); @@ -866,7 +845,6 @@ } if (--info->irq_used == 0) free_irq(dev->irq, info); - MOD_DEC_USE_COUNT; return 0; } diff -urN linux-2.5.70-bk9/drivers/net/ixgb/ixgb_main.c linux-2.5.70-bk10/drivers/net/ixgb/ixgb_main.c --- linux-2.5.70-bk9/drivers/net/ixgb/ixgb_main.c 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/ixgb/ixgb_main.c 2003-06-05 04:41:36.000000000 -0700 @@ -2315,7 +2315,7 @@ case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if (pci_dev_driver(pdev) == &ixgb_driver) ixgb_suspend(pdev, 3); } diff -urN linux-2.5.70-bk9/drivers/net/setup.c linux-2.5.70-bk10/drivers/net/setup.c --- linux-2.5.70-bk9/drivers/net/setup.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/setup.c 2003-06-05 04:41:36.000000000 -0700 @@ -9,8 +9,6 @@ #include #include -extern int dmascc_init(void); - extern int scc_enet_init(void); extern int fec_enet_init(void); @@ -29,10 +27,6 @@ /* * Early setup devices */ - -#if defined(CONFIG_DMASCC) - {dmascc_init, 0}, -#endif #if defined(CONFIG_SCC_ENET) {scc_enet_init, 0}, #endif diff -urN linux-2.5.70-bk9/drivers/net/sk98lin/h/skdrv2nd.h linux-2.5.70-bk10/drivers/net/sk98lin/h/skdrv2nd.h --- linux-2.5.70-bk9/drivers/net/sk98lin/h/skdrv2nd.h 2003-05-26 18:01:00.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/sk98lin/h/skdrv2nd.h 2003-06-05 04:41:36.000000000 -0700 @@ -383,6 +383,7 @@ int Mtu; int Up; SK_AC *pAC; + struct proc_dir_entry *proc; }; typedef struct s_TxPort TX_PORT; diff -urN linux-2.5.70-bk9/drivers/net/sk98lin/skge.c linux-2.5.70-bk10/drivers/net/sk98lin/skge.c --- linux-2.5.70-bk9/drivers/net/sk98lin/skge.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/sk98lin/skge.c 2003-06-05 04:41:36.000000000 -0700 @@ -351,11 +351,7 @@ static const char SK_Root_Dir_entry[] = "sk98lin"; static struct proc_dir_entry *pSkRootDir; - -//extern struct proc_dir_entry Our_Proc_Dir; -extern int sk_proc_read(char *buffer, char **buffer_location, - off_t offset, int buffer_length, int *eof, void *data); - +extern struct file_operations sk_proc_fops; #ifdef DEBUG static void DumpMsg(struct sk_buff*, char*); @@ -399,7 +395,6 @@ struct pci_dev *pdev = NULL; unsigned long base_address; struct net_device *dev = NULL; - struct proc_dir_entry *pProcFile; if (probed) return -ENODEV; @@ -420,7 +415,6 @@ while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) { - dev = NULL; pNet = NULL; if (pci_enable_device(pdev)) @@ -431,7 +425,8 @@ pci_set_dma_mask(pdev, (u64) 0xffffffff)) continue; - if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) { + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; @@ -440,7 +435,7 @@ pNet = dev->priv; pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); if (pNet->pAC == NULL){ - kfree(dev->priv); + kfree(dev); printk(KERN_ERR "Unable to allocate adapter " "structure!\n"); break; @@ -477,15 +472,6 @@ proc_root_initialized = 1; } - pProcFile = create_proc_entry(dev->name, - S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = sk_proc_read; - pProcFile->write_proc = NULL; - pProcFile->nlink = 1; - pProcFile->size = sizeof(dev->name+1); - pProcFile->data = (void*)pProcFile; - pProcFile->owner = THIS_MODULE; - /* * Dummy value. */ @@ -532,11 +518,29 @@ pNet->PortNr = 0; pNet->NetNr = 0; + if (register_netdev(dev) != 0) { + printk(KERN_ERR "Unable to register etherdev\n"); + sk98lin_root_dev = pAC->Next; + remove_proc_entry(dev->name, pSkRootDir); + FreeResources(dev); + kfree(dev); + continue; + } + + pNet->proc = create_proc_entry(dev->name, + S_IFREG | 0444, pSkRootDir); + if (pNet->proc) { + pNet->proc->data = dev; + pNet->proc->owner = THIS_MODULE; + pNet->proc->proc_fops = &sk_proc_fops; + } + boards_found++; /* More then one port found */ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) { + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; @@ -559,20 +563,25 @@ dev->do_ioctl = &SkGeIoctl; dev->change_mtu = &SkGeChangeMtu; - pProcFile = create_proc_entry(dev->name, - S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = sk_proc_read; - pProcFile->write_proc = NULL; - pProcFile->nlink = 1; - pProcFile->size = sizeof(dev->name+1); - pProcFile->data = (void*)pProcFile; - pProcFile->owner = THIS_MODULE; - memcpy((caddr_t) &dev->dev_addr, (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); printk("%s: %s\n", dev->name, pAC->DeviceStr); printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "Unable to register etherdev\n"); + kfree(dev); + break; + } + + pNet->proc = create_proc_entry(dev->name, + S_IFREG | 0444, pSkRootDir); + if (pNet->proc) { + pNet->proc->data = dev; + pNet->proc->owner = THIS_MODULE; + pNet->proc->proc_fops = &sk_proc_fops; + } } @@ -740,6 +749,7 @@ return cards ? 0 : -ENODEV; } /* skge_init_module */ +spinlock_t sk_devs_lock = SPIN_LOCK_UNLOCKED; /***************************************************************************** * @@ -766,6 +776,11 @@ netif_stop_queue(sk98lin_root_dev); SkGeYellowLED(pAC, pAC->IoBase, 0); + if (pNet->proc) { + spin_lock(&sk_devs_lock); + pNet->proc->data = NULL; + spin_unlock(&sk_devs_lock); + } if(pAC->BoardLevel == 2) { /* board is still alive */ @@ -792,6 +807,12 @@ } if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ + pNet = (DEV_NET*) pAC->dev[1]->priv; + if (pNet->proc) { + spin_lock(&sk_devs_lock); + pNet->proc->data = NULL; + spin_unlock(&sk_devs_lock); + } unregister_netdev(pAC->dev[1]); kfree(pAC->dev[1]); } diff -urN linux-2.5.70-bk9/drivers/net/sk98lin/skproc.c linux-2.5.70-bk10/drivers/net/sk98lin/skproc.c --- linux-2.5.70-bk9/drivers/net/sk98lin/skproc.c 2003-05-26 18:00:22.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/sk98lin/skproc.c 2003-06-05 04:41:36.000000000 -0700 @@ -46,378 +46,168 @@ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" -#define ZEROPAD 1 /* pad with zero */ -#define SIGN 2 /* unsigned/signed long */ -#define PLUS 4 /* show plus */ -#define SPACE 8 /* space if plus */ -#define LEFT 16 /* left justified */ -//#define SPECIAL 32 /* 0x */ -#define LARGE 64 - -extern char * SkNumber(char * str, long long num, int base, int size, - int precision ,int type); -int proc_read(char *buffer, - char **buffer_location, - off_t offset, - int buffer_length, - int *eof, - void *data); - - -extern struct net_device *sk98lin_root_dev; - -/***************************************************************************** - * - * proc_read - print "summaries" entry - * - * Description: - * This function fills the proc entry with statistic data about - * the ethernet device. - * - * - * Returns: buffer with statistic data - * - */ -int sk_proc_read(char *buffer, -char **buffer_location, -off_t offset, -int buffer_length, -int *eof, -void *data) + +extern spinlock_t sk_devs_lock; + +static int sk_show_dev(struct net_device *dev, char *buf) { + DEV_NET *pNet = (DEV_NET*) dev->priv; + SK_AC *pAC = pNet->pAC; + int t = pNet->PortNr; + SK_RLMT_NET *rlmt = &pAC->Rlmt.Net[t]; + unsigned long Flags; + unsigned Size; int len = 0; - int t; int i; - DEV_NET *pNet; - SK_AC *pAC; - char test_buf[100]; - unsigned long Flags; - unsigned int Size; - struct net_device *next; - struct net_device *SkgeProcDev = sk98lin_root_dev; - SK_PNMI_STRUCT_DATA *pPnmiStruct; + SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct; SK_PNMI_STAT *pPnmiStat; - struct proc_dir_entry *file = (struct proc_dir_entry*) data; - while (SkgeProcDev) { - pNet = (DEV_NET*) SkgeProcDev->priv; - pAC = pNet->pAC; - next = pAC->Next; - pPnmiStruct = &pAC->PnmiStruct; - /* NetIndex in GetStruct is now required, zero is only dummy */ - - for (t=pAC->GIni.GIMacsFound; t > 0; t--) { - if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1) - t--; - - spin_lock_irqsave(&pAC->SlowPathLock, Flags); - Size = SK_PNMI_STRUCT_SIZE; - SkPnmiGetStruct(pAC, pAC->IoBase, - pPnmiStruct, &Size, t-1); - spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - - if (strcmp(pAC->dev[t-1]->name, file->name) == 0) { - pPnmiStat = &pPnmiStruct->Stat[0]; - len = sprintf(buffer, - "\nDetailed statistic for device %s\n", - pAC->dev[t-1]->name); - len += sprintf(buffer + len, - "==================================\n"); - - /* Board statistics */ - len += sprintf(buffer + len, - "\nBoard statistics\n\n"); - len += sprintf(buffer + len, - "Active Port %c\n", - 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. - Net[t-1].PrefPort]->PortNumber); - len += sprintf(buffer + len, - "Preferred Port %c\n", - 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. - Net[t-1].PrefPort]->PortNumber); - - len += sprintf(buffer + len, - "Bus speed (Mhz) %d\n", - pPnmiStruct->BusSpeed); - - len += sprintf(buffer + len, - "Bus width (Bit) %d\n", - pPnmiStruct->BusWidth); - - for (i=0; i < SK_MAX_SENSORS; i ++) { - if (strcmp(pAC->I2c.SenTable[i].SenDesc, - "Temperature") == 0 ) { - len += sprintf(buffer + len, - "Temperature (C) %d.%d\n", - pAC->I2c.SenTable[i].SenValue / 10, - pAC->I2c.SenTable[i].SenValue % 10); - len += sprintf(buffer + len, - "Temperature (F) %d.%d\n", - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200)/100, - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200) % 10); - } else if (strcmp(pAC->I2c.SenTable[i].SenDesc, - "Speed Fan") == 0 ) { - len += sprintf(buffer + len, - "Speed Fan %d\n", - pAC->I2c.SenTable[i].SenValue); - } else { - len += sprintf(buffer + len, - "%-20s %d.%d\n", - pAC->I2c.SenTable[i].SenDesc, - pAC->I2c.SenTable[i].SenValue / 1000, - pAC->I2c.SenTable[i].SenValue % 1000); - } - } - - /*Receive statistics */ - - len += sprintf(buffer + len, - "\nReceive statistics\n\n"); - - len += sprintf(buffer + len, - "Received bytes %s\n", - SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received packets %s\n", - SkNumber(test_buf, pPnmiStat->StatRxOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFcsCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received dropped %s\n", - SkNumber(test_buf, pPnmiStruct->RxNoBufCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received multicast %s\n", - SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received errors types\n"); - len += sprintf(buffer + len, - " length errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxRuntCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " over errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " crc errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFcsCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " frame errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFramingCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " fifo errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " missed errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxMissedCts, - 10, 0, -1, 0)); - - /*Transmit statistics */ - len += sprintf(buffer + len, - "\nTransmit statistics\n\n"); - - len += sprintf(buffer + len, - "Transmit bytes %s\n", - SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit packets %s\n", - SkNumber(test_buf, pPnmiStat->StatTxOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit dropped %s\n", - SkNumber(test_buf, pPnmiStruct->TxNoBufCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit collisions %s\n", - SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmited errors types\n"); - len += sprintf(buffer + len, - " aborted errors %ld\n", - pAC->stats.tx_aborted_errors); - len += sprintf(buffer + len, - " carrier errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " fifo errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " heartbeat errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " window errors %ld\n", - pAC->stats.tx_window_errors); - } + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + Size = SK_PNMI_STRUCT_SIZE; + SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, t); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + pPnmiStat = &pPnmiStruct->Stat[0]; + + len = sprintf(buf, "\nDetailed statistic for device %s\n", dev->name); + len += sprintf(buf + len, "==================================\n"); + + /* Board statistics */ + len += sprintf(buf + len, "\nBoard statistics\n\n"); + len += sprintf(buf + len, "Active Port %c\n", + 'A' + rlmt->Port[rlmt->ActivePort]->PortNumber); + len += sprintf(buf + len, "Preferred Port %c\n", + 'A' + rlmt->Port[rlmt->PrefPort]->PortNumber); + + len += sprintf(buf + len, "Bus speed (Mhz) %d\n", + pPnmiStruct->BusSpeed); + + len += sprintf(buf + len, "Bus width (Bit) %d\n", + pPnmiStruct->BusWidth); + + for (i=0; i < SK_MAX_SENSORS; i ++) { + SK_SENSOR *sens = &pAC->I2c.SenTable[i]; + SK_I32 val = sens->SenValue; + if (strcmp(sens->SenDesc, "Temperature") == 0 ) { + len += sprintf(buf + len, + "Temperature (C) %d.%d\n", + val / 10, val % 10); + val = val * 18 + 3200; + len += sprintf(buf + len, + "Temperature (F) %d.%d\n", + val/100, val % 10); + } else if (strcmp(sens->SenDesc, "Speed Fan") == 0 ) { + len += sprintf(buf + len, + "Speed Fan %d\n", + val); + } else { + len += sprintf(buf + len, + "%-20s %d.%d\n", + sens->SenDesc, val / 1000, val % 1000); } - SkgeProcDev = next; - } - if (offset >= len) { - *eof = 1; - return 0; } + + /*Receive statistics */ + + len += sprintf(buf + len, "\nReceive statistics\n\n"); - *buffer_location = buffer + offset; - if (buffer_length >= len - offset) { - *eof = 1; - } - return (min_t(int, buffer_length, len - offset)); + len += sprintf(buf + len, "Received bytes %Ld\n", + (unsigned long long) pPnmiStat->StatRxOctetsOkCts); + len += sprintf(buf + len, "Received packets %Ld\n", + (unsigned long long) pPnmiStat->StatRxOkCts); + len += sprintf(buf + len, "Received errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFcsCts); + len += sprintf(buf + len, "Received dropped %Ld\n", + (unsigned long long) pPnmiStruct->RxNoBufCts); + len += sprintf(buf + len, "Received multicast %Ld\n", + (unsigned long long) pPnmiStat->StatRxMulticastOkCts); + len += sprintf(buf + len, "Received errors types\n"); + len += sprintf(buf + len, " length errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxRuntCts); + len += sprintf(buf + len, " over errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); + len += sprintf(buf + len, " crc errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFcsCts); + len += sprintf(buf + len, " frame errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFramingCts); + len += sprintf(buf + len, " fifo errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); + len += sprintf(buf + len, " missed errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxMissedCts); + + /*Transmit statistics */ + len += sprintf(buf + len, "\nTransmit statistics\n\n"); + + len += sprintf(buf + len, "Transmit bytes %Ld\n", + (unsigned long long) pPnmiStat->StatTxOctetsOkCts); + len += sprintf(buf + len, "Transmit packets %Ld\n", + (unsigned long long) pPnmiStat->StatTxOkCts); + len += sprintf(buf + len, "Transmit errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sprintf(buf + len, "Transmit dropped %Ld\n", + (unsigned long long) pPnmiStruct->TxNoBufCts); + len += sprintf(buf + len, "Transmit collisions %Ld\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sprintf(buf + len, "Transmited errors types\n"); + len += sprintf(buf + len, " aborted errors %ld\n", + pAC->stats.tx_aborted_errors); + len += sprintf(buf + len, " carrier errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sprintf(buf + len, " fifo errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxFifoUnderrunCts); + len += sprintf(buf + len, " heartbeat errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sprintf(buf + len, " window errors %ld\n", + pAC->stats.tx_window_errors); + return len; } - - - - -/***************************************************************************** - * - * SkDoDiv - convert 64bit number - * - * Description: - * This function "converts" a long long number. - * - * Returns: - * remainder of division - */ -static long SkDoDiv (long long Dividend, int Divisor, long long *pErg) +static ssize_t sk_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) { - long Rest; - long long Ergebnis; - long Akku; - - - Akku = Dividend >> 32; - - Ergebnis = ((long long) (Akku / Divisor)) << 32; - Rest = Akku % Divisor ; - - Akku = Rest << 16; - Akku |= ((Dividend & 0xFFFF0000) >> 16); - - - Ergebnis += ((long long) (Akku / Divisor)) << 16; - Rest = Akku % Divisor ; - - Akku = Rest << 16; - Akku |= (Dividend & 0xFFFF); + struct inode * inode = file->f_dentry->d_inode; + struct proc_dir_entry *entry = PDE(inode); + char *page = (char *)__get_free_page(GFP_KERNEL); + struct net_device *dev; + loff_t pos = *ppos; + ssize_t res = 0; + int len = 0; - Ergebnis += (Akku / Divisor); - Rest = Akku % Divisor ; + if (!page) + return -ENOMEM; - *pErg = Ergebnis; - return (Rest); + spin_lock(&sk_devs_lock); + dev = entry->data; + if (dev) + len = sk_show_dev(dev, page); + spin_unlock(&sk_devs_lock); + + if (pos >= 0 && pos < len) { + res = nbytes; + if (res > len - pos) + res = len - pos; + if (copy_to_user(page + pos, buf, nbytes)) + res = -EFAULT; + else + *ppos = pos + res; + } + free_page((unsigned long) page); + return nbytes; } - -#if 0 -#define do_div(n,base) ({ \ -long long __res; \ -__res = ((unsigned long long) n) % (unsigned) base; \ -n = ((unsigned long long) n) / (unsigned) base; \ -__res; }) - -#endif - - -/***************************************************************************** - * - * SkNumber - Print results - * - * Description: - * This function converts a long long number into a string. - * - * Returns: - * number as string - */ -char * SkNumber(char * str, long long num, int base, int size, int precision - ,int type) +static loff_t sk_lseek(struct file *file, loff_t offset, int orig) { - char c,sign,tmp[66], *strorg = str; - const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; - int i; - - if (type & LARGE) - digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - if (type & LEFT) - type &= ~ZEROPAD; - if (base < 2 || base > 36) - return 0; - c = (type & ZEROPAD) ? '0' : ' '; - sign = 0; - if (type & SIGN) { - if (num < 0) { - sign = '-'; - num = -num; - size--; - } else if (type & PLUS) { - sign = '+'; - size--; - } else if (type & SPACE) { - sign = ' '; - size--; - } - } - if (type & SPECIAL) { - if (base == 16) - size -= 2; - else if (base == 8) - size--; - } - i = 0; - if (num == 0) - tmp[i++]='0'; - else while (num != 0) - tmp[i++] = digits[SkDoDiv(num,base, &num)]; - - if (i > precision) - precision = i; - size -= precision; - if (!(type&(ZEROPAD+LEFT))) - while(size-->0) - *str++ = ' '; - if (sign) - *str++ = sign; - if (type & SPECIAL) { - if (base==8) - *str++ = '0'; - else if (base==16) { - *str++ = '0'; - *str++ = digits[33]; - } + switch (orig) { + case 1: + offset += file->f_pos; + case 0: + if (offset >= 0) + return file->f_pos = offset; } - if (!(type & LEFT)) - while (size-- > 0) - *str++ = c; - while (i < precision--) - *str++ = '0'; - while (i-- > 0) - *str++ = tmp[i]; - while (size-- > 0) - *str++ = ' '; - - str[0] = '\0'; - - return strorg; + return -EINVAL; } - - +struct file_operations sk_proc_fops = { + .read = sk_read, + .llseek = sk_lseek, +}; diff -urN linux-2.5.70-bk9/drivers/net/wan/sdla.c linux-2.5.70-bk10/drivers/net/wan/sdla.c --- linux-2.5.70-bk9/drivers/net/wan/sdla.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/net/wan/sdla.c 2003-06-05 04:41:36.000000000 -0700 @@ -1682,11 +1682,13 @@ static void __exit exit_sdla(void) { +#ifdef MODULE unregister_netdev(&sdla0); if (sdla0.priv) kfree(sdla0.priv); if (sdla0.irq) free_irq(sdla0.irq, &sdla0); +#endif } MODULE_LICENSE("GPL"); diff -urN linux-2.5.70-bk9/drivers/parport/parport_pc.c linux-2.5.70-bk10/drivers/parport/parport_pc.c --- linux-2.5.70-bk9/drivers/parport/parport_pc.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk10/drivers/parport/parport_pc.c 2003-06-05 04:41:36.000000000 -0700 @@ -2979,10 +2979,10 @@ static int __init parport_pc_init_superio (int autoirq, int autodma) { const struct pci_device_id *id; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; int ret = 0; - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { id = pci_match_device (parport_pc_pci_tbl, pdev); if (id == NULL || id->driver_data >= last_sio) continue; diff -urN linux-2.5.70-bk9/drivers/pci/Makefile linux-2.5.70-bk10/drivers/pci/Makefile --- linux-2.5.70-bk9/drivers/pci/Makefile 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/Makefile 2003-06-05 04:41:36.000000000 -0700 @@ -12,6 +12,9 @@ obj-$(CONFIG_PCI) += setup-res.o endif +# Build the PCI Hotplug drivers if we were asked to +obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ + # # Some architectures use the generic PCI setup functions # diff -urN linux-2.5.70-bk9/drivers/pci/access.c linux-2.5.70-bk10/drivers/pci/access.c --- linux-2.5.70-bk9/drivers/pci/access.c 2003-05-26 18:01:02.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/access.c 2003-06-05 04:41:36.000000000 -0700 @@ -7,7 +7,7 @@ * configuration space. */ -spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; /* * Wrappers for all PCI configuration access functions. They just check @@ -60,4 +60,3 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); -EXPORT_SYMBOL(pci_lock); diff -urN linux-2.5.70-bk9/drivers/pci/bus.c linux-2.5.70-bk10/drivers/pci/bus.c --- linux-2.5.70-bk9/drivers/pci/bus.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/bus.c 2003-06-05 04:41:36.000000000 -0700 @@ -94,9 +94,7 @@ device_add(&dev->dev); list_add_tail(&dev->global_list, &pci_devices); -#ifdef CONFIG_PROC_FS pci_proc_attach_device(dev); -#endif pci_create_sysfs_dev_files(dev); } @@ -129,6 +127,5 @@ } } -EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL(pci_bus_add_devices); EXPORT_SYMBOL(pci_enable_bridges); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/Kconfig linux-2.5.70-bk10/drivers/pci/hotplug/Kconfig --- linux-2.5.70-bk9/drivers/pci/hotplug/Kconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/Kconfig 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,120 @@ +# +# PCI Hotplug support +# + +menu "PCI Hotplug Support" + depends on HOTPLUG + +config HOTPLUG_PCI + tristate "Support for PCI Hotplug (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + ---help--- + Say Y here if you have a motherboard with a PCI Hotplug controller. + This allows you to add and remove PCI cards while the machine is + powered up and running. The file system pcihpfs must be mounted + in order to interact with any PCI Hotplug controllers. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pci_hotplug. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +config HOTPLUG_PCI_COMPAQ + tristate "Compaq PCI Hotplug driver" + depends on HOTPLUG_PCI && X86 + help + Say Y here if you have a motherboard with a Compaq PCI Hotplug + controller. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpqphp. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +config HOTPLUG_PCI_COMPAQ_NVRAM + bool "Save configuration into NVRAM on Compaq servers" + depends on HOTPLUG_PCI_COMPAQ + help + Say Y here if you have a Compaq server that has a PCI Hotplug + controller. This will allow the PCI Hotplug driver to store the PCI + system configuration options in NVRAM. + + When in doubt, say N. + +config HOTPLUG_PCI_IBM + tristate "IBM PCI Hotplug driver" + depends on HOTPLUG_PCI && X86_IO_APIC && X86 + help + Say Y here if you have a motherboard with a IBM PCI Hotplug + controller. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpqphp. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +config HOTPLUG_PCI_ACPI + tristate "ACPI PCI Hotplug driver" + depends on ACPI_BUS && HOTPLUG_PCI + help + Say Y here if you have a system that supports PCI Hotplug using + ACPI. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called acpiphp. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +config HOTPLUG_PCI_CPCI + tristate "CompactPCI Hotplug driver" + depends on HOTPLUG_PCI + help + Say Y here if you have a CompactPCI system card with CompactPCI + hotswap support per the PICMG 2.1 specification. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpci_hotplug. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +config HOTPLUG_PCI_CPCI_ZT5550 + tristate "Ziatech ZT5550 CompactPCI Hotplug driver" + depends on HOTPLUG_PCI_CPCI && X86 + help + Say Y here if you have an Performance Technologies (formerly Intel, + formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpcihp_zt5550. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +config HOTPLUG_PCI_CPCI_GENERIC + tristate "Generic port I/O CompactPCI Hotplug driver" + depends on HOTPLUG_PCI_CPCI && X86 + help + Say Y here if you have a CompactPCI system card that exposes the #ENUM + hotswap signal as a bit in a system register that can be read through + standard port I/O. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpcihp_generic. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +endmenu + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/Makefile linux-2.5.70-bk10/drivers/pci/hotplug/Makefile --- linux-2.5.70-bk9/drivers/pci/hotplug/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/Makefile 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,44 @@ +# +# Makefile for the Linux kernel pci hotplug controller drivers. +# + +obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o +obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o +obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o + +pci_hotplug-objs := pci_hotplug_core.o + +ifdef CONFIG_HOTPLUG_PCI_CPCI +pci_hotplug-objs += cpci_hotplug_core.o \ + cpci_hotplug_pci.o +endif + +cpqphp-objs := cpqphp_core.o \ + cpqphp_ctrl.o \ + cpqphp_sysfs.o \ + cpqphp_pci.o + +ibmphp-objs := ibmphp_core.o \ + ibmphp_ebda.o \ + ibmphp_pci.o \ + ibmphp_res.o \ + ibmphp_hpc.o + +acpiphp-objs := acpiphp_core.o \ + acpiphp_glue.o \ + acpiphp_pci.o \ + acpiphp_res.o + +ifdef CONFIG_HOTPLUG_PCI_ACPI + EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi + ifdef CONFIG_ACPI_DEBUG + EXTRA_CFLAGS += -DACPI_DEBUG_OUTPUT + endif +endif + +ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) + cpqphp-objs += cpqphp_nvram.o +endif diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp.h linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp.h --- linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,262 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * , + * + * + */ + +#ifndef _ACPIPHP_H +#define _ACPIPHP_H + +#include +#include "pci_hotplug.h" + +#define dbg(format, arg...) \ + do { \ + if (acpiphp_debug) \ + printk(KERN_DEBUG "%s: " format, \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) + +#define SLOT_MAGIC 0x67267322 +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ + +struct acpiphp_bridge; +struct acpiphp_slot; +struct pci_resource; + +/* + * struct slot - slot information for each *physical* slot + */ +struct slot { + u32 magic; + u8 number; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; + + struct acpiphp_slot *acpi_slot; +}; + +/* + * struct pci_resource - describes pci resource (mem, pfmem, io, bus) + */ +struct pci_resource { + struct pci_resource * next; + u64 base; + u32 length; +}; + +/** + * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters + * @cache_line_size in DWORD + * @latency_timer in PCI clock + * @enable_SERR 0 or 1 + * @enable_PERR 0 or 1 + */ +struct hpp_param { + u8 cache_line_size; + u8 latency_timer; + u8 enable_SERR; + u8 enable_PERR; +}; + + +/** + * struct acpiphp_bridge - PCI bridge information + * + * for each bridge device in ACPI namespace + */ +struct acpiphp_bridge { + struct list_head list; + acpi_handle handle; + struct acpiphp_slot *slots; + int type; + int nr_slots; + + u8 seg; + u8 bus; + u8 sub; + + u32 flags; + + /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ + struct pci_bus *pci_bus; + + /* PCI-to-PCI bridge device */ + struct pci_dev *pci_dev; + + /* ACPI 2.0 _HPP parameters */ + struct hpp_param hpp; + + spinlock_t res_lock; + + /* available resources on this bus */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; +}; + + +/** + * struct acpiphp_slot - PCI slot information + * + * PCI slot information for each *physical* PCI slot + */ +struct acpiphp_slot { + struct acpiphp_slot *next; + struct acpiphp_bridge *bridge; /* parent */ + struct list_head funcs; /* one slot may have different + objects (i.e. for each function) */ + struct semaphore crit_sect; + + u32 id; /* slot id (serial #) for hotplug core */ + u8 device; /* pci device# */ + + u32 sun; /* ACPI _SUN (slot unique number) */ + u32 slotno; /* slot number relative to bridge */ + u32 flags; /* see below */ +}; + + +/** + * struct acpiphp_func - PCI function information + * + * PCI function information for each object in ACPI namespace + * typically 8 objects per slot (i.e. for each PCI function) + */ +struct acpiphp_func { + struct acpiphp_slot *slot; /* parent */ + + struct list_head sibling; + struct pci_dev *pci_dev; + + acpi_handle handle; + + u8 function; /* pci function# */ + u32 flags; /* see below */ + + /* resources used for this function */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; +}; + + +/* PCI bus bridge HID */ +#define ACPI_PCI_HOST_HID "PNP0A03" + +/* PCI BRIDGE type */ +#define BRIDGE_TYPE_HOST 0 +#define BRIDGE_TYPE_P2P 1 + +/* ACPI _STA method value (ignore bit 4; battery present) */ +#define ACPI_STA_PRESENT (0x00000001) +#define ACPI_STA_ENABLED (0x00000002) +#define ACPI_STA_SHOW_IN_UI (0x00000004) +#define ACPI_STA_FUNCTIONING (0x00000008) +#define ACPI_STA_ALL (0x0000000f) + +/* bridge flags */ +#define BRIDGE_HAS_STA (0x00000001) +#define BRIDGE_HAS_EJ0 (0x00000002) +#define BRIDGE_HAS_HPP (0x00000004) +#define BRIDGE_HAS_PS0 (0x00000010) +#define BRIDGE_HAS_PS1 (0x00000020) +#define BRIDGE_HAS_PS2 (0x00000040) +#define BRIDGE_HAS_PS3 (0x00000080) + +/* slot flags */ + +#define SLOT_POWEREDON (0x00000001) +#define SLOT_ENABLED (0x00000002) +#define SLOT_MULTIFUNCTION (x000000004) + +/* function flags */ + +#define FUNC_HAS_STA (0x00000001) +#define FUNC_HAS_EJ0 (0x00000002) +#define FUNC_HAS_PS0 (0x00000010) +#define FUNC_HAS_PS1 (0x00000020) +#define FUNC_HAS_PS2 (0x00000040) +#define FUNC_HAS_PS3 (0x00000080) + +/* not yet */ +#define SLOT_SUPPORT_66MHZ (0x00010000) +#define SLOT_SUPPORT_100MHZ (0x00020000) +#define SLOT_SUPPORT_133MHZ (0x00040000) +#define SLOT_SUPPORT_PCIX (0x00080000) + +/* function prototypes */ + +/* acpiphp_glue.c */ +extern int acpiphp_glue_init (void); +extern void acpiphp_glue_exit (void); +extern int acpiphp_get_num_slots (void); +extern struct acpiphp_slot *get_slot_from_id (int id); +typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); +extern int acpiphp_for_each_slot (acpiphp_callback fn, void *data); + +extern int acpiphp_check_bridge (struct acpiphp_bridge *bridge); +extern int acpiphp_enable_slot (struct acpiphp_slot *slot); +extern int acpiphp_disable_slot (struct acpiphp_slot *slot); +extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); +extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); +extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); +extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); + +/* acpiphp_pci.c */ +extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); +extern int acpiphp_configure_slot (struct acpiphp_slot *slot); +extern int acpiphp_configure_function (struct acpiphp_func *func); +extern int acpiphp_unconfigure_function (struct acpiphp_func *func); +extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); +extern int acpiphp_init_func_resource (struct acpiphp_func *func); + +/* acpiphp_res.c */ +extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); +extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); +extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); +extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); +extern void acpiphp_free_resource (struct pci_resource **res); +extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ +extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ + +/* variables */ +extern int acpiphp_debug; + +#endif /* _ACPIPHP_H */ diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_core.c linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_core.c --- linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_core.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,505 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * , + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" +#include "acpiphp.h" + +static LIST_HEAD(slot_list); + +#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) + #define MY_NAME "acpiphp" +#else + #define MY_NAME THIS_MODULE->name +#endif + +static int debug; +int acpiphp_debug; + +/* local variables */ +static int num_slots; + +#define DRIVER_VERSION "0.4" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " +#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); + +static struct hotplug_slot_ops acpi_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL\n", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot\n", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!\n", function); + return -1; + } + return 0; +} + + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check(slot, function)) + return NULL; + return slot; +} + + +/** + * enable_slot - power on and enable a slot + * @hotplug_slot: slot to enable + * + * Actual tasks are done in acpiphp_enable_slot() + * + */ +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* enable the specified slot */ + retval = acpiphp_enable_slot(slot->acpi_slot); + + return retval; +} + + +/** + * disable_slot - disable and power off a slot + * @hotplug_slot: slot to disable + * + * Actual tasks are done in acpiphp_disable_slot() + * + */ +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* disable the specified slot */ + retval = acpiphp_disable_slot(slot->acpi_slot); + + return retval; +} + + +/** + * set_attention_status - set attention LED + * + * TBD: + * ACPI doesn't have known method to manipulate + * attention status LED. + * + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + int retval = 0; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + switch (status) { + case 0: + /* FIXME turn light off */ + hotplug_slot->info->attention_status = 0; + break; + + case 1: + default: + /* FIXME turn light on */ + hotplug_slot->info->attention_status = 1; + break; + } + + return retval; +} + + +/** + * hardware_test - hardware test + * + * We have nothing to do for now... + * + */ +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + err("No hardware tests are defined for this driver\n"); + retval = -ENODEV; + + return retval; +} + + +/** + * get_power_status - get power status of a slot + * @hotplug_slot: slot to get status + * @value: pointer to store status + * + * Some platforms may not implement _STA method properly. + * In that case, the value returned may not be reliable. + * + */ +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_power_status(slot->acpi_slot); + + return retval; +} + + +/** + * get_attention_status - get attention LED status + * + * TBD: + * ACPI doesn't provide any formal means to access attention LED status. + * + */ +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + int retval = 0; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = hotplug_slot->info->attention_status; + + return retval; +} + + +/** + * get_latch_status - get latch status of a slot + * @hotplug_slot: slot to get status + * @value: pointer to store status + * + * ACPI doesn't provide any formal means to access latch status. + * Instead, we fake latch status from _STA + * + */ +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_latch_status(slot->acpi_slot); + + return retval; +} + + +/** + * get_adapter_status - get adapter status of a slot + * @hotplug_slot: slot to get status + * @value: pointer to store status + * + * ACPI doesn't provide any formal means to access adapter status. + * Instead, we fake adapter status from _STA + * + */ +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_adapter_status(slot->acpi_slot); + + return retval; +} + + +/* return dummy value because ACPI doesn't provide any method... */ +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + + +/* return dummy value because ACPI doesn't provide any method... */ +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + + +static int init_acpi (void) +{ + int retval; + + /* initialize internal data structure etc. */ + retval = acpiphp_glue_init(); + + /* read initial number of slots */ + if (!retval) { + num_slots = acpiphp_get_num_slots(); + if (num_slots == 0) + retval = -ENODEV; + } + + return retval; +} + + +/** + * make_slot_name - make a slot name that appears in pcihpfs + * @slot: slot to name + * + */ +static void make_slot_name (struct slot *slot) +{ + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", + slot->acpi_slot->sun, + slot->acpi_slot->bridge->bus, + slot->acpi_slot->device); +} + +/** + * init_slots - initialize 'struct slot' structures for each slot + * + */ +static int init_slots (void) +{ + struct slot *slot; + int retval = 0; + int i; + + for (i = 0; i < num_slots; ++i) { + slot = kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + memset(slot, 0, sizeof(struct slot)); + + slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) { + kfree(slot); + return -ENOMEM; + } + memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); + + slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); + if (!slot->hotplug_slot->info) { + kfree(slot->hotplug_slot); + kfree(slot); + return -ENOMEM; + } + memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); + + slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); + if (!slot->hotplug_slot->name) { + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot); + kfree(slot); + return -ENOMEM; + } + + slot->magic = SLOT_MAGIC; + slot->number = i; + + slot->hotplug_slot->private = slot; + slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + + slot->acpi_slot = get_slot_from_id(i); + slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot); + slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); + slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); + + make_slot_name(slot); + + retval = pci_hp_register(slot->hotplug_slot); + if (retval) { + err("pci_hp_register failed with error %d\n", retval); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + return retval; + } + + /* add slot to our internal list */ + list_add(&slot->slot_list, &slot_list); + info("Slot [%s] registered\n", slot->hotplug_slot->name); + } + + return retval; +} + + +static void cleanup_slots (void) +{ + struct list_head *tmp, *n; + struct slot *slot; + + list_for_each_safe (tmp, n, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + } + + return; +} + + +static int __init acpiphp_init(void) +{ + int retval; + + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + acpiphp_debug = debug; + + /* read all the ACPI info from the system */ + retval = init_acpi(); + if (retval) + return retval; + + retval = init_slots(); + if (retval) + return retval; + + return 0; +} + + +static void __exit acpiphp_exit(void) +{ + cleanup_slots(); + /* deallocate internal data structures etc. */ + acpiphp_glue_exit(); +} + +module_init(acpiphp_init); +module_exit(acpiphp_exit); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_glue.c linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_glue.c --- linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_glue.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_glue.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1336 @@ +/* + * ACPI PCI HotPlug glue functions to ACPI CA subsystem + * + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" +#include "pci_hotplug.h" +#include "acpiphp.h" + +static LIST_HEAD(bridge_list); + +#define MY_NAME "acpiphp_glue" + +static void handle_hotplug_event_bridge (acpi_handle, u32, void *); +static void handle_hotplug_event_func (acpi_handle, u32, void *); + +/* + * initialization & terminatation routines + */ + +/** + * is_ejectable - determine if a slot is ejectable + * @handle: handle to acpi namespace + * + * Ejectable slot should satisfy at least these conditions: + * + * 1. has _ADR method + * 2. has _EJ0 method + * + * optionally + * + * 1. has _STA method + * 2. has _PS0 method + * 3. has _PS3 method + * 4. .. + * + */ +static int is_ejectable (acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_ADR", &tmp); + if (ACPI_FAILURE(status)) { + return 0; + } + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) { + return 0; + } + + return 1; +} + + +/* callback routine to check the existence of ejectable slots */ +static acpi_status +is_ejectable_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + if (is_ejectable(handle)) { + (*count)++; + /* only one ejectable slot is enough */ + return AE_CTRL_TERMINATE; + } else { + return AE_OK; + } +} + + +/* callback routine to register each ACPI PCI slot object */ +static acpi_status +register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; + struct acpiphp_slot *slot; + struct acpiphp_func *newfunc; + acpi_handle tmp; + acpi_status status = AE_OK; + unsigned long adr, sun; + int device, function; + static int num_slots = 0; /* XXX if we support I/O node hotplug... */ + + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); + + if (ACPI_FAILURE(status)) + return AE_OK; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + + if (ACPI_FAILURE(status)) + return AE_OK; + + device = (adr >> 16) & 0xffff; + function = adr & 0xffff; + + newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL); + if (!newfunc) + return AE_NO_MEMORY; + memset(newfunc, 0, sizeof(struct acpiphp_func)); + + INIT_LIST_HEAD(&newfunc->sibling); + newfunc->handle = handle; + newfunc->function = function; + newfunc->flags = FUNC_HAS_EJ0; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) + newfunc->flags |= FUNC_HAS_STA; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) + newfunc->flags |= FUNC_HAS_PS0; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) + newfunc->flags |= FUNC_HAS_PS3; + + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + sun = -1; + + /* search for objects that share the same slot */ + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->device == device) { + if (slot->sun != sun) + warn("sibling found, but _SUN doesn't match!\n"); + break; + } + + if (!slot) { + slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); + if (!slot) { + kfree(newfunc); + return AE_NO_MEMORY; + } + + memset(slot, 0, sizeof(struct acpiphp_slot)); + slot->bridge = bridge; + slot->id = num_slots++; + slot->device = device; + slot->sun = sun; + INIT_LIST_HEAD(&slot->funcs); + init_MUTEX(&slot->crit_sect); + + slot->next = bridge->slots; + bridge->slots = slot; + + bridge->nr_slots++; + + dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", + slot->bridge->bus, slot->device, slot->sun); + } + + newfunc->slot = slot; + list_add_tail(&newfunc->sibling, &slot->funcs); + + /* associate corresponding pci_dev */ + newfunc->pci_dev = pci_find_slot(bridge->bus, + PCI_DEVFN(device, function)); + if (newfunc->pci_dev) { + if (acpiphp_init_func_resource(newfunc) < 0) { + kfree(newfunc); + return AE_ERROR; + } + slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); + } + + /* install notify handler */ + status = acpi_install_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func, + newfunc); + + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); + kfree(newfunc); + return status; + } + + return AE_OK; +} + + +/* see if it's worth looking at this bridge */ +static int detect_ejectable_slots (acpi_handle *bridge_handle) +{ + acpi_status status; + int count; + + count = 0; + + /* only check slots defined directly below bridge object */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, + is_ejectable_slot, (void *)&count, NULL); + + return count; +} + + +/* decode ACPI _CRS data and convert into our internal resource list + * TBD: _TRA, etc. + */ +static acpi_status +decode_acpi_resource (struct acpi_resource *resource, void *context) +{ + struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; + struct acpi_resource_address64 address; + struct pci_resource *res; + + if (resource->id != ACPI_RSTYPE_ADDRESS16 && + resource->id != ACPI_RSTYPE_ADDRESS32 && + resource->id != ACPI_RSTYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + + if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { + dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, address.min_address_range, address.max_address_range); + res = acpiphp_make_resource(address.min_address_range, + address.address_length); + if (!res) { + err("out of memory\n"); + return AE_OK; + } + + switch (address.resource_type) { + case ACPI_MEMORY_RANGE: + if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { + res->next = bridge->p_mem_head; + bridge->p_mem_head = res; + } else { + res->next = bridge->mem_head; + bridge->mem_head = res; + } + break; + case ACPI_IO_RANGE: + res->next = bridge->io_head; + bridge->io_head = res; + break; + case ACPI_BUS_NUMBER_RANGE: + res->next = bridge->bus_head; + bridge->bus_head = res; + break; + default: + /* invalid type */ + kfree(res); + break; + } + } + + return AE_OK; +} + +/* decode ACPI 2.0 _HPP hot plug parameters */ +static void decode_hpp(struct acpiphp_bridge *bridge) +{ + acpi_status status; + struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + union acpi_object *package; + int i; + + /* default numbers */ + bridge->hpp.cache_line_size = 0x10; + bridge->hpp.latency_timer = 0x40; + bridge->hpp.enable_SERR = 0; + bridge->hpp.enable_PERR = 0; + + status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); + + if (ACPI_FAILURE(status)) { + dbg("_HPP evaluation failed\n"); + return; + } + + package = (union acpi_object *) buffer.pointer; + + if (!package || package->type != ACPI_TYPE_PACKAGE || + package->package.count != 4 || !package->package.elements) { + err("invalid _HPP object; ignoring\n"); + goto err_exit; + } + + for (i = 0; i < 4; i++) { + if (package->package.elements[i].type != ACPI_TYPE_INTEGER) { + err("invalid _HPP parameter type; ignoring\n"); + goto err_exit; + } + } + + bridge->hpp.cache_line_size = package->package.elements[0].integer.value; + bridge->hpp.latency_timer = package->package.elements[1].integer.value; + bridge->hpp.enable_SERR = package->package.elements[2].integer.value; + bridge->hpp.enable_PERR = package->package.elements[3].integer.value; + + dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n", + bridge->hpp.cache_line_size, + bridge->hpp.latency_timer, + bridge->hpp.enable_SERR, + bridge->hpp.enable_PERR); + + bridge->flags |= BRIDGE_HAS_HPP; + + err_exit: + kfree(buffer.pointer); +} + + +/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ +static void init_bridge_misc (struct acpiphp_bridge *bridge) +{ + acpi_status status; + + /* decode ACPI 2.0 _HPP (hot plug parameters) */ + decode_hpp(bridge); + + /* subtract all resources already allocated */ + acpiphp_detect_pci_resource(bridge); + + /* register all slot objects under this bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, + register_slot, bridge, NULL); + + /* install notify handler */ + status = acpi_install_notify_handler(bridge->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, + bridge); + + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); + } + + list_add(&bridge->list, &bridge_list); + + dbg("Bridge resource:\n"); + acpiphp_dump_resource(bridge); +} + + +/* allocate and initialize host bridge data structure */ +static void add_host_bridge (acpi_handle *handle, int seg, int bus) +{ + acpi_status status; + struct acpiphp_bridge *bridge; + + bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); + if (bridge == NULL) + return; + + memset(bridge, 0, sizeof(struct acpiphp_bridge)); + + bridge->type = BRIDGE_TYPE_HOST; + bridge->handle = handle; + bridge->seg = seg; + bridge->bus = bus; + + bridge->pci_bus = pci_find_bus(bus); + + bridge->res_lock = SPIN_LOCK_UNLOCKED; + + /* to be overridden when we decode _CRS */ + bridge->sub = bridge->bus; + + /* decode resources */ + + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + decode_acpi_resource, bridge); + + if (ACPI_FAILURE(status)) { + err("failed to decode bridge resources\n"); + kfree(bridge); + return; + } + + acpiphp_resource_sort_and_combine(&bridge->io_head); + acpiphp_resource_sort_and_combine(&bridge->mem_head); + acpiphp_resource_sort_and_combine(&bridge->p_mem_head); + acpiphp_resource_sort_and_combine(&bridge->bus_head); + + dbg("ACPI _CRS resource:\n"); + acpiphp_dump_resource(bridge); + + if (bridge->bus_head) { + bridge->bus = bridge->bus_head->base; + bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; + } + + init_bridge_misc(bridge); +} + + +/* allocate and initialize PCI-to-PCI bridge data structure */ +static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn) +{ + struct acpiphp_bridge *bridge; + u8 tmp8; + u16 tmp16; + u64 base64, limit64; + u32 base, limit, base32u, limit32u; + + bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); + if (bridge == NULL) { + err("out of memory\n"); + return; + } + + memset(bridge, 0, sizeof(struct acpiphp_bridge)); + + bridge->type = BRIDGE_TYPE_P2P; + bridge->handle = handle; + bridge->seg = seg; + + bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); + if (!bridge->pci_dev) { + err("Can't get pci_dev\n"); + kfree(bridge); + return; + } + + bridge->pci_bus = bridge->pci_dev->subordinate; + if (!bridge->pci_bus) { + err("This is not a PCI-to-PCI bridge!\n"); + kfree(bridge); + return; + } + + bridge->res_lock = SPIN_LOCK_UNLOCKED; + + bridge->bus = bridge->pci_bus->number; + bridge->sub = bridge->pci_bus->subordinate; + + /* + * decode resources under this P2P bridge + */ + + /* I/O resources */ + pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); + base = tmp8; + pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); + limit = tmp8; + + switch (base & PCI_IO_RANGE_TYPE_MASK) { + case PCI_IO_RANGE_TYPE_16: + base = (base << 8) & 0xf000; + limit = ((limit << 8) & 0xf000) + 0xfff; + bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->io_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("16bit I/O range: %04x-%04x\n", + (u32)bridge->io_head->base, + (u32)(bridge->io_head->base + bridge->io_head->length - 1)); + break; + case PCI_IO_RANGE_TYPE_32: + pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); + base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); + pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); + limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; + bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->io_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit I/O range: %08x-%08x\n", + (u32)bridge->io_head->base, + (u32)(bridge->io_head->base + bridge->io_head->length - 1)); + break; + case 0x0f: + dbg("I/O space unsupported\n"); + break; + default: + warn("Unknown I/O range type\n"); + } + + /* Memory resources (mandatory for P2P bridge) */ + pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); + base = (tmp16 & 0xfff0) << 16; + pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); + limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; + bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit Memory range: %08x-%08x\n", + (u32)bridge->mem_head->base, + (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); + + /* Prefetchable Memory resources (optional) */ + pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); + base = tmp16; + pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); + limit = tmp16; + + switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { + case PCI_PREF_RANGE_TYPE_32: + base = (base & 0xfff0) << 16; + limit = ((limit & 0xfff0) << 16) | 0xfffff; + bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->p_mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit Prefetchable memory range: %08x-%08x\n", + (u32)bridge->p_mem_head->base, + (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); + break; + case PCI_PREF_RANGE_TYPE_64: + pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); + pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); + base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); + limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; + + bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); + if (!bridge->p_mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", + (u32)(bridge->p_mem_head->base >> 32), + (u32)(bridge->p_mem_head->base & 0xffffffff), + (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), + (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); + break; + case 0x0f: + break; + default: + warn("Unknown prefetchale memory type\n"); + } + + init_bridge_misc(bridge); +} + + +/* callback routine to find P2P bridges */ +static acpi_status +find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_handle dummy_handle; + unsigned long *segbus = context; + unsigned long tmp; + int seg, bus, device, function; + struct pci_dev *dev; + + /* get PCI address */ + seg = (*segbus >> 8) & 0xff; + bus = *segbus & 0xff; + + status = acpi_get_handle(handle, "_ADR", &dummy_handle); + if (ACPI_FAILURE(status)) + return AE_OK; /* continue */ + + status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dbg("%s: _ADR evaluation failure\n", __FUNCTION__); + return AE_OK; + } + + device = (tmp >> 16) & 0xffff; + function = tmp & 0xffff; + + dev = pci_find_slot(bus, PCI_DEVFN(device, function)); + + if (!dev) + return AE_OK; + + if (!dev->subordinate) + return AE_OK; + + /* check if this bridge has ejectable slots */ + if (detect_ejectable_slots(handle) > 0) { + dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name); + add_p2p_bridge(handle, seg, bus, device, function); + } + + return AE_OK; +} + + +/* find hot-pluggable slots, and then find P2P bridge */ +static int add_bridges(struct acpi_device *device) +{ + acpi_handle *handle = device->handle; + acpi_status status; + unsigned long tmp; + int seg, bus; + acpi_handle dummy_handle; + + /* if the bridge doesn't have _STA, we assume it is always there */ + status = acpi_get_handle(handle, "_STA", &dummy_handle); + if (ACPI_SUCCESS(status)) { + status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dbg("%s: _STA evaluation failure\n", __FUNCTION__); + return 0; + } + if ((tmp & ACPI_STA_FUNCTIONING) == 0) + /* don't register this object */ + return 0; + } + + /* get PCI segment number */ + status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); + + seg = ACPI_SUCCESS(status) ? tmp : 0; + + /* get PCI bus number */ + status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); + + if (ACPI_SUCCESS(status)) { + bus = tmp; + } else { + warn("can't get bus number, assuming 0\n"); + bus = 0; + } + + /* check if this bridge has ejectable slots */ + if (detect_ejectable_slots(handle) > 0) { + dbg("found PCI host-bus bridge with hot-pluggable slots\n"); + add_host_bridge(handle, seg, bus); + return 0; + } + + tmp = seg << 8 | bus; + + /* search P2P bridges under this host bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, + find_p2p_bridge, &tmp, NULL); + + if (ACPI_FAILURE(status)) + warn("find_p2p_bridge faied (error code = 0x%x)\n",status); + + return 0; +} + + +static int power_on_slot (struct acpiphp_slot *slot) +{ + acpi_status status; + struct acpiphp_func *func; + struct list_head *l; + int retval = 0; + + /* is this already enabled? */ + if (slot->flags & SLOT_POWEREDON) + goto err_exit; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_PS0) { + dbg("%s: executing _PS0 on %s\n", __FUNCTION__, + func->pci_dev->slot_name); + status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _PS0 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } + } + } + + /* TBD: evaluate _STA to check if the slot is enabled */ + + slot->flags |= SLOT_POWEREDON; + + err_exit: + return retval; +} + + +static int power_off_slot (struct acpiphp_slot *slot) +{ + acpi_status status; + struct acpiphp_func *func; + struct list_head *l; + struct acpi_object_list arg_list; + union acpi_object arg; + + int retval = 0; + + /* is this already enabled? */ + if ((slot->flags & SLOT_POWEREDON) == 0) + goto err_exit; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_PS3) { + dbg("%s: executing _PS3 on %s\n", __FUNCTION__, + func->pci_dev->slot_name); + status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _PS3 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } + } + } + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_EJ0) { + dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, + func->pci_dev->slot_name); + + /* _EJ0 method take one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } + } + } + + /* TBD: evaluate _STA to check if the slot is disabled */ + + slot->flags &= (~SLOT_POWEREDON); + + err_exit: + return retval; +} + + +/** + * enable_device - enable, configure a slot + * @slot: slot to be enabled + * + * This function should be called per *physical slot*, + * not per each slot object in ACPI namespace. + * + */ +static int enable_device (struct acpiphp_slot *slot) +{ + u8 bus; + struct pci_dev *dev; + struct pci_bus *child; + struct list_head *l; + struct acpiphp_func *func; + int retval = 0; + int num; + + if (slot->flags & SLOT_ENABLED) + goto err_exit; + + /* sanity check: dev should be NULL when hot-plugged in */ + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + if (dev) { + /* This case shouldn't happen */ + err("pci_dev structure already exists.\n"); + retval = -1; + goto err_exit; + } + + /* allocate resources to device */ + retval = acpiphp_configure_slot(slot); + if (retval) + goto err_exit; + + /* returned `dev' is the *first function* only! */ + num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); + if (num) + pci_bus_add_devices(slot->bridge->pci_bus); + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + + if (!dev) { + err("No new device found\n"); + retval = -1; + goto err_exit; + } + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); + pci_do_scan_bus(child); + } + + /* associate pci_dev to our representation */ + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + func->pci_dev = pci_find_slot(slot->bridge->bus, + PCI_DEVFN(slot->device, + func->function)); + if (!func->pci_dev) + continue; + + /* configure device */ + retval = acpiphp_configure_function(func); + if (retval) + goto err_exit; + } + + slot->flags |= SLOT_ENABLED; + + dbg("Available resources:\n"); + acpiphp_dump_resource(slot->bridge); + + err_exit: + return retval; +} + + +/** + * disable_device - disable a slot + */ +static int disable_device (struct acpiphp_slot *slot) +{ + int retval = 0; + struct acpiphp_func *func; + struct list_head *l; + + /* is this slot already disabled? */ + if (!(slot->flags & SLOT_ENABLED)) + goto err_exit; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->pci_dev) { + if (acpiphp_unconfigure_function(func) == 0) { + func->pci_dev = NULL; + } else { + err("failed to unconfigure device\n"); + retval = -1; + goto err_exit; + } + } + } + + slot->flags &= (~SLOT_ENABLED); + + err_exit: + return retval; +} + + +/** + * get_slot_status - get ACPI slot status + * + * if a slot has _STA for each function and if any one of them + * returned non-zero status, return it + * + * if a slot doesn't have _STA and if any one of its functions' + * configuration space is configured, return 0x0f as a _STA + * + * otherwise return 0 + */ +static unsigned int get_slot_status (struct acpiphp_slot *slot) +{ + acpi_status status; + unsigned long sta = 0; + u32 dvid; + struct list_head *l; + struct acpiphp_func *func; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_STA) { + status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + break; + } else { + pci_bus_read_config_dword(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, + func->function), + PCI_VENDOR_ID, &dvid); + if (dvid != 0xffffffff) { + sta = ACPI_STA_ALL; + break; + } + } + } + + return (unsigned int)sta; +} + + +/* + * ACPI event handlers + */ + +/** + * handle_hotplug_event_bridge - handle ACPI event on bridges + * + * @handle: Notify()'ed acpi_handle + * @type: Notify code + * @context: pointer to acpiphp_bridge structure + * + * handles ACPI event notification on {host,p2p} bridges + * + */ +static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *context) +{ + struct acpiphp_bridge *bridge; + char objname[64]; + struct acpi_buffer buffer = { .length = sizeof(objname), + .pointer = objname }; + + bridge = (struct acpiphp_bridge *)context; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* bus re-enumerate */ + dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); + acpiphp_check_bridge(bridge); + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* device check */ + dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); + acpiphp_check_bridge(bridge); + break; + + case ACPI_NOTIFY_DEVICE_WAKE: + /* wake event */ + dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* request device eject */ + dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); + break; + + default: + warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); + break; + } +} + + +/** + * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * + * @handle: Notify()'ed acpi_handle + * @type: Notify code + * @context: pointer to acpiphp_func structure + * + * handles ACPI event notification on slots + * + */ +static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *context) +{ + struct acpiphp_func *func; + char objname[64]; + struct acpi_buffer buffer = { .length = sizeof(objname), + .pointer = objname }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + func = (struct acpiphp_func *)context; + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* bus re-enumerate */ + dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); + acpiphp_enable_slot(func->slot); + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* device check : re-enumerate from parent bus */ + dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); + acpiphp_check_bridge(func->slot->bridge); + break; + + case ACPI_NOTIFY_DEVICE_WAKE: + /* wake event */ + dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* request device eject */ + dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); + acpiphp_disable_slot(func->slot); + break; + + default: + warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); + break; + } +} + +static struct acpi_driver acpi_pci_hp_driver = { + .name = "pci_hp", + .class = "", + .ids = ACPI_PCI_HOST_HID, + .ops = { + .add = add_bridges, + } +}; + +/** + * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures + * + */ +int acpiphp_glue_init (void) +{ + acpi_status status; + + if (list_empty(&pci_root_buses)) + return -1; + + status = acpi_bus_register_driver(&acpi_pci_hp_driver); + + if (ACPI_FAILURE(status)) { + err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); + return -1; + } + + return 0; +} + + +/** + * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures + * + * This function frees all data allocated in acpiphp_glue_init() + */ +void acpiphp_glue_exit (void) +{ + struct list_head *l1, *l2, *n1, *n2; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot, *next; + struct acpiphp_func *func; + acpi_status status; + + list_for_each_safe (l1, n1, &bridge_list) { + bridge = (struct acpiphp_bridge *)l1; + slot = bridge->slots; + while (slot) { + next = slot->next; + list_for_each_safe (l2, n2, &slot->funcs) { + func = list_entry(l2, struct acpiphp_func, sibling); + acpiphp_free_resource(&func->io_head); + acpiphp_free_resource(&func->mem_head); + acpiphp_free_resource(&func->p_mem_head); + acpiphp_free_resource(&func->bus_head); + status = acpi_remove_notify_handler(func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + kfree(func); + } + kfree(slot); + slot = next; + } + status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + + acpiphp_free_resource(&bridge->io_head); + acpiphp_free_resource(&bridge->mem_head); + acpiphp_free_resource(&bridge->p_mem_head); + acpiphp_free_resource(&bridge->bus_head); + + kfree(bridge); + } +} + + +/** + * acpiphp_get_num_slots - count number of slots in a system + */ +int acpiphp_get_num_slots (void) +{ + struct list_head *node; + struct acpiphp_bridge *bridge; + int num_slots; + + num_slots = 0; + + list_for_each (node, &bridge_list) { + bridge = (struct acpiphp_bridge *)node; + dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); + num_slots += bridge->nr_slots; + } + + dbg("Total %dslots\n", num_slots); + return num_slots; +} + + +/** + * acpiphp_for_each_slot - call function for each slot + * @fn: callback function + * @data: context to be passed to callback function + * + */ +int acpiphp_for_each_slot(acpiphp_callback fn, void *data) +{ + struct list_head *node; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot; + int retval = 0; + + list_for_each (node, &bridge_list) { + bridge = (struct acpiphp_bridge *)node; + for (slot = bridge->slots; slot; slot = slot->next) { + retval = fn(slot, data); + if (!retval) + goto err_exit; + } + } + + err_exit: + return retval; +} + + +/* search matching slot from id */ +struct acpiphp_slot *get_slot_from_id (int id) +{ + struct list_head *node; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot; + + list_for_each (node, &bridge_list) { + bridge = (struct acpiphp_bridge *)node; + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->id == id) + return slot; + } + + /* should never happen! */ + err("%s: no object for id %d\n",__FUNCTION__, id); + return 0; +} + + +/** + * acpiphp_enable_slot - power on slot + */ +int acpiphp_enable_slot (struct acpiphp_slot *slot) +{ + int retval; + + down(&slot->crit_sect); + + /* wake up all functions */ + retval = power_on_slot(slot); + if (retval) + goto err_exit; + + if (get_slot_status(slot) == ACPI_STA_ALL) + /* configure all functions */ + retval = enable_device(slot); + + err_exit: + up(&slot->crit_sect); + return retval; +} + + +/** + * acpiphp_disable_slot - power off slot + */ +int acpiphp_disable_slot (struct acpiphp_slot *slot) +{ + int retval = 0; + + down(&slot->crit_sect); + + /* unconfigure all functions */ + retval = disable_device(slot); + if (retval) + goto err_exit; + + /* power off all functions */ + retval = power_off_slot(slot); + if (retval) + goto err_exit; + + acpiphp_resource_sort_and_combine(&slot->bridge->io_head); + acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); + acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); + acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); + dbg("Available resources:\n"); + acpiphp_dump_resource(slot->bridge); + + err_exit: + up(&slot->crit_sect); + return retval; +} + + +/** + * acpiphp_check_bridge - re-enumerate devices + */ +int acpiphp_check_bridge (struct acpiphp_bridge *bridge) +{ + struct acpiphp_slot *slot; + unsigned int sta; + int retval = 0; + int enabled, disabled; + + enabled = disabled = 0; + + for (slot = bridge->slots; slot; slot = slot->next) { + sta = get_slot_status(slot); + if (slot->flags & SLOT_ENABLED) { + /* if enabled but not present, disable */ + if (sta != ACPI_STA_ALL) { + retval = acpiphp_disable_slot(slot); + if (retval) { + err("Error occurred in enabling\n"); + up(&slot->crit_sect); + goto err_exit; + } + enabled++; + } + } else { + /* if disabled but present, enable */ + if (sta == ACPI_STA_ALL) { + retval = acpiphp_enable_slot(slot); + if (retval) { + err("Error occurred in enabling\n"); + up(&slot->crit_sect); + goto err_exit; + } + disabled++; + } + } + } + + dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); + + err_exit: + return retval; +} + + +/* + * slot enabled: 1 + * slot disabled: 0 + */ +u8 acpiphp_get_power_status (struct acpiphp_slot *slot) +{ + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_ENABLED) ? 1 : 0; +} + + +/* + * attention LED ON: 1 + * OFF: 0 + * + * TBD + * no direct attention led status information via ACPI + * + */ +u8 acpiphp_get_attention_status (struct acpiphp_slot *slot) +{ + return 0; +} + + +/* + * latch closed: 1 + * latch open: 0 + */ +u8 acpiphp_get_latch_status (struct acpiphp_slot *slot) +{ + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; +} + + +/* + * adapter presence : 1 + * absence : 0 + */ +u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot) +{ + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta == 0) ? 0 : 1; +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_pci.c linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_pci.c --- linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_pci.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_pci.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,511 @@ +/* + * ACPI PCI HotPlug PCI configuration space management + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include "../pci.h" +#include "pci_hotplug.h" +#include "acpiphp.h" + +#define MY_NAME "acpiphp_pci" + + +/* allocate mem/pmem/io resource to a new function */ +static int init_config_space (struct acpiphp_func *func) +{ + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct acpiphp_bridge *bridge; + struct pci_resource *res; + struct pci_bus *pbus; + int bus, device, function; + unsigned int devfn; + u16 tmp; + + bridge = func->slot->bridge; + pbus = bridge->pci_bus; + bus = bridge->bus; + device = func->slot->device; + function = func->function; + devfn = PCI_DEVFN(device, function); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_bus_write_config_dword(pbus, devfn, + address[count], 0xFFFFFFFF); + pci_bus_read_config_dword(pbus, devfn, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); + + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + + len = bar & 0xFFFFFFFC; + len = ~len + 1; + + dbg("len in IO %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_io_resource(&bridge->io_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested io for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + res->next = func->io_head; + func->io_head = res; + + } else { + /* This is Memory */ + if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + dbg("len in PFMEM %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource(&bridge->p_mem_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + + if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("inside the pfmem 64 case, count %d\n", count); + count += 1; + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)(res->base >> 32)); + } + + res->next = func->p_mem_head; + func->p_mem_head = res; + + } else { + /* regular memory */ + + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + dbg("len in MEM %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource(&bridge->mem_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + + if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)(res->base >> 32)); + } + + res->next = func->mem_head; + func->mem_head = res; + + } + } + } + + /* disable expansion rom */ + pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); + + /* set PCI parameters from _HPP */ + pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, + bridge->hpp.cache_line_size); + pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, + bridge->hpp.latency_timer); + + pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); + if (bridge->hpp.enable_SERR) + tmp |= PCI_COMMAND_SERR; + if (bridge->hpp.enable_PERR) + tmp |= PCI_COMMAND_PARITY; + pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); + + return 0; +} + +/* detect_used_resource - subtract resource under dev from bridge */ +static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) +{ + u32 bar, len; + u64 base; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct pci_resource *res; + + dbg("Device %s\n", dev->slot_name); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword(dev, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + pci_write_config_dword(dev, address[count], 0xFFFFFFFF); + pci_read_config_dword(dev, address[count], &len); + + if (len & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + base = bar & 0xFFFFFFFC; + len &= 0xFFFFFFFC; + len = ~len + 1; + + dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(&bridge->io_head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } else { + /* This is Memory */ + base = bar & 0xFFFFFFF0; + if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("prefetch mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } else { + /* regular memory */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } + } + + pci_write_config_dword(dev, address[count], bar); + } + + return 0; +} + + +/* detect_pci_resource_bus - subtract resource under pci_bus */ +static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus) +{ + struct list_head *l; + struct pci_dev *dev; + + list_for_each (l, &bus->devices) { + dev = pci_dev_b(l); + detect_used_resource(bridge, dev); + /* XXX recursive call */ + if (dev->subordinate) + detect_used_resource_bus(bridge, dev->subordinate); + } +} + + +/** + * acpiphp_detect_pci_resource - detect resources under bridge + * @bridge: detect all resources already used under this bridge + * + * collect all resources already allocated for all devices under a bridge. + */ +int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) +{ + detect_used_resource_bus(bridge, bridge->pci_bus); + + return 0; +} + + +/** + * acpiphp_init_slot_resource - gather resource usage information of a slot + * @slot: ACPI slot object to be checked, should have valid pci_dev member + * + * TBD: PCI-to-PCI bridge case + * use pci_dev->resource[] + */ +int acpiphp_init_func_resource (struct acpiphp_func *func) +{ + u64 base; + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct pci_resource *res; + struct pci_dev *dev; + + dev = func->pci_dev; + dbg("Hot-pluggable device %s\n", dev->slot_name); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword(dev, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + pci_write_config_dword(dev, address[count], 0xFFFFFFFF); + pci_read_config_dword(dev, address[count], &len); + + if (len & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + base = bar & 0xFFFFFFFC; + len &= 0xFFFFFFFC; + len = ~len + 1; + + dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); + + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->io_head; + func->io_head = res; + + } else { + /* This is Memory */ + base = bar & 0xFFFFFFF0; + if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("prefetch mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->p_mem_head; + func->p_mem_head = res; + + } else { + /* regular memory */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->mem_head; + func->mem_head = res; + + } + } + + pci_write_config_dword(dev, address[count], bar); + } +#if 1 + acpiphp_dump_func_resource(func); +#endif + + return 0; + + no_memory: + err("out of memory\n"); + acpiphp_free_resource(&func->io_head); + acpiphp_free_resource(&func->mem_head); + acpiphp_free_resource(&func->p_mem_head); + + return -1; +} + + +/** + * acpiphp_configure_slot - allocate PCI resources + * @slot: slot to be configured + * + * initializes a PCI functions on a device inserted + * into the slot + * + */ +int acpiphp_configure_slot (struct acpiphp_slot *slot) +{ + struct acpiphp_func *func; + struct list_head *l; + u8 hdr; + u32 dvid; + int retval = 0; + int is_multi = 0; + + pci_bus_read_config_byte(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, 0), + PCI_HEADER_TYPE, &hdr); + + if (hdr & 0x80) + is_multi = 1; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + if (is_multi || func->function == 0) { + pci_bus_read_config_dword(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, + func->function), + PCI_VENDOR_ID, &dvid); + if (dvid != 0xffffffff) { + retval = init_config_space(func); + if (retval) + break; + } + } + } + + return retval; +} + +/** + * acpiphp_configure_function - configure PCI function + * @func: function to be configured + * + * initializes a PCI functions on a device inserted + * into the slot + * + */ +int acpiphp_configure_function (struct acpiphp_func *func) +{ + /* all handled by the pci core now */ + return 0; +} + +/** + * acpiphp_unconfigure_function - unconfigure PCI function + * @func: function to be unconfigured + * + */ +int acpiphp_unconfigure_function (struct acpiphp_func *func) +{ + struct acpiphp_bridge *bridge; + int retval = 0; + + /* if pci_dev is NULL, ignore it */ + if (!func->pci_dev) + goto err_exit; + + pci_remove_bus_device(func->pci_dev); + + /* free all resources */ + bridge = func->slot->bridge; + + spin_lock(&bridge->res_lock); + acpiphp_move_resource(&func->io_head, &bridge->io_head); + acpiphp_move_resource(&func->mem_head, &bridge->mem_head); + acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); + acpiphp_move_resource(&func->bus_head, &bridge->bus_head); + spin_unlock(&bridge->res_lock); + + err_exit: + return retval; +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_res.c linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_res.c --- linux-2.5.70-bk9/drivers/pci/hotplug/acpiphp_res.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/acpiphp_res.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,699 @@ +/* + * ACPI PCI HotPlug Utility functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "pci_hotplug.h" +#include "acpiphp.h" + +#define MY_NAME "acpiphp_res" + + +/* + * sort_by_size - sort nodes by their length, smallest first + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return 1; + + if (!((*head)->next)) + return 0; + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return 0; +} + + +/* + * sort_by_max_size - sort nodes by their length, largest first + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return 1; + + if (!((*head)->next)) + return 0; + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return 0; +} + +/** + * get_io_resource - get resource for I/O ports + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + * + * difference from get_resource is handling of ISA aliasing space. + * + */ +struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_size(head)) + return NULL; + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + /* For IO make sure it's not in the ISA aliasing space */ + if (node->base & 0x300L) + continue; + + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + + return node; +} + + +/** + * get_max_resource - get the largest resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_max_size(head)) + return NULL; + + for (max = *head;max; max = max->next) { + + /* If not big enough we could probably just bail, + instead we'll continue to the next. */ + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (max->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((max->length - (temp_qword - max->base)) < size) + continue; + + split_node = acpiphp_make_resource(max->base, temp_qword - max->base); + + if (!split_node) + return NULL; + + max->base = temp_qword; + max->length -= split_node->length; + + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + /* this one isn't end aligned properly at the top + so we'll make a new entry and split it up */ + temp_qword = ((max->base + max->length) & ~(size - 1)); + + split_node = acpiphp_make_resource(temp_qword, + max->length + max->base - temp_qword); + + if (!split_node) + return NULL; + + max->length -= split_node->length; + + /* Put it in the list */ + split_node->next = max->next; + max->next = split_node; + } + + /* Make sure it didn't shrink too much when we aligned it */ + if (max->length < size) + continue; + + /* Now take it out of the list */ + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return max; + } + + /* If we get here, we couldn't find one */ + return NULL; +} + + +/** + * get_resource - get resource (mem, pfmem) + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + * + */ +struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_size(head)) + return NULL; + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", + __FUNCTION__, size, node, (u32)node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg("%s: got one!!!\n", __FUNCTION__); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return node; +} + +/** + * get_resource_with_base - get resource with specific base address + * + * this function + * returns the first node of "size" length located at specified base address. + * If it finds a node larger than "size" it will split it up. + * + * size must be a power of two. + * + */ +struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + for (node = *head; node; node = node->next) { + dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + (u32)base, size, node, (u32)node->base, node->length); + if (node->base > base) + continue; + + if ((node->base + node->length) < (base + size)) + continue; + + if (node->base < base) { + dbg(": split 1\n"); + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = base; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } + + dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + (u32)base, size, node, (u32)node->base, node->length); + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg(": split 2\n"); + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg(": got one!!!\n"); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return node; +} + + +/** + * acpiphp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int acpiphp_resource_sort_and_combine (struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + if (!(*head)) + return 1; + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return 0; /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(u32)(*head)->base); + dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } /* End of out_of_order loop */ + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + /* Combine */ + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return 0; +} + + +/** + * acpiphp_make_resource - make resource structure + * @base: base address of a resource + * @length: length of a resource + */ +struct pci_resource *acpiphp_make_resource (u64 base, u32 length) +{ + struct pci_resource *res; + + res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (res) { + memset(res, 0, sizeof(struct pci_resource)); + res->base = base; + res->length = length; + } + + return res; +} + + +/** + * acpiphp_move_resource - move linked resources from one to another + * @from: head of linked resource list + * @to: head of linked resource list + */ +void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) +{ + struct pci_resource *tmp; + + while (*from) { + tmp = (*from)->next; + (*from)->next = *to; + *to = *from; + *from = tmp; + } + + /* *from = NULL is guaranteed */ +} + + +/** + * acpiphp_free_resource - free all linked resources + * @res: head of linked resource list + */ +void acpiphp_free_resource (struct pci_resource **res) +{ + struct pci_resource *tmp; + + while (*res) { + tmp = (*res)->next; + kfree(*res); + *res = tmp; + } + + /* *res = NULL is guaranteed */ +} + + +/* debug support functions; will go away sometime :) */ +static void dump_resource(struct pci_resource *head) +{ + struct pci_resource *p; + int cnt; + + p = head; + cnt = 0; + + while (p) { + dbg("[%02d] %08x - %08x\n", + cnt++, (u32)p->base, (u32)p->base + p->length - 1); + p = p->next; + } +} + +void acpiphp_dump_resource(struct acpiphp_bridge *bridge) +{ + dbg("I/O resource:\n"); + dump_resource(bridge->io_head); + dbg("MEM resource:\n"); + dump_resource(bridge->mem_head); + dbg("PMEM resource:\n"); + dump_resource(bridge->p_mem_head); + dbg("BUS resource:\n"); + dump_resource(bridge->bus_head); +} + +void acpiphp_dump_func_resource(struct acpiphp_func *func) +{ + dbg("I/O resource:\n"); + dump_resource(func->io_head); + dbg("MEM resource:\n"); + dump_resource(func->mem_head); + dbg("PMEM resource:\n"); + dump_resource(func->p_mem_head); + dbg("BUS resource:\n"); + dump_resource(func->bus_head); +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpci_hotplug.h linux-2.5.70-bk10/drivers/pci/hotplug/cpci_hotplug.h --- linux-2.5.70-bk9/drivers/pci/hotplug/cpci_hotplug.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpci_hotplug.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,100 @@ +/* + * CompactPCI Hot Plug Core Functions + * + * Copyright (c) 2002 SOMA Networks, Inc. + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ + +#ifndef _CPCI_HOTPLUG_H +#define _CPCI_HOTPLUG_H + +#include +#include + +/* PICMG 2.12 R2.0 HS CSR bits: */ +#define HS_CSR_INS 0x0080 +#define HS_CSR_EXT 0x0040 +#define HS_CSR_PI 0x0030 +#define HS_CSR_LOO 0x0008 +#define HS_CSR_PIE 0x0004 +#define HS_CSR_EIM 0x0002 +#define HS_CSR_DHA 0x0001 + +#define SLOT_MAGIC 0x67267322 +struct slot { + u32 magic; + u8 number; + unsigned int devfn; + struct pci_bus *bus; + struct pci_dev *dev; + unsigned int extracting; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; +}; + +struct cpci_hp_controller_ops { + int (*query_enum) (void); + int (*enable_irq) (void); + int (*disable_irq) (void); + int (*check_irq) (void *dev_id); + int (*hardware_test) (struct slot* slot, u32 value); + u8 (*get_power) (struct slot* slot); + int (*set_power) (struct slot* slot, int value); +}; + +struct cpci_hp_controller { + unsigned int irq; + unsigned long irq_flags; + char *devname; + void *dev_id; + char *name; + struct cpci_hp_controller_ops *ops; +}; + +extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); +extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); +extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); +extern int cpci_hp_unregister_bus(struct pci_bus *bus); +extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn); +extern int cpci_hp_start(void); +extern int cpci_hp_stop(void); + +/* + * Internal function prototypes, these functions should not be used by + * board/chassis drivers. + */ +extern u8 cpci_get_attention_status(struct slot *slot); +extern u8 cpci_get_latch_status(struct slot *slot); +extern u8 cpci_get_adapter_status(struct slot *slot); +extern u16 cpci_get_hs_csr(struct slot * slot); +extern u16 cpci_set_hs_csr(struct slot * slot, u16 hs_csr); +extern int cpci_set_attention_status(struct slot *slot, int status); +extern int cpci_check_and_clear_ins(struct slot * slot); +extern int cpci_check_ext(struct slot * slot); +extern int cpci_clear_ext(struct slot * slot); +extern int cpci_led_on(struct slot * slot); +extern int cpci_led_off(struct slot * slot); +extern int cpci_configure_slot(struct slot *slot); +extern int cpci_unconfigure_slot(struct slot *slot); + +#endif /* _CPCI_HOTPLUG_H */ diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpci_hotplug_core.c linux-2.5.70-bk10/drivers/pci/hotplug/cpci_hotplug_core.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpci_hotplug_core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpci_hotplug_core.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,919 @@ +/* + * CompactPCI Hot Plug Driver + * + * Copyright (c) 2002 SOMA Networks, Inc. + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" +#include "cpci_hotplug.h" + +#define DRIVER_VERSION "0.2" +#define DRIVER_AUTHOR "Scott Murray " +#define DRIVER_DESC "CompactPCI Hot Plug Core" + +#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) +#define MY_NAME "cpci_hotplug" +#else +#define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if(cpci_debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* local variables */ +static spinlock_t list_lock; +static LIST_HEAD(slot_list); +static int slots; +int cpci_debug; +static struct cpci_hp_controller *controller; +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */ +static int thread_finished = 1; + +static int enable_slot(struct hotplug_slot *slot); +static int disable_slot(struct hotplug_slot *slot); +static int set_attention_status(struct hotplug_slot *slot, u8 value); +static int get_power_status(struct hotplug_slot *slot, u8 * value); +static int get_attention_status(struct hotplug_slot *slot, u8 * value); +static int get_latch_status(struct hotplug_slot *slot, u8 * value); +static int get_adapter_status(struct hotplug_slot *slot, u8 * value); + +static struct hotplug_slot_ops cpci_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .hardware_test = NULL, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, +}; + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int +slot_paranoia_check(struct slot *slot, const char *function) +{ + if(!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if(slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if(!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot * +get_slot(struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if(!hotplug_slot) { + dbg("%s - hotplug_slot == NULL", function); + return NULL; + } + + slot = (struct slot *) hotplug_slot->private; + if(slot_paranoia_check(slot, function)) + return NULL; + return slot; +} + +static int +update_latch_status(struct hotplug_slot *hotplug_slot, u8 value) +{ + struct hotplug_slot_info info; + + if(!(hotplug_slot && hotplug_slot->info)) + return -EINVAL; + memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); + info.latch_status = value; + return pci_hp_change_slot_info(hotplug_slot, &info); +} + +static int +update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value) +{ + struct hotplug_slot_info info; + + if(!(hotplug_slot && hotplug_slot->info)) + return -EINVAL; + memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); + info.adapter_status = value; + return pci_hp_change_slot_info(hotplug_slot, &info); +} + +static int +enable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if(slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + if(controller->ops->set_power) { + retval = controller->ops->set_power(slot, 1); + } + + return retval; +} + +static int +disable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if(slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* Unconfigure device */ + dbg("%s - unconfiguring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if((retval = cpci_unconfigure_slot(slot))) { + err("%s - could not unconfigure slot %s", + __FUNCTION__, slot->hotplug_slot->name); + return retval; + } + dbg("%s - finished unconfiguring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + + /* Clear EXT (by setting it) */ + if(cpci_clear_ext(slot)) { + err("%s - could not clear EXT for slot %s", + __FUNCTION__, slot->hotplug_slot->name); + retval = -ENODEV; + } + cpci_led_on(slot); + + if(controller->ops->set_power) { + retval = controller->ops->set_power(slot, 0); + } + + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + + slot->extracting = 0; + + return retval; +} + +static u8 +cpci_get_power_status(struct slot *slot) +{ + u8 power = 1; + + if(controller->ops->get_power) { + power = controller->ops->get_power(slot); + } + return power; +} + +static int +get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if(slot == NULL) + return -ENODEV; + *value = cpci_get_power_status(slot); + return 0; +} + +static int +get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if(slot == NULL) + return -ENODEV; + *value = cpci_get_attention_status(slot); + return 0; +} + +static int +set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if(slot == NULL) + return -ENODEV; + switch (status) { + case 0: + cpci_set_attention_status(slot, 0); + break; + + case 1: + default: + cpci_set_attention_status(slot, 1); + break; + } + + return 0; +} + +static int +get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + if(hotplug_slot == NULL || hotplug_slot->info == NULL) + return -ENODEV; + *value = hotplug_slot->info->latch_status; + return 0; +} + +static int +get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + if(hotplug_slot == NULL || hotplug_slot->info == NULL) + return -ENODEV; + *value = hotplug_slot->info->adapter_status; + return 0; +} + +#define SLOT_NAME_SIZE 6 +static void +make_slot_name(struct slot *slot) +{ + snprintf(slot->hotplug_slot->name, + SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); +} + +int +cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) +{ + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *info; + char *name; + int status = 0; + int i; + + if(!(controller && bus)) { + return -ENODEV; + } + if(last < first) { + return -EINVAL; + } + + /* + * Create a structure for each slot, and register that slot + * with the pci_hotplug subsystem. + */ + for (i = first; i <= last; ++i) { + slot = kmalloc(sizeof (struct slot), GFP_KERNEL); + if(!slot) + return -ENOMEM; + memset(slot, 0, sizeof (struct slot)); + + hotplug_slot = + kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); + if(!hotplug_slot) { + kfree(slot); + return -ENOMEM; + } + memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); + slot->hotplug_slot = hotplug_slot; + + info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL); + if(!info) { + kfree(hotplug_slot); + kfree(slot); + return -ENOMEM; + } + memset(info, 0, sizeof (struct hotplug_slot_info)); + hotplug_slot->info = info; + + name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); + if(!name) { + kfree(info); + kfree(hotplug_slot); + kfree(slot); + return -ENOMEM; + } + hotplug_slot->name = name; + + slot->magic = SLOT_MAGIC; + slot->bus = bus; + slot->number = i; + slot->devfn = PCI_DEVFN(i, 0); + + hotplug_slot->private = slot; + make_slot_name(slot); + hotplug_slot->ops = &cpci_hotplug_slot_ops; + + /* + * Initialize the slot info structure with some known + * good values. + */ + dbg("initializing slot %s", slot->hotplug_slot->name); + info->power_status = cpci_get_power_status(slot); + info->attention_status = cpci_get_attention_status(slot); + + dbg("registering slot %s", slot->hotplug_slot->name); + status = pci_hp_register(slot->hotplug_slot); + if(status) { + err("pci_hp_register failed with error %d", status); + kfree(info); + kfree(name); + kfree(hotplug_slot); + kfree(slot); + return status; + } + + /* Add slot to our internal list */ + spin_lock(&list_lock); + list_add(&slot->slot_list, &slot_list); + slots++; + spin_unlock(&list_lock); + } + return status; +} + +int +cpci_hp_unregister_bus(struct pci_bus *bus) +{ + struct slot *slot; + struct list_head *tmp; + int status; + + if(!bus) { + return -ENODEV; + } + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return -1; + } + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->bus == bus) { + dbg("deregistering slot %s", slot->hotplug_slot->name); + status = pci_hp_deregister(slot->hotplug_slot); + if(status) { + err("pci_hp_deregister failed with error %d", + status); + return status; + } + + list_del(&slot->slot_list); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + + slots--; + } + } + spin_unlock(&list_lock); + return 0; +} + +struct slot * +cpci_find_slot(struct pci_bus *bus, unsigned int devfn) +{ + struct slot *slot; + struct slot *found; + struct list_head *tmp; + + if(!bus) { + return NULL; + } + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return NULL; + } + found = NULL; + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->bus == bus && slot->devfn == devfn) { + found = slot; + break; + } + } + spin_unlock(&list_lock); + return found; +} + +/* This is the interrupt mode interrupt handler */ +irqreturn_t +cpci_hp_intr(int irq, void *data, struct pt_regs *regs) +{ + dbg("entered cpci_hp_intr"); + + /* Check to see if it was our interrupt */ + if((controller->irq_flags & SA_SHIRQ) && + !controller->ops->check_irq(controller->dev_id)) { + dbg("exited cpci_hp_intr, not our interrupt"); + return IRQ_NONE; + } + + /* Disable ENUM interrupt */ + controller->ops->disable_irq(); + + /* Trigger processing by the event thread */ + dbg("Signal event_semaphore"); + up(&event_semaphore); + dbg("exited cpci_hp_intr"); + return IRQ_HANDLED; +} + +/* + * According to PICMG 2.12 R2.0, section 6.3.2, upon + * initialization, the system driver shall clear the + * INS bits of the cold-inserted devices. + */ +static int +init_slots(void) +{ + struct slot *slot; + struct list_head *tmp; + struct pci_dev* dev; + + dbg("%s - enter", __FUNCTION__); + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return -1; + } + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + dbg("%s - looking at slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if(cpci_check_and_clear_ins(slot)) { + dbg("%s - cleared INS for slot %s", + __FUNCTION__, slot->hotplug_slot->name); + dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); + if(dev) { + if(update_adapter_status(slot->hotplug_slot, 1)) { + warn("failure to update adapter file"); + } + if(update_latch_status(slot->hotplug_slot, 1)) { + warn("failure to update latch file"); + } + slot->dev = dev; + } else { + err("%s - no driver attached to device in slot %s", + __FUNCTION__, slot->hotplug_slot->name); + } + } + } + spin_unlock(&list_lock); + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int +check_slots(void) +{ + struct slot *slot; + struct list_head *tmp; + int extracted; + int inserted; + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + err("no slots registered, shutting down"); + return -1; + } + extracted = inserted = 0; + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + dbg("%s - looking at slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if(cpci_check_and_clear_ins(slot)) { + u16 hs_csr; + + /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ + if(slot->dev) { + warn("slot %s already inserted", slot->hotplug_slot->name); + inserted++; + continue; + } + + /* Process insertion */ + dbg("%s - slot %s inserted", + __FUNCTION__, slot->hotplug_slot->name); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR (1) = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + /* Configure device */ + dbg("%s - configuring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if(cpci_configure_slot(slot)) { + err("%s - could not configure slot %s", + __FUNCTION__, slot->hotplug_slot->name); + continue; + } + dbg("%s - finished configuring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR (2) = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + if(update_latch_status(slot->hotplug_slot, 1)) { + warn("failure to update latch file"); + } + + if(update_adapter_status(slot->hotplug_slot, 1)) { + warn("failure to update adapter file"); + } + + cpci_led_off(slot); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR (3) = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + inserted++; + } else if(cpci_check_ext(slot)) { + u16 hs_csr; + + /* Process extraction request */ + dbg("%s - slot %s extracted", + __FUNCTION__, slot->hotplug_slot->name); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + if(!slot->extracting) { + if(update_latch_status(slot->hotplug_slot, 0)) { + warn("failure to update latch file"); + } + slot->extracting = 1; + } + extracted++; + } + } + spin_unlock(&list_lock); + if(inserted || extracted) { + return extracted; + } + else { + err("cannot find ENUM# source, shutting down"); + return -1; + } +} + +/* This is the interrupt mode worker thread body */ +static int +event_thread(void *data) +{ + int rc; + struct slot *slot; + struct list_head *tmp; + + lock_kernel(); + daemonize("cpci_hp_eventd"); + unlock_kernel(); + + dbg("%s - event thread started", __FUNCTION__); + while(1) { + dbg("event thread sleeping"); + down_interruptible(&event_semaphore); + dbg("event thread woken, thread_finished = %d", + thread_finished); + if(thread_finished || signal_pending(current)) + break; + while(controller->ops->query_enum()) { + rc = check_slots(); + if(rc > 0) { + /* Give userspace a chance to handle extraction */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + } else if(rc < 0) { + dbg("%s - error checking slots", __FUNCTION__); + thread_finished = 1; + break; + } + } + /* Check for someone yanking out a board */ + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->extracting) { + /* + * Hmmm, we're likely hosed at this point, should we + * bother trying to tell the driver or not? + */ + err("card in slot %s was improperly removed", + slot->hotplug_slot->name); + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + slot->extracting = 0; + } + } + + /* Re-enable ENUM# interrupt */ + dbg("%s - re-enabling irq", __FUNCTION__); + controller->ops->enable_irq(); + } + + dbg("%s - event thread signals exit", __FUNCTION__); + up(&thread_exit); + return 0; +} + +/* This is the polling mode worker thread body */ +static int +poll_thread(void *data) +{ + int rc; + struct slot *slot; + struct list_head *tmp; + + lock_kernel(); + daemonize("cpci_hp_polld"); + unlock_kernel(); + + while(1) { + if(thread_finished || signal_pending(current)) + break; + + while(controller->ops->query_enum()) { + rc = check_slots(); + if(rc > 0) { + /* Give userspace a chance to handle extraction */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + } else if(rc < 0) { + dbg("%s - error checking slots", __FUNCTION__); + thread_finished = 1; + break; + } + } + /* Check for someone yanking out a board */ + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->extracting) { + /* + * Hmmm, we're likely hosed at this point, should we + * bother trying to tell the driver or not? + */ + err("card in slot %s was improperly removed", + slot->hotplug_slot->name); + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + slot->extracting = 0; + } + } + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + } + dbg("poll thread signals exit"); + up(&thread_exit); + return 0; +} + +static int +cpci_start_thread(void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX_LOCKED(&event_semaphore); + init_MUTEX_LOCKED(&thread_exit); + thread_finished = 0; + + if(controller->irq) { + pid = kernel_thread(event_thread, 0, 0); + } else { + pid = kernel_thread(poll_thread, 0, 0); + } + if(pid < 0) { + err("Can't start up our thread"); + return -1; + } + dbg("Our thread pid = %d", pid); + return 0; +} + +static void +cpci_stop_thread(void) +{ + thread_finished = 1; + dbg("thread finish command given"); + if(controller->irq) { + up(&event_semaphore); + } + dbg("wait for thread to exit"); + down(&thread_exit); +} + +int +cpci_hp_register_controller(struct cpci_hp_controller *new_controller) +{ + int status = 0; + + if(!controller) { + controller = new_controller; + if(controller->irq) { + if(request_irq(controller->irq, + cpci_hp_intr, + controller->irq_flags, + MY_NAME, controller->dev_id)) { + err("Can't get irq %d for the hotplug cPCI controller", controller->irq); + status = -ENODEV; + } + dbg("%s - acquired controller irq %d", __FUNCTION__, + controller->irq); + } + } else { + err("cPCI hotplug controller already registered"); + status = -1; + } + return status; +} + +int +cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) +{ + int status = 0; + + if(controller) { + if(!thread_finished) { + cpci_stop_thread(); + } + if(controller->irq) { + free_irq(controller->irq, controller->dev_id); + } + controller = NULL; + } else { + status = -ENODEV; + } + return status; +} + +int +cpci_hp_start(void) +{ + static int first = 1; + int status; + + dbg("%s - enter", __FUNCTION__); + if(!controller) { + return -ENODEV; + } + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return -ENODEV; + } + spin_unlock(&list_lock); + + if(first) { + status = init_slots(); + if(status) { + return status; + } + first = 0; + } + + status = cpci_start_thread(); + if(status) { + return status; + } + dbg("%s - thread started", __FUNCTION__); + + if(controller->irq) { + /* Start enum interrupt processing */ + dbg("%s - enabling irq", __FUNCTION__); + controller->ops->enable_irq(); + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +int +cpci_hp_stop(void) +{ + if(!controller) { + return -ENODEV; + } + + if(controller->irq) { + /* Stop enum interrupt processing */ + dbg("%s - disabling irq", __FUNCTION__); + controller->ops->disable_irq(); + } + cpci_stop_thread(); + return 0; +} + +static void __exit +cleanup_slots(void) +{ + struct list_head *tmp; + struct slot *slot; + + /* + * Unregister all of our slots with the pci_hotplug subsystem, + * and free up all memory that we had allocated. + */ + spin_lock(&list_lock); + if(!slots) { + goto null_cleanup; + } + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + } + null_cleanup: + spin_unlock(&list_lock); + return; +} + +int __init +cpci_hotplug_init(int debug) +{ + spin_lock_init(&list_lock); + cpci_debug = debug; + + info(DRIVER_DESC " version: " DRIVER_VERSION); + return 0; +} + +void __exit +cpci_hotplug_exit(void) +{ + /* + * Clean everything up. + */ + cleanup_slots(); +} + + +EXPORT_SYMBOL_GPL(cpci_hp_register_controller); +EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); +EXPORT_SYMBOL_GPL(cpci_hp_register_bus); +EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); +EXPORT_SYMBOL_GPL(cpci_find_slot); +EXPORT_SYMBOL_GPL(cpci_hp_start); +EXPORT_SYMBOL_GPL(cpci_hp_stop); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpci_hotplug_pci.c linux-2.5.70-bk10/drivers/pci/hotplug/cpci_hotplug_pci.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpci_hotplug_pci.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpci_hotplug_pci.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,647 @@ +/* + * CompactPCI Hot Plug Driver PCI functions + * + * Copyright (c) 2002 by SOMA Networks, Inc. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ + +#include +#include +#include +#include +#include +#include "../pci.h" +#include "pci_hotplug.h" +#include "cpci_hotplug.h" + +#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) +#define MY_NAME "cpci_hotplug" +#else +#define MY_NAME THIS_MODULE->name +#endif + +extern int cpci_debug; + +#define dbg(format, arg...) \ + do { \ + if(cpci_debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + + +u8 cpci_get_attention_status(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + return hs_csr & 0x0008 ? 1 : 0; +} + +int cpci_set_attention_status(struct slot* slot, int status) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + if(status) { + hs_csr |= HS_CSR_LOO; + } else { + hs_csr &= ~HS_CSR_LOO; + } + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + return 0; + } + return 1; +} + +u16 cpci_get_hs_csr(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0xFFFF; + } + + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0xFFFF; + } + return hs_csr; +} + +u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr) +{ + int hs_cap; + u16 new_hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0xFFFF; + } + + /* Write out the new value */ + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + return 0xFFFF; + } + + /* Read back what we just wrote out */ + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &new_hs_csr)) { + return 0xFFFF; + } + return new_hs_csr; +} + +int cpci_check_and_clear_ins(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + int ins = 0; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + if(hs_csr & HS_CSR_INS) { + /* Clear INS (by setting it) */ + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + ins = 0; + } + ins = 1; + } + return ins; +} + +int cpci_check_ext(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + int ext = 0; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + if(hs_csr & HS_CSR_EXT) { + ext = 1; + } + return ext; +} + +int cpci_clear_ext(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return -ENODEV; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return -ENODEV; + } + if(hs_csr & HS_CSR_EXT) { + /* Clear EXT (by setting it) */ + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + return -ENODEV; + } + } + return 0; +} + +int cpci_led_on(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return -ENODEV; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return -ENODEV; + } + if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { + /* Set LOO */ + hs_csr |= HS_CSR_LOO; + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + err("Could not set LOO for slot %s", + slot->hotplug_slot->name); + return -ENODEV; + } + } + return 0; +} + +int cpci_led_off(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return -ENODEV; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return -ENODEV; + } + if(hs_csr & HS_CSR_LOO) { + /* Clear LOO */ + hs_csr &= ~HS_CSR_LOO; + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + err("Could not clear LOO for slot %s", + slot->hotplug_slot->name); + return -ENODEV; + } + } + return 0; +} + + +/* + * Device configuration functions + */ + +static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) +{ + u8 irq_pin; + int r; + + dbg("%s - enter", __FUNCTION__); + + /* NOTE: device already setup from prior scan */ + + /* FIXME: How would we know if we need to enable the expansion ROM? */ + pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L); + + /* Assign resources */ + dbg("assigning resources for %02x:%02x.%x", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + for (r = 0; r < 6; r++) { + struct resource *res = dev->resource + r; + if(res->flags) + pci_assign_resource(dev, r); + } + dbg("finished assigning resources for %02x:%02x.%x", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + + /* Does this function have an interrupt at all? */ + dbg("checking for function interrupt"); + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); + if(irq_pin) { + dbg("function uses interrupt pin %d", irq_pin); + } + + /* + * Need to explicitly set irq field to 0 so that it'll get assigned + * by the pcibios platform dependent code called by pci_enable_device. + */ + dev->irq = 0; + + dbg("enabling device"); + pci_enable_device(dev); /* XXX check return */ + dbg("now dev->irq = %d", dev->irq); + if(irq_pin && dev->irq) { + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + + /* Can't use pci_insert_device at the moment, do it manually for now */ + pci_proc_attach_device(dev); + dbg("notifying drivers"); + //pci_announce_device_to_drivers(dev); + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) +{ + int rc; + struct pci_bus* child; + struct resource* r; + u8 max, n; + u16 command; + + dbg("%s - enter", __FUNCTION__); + + /* Do basic bridge initialization */ + rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); + if(rc) { + printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__); + } + rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); + if(rc) { + printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__); + } + rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); + if(rc) { + printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__); + } + + /* + * Set parent bridge's subordinate field so that configuration space + * access will work in pci_scan_bridge and friends. + */ + max = pci_max_busnr(); + bus->subordinate = max + 1; + pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1); + + /* Scan behind bridge */ + n = pci_scan_bridge(bus, dev, max, 2); + child = pci_find_bus(max + 1); + if (!child) + return -ENODEV; + pci_proc_attach_bus(child); + + /* + * Update parent bridge's subordinate field if there were more bridges + * behind the bridge that was scanned. + */ + if(n > max) { + bus->subordinate = n; + pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n); + } + + /* + * Update the bridge resources of the bridge to accommodate devices + * behind it. + */ + pci_bus_size_bridges(child); + pci_bus_assign_resources(child); + + /* Enable resource mapping via command register */ + command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + r = child->resource[0]; + if(r && r->start) { + command |= PCI_COMMAND_IO; + } + r = child->resource[1]; + if(r && r->start) { + command |= PCI_COMMAND_MEMORY; + } + r = child->resource[2]; + if(r && r->start) { + command |= PCI_COMMAND_MEMORY; + } + rc = pci_write_config_word(dev, PCI_COMMAND, command); + if(rc) { + err("Error setting command register"); + return rc; + } + + /* Set bridge control register */ + command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA; + rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command); + if(rc) { + err("Error setting bridge control register"); + return rc; + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_bus) +{ + int rc; + struct pci_dev *dev = wrapped_dev->dev; + struct pci_bus *bus = wrapped_bus->bus; + struct slot* slot; + + dbg("%s - enter", __FUNCTION__); + + /* + * We need to fix up the hotplug representation with the Linux + * representation. + */ + slot = cpci_find_slot(dev->bus, dev->devfn); + if(slot) { + slot->dev = dev; + } + + /* If it's a bridge, scan behind it for devices */ + if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + rc = cpci_configure_bridge(bus, dev); + if(rc) + return rc; + } + + /* Actually configure device */ + if(dev) { + rc = cpci_configure_dev(bus, dev); + if(rc) + return rc; + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev *dev = wrapped_dev->dev; + struct slot* slot; + + dbg("%s - enter", __FUNCTION__); + if(!dev) + return -ENODEV; + + /* Remove the Linux representation */ + if(pci_remove_device_safe(dev) == 0) { + kfree(dev); + } else { + err("Could not remove device\n"); + return -1; + } + + /* + * Now remove the hotplug representation. + */ + slot = cpci_find_slot(dev->bus, dev->devfn); + if(slot) { + slot->dev = NULL; + } else { + dbg("No hotplug representation for %02x:%02x.%x", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus, + struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus *bus = wrapped_bus->bus; + struct pci_bus *parent = bus->self->bus; + + dbg("%s - enter", __FUNCTION__); + + /* The cleanup code for proc entries regarding buses should be in the kernel... */ + if(bus->procdir) + dbg("detach_pci_bus %s", bus->procdir->name); + pci_proc_detach_bus(bus); + + /* The cleanup code should live in the kernel... */ + bus->self->subordinate = NULL; + + /* unlink from parent bus */ + list_del(&bus->node); + + /* Now, remove */ + if(bus) + kfree(bus); + + /* Update parent's subordinate field */ + if(parent) { + u8 n = pci_bus_max_busnr(parent); + if(n < parent->subordinate) { + parent->subordinate = n; + pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n); + } + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static struct pci_visit configure_functions = { + .visit_pci_dev = configure_visit_pci_dev, +}; + +static struct pci_visit unconfigure_functions_phase2 = { + .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, + .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 +}; + + +int cpci_configure_slot(struct slot* slot) +{ + int rc = 0; + + dbg("%s - enter", __FUNCTION__); + + if(slot->dev == NULL) { + dbg("pci_dev null, finding %02x:%02x:%x", + slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); + slot->dev = pci_find_slot(slot->bus->number, slot->devfn); + } + + /* Still NULL? Well then scan for it! */ + if(slot->dev == NULL) { + dbg("pci_dev still null"); + + /* + * This will generate pci_dev structures for all functions, but + * we will only call this case when lookup fails. + */ + slot->dev = pci_scan_slot(slot->bus, slot->devfn); + if(slot->dev == NULL) { + err("Could not find PCI device for slot %02x", slot->number); + return 0; + } + } + dbg("slot->dev = %p", slot->dev); + if(slot->dev) { + struct pci_dev *dev; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + int i; + + memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + + for (i = 0; i < 8; i++) { + dev = pci_find_slot(slot->bus->number, + PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i)); + if(!dev) + continue; + wrapped_dev.dev = dev; + wrapped_bus.bus = slot->dev->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); + } + } + + dbg("%s - exit, rc = %d", __FUNCTION__, rc); + return rc; +} + +int cpci_unconfigure_slot(struct slot* slot) +{ + int rc = 0; + int i; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + struct pci_dev *dev; + + dbg("%s - enter", __FUNCTION__); + + if(!slot->dev) { + err("No device for slot %02x\n", slot->number); + return -ENODEV; + } + + memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + + for (i = 0; i < 8; i++) { + dev = pci_find_slot(slot->bus->number, + PCI_DEVFN(PCI_SLOT(slot->devfn), i)); + if(dev) { + wrapped_dev.dev = dev; + wrapped_bus.bus = dev->bus; + dbg("%s - unconfigure phase 2", __FUNCTION__); + rc = pci_visit_dev(&unconfigure_functions_phase2, + &wrapped_dev, &wrapped_bus); + if(rc) + break; + } + } + dbg("%s - exit, rc = %d", __FUNCTION__, rc); + return rc; +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpcihp_generic.c linux-2.5.70-bk10/drivers/pci/hotplug/cpcihp_generic.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpcihp_generic.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpcihp_generic.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,290 @@ +/* + * cpcihp_generic.c + * + * Generic port I/O CompactPCI driver + * + * Copyright 2002 SOMA Networks, Inc. + * Copyright 2001 Intel San Luis Obispo + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This generic CompactPCI hotplug driver should allow using the PCI hotplug + * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit + * in a system register that can be read through standard port I/O. + * + * Send feedback to + */ + +#include +#include +#include +#include +#include +#include "cpci_hotplug.h" + +#define DRIVER_VERSION "0.1" +#define DRIVER_AUTHOR "Scott Murray " +#define DRIVER_DESC "Generic port I/O CompactPCI Hot Plug Driver" + +#if !defined(CONFIG_HOTPLUG_CPCI_GENERIC_MODULE) +#define MY_NAME "cpcihp_generic" +#else +#define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if(debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* local variables */ +static int debug; +static char* bridge; +static u8 bridge_busnr; +static u8 bridge_slot; +static struct pci_bus *bus; +static u8 first_slot; +static u8 last_slot; +static u16 port; +static unsigned int enum_bit; +static u8 enum_mask; + +static struct cpci_hp_controller_ops generic_hpc_ops; +static struct cpci_hp_controller generic_hpc; + +/* The following allows configuring the driver when it's compiled into the kernel */ +#ifndef MODULE +static int __init cpcihp_generic_setup(char* str) +{ + char* p; + unsigned long tmp; + + if(!str) + return -EINVAL; + bridge = str; + + p = strchr(str, ','); + str = p + 1; + if(!(p && *str && *p == ',')) + goto setup_error; + tmp = simple_strtoul(str, &p, 0); + if(p == str || tmp > 0xff) { + err("hotplug bus first slot number out of range"); + goto setup_error; + } + first_slot = (u8) tmp; + + str = p + 1; + if(!(*str && *p == ',')) + return -EINVAL; + tmp = simple_strtoul(str, &p, 0); + if(p == str || tmp > 0xff) { + err("hotplug bus last slot number out of range"); + goto setup_error; + } + last_slot = (u8) tmp; + + str = p + 1; + if(!(*str && *p == ',')) + goto setup_error; + tmp = simple_strtoul(str, &p, 0); + if(p == str || tmp > 0xffff) { + err("port number out of range"); + goto setup_error; + } + port = (u16) tmp; + + str = p + 1; + if(!(*str && *p == ',')) + goto setup_error; + tmp = simple_strtoul(str, &p, 0); + if(p == str) { + err("invalid #ENUM bit number"); + goto setup_error; + } + enum_bit = (u8) tmp; + + str = p + 1; + if(*str && *p == ',') { + tmp = simple_strtoul(str, &p, 0); + if(p != str) + debug = (int) tmp; + } + return 0; +setup_error: + bridge = NULL; + return -EINVAL; +} + +__setup("cpcihp_generic=", cpcihp_generic_setup); +#endif + +static int __init validate_parameters(void) +{ + char* str; + char* p; + unsigned long tmp; + + if(!bridge) { + info("not configured, disabling."); + return 1; + } + str = bridge; + if(!*str) + return -EINVAL; + + tmp = simple_strtoul(str, &p, 16); + if(p == str || tmp > 0xff) { + err("Invalid hotplug bus bridge device bus number"); + return -EINVAL; + } + bridge_busnr = (u8) tmp; + dbg("bridge_busnr = 0x%02x", bridge_busnr); + if(*p != ':') { + err("Invalid hotplug bus bridge device"); + return -EINVAL; + } + str = p + 1; + tmp = simple_strtoul(str, &p, 16); + if(p == str || tmp > 0x1f) { + err("Invalid hotplug bus bridge device slot number"); + return -EINVAL; + } + bridge_slot = (u8) tmp; + dbg("bridge_slot = 0x%02x", bridge_slot); + + dbg("first_slot = 0x%02x", first_slot); + dbg("last_slot = 0x%02x", last_slot); + if(!(first_slot && last_slot)) { + err("Need to specify first_slot and last_slot"); + return -EINVAL; + } + if(last_slot < first_slot) { + err("first_slot must be less than last_slot"); + return -EINVAL; + } + + dbg("port = 0x%04x", port); + dbg("enum_bit = 0x%02x", enum_bit); + if(enum_bit > 7) { + err("Invalid #ENUM bit"); + return -EINVAL; + } + enum_mask = 1 << enum_bit; + return 0; +} + +static int query_enum(void) +{ + u8 value; + + value = inb_p(port); + return ((value & enum_mask) == enum_mask); +} + +static int __init cpcihp_generic_init(void) +{ + int status; + struct resource* r; + struct pci_dev* dev; + + info(DRIVER_DESC " version: " DRIVER_VERSION); + status = validate_parameters(); + if(status != 0) + return status; + + r = request_region(port, 1, "#ENUM hotswap signal register"); + if(!r) + return -EBUSY; + + dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0)); + if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { + err("Invalid bridge device %s", bridge); + return -EINVAL; + } + bus = dev->subordinate; + + memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller)); + generic_hpc_ops.query_enum = query_enum; + generic_hpc.ops = &generic_hpc_ops; + + status = cpci_hp_register_controller(&generic_hpc); + if(status != 0) { + err("Could not register cPCI hotplug controller"); + return -ENODEV; + } + dbg("registered controller"); + + status = cpci_hp_register_bus(bus, first_slot, last_slot); + if(status != 0) { + err("Could not register cPCI hotplug bus"); + goto init_bus_register_error; + } + dbg("registered bus"); + + status = cpci_hp_start(); + if(status != 0) { + err("Could not started cPCI hotplug system"); + goto init_start_error; + } + dbg("started cpci hp system"); + return 0; +init_start_error: + cpci_hp_unregister_bus(bus); +init_bus_register_error: + cpci_hp_unregister_controller(&generic_hpc); + err("status = %d", status); + return status; + +} + +static void __exit cpcihp_generic_exit(void) +{ + cpci_hp_stop(); + cpci_hp_unregister_bus(bus); + cpci_hp_unregister_controller(&generic_hpc); + release_region(port, 1); +} + +module_init(cpcihp_generic_init); +module_exit(cpcihp_generic_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); +MODULE_PARM(bridge, "s"); +MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, : (bus and slot are in hexadecimal)"); +MODULE_PARM(first_slot, "b"); +MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number"); +MODULE_PARM(last_slot, "b"); +MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number"); +MODULE_PARM(port, "h"); +MODULE_PARM_DESC(port, "#ENUM signal I/O port"); +MODULE_PARM(enum_bit, "i"); +MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)"); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpcihp_zt5550.c linux-2.5.70-bk10/drivers/pci/hotplug/cpcihp_zt5550.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpcihp_zt5550.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpcihp_zt5550.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,306 @@ +/* + * cpcihp_zt5550.c + * + * Intel/Ziatech ZT5550 CompactPCI Host Controller driver + * + * Copyright 2002 SOMA Networks, Inc. + * Copyright 2001 Intel San Luis Obispo + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ + +#include +#include +#include +#include +#include +#include "cpci_hotplug.h" +#include "cpcihp_zt5550.h" + +#define DRIVER_VERSION "0.2" +#define DRIVER_AUTHOR "Scott Murray " +#define DRIVER_DESC "ZT5550 CompactPCI Hot Plug Driver" + +#if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE) +#define MY_NAME "cpcihp_zt5550" +#else +#define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if(debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* local variables */ +static int debug; +static int poll; +static struct cpci_hp_controller_ops zt5550_hpc_ops; +static struct cpci_hp_controller zt5550_hpc; + +/* Primary cPCI bus bridge device */ +static struct pci_dev *bus0_dev; +static struct pci_bus *bus0; + +/* Host controller device */ +static struct pci_dev *hc_dev; + +/* Host controller register addresses */ +static void *hc_registers; +static void *csr_hc_index; +static void *csr_hc_data; +static void *csr_int_status; +static void *csr_int_mask; + + +static int zt5550_hc_config(struct pci_dev *pdev) +{ + /* Since we know that no boards exist with two HC chips, treat it as an error */ + if(hc_dev) { + err("too many host controller devices?"); + return -EBUSY; + } + hc_dev = pdev; + dbg("hc_dev = %p", hc_dev); + dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); + dbg("pci resource len %lx", pci_resource_len(hc_dev, 1)); + + if(!request_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1), MY_NAME)) { + err("cannot reserve MMIO region"); + return -ENOMEM; + } + + hc_registers = + ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); + if(!hc_registers) { + err("cannot remap MMIO region %lx @ %lx", + pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); + release_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1)); + return -ENODEV; + } + + csr_hc_index = hc_registers + CSR_HCINDEX; + csr_hc_data = hc_registers + CSR_HCDATA; + csr_int_status = hc_registers + CSR_INTSTAT; + csr_int_mask = hc_registers + CSR_INTMASK; + + /* + * Disable host control, fault and serial interrupts + */ + dbg("disabling host control, fault and serial interrupts"); + writeb((u8) HC_INT_MASK_REG, csr_hc_index); + writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data); + dbg("disabled host control, fault and serial interrupts"); + + /* + * Disable timer0, timer1 and ENUM interrupts + */ + dbg("disabling timer0, timer1 and ENUM interrupts"); + writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); + dbg("disabled timer0, timer1 and ENUM interrupts"); + return 0; +} + +static int zt5550_hc_cleanup(void) +{ + if(!hc_dev) + return -ENODEV; + release_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1)); + return 0; +} + +static int zt5550_hc_query_enum(void) +{ + u8 value; + + value = inb_p(ENUM_PORT); + return ((value & ENUM_MASK) == ENUM_MASK); +} + +static int zt5550_hc_check_irq(void *dev_id) +{ + int ret; + u8 reg; + + ret = 0; + if(dev_id == zt5550_hpc.dev_id) { + reg = readb(csr_int_status); + if(reg) + ret = 1; + } + return ret; +} + +static int zt5550_hc_enable_irq(void) +{ + u8 reg; + + if(hc_dev == NULL) { + return -ENODEV; + } + reg = readb(csr_int_mask); + reg = reg & ~ENUM_INT_MASK; + writeb(reg, csr_int_mask); + return 0; +} + +int zt5550_hc_disable_irq(void) +{ + u8 reg; + + if(hc_dev == NULL) { + return -ENODEV; + } + + reg = readb(csr_int_mask); + reg = reg | ENUM_INT_MASK; + writeb(reg, csr_int_mask); + return 0; +} + +static int __devinit zt5550_hc_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int status; + + status = zt5550_hc_config(pdev); + if(status != 0) { + return status; + } + dbg("returned from zt5550_hc_config"); + + memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); + zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; + zt5550_hpc.ops = &zt5550_hpc_ops; + if(!poll) { + zt5550_hpc.irq = hc_dev->irq; + zt5550_hpc.irq_flags = SA_SHIRQ; + zt5550_hpc.dev_id = hc_dev; + + zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; + zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; + zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; + } else { + info("using ENUM# polling mode"); + } + + status = cpci_hp_register_controller(&zt5550_hpc); + if(status != 0) { + err("could not register cPCI hotplug controller"); + goto init_hc_error; + } + dbg("registered controller"); + + /* Look for first device matching cPCI bus's bridge vendor and device IDs */ + if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC, + PCI_DEVICE_ID_DEC_21154, NULL))) { + status = -ENODEV; + goto init_register_error; + } + bus0 = bus0_dev->subordinate; + + status = cpci_hp_register_bus(bus0, 0x0a, 0x0f); + if(status != 0) { + err("could not register cPCI hotplug bus"); + goto init_register_error; + } + dbg("registered bus"); + + status = cpci_hp_start(); + if(status != 0) { + err("could not started cPCI hotplug system"); + cpci_hp_unregister_bus(bus0); + goto init_register_error; + } + dbg("started cpci hp system"); + + return 0; +init_register_error: + cpci_hp_unregister_controller(&zt5550_hpc); +init_hc_error: + err("status = %d", status); + zt5550_hc_cleanup(); + return status; + +} + +static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) +{ + cpci_hp_stop(); + cpci_hp_unregister_bus(bus0); + cpci_hp_unregister_controller(&zt5550_hpc); + zt5550_hc_cleanup(); +} + + +static struct pci_device_id zt5550_hc_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); + +static struct pci_driver zt5550_hc_driver = { + .name = "zt5550_hc", + .id_table = zt5550_hc_pci_tbl, + .probe = zt5550_hc_init_one, + .remove = __devexit_p(zt5550_hc_remove_one), +}; + +static int __init zt5550_init(void) +{ + struct resource* r; + + info(DRIVER_DESC " version: " DRIVER_VERSION); + r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); + if(!r) + return -EBUSY; + + return pci_module_init(&zt5550_hc_driver); +} + +static void __exit +zt5550_exit(void) +{ + pci_unregister_driver(&zt5550_hc_driver); + release_region(ENUM_PORT, 1); +} + +module_init(zt5550_init); +module_exit(zt5550_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); +MODULE_PARM(poll, "i"); +MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpcihp_zt5550.h linux-2.5.70-bk10/drivers/pci/hotplug/cpcihp_zt5550.h --- linux-2.5.70-bk9/drivers/pci/hotplug/cpcihp_zt5550.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpcihp_zt5550.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,79 @@ +/* + * cpcihp_zt5550.h + * + * Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions + * + * Copyright 2002 SOMA Networks, Inc. + * Copyright 2001 Intel San Luis Obispo + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ + +#ifndef _CPCIHP_ZT5550_H +#define _CPCIHP_ZT5550_H + +/* Direct registers */ +#define CSR_HCINDEX 0x00 +#define CSR_HCDATA 0x04 +#define CSR_INTSTAT 0x08 +#define CSR_INTMASK 0x09 +#define CSR_CNT0CMD 0x0C +#define CSR_CNT1CMD 0x0E +#define CSR_CNT0 0x10 +#define CSR_CNT1 0x14 + +/* Masks for interrupt bits in CSR_INTMASK direct register */ +#define CNT0_INT_MASK 0x01 +#define CNT1_INT_MASK 0x02 +#define ENUM_INT_MASK 0x04 +#define ALL_DIRECT_INTS_MASK 0x07 + +/* Indexed registers (through CSR_INDEX, CSR_DATA) */ +#define HC_INT_MASK_REG 0x04 +#define HC_STATUS_REG 0x08 +#define HC_CMD_REG 0x0C +#define ARB_CONFIG_GNT_REG 0x10 +#define ARB_CONFIG_CFG_REG 0x12 +#define ARB_CONFIG_REG 0x10 +#define ISOL_CONFIG_REG 0x18 +#define FAULT_STATUS_REG 0x20 +#define FAULT_CONFIG_REG 0x24 +#define WD_CONFIG_REG 0x2C +#define HC_DIAG_REG 0x30 +#define SERIAL_COMM_REG 0x34 +#define SERIAL_OUT_REG 0x38 +#define SERIAL_IN_REG 0x3C + +/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */ +#define SERIAL_INT_MASK 0x01 +#define FAULT_INT_MASK 0x02 +#define HCF_INT_MASK 0x04 +#define ALL_INDEXED_INTS_MASK 0x07 + +/* Digital I/O port storing ENUM# */ +#define ENUM_PORT 0xE1 +/* Mask to get to the ENUM# bit on the bus */ +#define ENUM_MASK 0x40 + +#endif /* _CPCIHP_ZT5550_H */ diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp.h linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp.h --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,912 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#ifndef _CPQPHP_H +#define _CPQPHP_H + +#include "pci_hotplug.h" +#include +#include /* for read? and write? functions */ +#include /* for delays */ + +#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) + #define MY_NAME "cpqphp.o" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + + +struct smbios_system_slot { + u8 type; + u8 length; + u16 handle; + u8 name_string_num; + u8 slot_type; + u8 slot_width; + u8 slot_current_usage; + u8 slot_length; + u16 slot_number; + u8 properties1; + u8 properties2; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_system_slot_offsets { + SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), + SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), + SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), + SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), + SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), + SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), + SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), + SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), + SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), + SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), + SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), +}; + +struct smbios_generic { + u8 type; + u8 length; + u16 handle; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_generic_offsets { + SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), + SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), + SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), +}; + +struct smbios_entry_point { + char anchor[4]; + u8 ep_checksum; + u8 ep_length; + u8 major_version; + u8 minor_version; + u16 max_size_entry; + u8 ep_rev; + u8 reserved[5]; + char int_anchor[5]; + u8 int_checksum; + u16 st_length; + u32 st_address; + u16 number_of_entrys; + u8 bcd_rev; +} __attribute__ ((packed)); + +/* offsets to the smbios entry point based on the above structure layout */ +enum smbios_entry_point_offsets { + ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), + EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), + EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), + MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), + MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), + MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), + EP_REV = offsetof(struct smbios_entry_point, ep_rev), + INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), + INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), + ST_LENGTH = offsetof(struct smbios_entry_point, st_length), + ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), + NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), + BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), +}; + +struct ctrl_reg { /* offset */ + u8 slot_RST; /* 0x00 */ + u8 slot_enable; /* 0x01 */ + u16 misc; /* 0x02 */ + u32 led_control; /* 0x04 */ + u32 int_input_clear; /* 0x08 */ + u32 int_mask; /* 0x0a */ + u8 reserved0; /* 0x10 */ + u8 reserved1; /* 0x11 */ + u8 reserved2; /* 0x12 */ + u8 gen_output_AB; /* 0x13 */ + u32 non_int_input; /* 0x14 */ + u32 reserved3; /* 0x18 */ + u32 reserved4; /* 0x1a */ + u32 reserved5; /* 0x20 */ + u8 reserved6; /* 0x24 */ + u8 reserved7; /* 0x25 */ + u16 reserved8; /* 0x26 */ + u8 slot_mask; /* 0x28 */ + u8 reserved9; /* 0x29 */ + u8 reserved10; /* 0x2a */ + u8 reserved11; /* 0x2b */ + u8 slot_SERR; /* 0x2c */ + u8 slot_power; /* 0x2d */ + u8 reserved12; /* 0x2e */ + u8 reserved13; /* 0x2f */ + u8 next_curr_freq; /* 0x30 */ + u8 reset_freq_mode; /* 0x31 */ +} __attribute__ ((packed)); + +/* offsets to the controller registers based on the above structure layout */ +enum ctrl_offsets { + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), + MISC = offsetof(struct ctrl_reg, misc), + LED_CONTROL = offsetof(struct ctrl_reg, led_control), + INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), + CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), + CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), + CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), + CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), + CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), + CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), + CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), + SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), + SLOT_POWER = offsetof(struct ctrl_reg, slot_power), + NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), + RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), +}; + +struct hrt { + char sig0; + char sig1; + char sig2; + char sig3; + u16 unused_IRQ; + u16 PCIIRQ; + u8 number_of_entries; + u8 revision; + u16 reserved1; + u32 reserved2; +} __attribute__ ((packed)); + +/* offsets to the hotplug resource table registers based on the above structure layout */ +enum hrt_offsets { + SIG0 = offsetof(struct hrt, sig0), + SIG1 = offsetof(struct hrt, sig1), + SIG2 = offsetof(struct hrt, sig2), + SIG3 = offsetof(struct hrt, sig3), + UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), + PCIIRQ = offsetof(struct hrt, PCIIRQ), + NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), + REVISION = offsetof(struct hrt, revision), + HRT_RESERVED1 = offsetof(struct hrt, reserved1), + HRT_RESERVED2 = offsetof(struct hrt, reserved2), +}; + +struct slot_rt { + u8 dev_func; + u8 primary_bus; + u8 secondary_bus; + u8 max_bus; + u16 io_base; + u16 io_length; + u16 mem_base; + u16 mem_length; + u16 pre_mem_base; + u16 pre_mem_length; +} __attribute__ ((packed)); + +/* offsets to the hotplug slot resource table registers based on the above structure layout */ +enum slot_rt_offsets { + DEV_FUNC = offsetof(struct slot_rt, dev_func), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), +}; + +struct pci_func { + struct pci_func *next; + u8 bus; + u8 device; + u8 function; + u8 is_a_board; + u16 status; + u8 configured; + u8 switch_save; + u8 presence_save; + u32 base_length[0x06]; + u8 base_type[0x06]; + u16 reserved2; + u32 config_space[0x20]; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct timer_list *p_task_event; + struct pci_dev* pci_dev; +}; + +#define SLOT_MAGIC 0x67267321 +struct slot { + u32 magic; + struct slot *next; + u8 bus; + u8 device; + u8 number; + u8 is_a_board; + u8 configured; + u8 state; + u8 switch_save; + u8 presence_save; + u32 capabilities; + u16 reserved2; + struct timer_list task_event; + u8 hp_slot; + struct controller *ctrl; + void *p_sm_slot; + struct hotplug_slot *hotplug_slot; +}; + +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +struct event_info { + u32 event_type; + u8 hp_slot; +}; + +struct controller { + struct controller *next; + u32 ctrl_int_comp; + struct semaphore crit_sect; /* critical section semaphore */ + void *hpc_reg; /* cookie for our pci controller location */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct pci_dev *pci_dev; + struct pci_bus *pci_bus; + struct event_info event_queue[10]; + struct slot *slot; + u8 next_event; + u8 interrupt; + u8 cfgspc_irq; + u8 bus; /* bus number for the pci hotplug controller */ + u8 rev; + u8 slot_device_offset; + u8 first_slot; + u8 add_support; + u8 push_flag; + enum pci_bus_speed speed; + enum pci_bus_speed speed_capability; + u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ + u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ + u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ + u8 alternate_base_address; /* 0 = not supported, 1 = supported */ + u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ + u8 pcix_speed_capability; /* PCI-X */ + u8 pcix_support; /* PCI-X */ + u16 vendor_id; + struct work_struct int_task_event; + wait_queue_head_t queue; /* sleep & wake process */ +}; + +struct irq_mapping { + u8 barber_pole; + u8 valid_INT; + u8 interrupt[4]; +}; + +struct resource_lists { + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct irq_mapping *irqs; +}; + +#define ROM_PHY_ADDR 0x0F0000 +#define ROM_PHY_LEN 0x00ffff + +#define PCI_HPC_ID 0xA0F7 +#define PCI_SUB_HPC_ID 0xA2F7 +#define PCI_SUB_HPC_ID2 0xA2F8 +#define PCI_SUB_HPC_ID3 0xA2F9 +#define PCI_SUB_HPC_ID_INTC 0xA2FA +#define PCI_SUB_HPC_ID4 0xA2FD + +#define INT_BUTTON_IGNORE 0 +#define INT_PRESENCE_ON 1 +#define INT_PRESENCE_OFF 2 +#define INT_SWITCH_CLOSE 3 +#define INT_SWITCH_OPEN 4 +#define INT_POWER_FAULT 5 +#define INT_POWER_FAULT_CLEAR 6 +#define INT_BUTTON_PRESS 7 +#define INT_BUTTON_RELEASE 8 +#define INT_BUTTON_CANCEL 9 + +#define STATIC_STATE 0 +#define BLINKINGON_STATE 1 +#define BLINKINGOFF_STATE 2 +#define POWERON_STATE 3 +#define POWEROFF_STATE 4 + +#define PCISLOT_INTERLOCK_CLOSED 0x00000001 +#define PCISLOT_ADAPTER_PRESENT 0x00000002 +#define PCISLOT_POWERED 0x00000004 +#define PCISLOT_66_MHZ_OPERATION 0x00000008 +#define PCISLOT_64_BIT_OPERATION 0x00000010 +#define PCISLOT_REPLACE_SUPPORTED 0x00000020 +#define PCISLOT_ADD_SUPPORTED 0x00000040 +#define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 +#define PCISLOT_66_MHZ_SUPPORTED 0x00000100 +#define PCISLOT_64_BIT_SUPPORTED 0x00000200 + + + +#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 + + +#define INTERLOCK_OPEN 0x00000002 +#define ADD_NOT_SUPPORTED 0x00000003 +#define CARD_FUNCTIONING 0x00000005 +#define ADAPTER_NOT_SAME 0x00000006 +#define NO_ADAPTER_PRESENT 0x00000009 +#define NOT_ENOUGH_RESOURCES 0x0000000B +#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C +#define POWER_FAILURE 0x0000000E + +#define REMOVE_NOT_SUPPORTED 0x00000003 + + +/* + * error Messages + */ +#define msg_initialization_err "Initialization failure, error=%d\n" +#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" +#define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" +#define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" +#define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" +#define msg_button_on "PCI slot #%d - powering on due to button press.\n" +#define msg_button_off "PCI slot #%d - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" + + +/* sysfs functions for the hotplug controller info */ +extern void cpqhp_create_ctrl_files (struct controller *ctrl); + +/* controller functions */ +extern void cpqhp_pushbutton_thread (unsigned long event_pointer); +extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs); +extern int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start); +extern int cpqhp_event_start_thread (void); +extern void cpqhp_event_stop_thread (void); +extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); +extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); +extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); + +/* resource functions */ +extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); + +/* pci functions */ +extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); +extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); +extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); +extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); +extern void cpqhp_destroy_board_resources (struct pci_func * func); +extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); +extern void cpqhp_destroy_resource_list (struct resource_lists * resources); +extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); +extern int cpqhp_unconfigure_device (struct pci_func* func); +extern struct slot *cpqhp_find_slot (struct controller *ctrl, u8 device); + +/* Global variables */ +extern int cpqhp_debug; +extern struct controller *cpqhp_ctrl_list; +extern struct pci_func *cpqhp_slot_list[256]; + +/* these can be gotten rid of, but for debugging they are purty */ +extern u8 cpqhp_nic_irq; +extern u8 cpqhp_disk_irq; + + + +/* inline functions */ + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + +/* + * return_resource + * + * Puts node back in the resource list pointed to by head + * + */ +static inline void return_resource (struct pci_resource **head, struct pci_resource *node) +{ + if (!node || !head) + return; + node->next = *head; + *head = node; +} + +static inline void set_SOGO (struct controller *ctrl) +{ + u16 misc; + + misc = readw(ctrl->hpc_reg + MISC); + misc = (misc | 0x0001) & 0xFFFB; + writew(misc, ctrl->hpc_reg + MISC); +} + + +static inline void amber_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= (0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void amber_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline int read_amber_LED (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= (0x01010000L << slot); + + return led_control ? 1 : 0; +} + + +static inline void green_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= 0x0101L << slot; + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + +static inline void green_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void green_LED_blink (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); + led_control |= (0x0001L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void slot_disable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= ~(0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline void slot_enable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable |= (0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline u8 is_slot_enabled (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= (0x01 << slot); + return slot_enable ? 1 : 0; +} + + +static inline u8 read_slot_enable (struct controller *ctrl) +{ + return readb(ctrl->hpc_reg + SLOT_ENABLE); +} + + +/* + * get_controller_speed - find the current frequency/mode of controller. + * + * @ctrl: controller to get frequency/mode for. + * + * Returns controller speed. + * + */ +static inline u8 get_controller_speed (struct controller *ctrl) +{ + u8 curr_freq; + u16 misc; + + if (ctrl->pcix_support) { + curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); + if ((curr_freq & 0xB0) == 0xB0) + return PCI_SPEED_133MHz_PCIX; + if ((curr_freq & 0xA0) == 0xA0) + return PCI_SPEED_100MHz_PCIX; + if ((curr_freq & 0x90) == 0x90) + return PCI_SPEED_66MHz_PCIX; + if (curr_freq & 0x10) + return PCI_SPEED_66MHz; + + return PCI_SPEED_33MHz; + } + + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; +} + + +/* + * get_adapter_speed - find the max supported frequency/mode of adapter. + * + * @ctrl: hotplug controller. + * @hp_slot: hotplug slot where adapter is installed. + * + * Returns adapter speed. + * + */ +static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot) +{ + u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); + dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); + if (ctrl->pcix_support) { + if (temp_dword & (0x10000 << hp_slot)) + return PCI_SPEED_133MHz_PCIX; + if (temp_dword & (0x100 << hp_slot)) + return PCI_SPEED_66MHz_PCIX; + } + + if (temp_dword & (0x01 << hp_slot)) + return PCI_SPEED_66MHz; + + return PCI_SPEED_33MHz; +} + +static inline void enable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power |= (0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + +static inline void disable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power &= ~(0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + + +static inline int cpq_get_attention_status (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return read_amber_LED (ctrl, hp_slot); +} + + +static inline int get_slot_enabled (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return is_slot_enabled (ctrl, hp_slot); +} + + +static inline int cpq_get_latch_status (struct controller *ctrl, struct slot *slot) +{ + u32 status; + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", + __FUNCTION__, slot->device, ctrl->slot_device_offset); + + status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); + + return(status == 0) ? 1 : 0; +} + + +static inline int get_presence_status (struct controller *ctrl, struct slot *slot) +{ + int presence_save = 0; + u8 hp_slot; + u32 tempdword; + + if (slot == NULL) + return 0; + + hp_slot = slot->device - ctrl->slot_device_offset; + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + + return presence_save; +} + +#define SLOT_NAME_SIZE 10 + +static inline void make_slot_name (char *buffer, int buffer_size, struct slot *slot) +{ + snprintf (buffer, buffer_size, "%d", slot->number); +} + + +static inline int wait_for_ctrl_irq (struct controller *ctrl) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + dbg("%s - start\n", __FUNCTION__); + add_wait_queue(&ctrl->queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + /* Sleep for up to 1 second to wait for the LED to change. */ + schedule_timeout(1*HZ); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctrl->queue, &wait); + if (signal_pending(current)) + retval = -EINTR; + + dbg("%s - end\n", __FUNCTION__); + return retval; +} + + +/** + * set_controller_speed - set the frequency and/or mode of a specific + * controller segment. + * + * @ctrl: controller to change frequency/mode for. + * @adapter_speed: the speed of the adapter we want to match. + * @hp_slot: the slot number where the adapter is installed. + * + * Returns 0 if we successfully change frequency and/or mode to match the + * adapter speed. + * + */ +static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot) +{ + struct slot *slot; + u8 reg; + u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + u16 reg16; + u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); + + if (ctrl->speed == adapter_speed) + return 0; + + /* We don't allow freq/mode changes if we find another adapter running + * in another slot on this controller */ + for(slot = ctrl->slot; slot; slot = slot->next) { + if (slot->device == (hp_slot + ctrl->slot_device_offset)) + continue; + if (!slot->hotplug_slot && !slot->hotplug_slot->info) + continue; + if (slot->hotplug_slot->info->adapter_status == 0) + continue; + /* If another adapter is running on the same segment but at a + * lower speed/mode, we allow the new adapter to function at + * this rate if supported */ + if (ctrl->speed < adapter_speed) + return 0; + + return 1; + } + + /* If the controller doesn't support freq/mode changes and the + * controller is running at a higher mode, we bail */ + if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) + return 1; + + /* But we allow the adapter to run at a lower rate if possible */ + if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) + return 0; + + /* We try to set the max speed supported by both the adapter and + * controller */ + if (ctrl->speed_capability < adapter_speed) { + if (ctrl->speed == ctrl->speed_capability) + return 0; + adapter_speed = ctrl->speed_capability; + } + + writel(0x0L, ctrl->hpc_reg + LED_CONTROL); + writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); + + set_SOGO(ctrl); + wait_for_ctrl_irq(ctrl); + + if (adapter_speed != PCI_SPEED_133MHz_PCIX) + reg = 0xF5; + else + reg = 0xF4; + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + + reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); + reg16 &= ~0x000F; + switch(adapter_speed) { + case(PCI_SPEED_133MHz_PCIX): + reg = 0x75; + reg16 |= 0xB; + break; + case(PCI_SPEED_100MHz_PCIX): + reg = 0x74; + reg16 |= 0xA; + break; + case(PCI_SPEED_66MHz_PCIX): + reg = 0x73; + reg16 |= 0x9; + break; + case(PCI_SPEED_66MHz): + reg = 0x73; + reg16 |= 0x1; + break; + default: /* 33MHz PCI 2.2 */ + reg = 0x71; + break; + + } + reg16 |= 0xB << 12; + writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); + + mdelay(5); + + /* Reenable interrupts */ + writel(0, ctrl->hpc_reg + INT_MASK); + + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + + /* Restart state machine */ + reg = ~0xF; + pci_read_config_byte(ctrl->pci_dev, 0x43, ®); + pci_write_config_byte(ctrl->pci_dev, 0x43, reg); + + /* Only if mode change...*/ + if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || + ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) + set_SOGO(ctrl); + + wait_for_ctrl_irq(ctrl); + mdelay(1100); + + /* Restore LED/Slot state */ + writel(leds, ctrl->hpc_reg + LED_CONTROL); + writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); + + set_SOGO(ctrl); + wait_for_ctrl_irq(ctrl); + + ctrl->speed = adapter_speed; + slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + info("Successfully changed frequency/mode for adapter in slot %d\n", + slot->number); + return 0; +} + +#endif + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_core.c linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_core.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_core.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1541 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, + * Torben Mathiasen + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ + + +/* Global variables */ +int cpqhp_debug; +struct controller *cpqhp_ctrl_list; /* = NULL */ +struct pci_func *cpqhp_slot_list[256]; + +/* local variables */ +static void *smbios_table; +static void *smbios_start; +static void *cpqhp_rom_start; +static u8 power_mode; +static int debug; + +#define DRIVER_VERSION "0.9.7" +#define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman " +#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(power_mode, "b"); +MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +#define CPQHPC_MODULE_MINOR 208 + +static int one_time_init (void); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int process_SI (struct hotplug_slot *slot); +static int process_SS (struct hotplug_slot *slot); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); +static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); + +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .set_attention_status = set_attention_status, + .enable_slot = process_SI, + .disable_slot = process_SS, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + + +static inline int is_slot64bit (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) + return 1; + + return 0; +} + +static inline int is_slot66mhz (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) + return 1; + + return 0; +} + +/** + * detect_SMBIOS_pointer - find the system Management BIOS Table in the specified region of memory. + * + * @begin: begin pointer for region to be scanned. + * @end: end pointer for region to be scanned. + * + * Returns pointer to the head of the SMBIOS tables (or NULL) + * + */ +static void * detect_SMBIOS_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(u32) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp); + temp2 = readb(fp+1); + temp3 = readb(fp+2); + temp4 = readb(fp+3); + if (temp1 == '_' && + temp2 == 'S' && + temp3 == 'M' && + temp4 == '_') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered SMBIOS Entry point at %p\n", fp); + + return fp; +} + +/** + * init_SERR - Initializes the per slot SERR generation. + * + * For unexpected switch opens + * + */ +static int init_SERR(struct controller * ctrl) +{ + u32 tempdword; + u32 number_of_slots; + u8 physical_slot; + + if (!ctrl) + return 1; + + tempdword = ctrl->first_slot; + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + // Loop through slots + while (number_of_slots) { + physical_slot = tempdword; + writeb(0, ctrl->hpc_reg + SLOT_SERR); + tempdword++; + number_of_slots--; + } + + return 0; +} + + +/* nice debugging output */ +static int pci_print_IRQ_route (void) +{ + struct irq_routing_table *routing_table; + int len; + int loop; + + u8 tbus, tdevice, tslot; + + routing_table = pcibios_get_irq_routing_table(); + if (routing_table == NULL) { + err("No BIOS Routing Table??? Not good\n"); + return -ENOMEM; + } + + len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + kfree(routing_table); + return -1; + } + + dbg("bus dev func slot\n"); + + for (loop = 0; loop < len; ++loop) { + tbus = routing_table->slots[loop].bus; + tdevice = routing_table->slots[loop].devfn; + tslot = routing_table->slots[loop].slot; + dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); + + } + kfree(routing_table); + return 0; +} + + +/* + * get_subsequent_smbios_entry + * + * Gets the first entry if previous == NULL + * Otherwise, returns the next entry + * Uses global SMBIOS Table pointer + * + * @curr: %NULL or pointer to previously returned structure + * + * returns a pointer to an SMBIOS structure or NULL if none found + */ +static void * get_subsequent_smbios_entry(void *smbios_start, void *smbios_table, void *curr) +{ + u8 bail = 0; + u8 previous_byte = 1; + void *p_temp; + void *p_max; + + if (!smbios_table || !curr) + return(NULL); + + // set p_max to the end of the table + p_max = smbios_start + readw(smbios_table + ST_LENGTH); + + p_temp = curr; + p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); + + while ((p_temp < p_max) && !bail) { + // Look for the double NULL terminator + // The first condition is the previous byte and the second is the curr + if (!previous_byte && !(readb(p_temp))) { + bail = 1; + } + + previous_byte = readb(p_temp); + p_temp++; + } + + if (p_temp < p_max) { + return p_temp; + } else { + return NULL; + } +} + + +/** + * get_SMBIOS_entry + * + * @type:SMBIOS structure type to be returned + * @previous: %NULL or pointer to previously returned structure + * + * Gets the first entry of the specified type if previous == NULL + * Otherwise, returns the next entry of the given type. + * Uses global SMBIOS Table pointer + * Uses get_subsequent_smbios_entry + * + * returns a pointer to an SMBIOS structure or %NULL if none found + */ +static void *get_SMBIOS_entry (void *smbios_start, void *smbios_table, u8 type, void * previous) +{ + if (!smbios_table) + return NULL; + + if (!previous) { + previous = smbios_start; + } else { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } + + while (previous) { + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } else { + break; + } + } + + return previous; +} + + +static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *smbios_table) +{ + struct slot *new_slot; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + void *slot_entry= NULL; + int result; + + dbg("%s\n", __FUNCTION__); + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!new_slot) + return -ENOMEM; + + memset(new_slot, 0, sizeof(struct slot)); + new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!new_slot->hotplug_slot) { + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!new_slot->hotplug_slot->info) { + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!new_slot->hotplug_slot->name) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->magic = SLOT_MAGIC; + new_slot->ctrl = ctrl; + new_slot->bus = ctrl->bus; + new_slot->device = slot_device; + new_slot->number = slot_number; + dbg("slot->number = %d\n",new_slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + } + + new_slot->p_sm_slot = slot_entry; + + init_timer(&new_slot->task_event); + new_slot->task_event.expires = jiffies + 5 * HZ; + new_slot->task_event.function = cpqhp_pushbutton_thread; + + //FIXME: these capabilities aren't used but if they are + // they need to be correctly implemented + new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(new_slot)) + new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(new_slot)) + new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (ctrl->speed == PCI_SPEED_66MHz) + new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + // Check presence + new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + // Check the switch state + new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + // Check the slot enable + new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + new_slot->hotplug_slot->private = new_slot; + make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); + new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); + new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); + new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); + + dbg ("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", + new_slot->bus, new_slot->device, new_slot->number, ctrl->slot_device_offset, slot_number); + result = pci_hp_register (new_slot->hotplug_slot); + if (result) { + err ("pci_hp_register failed with error %d\n", result); + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot->name); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return result; + } + + new_slot->next = ctrl->slot; + ctrl->slot = new_slot; + + number_of_slots--; + slot_device++; + slot_number++; + } + + return(0); +} + + +static int ctrl_slot_cleanup (struct controller * ctrl) +{ + struct slot *old_slot, *next_slot; + + old_slot = ctrl->slot; + ctrl->slot = NULL; + + while (old_slot) { + next_slot = old_slot->next; + pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot->info); + kfree(old_slot->hotplug_slot->name); + kfree(old_slot->hotplug_slot); + kfree(old_slot); + old_slot = next_slot; + } + + //Free IRQ associated with hot plug device + free_irq(ctrl->interrupt, ctrl); + //Unmap the memory + iounmap(ctrl->hpc_reg); + //Finally reclaim PCI mem + release_mem_region(pci_resource_start(ctrl->pci_dev, 0), + pci_resource_len(ctrl->pci_dev, 0)); + + return(0); +} + + +//============================================================================ +// function: get_slot_mapping +// +// Description: Attempts to determine a logical slot mapping for a PCI +// device. Won't work for more than one PCI-PCI bridge +// in a slot. +// +// Input: u8 bus_num - bus number of PCI device +// u8 dev_num - device number of PCI device +// u8 *slot - Pointer to u8 where slot number will +// be returned +// +// Output: SUCCESS or FAILURE +//============================================================================= +static int get_slot_mapping (struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + u32 work; + long len; + long loop; + + u8 tbus, tdevice, tslot, bridgeSlot; + + dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot); + + bridgeSlot = 0xFF; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + if (!PCIIRQRoutingInfoLength) + return -1; + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if ((tbus == bus_num) && (tdevice == dev_num)) { + *slot = tslot; + + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength); + return 0; + } else { + // Didn't get a match on the target PCI device. Check if the + // current IRQ table entry is a PCI-to-PCI bridge device. If so, + // and it's secondary bus matches the bus number for the target + // device, I need to save the bridge's slot number. If I can't + // find an entry for the target device, I will have to assume it's + // on the other side of the bridge, and assign it the bridge's slot. + bus->number = tbus; + pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_REVISION_ID, &work); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); + // See if bridge's secondary bus matches target bus. + if (((work >> 8) & 0x000000FF) == (long) bus_num) { + bridgeSlot = tslot; + } + } + } + + } + + // If we got here, we didn't find an entry in the IRQ mapping table + // for the target PCI device. If we did determine that the target + // device is on the other side of a PCI-to-PCI bridge, return the + // slot number for the bridge. + if (bridgeSlot != 0xFF) { + *slot = bridgeSlot; + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return 0; + } + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + // Couldn't find an entry in the routing table for this PCI device + return -1; +} + + +/** + * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int cpqhp_set_attention_status (struct controller *ctrl, struct pci_func *func, u32 status) +{ + u8 hp_slot; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (func == NULL) + return(1); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (status == 1) { + amber_LED_on (ctrl, hp_slot); + } else if (status == 0) { + amber_LED_off (ctrl, hp_slot); + } else { + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(1); + } + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(0); +} + + +/** + * set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + return cpqhp_set_attention_status(ctrl, slot_func, status); +} + + +static int process_SI (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + slot_func->bus = bus; + slot_func->device = device; + slot_func->function = function; + slot_func->configured = 0; + dbg("board_added(%p, %p)\n", slot_func, ctrl); + return cpqhp_process_SI(ctrl, slot_func); +} + + +static int process_SS (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + dbg("In power_down_board, slot_func = %p, ctrl = %p\n", slot_func, ctrl); + return cpqhp_process_SS(ctrl, slot_func); +} + + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + if (slot == NULL) + return -ENODEV; + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + return cpqhp_hardware_test (ctrl, value); +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_slot_enabled(ctrl, slot); + return 0; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_attention_status(ctrl, slot); + return 0; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_latch_status (ctrl, slot); + + return 0; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_presence_status (ctrl, slot); + + return 0; +} + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = ctrl->speed_capability; + + return 0; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = ctrl->speed; + + return 0; +} + +static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u8 num_of_slots = 0; + u8 hp_slot = 0; + u8 device; + u8 rev; + u8 bus_cap; + u16 temp_word; + u16 vendor_id; + u16 subsystem_vid; + u16 subsystem_deviceid; + u32 rc; + struct controller *ctrl; + struct pci_func *func; + + // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery + rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); + if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + dbg("Vendor ID: %x\n", vendor_id); + + rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + dbg("revision: %d\n", rev); + if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { + err(msg_HPC_rev_error); + return -ENODEV; + } + + /* Check for the proper subsytem ID's + * Intel uses a different SSID programming model than Compaq. + * For Intel, each SSID bit identifies a PHP capability. + * Also Intel HPC's may have RID=0. + */ + if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { + // TODO: This code can be made to support non-Compaq or Intel subsystem IDs + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); + if (rc) { + err("%s : pci_read_config_word failed\n", __FUNCTION__); + return rc; + } + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __FUNCTION__); + return -ENOMEM; + } + memset(ctrl, 0, sizeof(struct controller)); + + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); + if (rc) { + err("%s : pci_read_config_word failed\n", __FUNCTION__); + goto err_free_ctrl; + } + + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other functions */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + if (rev >= 0x13) { /* CIOBX */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 1; // PCI-X supported + ctrl->pcix_speed_capability = 1; + pci_read_config_byte(pdev, 0x41, &bus_cap); + if (bus_cap & 0x80) { + dbg("bus max supports 133MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; + break; + } + if (bus_cap & 0x40) { + dbg("bus max supports 100MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + break; + } + if (bus_cap & 20) { + dbg("bus max supports 66MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; + break; + } + if (bus_cap & 10) { + dbg("bus max supports 66MHz PCI\n"); + ctrl->speed_capability = PCI_SPEED_66MHz; + break; + } + + break; + } + + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_66MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID4: + /* First PCI-X implementation, 100MHz */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 1; // PCI-X supported + ctrl->pcix_speed_capability = 0; + break; + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) { + ctrl->speed_capability = PCI_SPEED_66MHz; + } else { + ctrl->speed_capability = PCI_SPEED_33MHz; + } + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) { + /* no push button */ + ctrl->push_button = 0; + } else { + /* push button supported */ + ctrl->push_button = 1; + } + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) { + /* no switch */ + ctrl->slot_switch_type = 0; + } else { + /* switch */ + ctrl->slot_switch_type = 1; + } + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) { + ctrl->defeature_PHP = 1; // PHP supported + } else { + ctrl->defeature_PHP = 0; // PHP not supported + } + + /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0010) { + ctrl->alternate_base_address = 1; // supported + } else { + ctrl->alternate_base_address = 0; // not supported + } + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) { + ctrl->pci_config_space = 1; // supported + } else { + ctrl->pci_config_space = 0; // not supported + } + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + /* PCI-X capable */ + ctrl->pcix_support = 1; + /* Frequency of operation in PCI-X mode */ + if (subsystem_deviceid & 0x0040) { + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + } else { + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + + } else { + err(msg_HPC_not_supported); + return -ENODEV; + } + + // Tell the user that we found one. + info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); + + dbg ("Hotplug controller capabilities:\n"); + dbg (" speed_capability %d\n", ctrl->speed_capability); + dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); + dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); + dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); + dbg (" pci_config_space %s\n", ctrl->pci_config_space == 0 ? "not supported" : "supported"); + dbg (" pcix_speed_capability %s\n", ctrl->pcix_speed_capability == 0 ? "not supported" : "supported"); + dbg (" pcix_support %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported"); + + ctrl->pci_dev = pdev; + pci_set_drvdata(pdev, ctrl); + + /* make our own copy of the pci bus structure, as we like tweaking it a lot */ + ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); + if (!ctrl->pci_bus) { + err("out of memory\n"); + rc = -ENOMEM; + goto err_free_ctrl; + } + memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); + + ctrl->bus = pdev->bus->number; + ctrl->rev = rev; + dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev); + + init_MUTEX(&ctrl->crit_sect); + init_waitqueue_head(&ctrl->queue); + + /* initialize our threads if they haven't already been started up */ + rc = one_time_init(); + if (rc) { + goto err_free_bus; + } + + dbg("pdev = %p\n", pdev); + dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); + dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), MY_NAME)) { + err("cannot reserve MMIO region\n"); + rc = -ENOMEM; + goto err_free_bus; + } + + ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!ctrl->hpc_reg) { + err("cannot remap MMIO region %lx @ %lx\n", pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); + rc = -ENODEV; + goto err_free_mem_region; + } + + // Check for 66Mhz operation + ctrl->speed = get_controller_speed(ctrl); + + + //************************************************** + // + // Save configuration headers for this and + // subordinate PCI buses + // + //************************************************** + + // find the physical slot number of the first hot plug slot + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of a slot. + // CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table) + rc = get_slot_mapping(ctrl->pci_bus, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot)); + dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc); + if (rc) { + err(msg_initialization_err, rc); + goto err_iounmap; + } + + // Store PCI Config Space for all devices on this bus + rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); + if (rc) { + err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); + goto err_iounmap; + } + + /* + * Get IO, memory, and IRQ resources for new devices + */ + // The next line is required for cpqhp_find_available_resources + ctrl->interrupt = pdev->irq; + + ctrl->cfgspc_irq = 0; + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq); + + rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); + ctrl->add_support = !rc; + if (rc) { + dbg("cpqhp_find_available_resources = 0x%x\n", rc); + err("unable to locate PCI configuration resources for hot plug add.\n"); + goto err_iounmap; + } + + /* + * Finish setting up the hot plug ctrl device + */ + ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + dbg("NumSlots %d \n", ctrl->slot_device_offset); + + ctrl->next_event = 0; + + /* Setup the slot information structures */ + rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table); + if (rc) { + err(msg_initialization_err, 6); + err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); + goto err_iounmap; + } + + /* Mask all general input interrupts */ + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); + + /* set up the interrupt */ + dbg("HPC interrupt = %d \n", ctrl->interrupt); + if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr, + SA_SHIRQ, MY_NAME, ctrl)) { + err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); + rc = -ENODEV; + goto err_iounmap; + } + + /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + temp_word = readw(ctrl->hpc_reg + MISC); + temp_word |= 0x4006; + writew(temp_word, ctrl->hpc_reg + MISC); + + // Changed 05/05/97 to clear all interrupts at start + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + writel(0x0L, ctrl->hpc_reg + INT_MASK); + + if (!cpqhp_ctrl_list) { + cpqhp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = cpqhp_ctrl_list; + cpqhp_ctrl_list = ctrl; + } + + // turn off empty slots here unless command line option "ON" set + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + + // find first device number for the ctrl + device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + + while (num_of_slots) { + dbg("num_of_slots: %d\n", num_of_slots); + func = cpqhp_slot_find(ctrl->bus, device, 0); + if (!func) + break; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("hp_slot: %d\n", hp_slot); + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + if (!power_mode) { + if (!func->is_a_board) { + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + } + } + + device++; + num_of_slots--; + } + + if (!power_mode) { + set_SOGO(ctrl); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + + rc = init_SERR(ctrl); + if (rc) { + err("init_SERR failed\n"); + up(&ctrl->crit_sect); + goto err_free_irq; + } + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + cpqhp_create_ctrl_files (ctrl); + + return 0; + +err_free_irq: + free_irq(ctrl->interrupt, ctrl); +err_iounmap: + iounmap(ctrl->hpc_reg); +err_free_mem_region: + release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +err_free_bus: + kfree(ctrl->pci_bus); +err_free_ctrl: + kfree(ctrl); + return rc; +} + + +static int one_time_init(void) +{ + int loop; + int retval = 0; + static int initialized = 0; + + if (initialized) + return 0; + + power_mode = 0; + + retval = pci_print_IRQ_route(); + if (retval) + goto error; + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) { + cpqhp_slot_list[loop] = NULL; + } + + // FIXME: We also need to hook the NMI handler eventually. + // this also needs to be worked with Christoph + // register_NMI_handler(); + + // Map rom address + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO;; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific hardware */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO;; + goto error; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO;; + goto error; + } + + initialized = 1; + + return retval; + +error: + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); + + return retval; +} + + +static void unload_cpqphpd(void) +{ + struct pci_func *next; + struct pci_func *TempSlot; + int loop; + u32 rc; + struct controller *ctrl; + struct controller *tctrl; + struct pci_resource *res; + struct pci_resource *tres; + + rc = compaq_nvram_store(cpqhp_rom_start); + + ctrl = cpqhp_ctrl_list; + + while (ctrl) { + if (ctrl->hpc_reg) { + u16 misc; + rc = read_slot_enable (ctrl); + + writeb(0, ctrl->hpc_reg + SLOT_SERR); + writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); + + misc = readw(ctrl->hpc_reg + MISC); + misc &= 0xFFFD; + writew(misc, ctrl->hpc_reg + MISC); + } + + ctrl_slot_cleanup(ctrl); + + res = ctrl->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + kfree (ctrl->pci_bus); + + tctrl = ctrl; + ctrl = ctrl->next; + kfree(tctrl); + } + + for (loop = 0; loop < 256; loop++) { + next = cpqhp_slot_list[loop]; + while (next != NULL) { + res = next->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + TempSlot = next; + next = next->next; + kfree(TempSlot); + } + } + + // Stop the notification mechanism + cpqhp_event_stop_thread(); + + //unmap the rom address + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); +} + + + +static struct pci_device_id hpcd_pci_tbl[] __devinitdata = { + { + /* handle any PCI Hotplug controller */ + .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), + .class_mask = ~0, + + /* no matter who makes it */ + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); + + + +static struct pci_driver cpqhpc_driver = { + .name = "pci_hotplug", + .id_table = hpcd_pci_tbl, + .probe = cpqhpc_probe, + /* remove: cpqhpc_remove_one, */ +}; + + + +static int __init cpqhpc_init(void) +{ + int result; + + cpqhp_debug = debug; + + result = pci_module_init(&cpqhpc_driver); + dbg("pci_module_init = %d\n", result); + if (result) + return result; + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + return 0; +} + + +static void __exit cpqhpc_cleanup(void) +{ + dbg("unload_cpqphpd()\n"); + unload_cpqphpd(); + + dbg("pci_unregister_driver\n"); + pci_unregister_driver(&cpqhpc_driver); +} + + +module_init(cpqhpc_init); +module_exit(cpqhpc_cleanup); + + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_ctrl.c linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_ctrl.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_ctrl.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_ctrl.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,3084 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" + +static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static int configure_new_function(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static void interrupt_event_handler(struct controller *ctrl); + +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ + +/* things needed for the long_delay function */ +static struct semaphore delay_sem; +static wait_queue_head_t delay_wait; + +/* delay is in jiffies to wait for */ +static void long_delay (int delay) +{ + DECLARE_WAITQUEUE(wait, current); + + /* only allow 1 customer into the delay queue at once + * yes this makes some people wait even longer, but who really cares? + * this is for _huge_ delays to make the hardware happy as the + * signals bounce around + */ + down (&delay_sem); + + init_waitqueue_head (&delay_wait); + + add_wait_queue(&delay_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delay); + remove_wait_queue(&delay_wait, &wait); + set_current_state(TASK_RUNNING); + + up (&delay_sem); +} + + +//FIXME: The following line needs to be somewhere else... +#define WRONG_BUS_FREQUENCY 0x07 +static u8 handle_switch_change(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + // Switch Change + dbg("cpqsbd: Switch interrupt received.\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x1L << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + //this is the structure that tells the worker thread + //what to do + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + //********************************* + // Switch opened + //********************************* + + func->switch_save = 0; + + taskInfo->event_type = INT_SWITCH_OPEN; + } else { + //********************************* + // Switch closed + //********************************* + + func->switch_save = 0x10; + + taskInfo->event_type = INT_SWITCH_CLOSE; + } + } + } + + return rc; +} + + +/* + * cpqhp_find_slot + */ +struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device) +{ + struct slot *slot; + + if (!ctrl) + return NULL; + + slot = ctrl->slot; + + while (slot && (slot->device != device)) { + slot = slot->next; + } + + return slot; +} + + +static u8 handle_presence_change(u16 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u8 temp_byte; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + struct slot *p_slot; + + if (!change) + return 0; + + //********************************* + // Presence Change + //********************************* + dbg("cpqsbd: Presence/Notify input change.\n"); + dbg(" Changed bits are 0x%4.4x\n", change ); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x0101 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); + if (!p_slot) + return 0; + + // If the switch closed, must be a button + // If not in button mode, nevermind + if (func->switch_save && (ctrl->push_button == 1)) { + temp_word = ctrl->ctrl_int_comp >> 16; + temp_byte = (temp_word >> hp_slot) & 0x01; + temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (temp_byte != func->presence_save) { + //********************************* + // button Pressed (doesn't do anything) + //********************************* + dbg("hp_slot %d button pressed\n", hp_slot); + taskInfo->event_type = INT_BUTTON_PRESS; + } else { + //********************************* + // button Released - TAKE ACTION!!!! + //********************************* + dbg("hp_slot %d button released\n", hp_slot); + taskInfo->event_type = INT_BUTTON_RELEASE; + + // Cancel if we are still blinking + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + taskInfo->event_type = INT_BUTTON_CANCEL; + dbg("hp_slot %d button cancel\n", hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + //info(msg_button_ignore, p_slot->number); + taskInfo->event_type = INT_BUTTON_IGNORE; + dbg("hp_slot %d button ignore\n", hp_slot); + } + } + } else { + // Switch is open, assume a presence change + // Save the presence state + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) || + (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) { + //********************************* + // Present + //********************************* + taskInfo->event_type = INT_PRESENCE_ON; + } else { + //********************************* + // Not Present + //********************************* + taskInfo->event_type = INT_PRESENCE_OFF; + } + } + } + } + + return rc; +} + + +static u8 handle_power_fault(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + //********************************* + // power fault + //********************************* + + info("power fault interrupt\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x01 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { + //********************************* + // power fault Cleared + //********************************* + func->status = 0x00; + + taskInfo->event_type = INT_POWER_FAULT_CLEAR; + } else { + //********************************* + // power fault + //********************************* + taskInfo->event_type = INT_POWER_FAULT; + + if (ctrl->rev < 4) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + set_SOGO (ctrl); + + // this is a fatal condition, we want to crash the + // machine to protect from data corruption + // simulated_NMI shouldn't ever return + //FIXME + //simulated_NMI(hp_slot, ctrl); + + //The following code causes a software crash just in + //case simulated_NMI did return + //FIXME + //panic(msg_power_fault); + } else { + // set power fault status for this board + func->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } + } + } + } + + return rc; +} + + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * do_pre_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + struct pci_resource *split_node; + u32 rc; + u32 temp_dword; + dbg("do_pre_bridge_resource_split\n"); + + if (!(*head) || !(*orig_head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + if ((*head)->base != (*orig_head)->base) + return(NULL); + + if ((*head)->length == (*orig_head)->length) + return(NULL); + + + // If we got here, there the bridge requires some of the resource, but + // we may be able to split some off of the front + + node = *head; + + if (node->length & (alignment -1)) { + // this one isn't an aligned length, so we'll make a new entry + // and split it up. + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + temp_dword = (node->length | (alignment-1)) + 1 - alignment; + + split_node->base = node->base; + split_node->length = temp_dword; + + node->length -= temp_dword; + node->base += split_node->length; + + // Put it in the list + *head = split_node; + split_node->next = node; + } + + if (node->length < alignment) { + return(NULL); + } + + // Now unlink it + if (*head == node) { + *head = node->next; + node->next = NULL; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + node->next = NULL; + } + + return(node); +} + + +/* + * do_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + u32 rc; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + node = *head; + + while (node->next) { + prevnode = node; + node = node->next; + kfree(prevnode); + } + + if (node->length < alignment) { + kfree(node); + return(NULL); + } + + if (node->base & (alignment - 1)) { + // Short circuit if adjusted size is too small + temp_dword = (node->base | (alignment-1)) + 1; + if ((node->length - (temp_dword - node->base)) < alignment) { + kfree(node); + return(NULL); + } + + node->length -= (temp_dword - node->base); + node->base = temp_dword; + } + + if (node->length & (alignment - 1)) { + // There's stuff in use after this node + kfree(node); + return(NULL); + } + + return(node); +} + + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + // For IO make sure it's not in the ISA aliasing space + if (node->base & 0x300L) + continue; + + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if (cpqhp_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + // If not big enough we could probably just bail, + // instead we'll continue to the next. + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (max->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + // Put it next in the list + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + // this one isn't end aligned properly at the top + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + // Put it in the list + split_node->next = max->next; + max->next = split_node; + } + + // Make sure it didn't shrink too much when we aligned it + if (max->length < size) + continue; + + // Now take it out of the list + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + // If we get here, we couldn't find one + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", + __FUNCTION__, size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg("%s: got one!!!\n", __FUNCTION__); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + + +/* + * cpqhp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int cpqhp_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } // End of out_of_order loop + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + // Combine + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + + +irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) +{ + struct controller *ctrl = data; + u8 schedule_flag = 0; + u8 reset; + u16 misc; + u32 Diff; + u32 temp_dword; + + + misc = readw(ctrl->hpc_reg + MISC); + //********************************* + // Check to see if it was our interrupt + //********************************* + if (!(misc & 0x000C)) { + return IRQ_NONE; + } + + if (misc & 0x0004) { + //********************************* + // Serial Output interrupt Pending + //********************************* + + // Clear the interrupt + misc |= 0x0004; + writew(misc, ctrl->hpc_reg + MISC); + + // Read to clear posted writes + misc = readw(ctrl->hpc_reg + MISC); + + dbg ("%s - waking up\n", __FUNCTION__); + wake_up_interruptible(&ctrl->queue); + } + + if (misc & 0x0008) { + // General-interrupt-input interrupt Pending + Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp; + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Clear the interrupt + writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Read it back to clear any posted writes + temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (!Diff) { + // Clear all interrupts + writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR); + } + + schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl); + schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl); + schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); + } + + reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); + if (reset & 0x40) { + /* Bus reset has completed */ + reset &= 0xCF; + writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE); + reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); + wake_up_interruptible(&ctrl->queue); + } + + if (schedule_flag) { + up(&event_semaphore); + dbg("Signal event_semaphore\n"); + } + return IRQ_HANDLED; +} + + +/** + * cpqhp_slot_create - Creates a node and adds it to the proper bus. + * @busnumber - bus where new node is to be located + * + * Returns pointer to the new node or NULL if unsuccessful + */ +struct pci_func *cpqhp_slot_create(u8 busnumber) +{ + struct pci_func *new_slot; + struct pci_func *next; + + new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); + + if (new_slot == NULL) { + // I'm not dead yet! + // You will be. + return(new_slot); + } + + memset(new_slot, 0, sizeof(struct pci_func)); + + new_slot->next = NULL; + new_slot->configured = 1; + + if (cpqhp_slot_list[busnumber] == NULL) { + cpqhp_slot_list[busnumber] = new_slot; + } else { + next = cpqhp_slot_list[busnumber]; + while (next->next != NULL) + next = next->next; + next->next = new_slot; + } + return(new_slot); +} + + +/* + * slot_remove - Removes a node from the linked list of slots. + * @old_slot: slot to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int slot_remove(struct pci_func * old_slot) +{ + struct pci_func *next; + + if (old_slot == NULL) + return(1); + + next = cpqhp_slot_list[old_slot->bus]; + + if (next == NULL) { + return(1); + } + + if (next == old_slot) { + cpqhp_slot_list[old_slot->bus] = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } + + while ((next->next != old_slot) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == old_slot) { + next->next = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } else + return(2); +} + + +/** + * bridge_slot_remove - Removes a node from the linked list of slots. + * @bridge: bridge to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int bridge_slot_remove(struct pci_func *bridge) +{ + u8 subordinateBus, secondaryBus; + u8 tempBus; + struct pci_func *next; + + if (bridge == NULL) + return(1); + + secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; + subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + + for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { + next = cpqhp_slot_list[tempBus]; + + while (!slot_remove(next)) { + next = cpqhp_slot_list[tempBus]; + } + } + + next = cpqhp_slot_list[bridge->bus]; + + if (next == NULL) { + return(1); + } + + if (next == bridge) { + cpqhp_slot_list[bridge->bus] = bridge->next; + kfree(bridge); + return(0); + } + + while ((next->next != bridge) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == bridge) { + next->next = bridge->next; + kfree(bridge); + return(0); + } else + return(2); +} + + +/** + * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed + * @bus: bus to find + * @device: device to find + * @index: is 0 for first function found, 1 for the second... + * + * Returns pointer to the node if successful, %NULL otherwise. + */ +struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) +{ + int found = -1; + struct pci_func *func; + + func = cpqhp_slot_list[bus]; + + if ((func == NULL) || ((func->device == device) && (index == 0))) + return(func); + + if (func->device == device) + found++; + + while (func->next != NULL) { + func = func->next; + + if (func->device == device) + found++; + + if (found == index) + return(func); + } + + return(NULL); +} + + +// DJZ: I don't think is_bridge will work as is. +//FIXME +static int is_bridge(struct pci_func * func) +{ + // Check the header type + if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) + return 1; + else + return 0; +} + + +/* the following routines constitute the bulk of the + hotplug controller logic + */ + + +/** + * board_replaced - Called after a board has been replaced in the system. + * + * This is only used if we don't have resources for hot add + * Turns power on for the board + * Checks to see if board is the same + * If board is same, reconfigures it + * If board isn't same, turns it back off. + * + */ +static u32 board_replaced(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + u8 adapter_speed; + u32 index; + u32 rc = 0; + u32 src = 8; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { + //********************************* + // The switch is open. + //********************************* + rc = INTERLOCK_OPEN; + } else if (is_slot_enabled (ctrl, hp_slot)) { + //********************************* + // The board is already on + //********************************* + rc = CARD_FUNCTIONING; + } else { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + adapter_speed = get_adapter_speed(ctrl, hp_slot); + if (ctrl->speed != adapter_speed) + if (set_controller_speed(ctrl, adapter_speed, hp_slot)) + rc = WRONG_BUS_FREQUENCY; + + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + slot_enable (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + // Wait for ~1 second because of hot plug spec + long_delay(1*HZ); + + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + rc = POWER_FAILURE; + func->status = 0; + } else + rc = cpqhp_valid_replace(ctrl, func); + + if (!rc) { + // It must be the same board + + rc = cpqhp_configure_board(ctrl, func); + + if (rc || src) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + else + return(1); + } + + func->status = 0; + func->switch_save = 0x10; + + index = 1; + while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { + rc |= cpqhp_configure_board(ctrl, func); + index++; + } + + if (rc) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + // Done configuring so turn LED on full time + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + rc = 0; + } else { + // Something is wrong + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + + } + return(rc); + +} + + +/** + * board_added - Called after a board has been added to the system. + * + * Turns power on for the board + * Configures board + * + */ +static u32 board_added(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + u8 adapter_speed; + int index; + u32 temp_register = 0xFFFFFFFF; + u32 rc = 0; + struct pci_func *new_slot = NULL; + struct slot *p_slot; + struct resource_lists res_lists; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", + __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + adapter_speed = get_adapter_speed(ctrl, hp_slot); + if (ctrl->speed != adapter_speed) + if (set_controller_speed(ctrl, adapter_speed, hp_slot)) + rc = WRONG_BUS_FREQUENCY; + + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + // turn on board and blink green LED + + // Wait for exclusive access to hardware + dbg("%s: before down\n", __FUNCTION__); + down(&ctrl->crit_sect); + dbg("%s: after down\n", __FUNCTION__); + + dbg("%s: before slot_enable\n", __FUNCTION__); + slot_enable (ctrl, hp_slot); + + dbg("%s: before green_LED_blink\n", __FUNCTION__); + green_LED_blink (ctrl, hp_slot); + + dbg("%s: before amber_LED_blink\n", __FUNCTION__); + amber_LED_off (ctrl, hp_slot); + + dbg("%s: before set_SOGO\n", __FUNCTION__); + set_SOGO(ctrl); + + // Wait for SOBS to be unset + dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__); + wait_for_ctrl_irq (ctrl); + dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__); + + // Done with exclusive hardware access + dbg("%s: before up\n", __FUNCTION__); + up(&ctrl->crit_sect); + dbg("%s: after up\n", __FUNCTION__); + + // Wait for ~1 second because of hot plug spec + dbg("%s: before long_delay\n", __FUNCTION__); + long_delay(1*HZ); + dbg("%s: after long_delay\n", __FUNCTION__); + + dbg("%s: func status = %x\n", __FUNCTION__, func->status); + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + rc = POWER_FAILURE; + func->status = 0; + } else { + // Get vendor/device ID u32 + ctrl->pci_bus->number = func->bus; + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); + dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc); + dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); + + if (rc != 0) { + // Something's wrong here + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); + } + // Preset return code. It will be changed later if things go okay. + rc = NO_ADAPTER_PRESENT; + } + + // All F's is an empty slot or an invalid board + if (temp_register != 0xFFFFFFFF) { // Check for a board in the slot + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + res_lists.irqs = NULL; + + rc = configure_new_device(ctrl, func, 0, &res_lists); + + dbg("%s: back from configure_new_device\n", __FUNCTION__); + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(rc); + } else { + cpqhp_save_slot_config(ctrl, func); + } + + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + + //next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present) + dbg("%s: configure linux pci_dev structure\n", __FUNCTION__); + index = 0; + do { + new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); + if (new_slot && !new_slot->pci_dev) { + cpqhp_configure_device(ctrl, new_slot); + } + } while (new_slot); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } else { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + return 0; +} + + +/** + * remove_board - Turns off slot and LED's + * + */ +static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) +{ + int index; + u8 skip = 0; + u8 device; + u8 hp_slot; + u8 temp_byte; + u32 rc; + struct resource_lists res_lists; + struct pci_func *temp_func; + + if (func == NULL) + return(1); + + if (cpqhp_unconfigure_device(func)) + return(1); + + device = func->device; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + + // When we get here, it is safe to change base Address Registers. + // We will attempt to save the base Address Register Lengths + if (replace_flag || !ctrl->add_support) + rc = cpqhp_save_base_addr_length(ctrl, func); + else if (!func->bus_head && !func->mem_head && + !func->p_mem_head && !func->io_head) { + // Here we check to see if we've saved any of the board's + // resources already. If so, we'll skip the attempt to + // determine what's being used. + index = 0; + temp_func = cpqhp_slot_find(func->bus, func->device, index++); + while (temp_func) { + if (temp_func->bus_head || temp_func->mem_head + || temp_func->p_mem_head || temp_func->io_head) { + skip = 1; + break; + } + temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++); + } + + if (!skip) + rc = cpqhp_save_used_resources(ctrl, func); + } + // Change status to shutdown + if (func->is_a_board) + func->status = 0x01; + func->configured = 0; + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // turn off SERR for slot + temp_byte = readb(ctrl->hpc_reg + SLOT_SERR); + temp_byte &= ~(0x01 << hp_slot); + writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (!replace_flag && ctrl->add_support) { + while (func) { + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + + cpqhp_return_board_resources(func, &res_lists); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + func = cpqhp_slot_find(ctrl->bus, device, 0); + } + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->switch_save = 0x10; + func->is_a_board = 0; + func->p_task_event = NULL; + } + + return 0; +} + + +static void pushbutton_helper_thread (unsigned long data) +{ + pushbutton_pending = data; + up(&event_semaphore); +} + + +// this is the main worker thread +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize("phpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished) break; + /* Do stuff here */ + if (pushbutton_pending) + cpqhp_pushbutton_thread(pushbutton_pending); + else + for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + + +int cpqhp_event_start_thread (void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX(&delay_sem); + init_MUTEX_LOCKED(&event_semaphore); + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + pid = kernel_thread(event_thread, 0, 0); + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + dbg("Our event thread pid = %d\n", pid); + return 0; +} + + +void cpqhp_event_stop_thread (void) +{ + event_finished = 1; + dbg("event_thread finish command given\n"); + up(&event_semaphore); + dbg("wait for event_thread to exit\n"); + down(&event_exit); +} + + +static int update_slot_info (struct controller *ctrl, struct slot *slot) +{ + struct hotplug_slot_info *info; + int result; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->power_status = get_slot_enabled(ctrl, slot); + info->attention_status = cpq_get_attention_status(ctrl, slot); + info->latch_status = cpq_get_latch_status(ctrl, slot); + info->adapter_status = get_presence_status(ctrl, slot); + result = pci_hp_change_slot_info(slot->hotplug_slot, info); + kfree (info); + return result; +} + +static void interrupt_event_handler(struct controller *ctrl) +{ + int loop = 0; + int change = 1; + struct pci_func *func; + u8 hp_slot; + struct slot *p_slot; + + while (change) { + change = 0; + + for (loop = 0; loop < 10; loop++) { + //dbg("loop %d\n", loop); + if (ctrl->event_queue[loop].event_type != 0) { + hp_slot = ctrl->event_queue[loop].hp_slot; + + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + if (!func) + return; + + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + if (!p_slot) + return; + + dbg("hp_slot %d, func %p, p_slot %p\n", + hp_slot, func, p_slot); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + dbg("button pressed\n"); + } else if (ctrl->event_queue[loop].event_type == + INT_BUTTON_CANCEL) { + dbg("button cancel\n"); + del_timer(&p_slot->task_event); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (p_slot->state == BLINKINGOFF_STATE) { + // slot is on + // turn on green LED + dbg("turn on green LED\n"); + green_LED_on (ctrl, hp_slot); + } else if (p_slot->state == BLINKINGON_STATE) { + // slot is off + // turn off green LED + dbg("turn off green LED\n"); + green_LED_off (ctrl, hp_slot); + } + + info(msg_button_cancel, p_slot->number); + + p_slot->state = STATIC_STATE; + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + // ***********button Released (No action on press...) + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { + dbg("button release\n"); + + if (is_slot_enabled (ctrl, hp_slot)) { + // slot is on + dbg("slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + // slot is off + dbg("slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + dbg("blink green LED and turn off amber\n"); + + amber_LED_off (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + init_timer(&p_slot->task_event); + p_slot->hp_slot = hp_slot; + p_slot->ctrl = ctrl; +// p_slot->physical_slot = physical_slot; + p_slot->task_event.expires = jiffies + 5 * HZ; // 5 second delay + p_slot->task_event.function = pushbutton_helper_thread; + p_slot->task_event.data = (u32) p_slot; + + dbg("add_timer p_slot = %p\n", p_slot); + add_timer(&p_slot->task_event); + } + // ***********POWER FAULT + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + dbg("power fault\n"); + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(ctrl, p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } // End of FOR loop + } + + return; +} + + +/** + * cpqhp_pushbutton_thread + * + * Scheduled procedure to handle blocking stuff for the pushbuttons + * Handles all pending events and exits. + * + */ +void cpqhp_pushbutton_thread (unsigned long slot) +{ + u8 hp_slot; + u8 device; + struct pci_func *func; + struct slot *p_slot = (struct slot *) slot; + struct controller *ctrl = (struct controller *) p_slot->ctrl; + + pushbutton_pending = 0; + hp_slot = p_slot->hp_slot; + + device = p_slot->device; + + if (is_slot_enabled (ctrl, hp_slot)) { + p_slot->state = POWEROFF_STATE; + // power Down board + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in %s\n", __FUNCTION__); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SS(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + // slot is off + + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in %s\n", __FUNCTION__); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SI(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } + + return; +} + + +int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func) +{ + u8 device, hp_slot; + u16 temp_word; + u32 tempdword; + int rc; + struct slot* p_slot; + int physical_slot = 0; + + if (!ctrl) + return(1); + + tempdword = 0; + + device = func->device; + hp_slot = device - ctrl->slot_device_offset; + p_slot = cpqhp_find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Check to see if the interlock is closed + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (tempdword & (0x01 << hp_slot)) { + return(1); + } + + if (func->is_a_board) { + rc = board_replaced(func, ctrl); + } else { + // add board + slot_remove(func); + + func = cpqhp_slot_create(ctrl->bus); + if (func == NULL) { + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + rc = board_added(func, ctrl); + if (rc) { + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 0; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= + (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + } + } + + if (rc) { + dbg("%s: rc = %d\n", __FUNCTION__, rc); + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return rc; +} + + +int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func) +{ + u8 device, class_code, header_type, BCR; + u8 index = 0; + u8 replace_flag; + u32 rc = 0; + unsigned int devfn; + struct slot* p_slot; + struct pci_bus *pci_bus = ctrl->pci_bus; + int physical_slot=0; + + device = func->device; + func = cpqhp_slot_find(ctrl->bus, device, index++); + p_slot = cpqhp_find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Make sure there are no video controllers here + while (func && !rc) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Check the Class Code + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + if (rc) + return rc; + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + /* Display/Video adapter (not supported) */ + rc = REMOVE_NOT_SUPPORTED; + } else { + // See if it's a bridge + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If it's a bridge, check the VGA Enable bit + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); + if (rc) + return rc; + + // If the VGA Enable bit is set, remove isn't supported + if (BCR & PCI_BRIDGE_CTL_VGA) { + rc = REMOVE_NOT_SUPPORTED; + } + } + } + + func = cpqhp_slot_find(ctrl->bus, device, index++); + } + + func = cpqhp_slot_find(ctrl->bus, device, 0); + if ((func != NULL) && !rc) { + //FIXME: Replace flag should be passed into process_SS + replace_flag = !(ctrl->add_support); + rc = remove_board(func, replace_flag, ctrl); + } else if (!rc) { + rc = 1; + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return(rc); +} + + + +/** + * hardware_test - runs hardware tests + * + * For hot plug ctrl folks to play with. + * test_num is the number entered in the GUI + * + */ +int cpqhp_hardware_test(struct controller *ctrl, int test_num) +{ + u32 save_LED; + u32 work_LED; + int loop; + int num_of_slots; + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; + + switch (test_num) { + case 1: + // Do stuff here! + + // Do that funky LED thing + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); // so we can restore them later + work_LED = 0x01010101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } + + writel (save_LED, ctrl->hpc_reg + LED_CONTROL); // put it back the way it was + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + break; + case 2: + // Do other stuff here! + break; + case 3: + // and more... + break; + } + return 0; +} + + +/** + * configure_new_device - Configures the PCI header information of one board. + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Returns 0 if success + * + */ +static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + u8 temp_byte, function, max_functions, stop_it; + int rc; + u32 ID; + struct pci_func *new_slot; + int index; + + new_slot = func; + + dbg("%s\n", __FUNCTION__); + // Check for Multi-function device + ctrl->pci_bus->number = func->bus; + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); + if (rc) { + dbg("%s: rc = %d\n", __FUNCTION__, rc); + return rc; + } + + if (temp_byte & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + rc = configure_new_function(ctrl, new_slot, behind_bridge, resources); + + if (rc) { + dbg("configure_new_function failed %d\n",rc); + index = 0; + + while (new_slot) { + new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++); + + if (new_slot) + cpqhp_return_board_resources(new_slot, resources); + } + + return(rc); + } + + function++; + + stop_it = 0; + + // The following loop skips to the next present function + // and creates a board structure + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); + + if (ID == 0xFFFFFFFF) { // There's nothing there. + function++; + } else { // There's something there + // Setup slot structure. + new_slot = cpqhp_slot_create(func->bus); + + if (new_slot == NULL) { + // Out of memory + return(1); + } + + new_slot->bus = func->bus; + new_slot->device = func->device; + new_slot->function = function; + new_slot->is_a_board = 1; + new_slot->status = 0; + + stop_it++; + } + } + + } while (function < max_functions); + dbg("returning from configure_new_device\n"); + + return 0; +} + + +/* + Configuration logic that involves the hotplug data structures and + their bookkeeping + */ + + +/** + * configure_new_function - Configures the PCI header information of one device + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Calls itself recursively for bridged devices. + * Returns 0 if success + * + */ +static int configure_new_function (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + int cloop; + u8 IRQ; + u8 temp_byte; + u8 device; + u8 class_code; + u16 command; + u16 temp_word; + u32 temp_dword; + u32 rc; + u32 temp_register; + u32 base; + u32 ID; + unsigned int devfn; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_resource *hold_mem_node; + struct pci_resource *hold_p_mem_node; + struct pci_resource *hold_IO_node; + struct pci_resource *hold_bus_node; + struct irq_mapping irqs; + struct pci_func *new_slot; + struct pci_bus *pci_bus; + struct resource_lists temp_resources; + + pci_bus = ctrl->pci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Check for Bridge + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); + if (rc) + return rc; + + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // set Primary bus + dbg("set Primary bus = %d\n", func->bus); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); + if (rc) + return rc; + + // find range of busses to use + dbg("find ranges of buses to use\n"); + bus_node = get_max_resource(&resources->bus_head, 1); + + // If we don't have any busses to allocate, we can't continue + if (!bus_node) + return -ENOMEM; + + // set Secondary bus + temp_byte = bus_node->base; + dbg("set Secondary bus = %d\n", bus_node->base); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate bus + temp_byte = bus_node->base + bus_node->length - 1; + dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate Latency Timer and base Latency Timer + temp_byte = 0x40; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + + // set Cache Line size + temp_byte = 0x08; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + if (rc) + return rc; + + // Setup the IO, memory, and prefetchable windows + + io_node = get_max_resource(&(resources->io_head), 0x1000); + if (!io_node) + return -ENOMEM; + mem_node = get_max_resource(&(resources->mem_head), 0x100000); + if (!mem_node) + return -ENOMEM; + p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000); + if (!p_mem_node) + return -ENOMEM; + dbg("Setup the IO, memory, and prefetchable windows\n"); + dbg("io_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); + dbg("mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); + dbg("p_mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); + + // set up the IRQ info + if (!resources->irqs) { + irqs.barber_pole = 0; + irqs.interrupt[0] = 0; + irqs.interrupt[1] = 0; + irqs.interrupt[2] = 0; + irqs.interrupt[3] = 0; + irqs.valid_INT = 0; + } else { + irqs.barber_pole = resources->irqs->barber_pole; + irqs.interrupt[0] = resources->irqs->interrupt[0]; + irqs.interrupt[1] = resources->irqs->interrupt[1]; + irqs.interrupt[2] = resources->irqs->interrupt[2]; + irqs.interrupt[3] = resources->irqs->interrupt[3]; + irqs.valid_INT = resources->irqs->valid_INT; + } + + // set up resource lists that are now aligned on top and bottom + // for anything behind the bridge. + temp_resources.bus_head = bus_node; + temp_resources.io_head = io_node; + temp_resources.mem_head = mem_node; + temp_resources.p_mem_head = p_mem_node; + temp_resources.irqs = &irqs; + + // Make copies of the nodes we are going to pass down so that + // if there is a problem,we can just use these to free resources + hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { + if (hold_bus_node) + kfree(hold_bus_node); + if (hold_IO_node) + kfree(hold_IO_node); + if (hold_mem_node) + kfree(hold_mem_node); + if (hold_p_mem_node) + kfree(hold_p_mem_node); + + return(1); + } + + memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); + + bus_node->base += 1; + bus_node->length -= 1; + bus_node->next = NULL; + + // If we have IO resources copy them and fill in the bridge's + // IO range registers + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; + + // set IO base and Limit registers + temp_byte = io_node->base >> 8; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + temp_byte = (io_node->base + io_node->length - 1) >> 8; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } + + // If we have memory resources copy them and fill in the bridge's + // memory range registers. Otherwise, fill in the range + // registers with values that disable them. + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; + + // set Mem base and Limit registers + temp_word = mem_node->base >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = (mem_node->base + mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } + + // If we have prefetchable memory resources copy them and + // fill in the bridge's memory range registers. Otherwise, + // fill in the range registers with values that disable them. + if (p_mem_node) { + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; + + // set Pre Mem base and Limit registers + temp_word = p_mem_node->base >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + kfree(hold_p_mem_node); + hold_p_mem_node = NULL; + } + + // Adjust this to compensate for extra adjustment in first loop + irqs.barber_pole--; + + rc = 0; + + // Here we actually find the devices and configure them + for (device = 0; (device <= 0x1F) && !rc; device++) { + irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; + + ID = 0xFFFFFFFF; + pci_bus->number = hold_bus_node->base; + pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), 0x00, &ID); + pci_bus->number = func->bus; + + if (ID != 0xFFFFFFFF) { // device Present + // Setup slot structure. + new_slot = cpqhp_slot_create(hold_bus_node->base); + + if (new_slot == NULL) { + // Out of memory + rc = -ENOMEM; + continue; + } + + new_slot->bus = hold_bus_node->base; + new_slot->device = device; + new_slot->function = 0; + new_slot->is_a_board = 1; + new_slot->status = 0; + + rc = configure_new_device(ctrl, new_slot, 1, &temp_resources); + dbg("configure_new_device rc=0x%x\n",rc); + } // End of IF (device in slot?) + } // End of FOR loop + + if (rc) { + cpqhp_destroy_resource_list(&temp_resources); + + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return(rc); + } + // save the interrupt routing information + if (resources->irqs) { + resources->irqs->interrupt[0] = irqs.interrupt[0]; + resources->irqs->interrupt[1] = irqs.interrupt[1]; + resources->irqs->interrupt[2] = irqs.interrupt[2]; + resources->irqs->interrupt[3] = irqs.interrupt[3]; + resources->irqs->valid_INT = irqs.valid_INT; + } else if (!behind_bridge) { + // We need to hook up the interrupts here + for (cloop = 0; cloop < 4; cloop++) { + if (irqs.valid_INT & (0x01 << cloop)) { + rc = cpqhp_set_irq(func->bus, func->device, + 0x0A + cloop, irqs.interrupt[cloop]); + if (rc) { + cpqhp_destroy_resource_list (&temp_resources); + + return_resource(&(resources-> bus_head), hold_bus_node); + return_resource(&(resources-> io_head), hold_IO_node); + return_resource(&(resources-> mem_head), hold_mem_node); + return_resource(&(resources-> p_mem_head), hold_p_mem_node); + return rc; + } + } + } // end of for loop + } + // Return unused bus resources + // First use the temporary node to store information for the board + if (hold_bus_node && bus_node && temp_resources.bus_head) { + hold_bus_node->length = bus_node->base - hold_bus_node->base; + + hold_bus_node->next = func->bus_head; + func->bus_head = hold_bus_node; + + temp_byte = temp_resources.bus_head->base - 1; + + // set subordinate bus + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + + if (temp_resources.bus_head->length == 0) { + kfree(temp_resources.bus_head); + temp_resources.bus_head = NULL; + } else { + return_resource(&(resources->bus_head), temp_resources.bus_head); + } + } + + // If we have IO space available and there is some left, + // return the unused portion + if (hold_IO_node && temp_resources.io_head) { + io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), + &hold_IO_node, 0x1000); + + // Check if we were able to split something off + if (io_node) { + hold_IO_node->base = io_node->base + io_node->length; + + temp_byte = (hold_IO_node->base) >> 8; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + return_resource(&(resources->io_head), io_node); + } + + io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); + + // Check if we were able to split something off + if (io_node) { + // First use the temporary node to store information for the board + hold_IO_node->length = io_node->base - hold_IO_node->base; + + // If we used any, add it to the board's list + if (hold_IO_node->length) { + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + + temp_byte = (io_node->base - 1) >> 8; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + } else { + // it doesn't need any IO + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_LIMIT, temp_word); + + return_resource(&(resources->io_head), io_node); + kfree(hold_IO_node); + } + } else { + // it used most of the range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + } else if (hold_IO_node) { + // it used the whole range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + // If we have memory space available and there is some left, + // return the unused portion + if (hold_mem_node && temp_resources.mem_head) { + mem_node = do_pre_bridge_resource_split(&(temp_resources. mem_head), + &hold_mem_node, 0x100000); + + // Check if we were able to split something off + if (mem_node) { + hold_mem_node->base = mem_node->base + mem_node->length; + + temp_word = (hold_mem_node->base) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + return_resource(&(resources->mem_head), mem_node); + } + + mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000); + + // Check if we were able to split something off + if (mem_node) { + // First use the temporary node to store information for the board + hold_mem_node->length = mem_node->base - hold_mem_node->base; + + if (hold_mem_node->length) { + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + + // configure end address + temp_word = (mem_node->base - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + // Return unused resources to the pool + return_resource(&(resources->mem_head), mem_node); + } else { + // it doesn't need any Mem + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->mem_head), mem_node); + kfree(hold_mem_node); + } + } else { + // it used most of the range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + } else if (hold_mem_node) { + // it used the whole range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + // If we have prefetchable memory space available and there is some + // left at the end, return the unused portion + if (hold_p_mem_node && temp_resources.p_mem_head) { + p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), + &hold_p_mem_node, 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; + + temp_word = (hold_p_mem_node->base) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } + + p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + // First use the temporary node to store information for the board + hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; + + // If we used any, add it to the board's list + if (hold_p_mem_node->length) { + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + + temp_word = (p_mem_node->base - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } else { + // it doesn't need any PMem + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + kfree(hold_p_mem_node); + } + } else { + // it used the most of the range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + } else if (hold_p_mem_node) { + // it used the whole range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + // We should be configuring an IRQ and the bridge's base address + // registers if it needs them. Although we have never seen such + // a device + + // enable card + command = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); + + // set Bridge Control Register + command = 0x07; // = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Standard device + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + // Display (video) adapter (not supported) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + // Figure out IO and memory needs + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + + dbg("CND: bus=%d, devfn=%d, offset=%d\n", pci_bus->number, devfn, cloop); + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + + rc = pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register); + dbg("CND: base = 0x%x\n", temp_register); + + if (temp_register) { // If this register is implemented + if ((temp_register & 0x03L) == 0x01) { + // Map IO + + // set base = amount of IO space + base = temp_register & 0xFFFFFFFC; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + io_node = get_io_resource(&(resources->io_head), base); + dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n", + io_node->base, io_node->length, io_node->next); + dbg("func (%p) io_head (%p)\n", func, func->io_head); + + // allocate the resource to the board + if (io_node) { + base = io_node->base; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x08) { + // Map prefetchable memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + p_mem_node = get_resource(&(resources->p_mem_head), base); + + // allocate the resource to the board + if (p_mem_node) { + base = p_mem_node->base; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x00) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x04) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x06) { + // Those bits are reserved, we can't handle this + return(1); + } else { + // Requesting space below 1M + return(NOT_ENOUGH_RESOURCES); + } + + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); + + // Check for 64-bit base + if ((temp_register & 0x07L) == 0x04) { + cloop += 4; + + // Upper 32 bits of address always zero on today's systems + // FIXME this is probably not true on Alpha and ia64??? + base = 0; + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); + } + } + } // End of base register loop + + // Figure out which interrupt pin this function uses + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); + + // If this function needs an interrupt and we are behind a bridge + // and the pin is tied to something that's alread mapped, + // set this one the same + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & + (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { + // We have to share with something already set up + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; + } else { + // Program IRQ based on card type + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_STORAGE) { + IRQ = cpqhp_disk_irq; + } else { + IRQ = cpqhp_nic_irq; + } + } + + // IRQ Line + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); + + if (!behind_bridge) { + rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); + if (rc) + return(1); + } else { + //TBD - this code may also belong in the other clause of this If statement + resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; + resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; + } + + // Latency Timer + temp_byte = 0x40; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + + // Cache Line size + temp_byte = 0x08; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + + // disable ROM base Address + temp_dword = 0x00L; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_dword); + + // enable card + temp_word = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, temp_word); + } // End of Not-A-Bridge else + else { + // It's some strange type of PCI adapter (Cardbus?) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + func->configured = 1; + + return 0; +} + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_nvram.c linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_nvram.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_nvram.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_nvram.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,667 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" +#include "cpqphp_nvram.h" + + +#define ROM_INT15_PHY_ADDR 0x0FF859 +#define READ_EV 0xD8A4 +#define WRITE_EV 0xD8A5 + +struct register_foo { + union { + unsigned long lword; /* eax */ + unsigned short word; /* ax */ + + struct { + unsigned char low; /* al */ + unsigned char high; /* ah */ + } byte; + } data; + + unsigned char opcode; /* see below */ + unsigned long length; /* if the reg. is a pointer, how much data */ +} __attribute__ ((packed)); + +struct all_reg { + struct register_foo eax_reg; + struct register_foo ebx_reg; + struct register_foo ecx_reg; + struct register_foo edx_reg; + struct register_foo edi_reg; + struct register_foo esi_reg; + struct register_foo eflags_reg; +} __attribute__ ((packed)); + + +struct ev_hrt_header { + u8 Version; + u8 num_of_ctrl; + u8 next; +}; + +struct ev_hrt_ctrl { + u8 bus; + u8 device; + u8 function; + u8 mem_avail; + u8 p_mem_avail; + u8 io_avail; + u8 bus_avail; + u8 next; +}; + + +static u8 evbuffer_init; +static u8 evbuffer_length; +static u8 evbuffer[1024]; + +static void *compaq_int15_entry_point; + +static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ + + +/* This is a series of function that deals with + setting & getting the hotplug resource table in some environment variable. +*/ + +/* + * We really shouldn't be doing this unless there is a _very_ good reason to!!! + * greg k-h + */ + + +static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) +{ + u8 **tByte; + + if ((*used + 1) > *avail) + return(1); + + *((u8*)*p_buffer) = value; + tByte = (u8**)p_buffer; + (*tByte)++; + *used+=1; + return(0); +} + + +static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) +{ + if ((*used + 4) > *avail) + return(1); + + **p_buffer = value; + (*p_buffer)++; + *used+=4; + return(0); +} + + +/* + * check_for_compaq_ROM + * + * this routine verifies that the ROM OEM string is 'COMPAQ' + * + * returns 0 for non-Compaq ROM, 1 for Compaq ROM + */ +static int check_for_compaq_ROM (void *rom_start) +{ + u8 temp1, temp2, temp3, temp4, temp5, temp6; + int result = 0; + + temp1 = readb(rom_start + 0xffea + 0); + temp2 = readb(rom_start + 0xffea + 1); + temp3 = readb(rom_start + 0xffea + 2); + temp4 = readb(rom_start + 0xffea + 3); + temp5 = readb(rom_start + 0xffea + 4); + temp6 = readb(rom_start + 0xffea + 5); + if ((temp1 == 'C') && + (temp2 == 'O') && + (temp3 == 'M') && + (temp4 == 'P') && + (temp5 == 'A') && + (temp6 == 'Q')) { + result = 1; + } + dbg ("%s - returned %d\n", __FUNCTION__, result); + return result; +} + + +static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) +{ + unsigned long flags; + int op = operation; + int ret_val; + + if (!compaq_int15_entry_point) + return -ENODEV; + + spin_lock_irqsave(&int15_lock, flags); + __asm__ ( + "xorl %%ebx,%%ebx\n" \ + "xorl %%edx,%%edx\n" \ + "pushf\n" \ + "push %%cs\n" \ + "cli\n" \ + "call *%6\n" + : "=c" (*buf_size), "=a" (ret_val) + : "a" (op), "c" (*buf_size), "S" (ev_name), + "D" (buffer), "m" (compaq_int15_entry_point) + : "%ebx", "%edx"); + spin_unlock_irqrestore(&int15_lock, flags); + + return((ret_val & 0xFF00) >> 8); +} + + +/* + * load_HRT + * + * Read the hot plug Resource Table from NVRAM + */ +static int load_HRT (void *rom_start) +{ + u32 available; + u32 temp_dword; + u8 temp_byte = 0xFF; + u32 rc; + + if (!check_for_compaq_ROM(rom_start)) { + return -ENODEV; + } + + available = 1024; + + // Now load the EV + temp_dword = available; + + rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); + + evbuffer_length = temp_dword; + + // We're maintaining the resource lists so write FF to invalidate old info + temp_dword = 1; + + rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); + + return rc; +} + + +/* + * store_HRT + * + * Save the hot plug Resource Table in NVRAM + */ +static u32 store_HRT (void *rom_start) +{ + u32 *buffer; + u32 *pFill; + u32 usedbytes; + u32 available; + u32 temp_dword; + u32 rc; + u8 loop; + u8 numCtrl = 0; + struct controller *ctrl; + struct pci_resource *resNode; + struct ev_hrt_header *p_EV_header; + struct ev_hrt_ctrl *p_ev_ctrl; + + available = 1024; + + if (!check_for_compaq_ROM(rom_start)) { + return(1); + } + + buffer = (u32*) evbuffer; + + if (!buffer) + return(1); + + pFill = buffer; + usedbytes = 0; + + p_EV_header = (struct ev_hrt_header *) pFill; + + ctrl = cpqhp_ctrl_list; + + // The revision of this structure + rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); + if (rc) + return(rc); + + // The number of controllers + rc = add_byte( &pFill, 1, &usedbytes, &available); + if (rc) + return(rc); + + while (ctrl) { + p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; + + numCtrl++; + + // The bus number + rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); + if (rc) + return(rc); + + // The device Number + rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); + if (rc) + return(rc); + + // The function Number + rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); + if (rc) + return(rc); + + // Skip the number of available entries + rc = add_dword( &pFill, 0, &usedbytes, &available); + if (rc) + return(rc); + + // Figure out memory Available + + resNode = ctrl->mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->mem_avail = loop; + + // Figure out prefetchable memory Available + + resNode = ctrl->p_mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->p_mem_avail = loop; + + // Figure out IO Available + + resNode = ctrl->io_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->io_avail = loop; + + // Figure out bus Available + + resNode = ctrl->bus_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->bus_avail = loop; + + ctrl = ctrl->next; + } + + p_EV_header->num_of_ctrl = numCtrl; + + // Now store the EV + + temp_dword = usedbytes; + + rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword); + + dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); + + evbuffer_length = temp_dword; + + if (rc) { + err(msg_unable_to_save); + return(1); + } + + return(0); +} + + +void compaq_nvram_init (void *rom_start) +{ + if (rom_start) { + compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); + } + dbg("int15 entry = %p\n", compaq_int15_entry_point); + + /* initialize our int15 lock */ + spin_lock_init(&int15_lock); +} + + +int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + u8 bus, device, function; + u8 nummem, numpmem, numio, numbus; + u32 rc; + u8 *p_byte; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct ev_hrt_ctrl *p_ev_ctrl; + struct ev_hrt_header *p_EV_header; + + if (!evbuffer_init) { + // Read the resource list information in from NVRAM + if (load_HRT(rom_start)) + memset (evbuffer, 0, 1024); + + evbuffer_init = 1; + } + + // If we saved information in NVRAM, use it now + p_EV_header = (struct ev_hrt_header *) evbuffer; + + // The following code is for systems where version 1.0 of this + // driver has been loaded, but doesn't support the hardware. + // In that case, the driver would incorrectly store something + // in NVRAM. + if ((p_EV_header->Version == 2) || + ((p_EV_header->Version == 1) && !ctrl->push_flag)) { + p_byte = &(p_EV_header->next); + + p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + + while ((bus != ctrl->bus) || + (device != PCI_SLOT(ctrl->pci_dev->devfn)) || + (function != PCI_FUNC(ctrl->pci_dev->devfn))) { + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + // Skip forward to the next entry + p_byte += (nummem + numpmem + numio + numbus) * 8; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + } + + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + while (nummem--) { + mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!mem_node) + break; + + mem_node->base = *(u32*)p_byte; + dbg("mem base = %8.8x\n",mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(mem_node); + return 2; + } + + mem_node->length = *(u32*)p_byte; + dbg("mem length = %8.8x\n",mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(mem_node); + return 2; + } + + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } + + while (numpmem--) { + p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!p_mem_node) + break; + + p_mem_node->base = *(u32*)p_byte; + dbg("pre-mem base = %8.8x\n",p_mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(p_mem_node); + return 2; + } + + p_mem_node->length = *(u32*)p_byte; + dbg("pre-mem length = %8.8x\n",p_mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(p_mem_node); + return 2; + } + + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } + + while (numio--) { + io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!io_node) + break; + + io_node->base = *(u32*)p_byte; + dbg("io base = %8.8x\n",io_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(io_node); + return 2; + } + + io_node->length = *(u32*)p_byte; + dbg("io length = %8.8x\n",io_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(io_node); + return 2; + } + + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } + + while (numbus--) { + bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!bus_node) + break; + + bus_node->base = *(u32*)p_byte; + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(bus_node); + return 2; + } + + bus_node->length = *(u32*)p_byte; + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(bus_node); + return 2; + } + + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) + return(rc); + } else { + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) + return 1; + } + + return 0; +} + + +int compaq_nvram_store (void *rom_start) +{ + int rc = 1; + + if (rom_start == NULL) + return -ENODEV; + + if (evbuffer_init) { + rc = store_HRT(rom_start); + if (rc) { + err(msg_unable_to_save); + } + } + return rc; +} + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_nvram.h linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_nvram.h --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_nvram.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_nvram.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,57 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#ifndef _CPQPHP_NVRAM_H +#define _CPQPHP_NVRAM_H + +#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM + +static inline void compaq_nvram_init (void *rom_start) +{ + return; +} + +static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + return 0; +} + +static inline int compaq_nvram_store (void *rom_start) +{ + return 0; +} + +#else + +extern void compaq_nvram_init (void *rom_start); +extern int compaq_nvram_load (void *rom_start, struct controller *ctrl); +extern int compaq_nvram_store (void *rom_start); + +#endif + +#endif + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_pci.c linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_pci.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_pci.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_pci.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1549 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../pci.h" +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ + + +u8 cpqhp_nic_irq; +u8 cpqhp_disk_irq; + +static u16 unused_IRQ; + +/* + * detect_HRT_floating_pointer + * + * find the Hot Plug Resource Table in the specified region of memory. + * + */ +static void *detect_HRT_floating_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(struct hrt) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp + SIG0); + temp2 = readb(fp + SIG1); + temp3 = readb(fp + SIG2); + temp4 = readb(fp + SIG3); + if (temp1 == '$' && + temp2 == 'H' && + temp3 == 'R' && + temp4 == 'T') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered Hotplug Resource Table at %p\n", fp); + return fp; +} + + +int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +{ + unsigned char bus; + struct pci_bus *child; + int num; + + if (func->pci_dev == NULL) + func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + + /* No pci device, we need to create it then */ + if (func->pci_dev == NULL) { + dbg("INFO: pci_dev still null\n"); + + num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function)); + if (num) + pci_bus_add_devices(ctrl->pci_dev->bus); + + func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + if (func->pci_dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return 0; + } + } + + if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); + pci_do_scan_bus(child); + } + + return 0; +} + + +int cpqhp_unconfigure_device(struct pci_func* func) +{ + int j; + + dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); + + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); + if (temp) + pci_remove_bus_device(temp); + } + return 0; +} + +static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value) +{ + u32 vendID = 0; + + if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1) + return -1; + if (vendID == 0xffffffff) + return -1; + return pci_bus_read_config_dword (bus, devfn, offset, value); +} + + +/* + * cpqhp_set_irq + * + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: pointer to u8 where slot number will be returned + */ +int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) +{ + int rc; + u16 temp_word; + struct pci_dev fakedev; + struct pci_bus fakebus; + + fakedev.devfn = dev_num << 3; + fakedev.bus = &fakebus; + fakebus.number = bus_num; + dbg("%s: dev %d, bus %d, pin %d, num %d\n", + __FUNCTION__, dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); + dbg("%s: rc %d\n", __FUNCTION__, rc); + if (!rc) + return !rc; + + // set the Edge Level Control Register (ELCR) + temp_word = inb(0x4d0); + temp_word |= inb(0x4d1) << 8; + + temp_word |= 0x01 << irq_num; + + // This should only be for x86 as it sets the Edge Level Control Register + outb((u8) (temp_word & 0xFF), 0x4d0); + outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); + + return 0; +} + + +/* + * WTF??? This function isn't in the code, yet a function calls it, but the + * compiler optimizes it away? strange. Here as a placeholder to keep the + * compiler happy. + */ +static int PCI_ScanBusNonBridge (u8 bus, u8 device) +{ + return 0; +} + +static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) +{ + u8 tdevice; + u32 work; + u8 tbus; + + ctrl->pci_bus->number = bus_num; + + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) + continue; + dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. Not a bridge ? + if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { + *dev_num = tdevice; + dbg("found it !\n"); + return 0; + } + } + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) + continue; + dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. bridge ? + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); + dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); + if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) + return 0; + } + } + + return -1; +} + + +static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + long len; + long loop; + u32 work; + + u8 tbus, tdevice, tslot; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + if (!PCIIRQRoutingInfoLength) + return -1; + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if (tslot == slot) { + *bus_num = tbus; + *dev_num = tdevice; + ctrl->pci_bus->number = tbus; + pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); + if (!nobridge || (work == 0xffffffff)) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); + pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); + dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus); + dbg("Scan bus for Non Bridge: bus %d\n", tbus); + if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { + *bus_num = tbus; + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + } else { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + } + } + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; +} + + +int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) +{ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) +} + + +/* More PCI configuration routines; this time centered around hotplug controller */ + + +/* + * cpqhp_save_config + * + * Reads configuration for all slots in a PCI bus and saves info. + * + * Note: For non-hot plug busses, the slot # saved is the device # + * + * returns 0 if success + */ +int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + struct pci_func *new_slot; + int sub_bus; + int FirstSupported; + int LastSupported; + int max_functions; + int function; + u8 DevError; + int device = 0; + int cloop = 0; + int stop_it; + int index; + + // Decide which slots are supported + + if (is_hot_plug) { + //********************************* + // is_hot_plug is the slot mask + //********************************* + FirstSupported = is_hot_plug >> 4; + LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; + } else { + FirstSupported = 0; + LastSupported = 0x1F; + } + + // Save PCI configuration space for all devices in supported slots + ctrl->pci_bus->number = busnumber; + for (device = FirstSupported; device <= LastSupported; device++) { + ID = 0xFFFFFFFF; + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If multi-function device, set max_functions to 8 + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge + // Recurse the subordinate bus + // get the subordinate bus number + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + // Save secondary bus cfg spc + // with this recursive call. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return rc; + ctrl->pci_bus->number = busnumber; + } + } + + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) + new_slot = cpqhp_slot_find(busnumber, device, index++); + + if (!new_slot) { + // Setup slot structure. + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + // In case of unsupported board + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in Class Code and Header type. + + while ((function < max_functions)&&(!stop_it)) { + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else if (is_hot_plug) { + // Setup slot structure with entry for empty slot + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) { + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + } // End of FOR loop + + return(0); +} + + +/* + * cpqhp_save_slot_config + * + * Saves configuration info for all PCI devices in a given slot + * including subordinate busses. + * + * returns 0 if success + */ +int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + int sub_bus; + int max_functions; + int function; + int cloop = 0; + int stop_it; + + ID = 0xFFFFFFFF; + + ctrl->pci_bus->number = new_slot->bus; + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Recurse the subordinate bus + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + // Save the config headers for the secondary bus. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return(rc); + ctrl->pci_bus->number = new_slot->bus; + + } // End of IF + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) { + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in the Class Code and the Header type. + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else { + return(2); + } + + return(0); +} + + +/* + * cpqhp_save_base_addr_length + * + * Saves the length of all base address registers for the + * specified slot. this is for hot plug REPLACE + * + * returns 0 if success + */ +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + int sub_bus; + u32 temp_register; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Check for Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + // PCI-PCI Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_save_base_addr_length(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + pci_bus->number = func->bus; + + //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = + base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + + } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + // base = amount of memory space requested + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_save_used_resources + * + * Stores used resource information for existing boards. this is + * for boards that were in the system when this driver was loaded. + * this function is for hot plug ADD + * + * returns 0 if success + */ +int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 temp_byte; + u8 b_base; + u8 b_length; + u16 command; + u16 save_command; + u16 w_base; + u16 w_length; + u32 temp_register; + u32 save_base; + u32 base; + int index = 0; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while ((func != NULL) && func->is_a_board) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Save the command register + pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command); + + // disable card + command = 0x00; + pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); + + // Check for Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Clear Bridge Control Register + command = 0x00; + pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); + + bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = temp_byte - secondary_bus + 1; + + bus_node->next = func->bus_head; + func->bus_head = bus_node; + + // Save IO base and Limit registers + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &b_base); + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &b_length); + + if ((b_base <= b_length) && (save_command & 0x01)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (b_base & 0xF0) << 8; + io_node->length = (b_length - b_base + 0x10) << 8; + + io_node->next = func->io_head; + func->io_head = io_node; + } + + // Save memory base and Limit registers + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = w_base << 16; + mem_node->length = (w_length - w_base + 0x10) << 16; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + + // Save prefetchable memory base and Limit registers + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = w_base << 16; + p_mem_node->length = (w_length - w_base + 0x10) << 16; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = + save_base & (~0x03L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else if ((header_type & 0x7F) == 0x00) { // Standard header + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = save_base & (~0x01L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_configure_board + * + * Copies saved configuration information to one slot. + * this is called recursively for bridge devices. + * this is for hot plug REPLACE! + * + * returns 0 if success + */ +int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) +{ + int cloop; + u8 header_type; + u8 secondary_bus; + int sub_bus; + struct pci_func *next; + u32 temp; + u32 rc; + int index = 0; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Start at the top of config space so that the control + // registers are programmed last + for (cloop = 0x3C; cloop > 0; cloop -= 4) { + pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); + } + + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + // If this is a bridge device, restore subordinate devices + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_configure_board(ctrl, next); + + if (rc) + return rc; + + next = next->next; + } + } else { + + // Check all the base Address Registers to make sure + // they are the same. If not, the board is different. + + for (cloop = 16; cloop < 40; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); + + if (temp != func->config_space[cloop >> 2]) { + dbg("Config space compare failure!!! offset = %x\n", cloop); + dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); + dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]); + return 1; + } + } + } + + func->configured = 1; + + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return 0; +} + + +/* + * cpqhp_valid_replace + * + * this function checks to see if a board is the same as the + * one it is replacing. this check will detect if the device's + * vendor or device id's are the same + * + * returns 0 if the board is the same nonzero otherwise + */ +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + u32 temp_register = 0; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + if (!func->is_a_board) + return(ADD_NOT_SUPPORTED); + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); + + // No adapter present + if (temp_register == 0xFFFFFFFF) + return(NO_ADAPTER_PRESENT); + + if (temp_register != func->config_space[0]) + return(ADAPTER_NOT_SAME); + + // Check for same revision number and class code + pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); + + // Adapter not the same + if (temp_register != func->config_space[0x08 >> 2]) + return(ADAPTER_NOT_SAME); + + // Check for Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // In order to continue checking, we must program the + // bus registers in the bridge to respond to accesses + // for it's subordinate bus(es) + + temp_register = func->config_space[0x18 >> 2]; + pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); + + secondary_bus = (temp_register >> 8) & 0xFF; + + next = cpqhp_slot_list[secondary_bus]; + + while (next != NULL) { + rc = cpqhp_valid_replace(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + + } + // Check to see if it is a standard config header + else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Check subsystem vendor and ID + pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); + + if (temp_register != func->config_space[0x2C >> 2]) { + // If it's a SMART-2 and the register isn't filled + // in, ignore the difference because + // they just have an old rev of the firmware + + if (!((func->config_space[0] == 0xAE100E11) + && (temp_register == 0x00L))) + return(ADAPTER_NOT_SAME); + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Check information in slot structure + if (func->base_length[(cloop - 0x10) >> 2] != base) + return(ADAPTER_NOT_SAME); + + if (func->base_type[(cloop - 0x10) >> 2] != type) + return(ADAPTER_NOT_SAME); + + } // End of base register loop + + } // End of (type 0 config space) else + else { + // this is not a type 0 or 1 config space header so + // we don't know how to do it + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + // Get the next function + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + + return(0); +} + + +/* + * cpqhp_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start) +{ + u8 temp; + u8 populated_slot; + u8 bridged_slot; + void *one_slot; + struct pci_func *func = NULL; + int i = 10, index; + u32 temp_dword, rc; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + void *rom_resource_table; + + rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); + dbg("rom_resource_table = %p\n", rom_resource_table); + + if (rom_resource_table == NULL) { + return -ENODEV; + } + // Sum all resources and setup resource maps + unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); + dbg("unused_IRQ = %x\n", unused_IRQ); + + temp = 0; + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_disk_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); + unused_IRQ = unused_IRQ >> 1; + temp++; + + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_nic_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); + unused_IRQ = readl(rom_resource_table + PCIIRQ); + + temp = 0; + + if (!cpqhp_nic_irq) { + cpqhp_nic_irq = ctrl->cfgspc_irq; + } + + if (!cpqhp_disk_irq) { + cpqhp_disk_irq = ctrl->cfgspc_irq; + } + + dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); + + rc = compaq_nvram_load(rom_start, ctrl); + if (rc) + return rc; + + one_slot = rom_resource_table + sizeof (struct hrt); + + i = readb(rom_resource_table + NUMBER_OF_ENTRIES); + dbg("number_of_entries = %d\n", i); + + if (!readb(one_slot + SECONDARY_BUS)) { + return(1); + } + + dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); + + while (i && readb(one_slot + SECONDARY_BUS)) { + u8 dev_func = readb(one_slot + DEV_FUNC); + u8 primary_bus = readb(one_slot + PRIMARY_BUS); + u8 secondary_bus = readb(one_slot + SECONDARY_BUS); + u8 max_bus = readb(one_slot + MAX_BUS); + u16 io_base = readw(one_slot + IO_BASE); + u16 io_length = readw(one_slot + IO_LENGTH); + u16 mem_base = readw(one_slot + MEM_BASE); + u16 mem_length = readw(one_slot + MEM_LENGTH); + u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); + u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); + + dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", + dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, + primary_bus, secondary_bus, max_bus); + + // If this entry isn't for our controller's bus, ignore it + if (primary_bus != ctrl->bus) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // find out if this entry is for an occupied slot + ctrl->pci_bus->number = primary_bus; + pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); + dbg("temp_D_word = %x\n", temp_dword); + + if (temp_dword != 0xFFFFFFFF) { + index = 0; + func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); + + while (func && (func->function != (dev_func & 0x07))) { + dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); + func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); + } + + // If we can't find a match, skip this table entry + if (!func) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // this may not work and shouldn't be used + if (secondary_bus != primary_bus) + bridged_slot = 1; + else + bridged_slot = 0; + + populated_slot = 1; + } else { + populated_slot = 0; + bridged_slot = 0; + } + + + // If we've got a valid IO base, use it + + temp_dword = io_base + io_length; + + if ((io_base) && (temp_dword < 0x10000)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = io_base; + io_node->length = io_length; + + dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } else { + io_node->next = func->io_head; + func->io_head = io_node; + } + } + + // If we've got a valid memory base, use it + temp_dword = mem_base + mem_length; + if ((mem_base) && (temp_dword < 0x10000)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = mem_base << 16; + + mem_node->length = mem_length << 16; + + dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } else { + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + } + + // If we've got a valid prefetchable memory base, and + // the base + length isn't greater than 0xFFFF + temp_dword = pre_mem_base + pre_mem_length; + if ((pre_mem_base) && (temp_dword < 0x10000)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = pre_mem_base << 16; + + p_mem_node->length = pre_mem_length << 16; + dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); + dbg("populated slot =%d \n", populated_slot); + + if (!populated_slot) { + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } else { + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } + + // If we've got a valid bus number, use it + // The second condition is to ignore bus numbers on + // populated slots that don't have PCI-PCI bridges + if (secondary_bus && (secondary_bus != primary_bus)) { + bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = max_bus - secondary_bus + 1; + dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } else { + bus_node->next = func->bus_head; + func->bus_head = bus_node; + } + } + + i--; + one_slot += sizeof (struct slot_rt); + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + return(rc); +} + + +/* + * cpqhp_return_board_resources + * + * this routine returns all resources allocated to a board to + * the available pool. + * + * returns 0 if success + */ +int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +{ + int rc = 0; + struct pci_resource *node; + struct pci_resource *t_node; + dbg("%s\n", __FUNCTION__); + + if (!func) + return(1); + + node = func->io_head; + func->io_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->io_head), node); + node = t_node; + } + + node = func->mem_head; + func->mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->mem_head), node); + node = t_node; + } + + node = func->p_mem_head; + func->p_mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->p_mem_head), node); + node = t_node; + } + + node = func->bus_head; + func->bus_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->bus_head), node); + node = t_node; + } + + rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); + + return(rc); +} + + +/* + * cpqhp_destroy_resource_list + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_resource_list (struct resource_lists * resources) +{ + struct pci_resource *res, *tres; + + res = resources->io_head; + resources->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->mem_head; + resources->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->p_mem_head; + resources->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->bus_head; + resources->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + + +/* + * cpqhp_destroy_board_resources + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_board_resources (struct pci_func * func) +{ + struct pci_resource *res, *tres; + + res = func->io_head; + func->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->mem_head; + func->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->p_mem_head; + func->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->bus_head; + func->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_sysfs.c linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_sysfs.c --- linux-2.5.70-bk9/drivers/pci/hotplug/cpqphp_sysfs.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/cpqphp_sysfs.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,143 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cpqphp.h" + + +/* A few routines that create sysfs entries for the hot plug controller */ + +static int show_ctrl (struct device *dev, char *buf) +{ + struct pci_dev *pci_dev; + struct controller *ctrl; + char * out = buf; + int index; + struct pci_resource *res; + + pci_dev = container_of (dev, struct pci_dev, dev); + ctrl = pci_get_drvdata(pci_dev); + + out += sprintf(buf, "Free resources: memory\n"); + index = 11; + res = ctrl->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: prefetchable memory\n"); + index = 11; + res = ctrl->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: IO\n"); + index = 11; + res = ctrl->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: bus numbers\n"); + index = 11; + res = ctrl->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + + return out - buf; +} +static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); + +static int show_dev (struct device *dev, char *buf) +{ + struct pci_dev *pci_dev; + struct controller *ctrl; + char * out = buf; + int index; + struct pci_resource *res; + struct pci_func *new_slot; + struct slot *slot; + + pci_dev = container_of (dev, struct pci_dev, dev); + ctrl = pci_get_drvdata(pci_dev); + + slot=ctrl->slot; + + while (slot) { + new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); + if (!new_slot) + break; + out += sprintf(out, "assigned resources: memory\n"); + index = 11; + res = new_slot->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: prefetchable memory\n"); + index = 11; + res = new_slot->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: IO\n"); + index = 11; + res = new_slot->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: bus numbers\n"); + index = 11; + res = new_slot->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + slot=slot->next; + } + + return out - buf; +} +static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); + +void cpqhp_create_ctrl_files (struct controller *ctrl) +{ + device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); + device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp.h linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp.h --- linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,772 @@ +#ifndef __IBMPHP_H +#define __IBMPHP_H + +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include "pci_hotplug.h" + +extern int ibmphp_debug; + +#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE) + #define MY_NAME "ibmphpd" +#else + #define MY_NAME THIS_MODULE->name +#endif +#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* EBDA stuff */ + +/*********************************************************** +* SLOT CAPABILITY * +***********************************************************/ + +#define EBDA_SLOT_133_MAX 0x20 +#define EBDA_SLOT_100_MAX 0x10 +#define EBDA_SLOT_66_MAX 0x02 +#define EBDA_SLOT_PCIX_CAP 0x08 + + +/************************************************************ +* RESOURE TYPE * +************************************************************/ + +#define EBDA_RSRC_TYPE_MASK 0x03 +#define EBDA_IO_RSRC_TYPE 0x00 +#define EBDA_MEM_RSRC_TYPE 0x01 +#define EBDA_PFM_RSRC_TYPE 0x03 +#define EBDA_RES_RSRC_TYPE 0x02 + + +/************************************************************* +* IO RESTRICTION TYPE * +*************************************************************/ + +#define EBDA_IO_RESTRI_MASK 0x0c +#define EBDA_NO_RESTRI 0x00 +#define EBDA_AVO_VGA_ADDR 0x04 +#define EBDA_AVO_VGA_ADDR_AND_ALIA 0x08 +#define EBDA_AVO_ISA_ADDR 0x0c + + +/************************************************************** +* DEVICE TYPE DEF * +**************************************************************/ + +#define EBDA_DEV_TYPE_MASK 0x10 +#define EBDA_PCI_DEV 0x10 +#define EBDA_NON_PCI_DEV 0x00 + + +/*************************************************************** +* PRIMARY DEF DEFINITION * +***************************************************************/ + +#define EBDA_PRI_DEF_MASK 0x20 +#define EBDA_PRI_PCI_BUS_INFO 0x20 +#define EBDA_NORM_DEV_RSRC_INFO 0x00 + + +//-------------------------------------------------------------- +// RIO TABLE DATA STRUCTURE +//-------------------------------------------------------------- + +struct rio_table_hdr { + u8 ver_num; + u8 scal_count; + u8 riodev_count; + u16 offset; +}; + +//------------------------------------------------------------- +// SCALABILITY DETAIL +//------------------------------------------------------------- + +struct scal_detail { + u8 node_id; + u32 cbar; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 port2_node_connect; + u8 port2_port_connect; + u8 chassis_num; +// struct list_head scal_detail_list; +}; + +//-------------------------------------------------------------- +// RIO DETAIL +//-------------------------------------------------------------- + +struct rio_detail { + u8 rio_node_id; + u32 bbar; + u8 rio_type; + u8 owner_id; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 first_slot_num; + u8 status; + u8 wpindex; + u8 chassis_num; + struct list_head rio_detail_list; +}; + +struct opt_rio { + u8 rio_type; + u8 chassis_num; + u8 first_slot_num; + u8 middle_num; + struct list_head opt_rio_list; +}; + +struct opt_rio_lo { + u8 rio_type; + u8 chassis_num; + u8 first_slot_num; + u8 middle_num; + u8 pack_count; + struct list_head opt_rio_lo_list; +}; + +/**************************************************************** +* HPC DESCRIPTOR NODE * +****************************************************************/ + +struct ebda_hpc_list { + u8 format; + u16 num_ctlrs; + short phys_addr; +// struct list_head ebda_hpc_list; +}; +/***************************************************************** +* IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS * +* STRUCTURE * +*****************************************************************/ + +struct ebda_hpc_slot { + u8 slot_num; + u32 slot_bus_num; + u8 ctl_index; + u8 slot_cap; +}; + +struct ebda_hpc_bus { + u32 bus_num; + u8 slots_at_33_conv; + u8 slots_at_66_conv; + u8 slots_at_66_pcix; + u8 slots_at_100_pcix; + u8 slots_at_133_pcix; +}; + + +/******************************************************************** +* THREE TYPE OF HOT PLUG CONTROLER * +********************************************************************/ + +struct isa_ctlr_access { + u16 io_start; + u16 io_end; +}; + +struct pci_ctlr_access { + u8 bus; + u8 dev_fun; +}; + +struct wpeg_i2c_ctlr_access { + ulong wpegbbar; + u8 i2c_addr; +}; + +#define HPC_DEVICE_ID 0x0246 +#define HPC_SUBSYSTEM_ID 0x0247 +#define HPC_PCI_OFFSET 0x40 +/************************************************************************* +* RSTC DESCRIPTOR NODE * +*************************************************************************/ + +struct ebda_rsrc_list { + u8 format; + u16 num_entries; + u16 phys_addr; + struct ebda_rsrc_list *next; +}; + + +/*************************************************************************** +* PCI RSRC NODE * +***************************************************************************/ + +struct ebda_pci_rsrc { + u8 rsrc_type; + u8 bus_num; + u8 dev_fun; + u32 start_addr; + u32 end_addr; + u8 marked; /* for NVRAM */ + struct list_head ebda_pci_rsrc_list; +}; + + +/*********************************************************** +* BUS_INFO DATE STRUCTURE * +***********************************************************/ + +struct bus_info { + u8 slot_min; + u8 slot_max; + u8 slot_count; + u8 busno; + u8 controller_id; + u8 current_speed; + u8 current_bus_mode; + u8 index; + u8 slots_at_33_conv; + u8 slots_at_66_conv; + u8 slots_at_66_pcix; + u8 slots_at_100_pcix; + u8 slots_at_133_pcix; + struct list_head bus_info_list; +}; + + +/*********************************************************** +* GLOBAL VARIABLES * +***********************************************************/ +extern struct list_head ibmphp_ebda_pci_rsrc_head; +extern struct list_head ibmphp_slot_head; +extern struct list_head ibmphp_res_head; +/*********************************************************** +* FUNCTION PROTOTYPES * +***********************************************************/ + +extern void ibmphp_free_ebda_hpc_queue (void); +extern int ibmphp_access_ebda (void); +extern struct slot *ibmphp_get_slot_from_physical_num (u8); +extern int ibmphp_get_total_hp_slots (void); +extern void ibmphp_free_ibm_slot (struct slot *); +extern void ibmphp_free_bus_info_queue (void); +extern void ibmphp_free_ebda_pci_rsrc_queue (void); +extern struct bus_info *ibmphp_find_same_bus_num (u32); +extern int ibmphp_get_bus_index (u8); +extern u16 ibmphp_get_total_controllers (void); +extern int ibmphp_register_pci (void); + +/* passed parameters */ +#define MEM 0 +#define IO 1 +#define PFMEM 2 + +/* bit masks */ +#define RESTYPE 0x03 +#define IOMASK 0x00 /* will need to take its complement */ +#define MMASK 0x01 +#define PFMASK 0x03 +#define PCIDEVMASK 0x10 /* we should always have PCI devices */ +#define PRIMARYBUSMASK 0x20 + +/* pci specific defines */ +#define PCI_VENDOR_ID_NOTVALID 0xFFFF +#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 +#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 + +#define LATENCY 0x64 +#define CACHE 64 +#define DEVICEENABLE 0x015F /* CPQ has 0x0157 */ + +#define IOBRIDGE 0x1000 /* 4k */ +#define MEMBRIDGE 0x100000 /* 1M */ + +/* irqs */ +#define SCSI_IRQ 0x09 +#define LAN_IRQ 0x0A +#define OTHER_IRQ 0x0B + +/* Data Structures */ + +/* type is of the form x x xx xx + * | | | |_ 00 - I/O, 01 - Memory, 11 - PFMemory + * | | - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid + * | | VGA and their aliases, 11 - Avoid ISA + * | - 1 - PCI device, 0 - non pci device + * - 1 - Primary PCI Bus Information (0 if Normal device) + * the IO restrictions [2:3] are only for primary buses + */ + + +/* we need this struct because there could be several resource blocks + * allocated per primary bus in the EBDA + */ +struct range_node { + int rangeno; + u32 start; + u32 end; + struct range_node *next; +}; + +struct bus_node { + u8 busno; + int noIORanges; + struct range_node *rangeIO; + int noMemRanges; + struct range_node *rangeMem; + int noPFMemRanges; + struct range_node *rangePFMem; + int needIOUpdate; + int needMemUpdate; + int needPFMemUpdate; + struct resource_node *firstIO; /* first IO resource on the Bus */ + struct resource_node *firstMem; /* first memory resource on the Bus */ + struct resource_node *firstPFMem; /* first prefetchable memory resource on the Bus */ + struct resource_node *firstPFMemFromMem; /* when run out of pfmem available, taking from Mem */ + struct list_head bus_list; +}; + +struct resource_node { + int rangeno; + u8 busno; + u8 devfunc; + u32 start; + u32 end; + u32 len; + int type; /* MEM, IO, PFMEM */ + u8 fromMem; /* this is to indicate that the range is from + * from the Memory bucket rather than from PFMem */ + struct resource_node *next; + struct resource_node *nextRange; /* for the other mem range on bus */ +}; + +struct res_needed { + u32 mem; + u32 pfmem; + u32 io; + u8 not_correct; /* needed for return */ + int devices[32]; /* for device numbers behind this bridge */ +}; + +/* functions */ + +extern int ibmphp_rsrc_init (void); +extern int ibmphp_add_resource (struct resource_node *); +extern int ibmphp_remove_resource (struct resource_node *); +extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); +extern int ibmphp_check_resource (struct resource_node *, u8); +extern int ibmphp_remove_bus (struct bus_node *, u8); +extern void ibmphp_free_resources (void); +extern int ibmphp_add_pfmem_from_mem (struct resource_node *); +extern struct bus_node *ibmphp_find_res_bus (u8); +extern void ibmphp_print_test (void); /* for debugging purposes */ + +extern void ibmphp_hpc_initvars (void); +extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); +extern int ibmphp_hpc_writeslot (struct slot *, u8); +extern void ibmphp_lock_operations (void); +extern void ibmphp_unlock_operations (void); +extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *); +extern int ibmphp_hpc_start_poll_thread (void); +extern void ibmphp_hpc_stop_poll_thread (void); + +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// HPC return codes +//---------------------------------------------------------------------------- +#define FALSE 0x00 +#define TRUE 0x01 +#define HPC_ERROR 0xFF + +//----------------------------------------------------------------------------- +// BUS INFO +//----------------------------------------------------------------------------- +#define BUS_SPEED 0x30 +#define BUS_MODE 0x40 +#define BUS_MODE_PCIX 0x01 +#define BUS_MODE_PCI 0x00 +#define BUS_SPEED_2 0x20 +#define BUS_SPEED_1 0x10 +#define BUS_SPEED_33 0x00 +#define BUS_SPEED_66 0x01 +#define BUS_SPEED_100 0x02 +#define BUS_SPEED_133 0x03 +#define BUS_SPEED_66PCIX 0x04 +#define BUS_SPEED_66UNKNOWN 0x05 +#define BUS_STATUS_AVAILABLE 0x01 +#define BUS_CONTROL_AVAILABLE 0x02 +#define SLOT_LATCH_REGS_SUPPORTED 0x10 + +#define PRGM_MODEL_REV_LEVEL 0xF0 +#define MAX_ADAPTER_NONE 0x09 + +//---------------------------------------------------------------------------- +// HPC 'write' operations/commands +//---------------------------------------------------------------------------- +// Command Code State Write to reg +// Machine at index +//------------------------- ---- ------- ------------ +#define HPC_CTLR_ENABLEIRQ 0x00 // N 15 +#define HPC_CTLR_DISABLEIRQ 0x01 // N 15 +#define HPC_SLOT_OFF 0x02 // Y 0-14 +#define HPC_SLOT_ON 0x03 // Y 0-14 +#define HPC_SLOT_ATTNOFF 0x04 // N 0-14 +#define HPC_SLOT_ATTNON 0x05 // N 0-14 +#define HPC_CTLR_CLEARIRQ 0x06 // N 15 +#define HPC_CTLR_RESET 0x07 // Y 15 +#define HPC_CTLR_IRQSTEER 0x08 // N 15 +#define HPC_BUS_33CONVMODE 0x09 // Y 31-34 +#define HPC_BUS_66CONVMODE 0x0A // Y 31-34 +#define HPC_BUS_66PCIXMODE 0x0B // Y 31-34 +#define HPC_BUS_100PCIXMODE 0x0C // Y 31-34 +#define HPC_BUS_133PCIXMODE 0x0D // Y 31-34 +#define HPC_ALLSLOT_OFF 0x11 // Y 15 +#define HPC_ALLSLOT_ON 0x12 // Y 15 +#define HPC_SLOT_BLINKLED 0x13 // N 0-14 + +//---------------------------------------------------------------------------- +// read commands +//---------------------------------------------------------------------------- +#define READ_SLOTSTATUS 0x01 +#define READ_EXTSLOTSTATUS 0x02 +#define READ_BUSSTATUS 0x03 +#define READ_CTLRSTATUS 0x04 +#define READ_ALLSTAT 0x05 +#define READ_ALLSLOT 0x06 +#define READ_SLOTLATCHLOWREG 0x07 +#define READ_REVLEVEL 0x08 +#define READ_HPCOPTIONS 0x09 +//---------------------------------------------------------------------------- +// slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER 0x01 +#define HPC_SLOT_CONNECT 0x02 +#define HPC_SLOT_ATTN 0x04 +#define HPC_SLOT_PRSNT2 0x08 +#define HPC_SLOT_PRSNT1 0x10 +#define HPC_SLOT_PWRGD 0x20 +#define HPC_SLOT_BUS_SPEED 0x40 +#define HPC_SLOT_LATCH 0x80 + +//---------------------------------------------------------------------------- +// HPC_SLOT_POWER status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER_OFF 0x00 +#define HPC_SLOT_POWER_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_CONNECT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_CONNECTED 0x00 +#define HPC_SLOT_DISCONNECTED 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_ATTN status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_OFF 0x00 +#define HPC_SLOT_ATTN_ON 0x01 +#define HPC_SLOT_ATTN_BLINK 0x02 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PRSNT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_EMPTY 0x00 +#define HPC_SLOT_PRSNT_7 0x01 +#define HPC_SLOT_PRSNT_15 0x02 +#define HPC_SLOT_PRSNT_25 0x03 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PWRGD status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PWRGD_FAULT_NONE 0x00 +#define HPC_SLOT_PWRGD_GOOD 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_BUS_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_SPEED_OK 0x00 +#define HPC_SLOT_BUS_SPEED_MISM 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_LATCH status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_LATCH_OPEN 0x01 // NOTE : in PCI spec bit off = open +#define HPC_SLOT_LATCH_CLOSED 0x00 // NOTE : in PCI spec bit on = closed + + +//---------------------------------------------------------------------------- +// extended slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX 0x01 +#define HPC_SLOT_SPEED1 0x02 +#define HPC_SLOT_SPEED2 0x04 +#define HPC_SLOT_BLINK_ATTN 0x08 +#define HPC_SLOT_RSRVD1 0x10 +#define HPC_SLOT_RSRVD2 0x20 +#define HPC_SLOT_BUS_MODE 0x40 +#define HPC_SLOT_RSRVD3 0x80 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_PCIX_CAP status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX_NO 0x00 +#define HPC_SLOT_PCIX_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_SPEED_33 0x00 +#define HPC_SLOT_SPEED_66 0x01 +#define HPC_SLOT_SPEED_133 0x02 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_ATTN_BLINK status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_BLINK_OFF 0x00 +#define HPC_SLOT_ATTN_BLINK_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_BUS_MODE status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_MODE_OK 0x00 +#define HPC_SLOT_BUS_MODE_MISM 0x01 + +//---------------------------------------------------------------------------- +// Controller status +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING 0x01 +#define HPC_CTLR_FINISHED 0x02 +#define HPC_CTLR_RESULT0 0x04 +#define HPC_CTLR_RESULT1 0x08 +#define HPC_CTLR_RESULE2 0x10 +#define HPC_CTLR_RESULT3 0x20 +#define HPC_CTLR_IRQ_ROUTG 0x40 +#define HPC_CTLR_IRQ_PENDG 0x80 + +//---------------------------------------------------------------------------- +// HPC_CTLR_WROKING status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING_NO 0x00 +#define HPC_CTLR_WORKING_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_FINISHED status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_FINISHED_NO 0x00 +#define HPC_CTLR_FINISHED_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_RESULT status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_RESULT_SUCCESS 0x00 +#define HPC_CTLR_RESULT_FAILED 0x01 +#define HPC_CTLR_RESULT_RSVD 0x02 +#define HPC_CTLR_RESULT_NORESP 0x03 + + +//---------------------------------------------------------------------------- +// macro for slot info +//---------------------------------------------------------------------------- +#define SLOT_POWER(s) ((u8) ((s & HPC_SLOT_POWER) \ + ? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF)) + +#define SLOT_CONNECT(s) ((u8) ((s & HPC_SLOT_CONNECT) \ + ? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED)) + +#define SLOT_ATTN(s,es) ((u8) ((es & HPC_SLOT_BLINK_ATTN) \ + ? HPC_SLOT_ATTN_BLINK \ + : ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF))) + +#define SLOT_PRESENT(s) ((u8) ((s & HPC_SLOT_PRSNT1) \ + ? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \ + : ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7))) + +#define SLOT_PWRGD(s) ((u8) ((s & HPC_SLOT_PWRGD) \ + ? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE)) + +#define SLOT_BUS_SPEED(s) ((u8) ((s & HPC_SLOT_BUS_SPEED) \ + ? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK)) + +#define SLOT_LATCH(s) ((u8) ((s & HPC_SLOT_LATCH) \ + ? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN)) + +#define SLOT_PCIX(es) ((u8) ((es & HPC_SLOT_PCIX) \ + ? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO)) + +#define SLOT_SPEED(es) ((u8) ((es & HPC_SLOT_SPEED2) \ + ? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133 \ + : HPC_SLOT_SPEED_66) \ + : HPC_SLOT_SPEED_33)) + +#define SLOT_BUS_MODE(es) ((u8) ((es & HPC_SLOT_BUS_MODE) \ + ? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK)) + +//-------------------------------------------------------------------------- +// macro for bus info +//--------------------------------------------------------------------------- +#define CURRENT_BUS_SPEED(s) ((u8) (s & BUS_SPEED_2) \ + ? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \ + : ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33)) + +#define CURRENT_BUS_MODE(s) ((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI) + +#define READ_BUS_STATUS(s) ((u8) (s->options & BUS_STATUS_AVAILABLE)) + +#define READ_BUS_MODE(s) ((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20) + +#define SET_BUS_STATUS(s) ((u8) (s->options & BUS_CONTROL_AVAILABLE)) + +#define READ_SLOT_LATCH(s) ((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED)) + +//---------------------------------------------------------------------------- +// macro for controller info +//---------------------------------------------------------------------------- +#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \ + ? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO)) +#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \ + ? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO)) +#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1) \ + ? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \ + : HPC_CTLR_RESULT_RSVD) \ + : ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \ + : HPC_CTLR_RESULT_SUCCESS))) + +// command that affect the state machine of HPC +#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF) || \ + (c == HPC_SLOT_ON) || \ + (c == HPC_CTLR_RESET) || \ + (c == HPC_BUS_33CONVMODE) || \ + (c == HPC_BUS_66CONVMODE) || \ + (c == HPC_BUS_66PCIXMODE) || \ + (c == HPC_BUS_100PCIXMODE) || \ + (c == HPC_BUS_133PCIXMODE) || \ + (c == HPC_ALLSLOT_OFF) || \ + (c == HPC_ALLSLOT_ON)) + + +/* Core part of the driver */ + +#define ENABLE 1 +#define DISABLE 0 + +#define CARD_INFO 0x07 +#define PCIX133 0x07 +#define PCIX66 0x05 +#define PCI66 0x04 + +extern struct pci_bus *ibmphp_pci_bus; + +/* Variables */ + +struct pci_func { + struct pci_dev *dev; /* from the OS */ + u8 busno; + u8 device; + u8 function; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *pfmem[6]; + struct pci_func *next; + int devices[32]; /* for bridge config */ + u8 irq[4]; /* for interrupt config */ + u8 bus; /* flag for unconfiguring, to say if PPB */ +}; + +struct slot { + u8 bus; + u8 device; + u8 number; + u8 real_physical_slot_num; + char name[100]; + u32 capabilities; + u8 supported_speed; + u8 supported_bus_mode; + struct hotplug_slot *hotplug_slot; + struct controller *ctrl; + struct pci_func *func; + u8 irq[4]; + u8 flag; /* this is for disable slot and polling */ + int bit_mode; /* 0 = 32, 1 = 64 */ + u8 ctlr_index; + struct bus_info *bus_on; + struct list_head ibm_slot_list; + u8 status; + u8 ext_status; + u8 busstatus; +}; + +struct controller { + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + struct pci_dev *ctrl_dev; /* in case where controller is PCI */ + u8 starting_slot_num; /* starting and ending slot #'s this ctrl controls*/ + u8 ending_slot_num; + u8 revision; + u8 options; /* which options HPC supports */ + u8 status; + u8 ctlr_id; + u8 slot_count; + u8 bus_count; + u8 ctlr_relative_id; + u32 irq; + union { + struct isa_ctlr_access isa_ctlr; + struct pci_ctlr_access pci_ctlr; + struct wpeg_i2c_ctlr_access wpeg_ctlr; + } u; + u8 ctlr_type; + struct list_head ebda_hpc_list; +}; + +/* Functions */ + +extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ +extern int ibmphp_disable_slot (struct hotplug_slot *); /* This function is called from HPC, so we need it to not be static */ +extern int ibmphp_do_disable_slot (struct slot *slot_cur); +extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ +extern int ibmphp_configure_card (struct pci_func *, u8); +extern int ibmphp_unconfigure_card (struct slot **, int); +extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; + +static inline void long_delay (int delay) +{ + set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout (delay); +} + +#endif //__IBMPHP_H + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_core.c linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_core.c --- linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_core.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1416 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../pci.h" +#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ +#include "ibmphp.h" + +#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) +#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF) +#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED) +#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) +#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) + +#define DRIVER_VERSION "0.6" +#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" + +int ibmphp_debug; + +static int debug; +MODULE_PARM (debug, "i"); +MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); +MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION (DRIVER_DESC); + +struct pci_bus *ibmphp_pci_bus; +static int max_slots; + +static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */ + +static int init_flag; + +/* +static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8); + +static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) +{ + return get_max_adapter_speed_1 (hs, value, 1); +} +*/ +static inline int get_cur_bus_info (struct slot **sl) +{ + int rc = 1; + struct slot * slot_cur = *sl; + + debug ("options = %x\n", slot_cur->ctrl->options); + debug ("revision = %x\n", slot_cur->ctrl->revision); + + if (READ_BUS_STATUS (slot_cur->ctrl)) + rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL); + + if (rc) + return rc; + + slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus); + if (READ_BUS_MODE (slot_cur->ctrl)) + slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus); + else + slot_cur->bus_on->current_bus_mode = 0xFF; + + debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); + + *sl = slot_cur; + return 0; +} + +static inline int slot_update (struct slot **sl) +{ + int rc; + rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); + if (rc) + return rc; + if (!init_flag) + return get_cur_bus_info (sl); + return rc; +} + +static int __init get_max_slots (void) +{ + struct slot * slot_cur; + struct list_head * tmp; + u8 slot_count = 0; + + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + /* sometimes the hot-pluggable slots start with 4 (not always from 1 */ + slot_count = max (slot_count, slot_cur->number); + } + return slot_count; +} + +/* This routine will put the correct slot->device information per slot. It's + * called from initialization of the slot structures. It will also assign + * interrupt numbers per each slot. + * Parameters: struct slot + * Returns 0 or errors + */ +int ibmphp_init_devno (struct slot **cur_slot) +{ + struct irq_routing_table *rtable; + int len; + int loop; + int i; + + rtable = pcibios_get_irq_routing_table (); + if (!rtable) { + err ("no BIOS routing table...\n"); + return -ENOMEM; + } + + len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); + + if (!len) + return -1; + for (loop = 0; loop < len; loop++) { + if ((*cur_slot)->number == rtable->slots[loop].slot) { + if ((*cur_slot)->bus == rtable->slots[loop].bus) { + (*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn); + for (i = 0; i < 4; i++) + (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); + + debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); + debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); + debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); + debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); + + debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); + debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); + debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); + debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); + debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); + + debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link); + debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); + debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); + debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); + debug ("end of init_devno\n"); + return 0; + } + } + } + + return -1; +} + +static inline int power_on (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_ON; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power on failed\n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_on \n"); + return -EIO; + } + long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ + return 0; +} + +static inline int power_off (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_OFF; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power off failed \n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_off \n"); + return -EIO; + } + return 0; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) +{ + int rc = 0; + struct slot *pslot; + u8 cmd; + int hpcrc = 0; + + debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); + ibmphp_lock_operations (); + cmd = 0x00; // avoid compiler warning + + if (hotplug_slot) { + switch (value) { + case HPC_SLOT_ATTN_OFF: + cmd = HPC_SLOT_ATTNOFF; + break; + case HPC_SLOT_ATTN_ON: + cmd = HPC_SLOT_ATTNON; + break; + case HPC_SLOT_ATTN_BLINK: + cmd = HPC_SLOT_BLINKLED; + break; + default: + rc = -ENODEV; + err ("set_attention_status - Error : invalid input [%x]\n", value); + break; + } + if (rc == 0) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) + hpcrc = ibmphp_hpc_writeslot (pslot, cmd); + else + rc = -ENODEV; + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + + debug ("set_attention_status - Exit rc[%d]\n", rc); + return rc; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_ATTN (myslot.status, myslot.ext_status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_LATCH (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_PWRGD (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 present; + int hpcrc = 0; + struct slot myslot; + + debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + present = SLOT_PRESENT (myslot.status); + if (present == HPC_SLOT_EMPTY) + *value = 0; + else + *value = 1; + rc = 0; + } + } + } else + rc = -ENODEV; + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, + hotplug_slot, value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + mode = pslot->supported_bus_mode; + *value = pslot->supported_speed; + switch (*value) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + *value += 0x01; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + *value = pslot->supported_speed + 0x01; + break; + default: + /* Note (will need to change): there would be soon 256, 512 also */ + rc = -ENODEV; + } + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); + return rc; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, + hotplug_slot, value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = get_cur_bus_info (&pslot); + if (!rc) { + mode = pslot->bus_on->current_bus_mode; + *value = pslot->bus_on->current_speed; + switch (*value) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + *value += 0x01; + else if (mode == BUS_MODE_PCI) + ; + else + *value = PCI_SPEED_UNKNOWN; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + *value += 0x01; + break; + default: + /* Note of change: there would also be 256, 512 soon */ + rc = -ENODEV; + } + } + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); + return rc; +} +/* +static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + if (flag) + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + + if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) { + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_SPEED (myslot.ext_status); + rc = 0; + } + } else { + *value = MAX_ADAPTER_NONE; + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + if (flag) + ibmphp_unlock_operations (); + + debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value) +{ + int rc = -ENODEV; + struct slot *pslot = NULL; + + debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot); + + ibmphp_lock_operations (); + + if (hotplug_slot) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + snprintf (value, 100, "Bus %x", pslot->bus); + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} +*/ + +/******************************************************************************* + * This routine will initialize the ops data structure used in the validate + * function. It will also power off empty slots that are powered on since BIOS + * leaves those on, albeit disconnected + ******************************************************************************/ +static int __init init_ops (void) +{ + struct slot *slot_cur; + struct list_head *tmp; + int retval; + int rc; + + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + + if (!slot_cur) + return -ENODEV; + + debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); + if (slot_cur->ctrl->revision == 0xFF) + if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision)) + return -1; + + if (slot_cur->bus_on->current_speed == 0xFF) + if (get_cur_bus_info (&slot_cur)) + return -1; + + if (slot_cur->ctrl->options == 0xFF) + if (get_hpc_options (slot_cur, &slot_cur->ctrl->options)) + return -1; + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + debug ("status = %x\n", slot_cur->status); + debug ("ext_status = %x\n", slot_cur->ext_status); + debug ("SLOT_POWER = %x\n", SLOT_POWER (slot_cur->status)); + debug ("SLOT_PRESENT = %x\n", SLOT_PRESENT (slot_cur->status)); + debug ("SLOT_LATCH = %x\n", SLOT_LATCH (slot_cur->status)); + + if ((SLOT_PWRGD (slot_cur->status)) && + !(SLOT_PRESENT (slot_cur->status)) && + !(SLOT_LATCH (slot_cur->status))) { + debug ("BEFORE POWER OFF COMMAND\n"); + rc = power_off (slot_cur); + if (rc) + return rc; + + /* retval = slot_update (&slot_cur); + * if (retval) + * return retval; + * ibmphp_update_slot_info (slot_cur); + */ + } + } + init_flag = 0; + return 0; +} + +/* This operation will check whether the slot is within the bounds and + * the operation is valid to perform on that slot + * Parameters: slot, operation + * Returns: 0 or error codes + */ +static int validate (struct slot *slot_cur, int opn) +{ + int number; + int retval; + + if (!slot_cur) + return -ENODEV; + number = slot_cur->number; + if ((number > max_slots) || (number < 0)) + return -EBADSLT; + debug ("slot_number in validate is %d\n", slot_cur->number); + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + switch (opn) { + case ENABLE: + if (!(SLOT_PWRGD (slot_cur->status)) && + (SLOT_PRESENT (slot_cur->status)) && + !(SLOT_LATCH (slot_cur->status))) + return 0; + break; + case DISABLE: + if ((SLOT_PWRGD (slot_cur->status)) && + (SLOT_PRESENT (slot_cur->status)) && + !(SLOT_LATCH (slot_cur->status))) + return 0; + break; + default: + break; + } + err ("validate failed....\n"); + return -EINVAL; +} + +/******************************************************************************** + * This routine is for updating the data structures in the hotplug core + * Parameters: struct slot + * Returns: 0 or error + *******************************************************************************/ +int ibmphp_update_slot_info (struct slot *slot_cur) +{ + struct hotplug_slot_info *info; + int rc; + u8 bus_speed; + u8 mode; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + err ("out of system memory \n"); + return -ENOMEM; + } + + info->power_status = SLOT_PWRGD (slot_cur->status); + info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status); + info->latch_status = SLOT_LATCH (slot_cur->status); + if (!SLOT_PRESENT (slot_cur->status)) { + info->adapter_status = 0; +// info->max_adapter_speed_status = MAX_ADAPTER_NONE; + } else { + info->adapter_status = 1; +// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0); + } + + bus_speed = slot_cur->bus_on->current_speed; + mode = slot_cur->bus_on->current_bus_mode; + + switch (bus_speed) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + bus_speed += 0x01; + else if (mode == BUS_MODE_PCI) + ; + else + bus_speed = PCI_SPEED_UNKNOWN; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + bus_speed += 0x01; + break; + default: + bus_speed = PCI_SPEED_UNKNOWN; + } + + info->cur_bus_speed = bus_speed; + info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed; + // To do: bus_names + + rc = pci_hp_change_slot_info (slot_cur->hotplug_slot, info); + kfree (info); + return rc; +} + + +/****************************************************************************** + * This function will return the pci_func, given bus and devfunc, or NULL. It + * is called from visit routines + ******************************************************************************/ + +static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) +{ + struct pci_func *func_cur; + struct slot *slot_cur; + struct list_head * tmp; + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + if (slot_cur->func) { + func_cur = slot_cur->func; + while (func_cur) { + if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function)) + return func_cur; + func_cur = func_cur->next; + } + } + } + return NULL; +} + +/************************************************************* + * This routine frees up memory used by struct slot, including + * the pointers to pci_func, bus, hotplug_slot, controller, + * and deregistering from the hotplug core + *************************************************************/ +static void free_slots (void) +{ + struct slot *slot_cur; + struct list_head * tmp; + struct list_head * next; + + debug ("%s -- enter\n", __FUNCTION__); + + list_for_each_safe (tmp, next, &ibmphp_slot_head) { + + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + + pci_hp_deregister (slot_cur->hotplug_slot); + + if (slot_cur->hotplug_slot) { + kfree (slot_cur->hotplug_slot); + slot_cur->hotplug_slot = NULL; + } + + if (slot_cur->ctrl) + slot_cur->ctrl = NULL; + + if (slot_cur->bus_on) + slot_cur->bus_on = NULL; + + ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */ + + kfree (slot_cur); + slot_cur = NULL; + } + debug ("%s -- exit\n", __FUNCTION__); +} + +static int ibm_unconfigure_device (struct pci_func *func) +{ + struct pci_dev *temp; + u8 j; + + debug ("inside %s\n", __FUNCTION__); + debug ("func->device = %x, func->function = %x\n", func->device, func->function); + debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); + + for (j = 0; j < 0x08; j++) { + temp = pci_find_slot (func->busno, (func->device << 3) | j); + if (temp) + pci_remove_bus_device(temp); + } + return 0; +} + +/* + * The following function is to fix kernel bug regarding + * getting bus entries, here we manually add those primary + * bus entries to kernel bus structure whenever apply + */ + +static u8 bus_structure_fixup (u8 busno) +{ + struct pci_bus *bus; + struct pci_dev *dev; + u16 l; + + if (pci_find_bus(busno) || !(ibmphp_find_same_bus_num (busno))) + return 1; + + bus = kmalloc (sizeof (*bus), GFP_KERNEL); + if (!bus) { + err ("%s - out of memory\n", __FUNCTION__); + return 1; + } + dev = kmalloc (sizeof (*dev), GFP_KERNEL); + if (!dev) { + kfree (bus); + err ("%s - out of memory\n", __FUNCTION__); + return 1; + } + + bus->number = busno; + bus->ops = ibmphp_pci_bus->ops; + dev->bus = bus; + for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) { + if (!pci_read_config_word (dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { + debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__); + pci_scan_bus (busno, ibmphp_pci_bus->ops, NULL); + break; + } + } + + kfree (dev); + kfree (bus); + + return 0; +} + +static int ibm_configure_device (struct pci_func *func) +{ + unsigned char bus; + struct pci_bus *child; + int num; + int flag = 0; /* this is to make sure we don't double scan the bus, for bridged devices primarily */ + + if (!(bus_structure_fixup (func->busno))) + flag = 1; + if (func->dev == NULL) + func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function)); + + if (func->dev == NULL) { + struct pci_bus *bus = pci_find_bus(func->busno); + if (!bus) + return 0; + + num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function)); + if (num) + pci_bus_add_devices(bus); + + func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function)); + if (func->dev == NULL) { + err ("ERROR... : pci_dev still NULL \n"); + return 0; + } + } + if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { + pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus); + pci_do_scan_bus (child); + } + + return 0; +} + +/******************************************************* + * Returns whether the bus is empty or not + *******************************************************/ +static int is_bus_empty (struct slot * slot_cur) +{ + int rc; + struct slot * tmp_slot; + u8 i = slot_cur->bus_on->slot_min; + + while (i <= slot_cur->bus_on->slot_max) { + if (i == slot_cur->number) { + i++; + continue; + } + tmp_slot = ibmphp_get_slot_from_physical_num (i); + if (!tmp_slot) + return 0; + rc = slot_update (&tmp_slot); + if (rc) + return 0; + if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status)) + return 0; + i++; + } + return 1; +} + +/*********************************************************** + * If the HPC permits and the bus currently empty, tries to set the + * bus speed and mode at the maximum card and bus capability + * Parameters: slot + * Returns: bus is set (0) or error code + ***********************************************************/ +static int set_bus (struct slot * slot_cur) +{ + int rc; + u8 speed; + u8 cmd = 0x0; + struct pci_dev *dev = NULL; + int retval; + + debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number); + if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) { + rc = slot_update (&slot_cur); + if (rc) + return rc; + speed = SLOT_SPEED (slot_cur->ext_status); + debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); + switch (speed) { + case HPC_SLOT_SPEED_33: + cmd = HPC_BUS_33CONVMODE; + break; + case HPC_SLOT_SPEED_66: + if (SLOT_PCIX (slot_cur->ext_status)) { + if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX)) + cmd = HPC_BUS_66PCIXMODE; + else if (!SLOT_BUS_MODE (slot_cur->ext_status)) + /* if max slot/bus capability is 66 pci + and there's no bus mode mismatch, then + the adapter supports 66 pci */ + cmd = HPC_BUS_66CONVMODE; + else + cmd = HPC_BUS_33CONVMODE; + } else { + if (slot_cur->supported_speed >= BUS_SPEED_66) + cmd = HPC_BUS_66CONVMODE; + else + cmd = HPC_BUS_33CONVMODE; + } + break; + case HPC_SLOT_SPEED_133: + switch (slot_cur->supported_speed) { + case BUS_SPEED_33: + cmd = HPC_BUS_33CONVMODE; + break; + case BUS_SPEED_66: + if (slot_cur->supported_bus_mode == BUS_MODE_PCIX) + cmd = HPC_BUS_66PCIXMODE; + else + cmd = HPC_BUS_66CONVMODE; + break; + case BUS_SPEED_100: + cmd = HPC_BUS_100PCIXMODE; + break; + case BUS_SPEED_133: + /* This is to take care of the bug in CIOBX chip */ + while ((dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + 0x0101, dev)) != NULL) + ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE); + cmd = HPC_BUS_133PCIXMODE; + break; + default: + err ("Wrong bus speed \n"); + return -ENODEV; + } + break; + default: + err ("wrong slot speed \n"); + return -ENODEV; + } + debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd); + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("setting bus speed failed\n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in set_bus \n"); + return -EIO; + } + } + /* This is for x440, once Brandon fixes the firmware, + will not need this delay */ + long_delay (1 * HZ); + debug ("%s -Exit \n", __FUNCTION__); + return 0; +} + +/* This routine checks the bus limitations that the slot is on from the BIOS. + * This is used in deciding whether or not to power up the slot. + * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on + * same bus) + * Parameters: slot + * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus + */ +static int check_limitations (struct slot *slot_cur) +{ + u8 i; + struct slot * tmp_slot; + u8 count = 0; + u8 limitation = 0; + + for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) { + tmp_slot = ibmphp_get_slot_from_physical_num (i); + if (!tmp_slot) + return -ENODEV; + if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) + count++; + } + get_cur_bus_info (&slot_cur); + switch (slot_cur->bus_on->current_speed) { + case BUS_SPEED_33: + limitation = slot_cur->bus_on->slots_at_33_conv; + break; + case BUS_SPEED_66: + if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX) + limitation = slot_cur->bus_on->slots_at_66_pcix; + else + limitation = slot_cur->bus_on->slots_at_66_conv; + break; + case BUS_SPEED_100: + limitation = slot_cur->bus_on->slots_at_100_pcix; + break; + case BUS_SPEED_133: + limitation = slot_cur->bus_on->slots_at_133_pcix; + break; + } + + if ((count + 1) > limitation) + return -EINVAL; + return 0; +} + +static inline void print_card_capability (struct slot *slot_cur) +{ + info ("capability of the card is "); + if ((slot_cur->ext_status & CARD_INFO) == PCIX133) + info (" 133 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) + info (" 66 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCI66) + info (" 66 MHz PCI \n"); + else + info (" 33 MHz PCI \n"); + +} + +/* This routine will power on the slot, configure the device(s) and find the + * drivers for them. + * Parameters: hotplug_slot + * Returns: 0 or failure codes + */ +static int enable_slot (struct hotplug_slot *hs) +{ + int rc, i, rcpr; + struct slot *slot_cur; + u8 function; + struct pci_func *tmp_func; + + ibmphp_lock_operations (); + + debug ("ENABLING SLOT........ \n"); + slot_cur = (struct slot *) hs->private; + + if ((rc = validate (slot_cur, ENABLE))) { + err ("validate function failed \n"); + goto error_nopower; + } + + attn_LED_blink (slot_cur); + + rc = set_bus (slot_cur); + if (rc) { + err ("was not able to set the bus \n"); + goto error_nopower; + } + + /*-----------------debugging------------------------------*/ + get_cur_bus_info (&slot_cur); + debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); + /*----------------------------------------------------------*/ + + rc = check_limitations (slot_cur); + if (rc) { + err ("Adding this card exceeds the limitations of this bus.\n"); + err ("(i.e., >1 133MHz cards running on same bus, or " + ">2 66 PCI cards running on same bus\n."); + err ("Try hot-adding into another bus \n"); + rc = -EINVAL; + goto error_nopower; + } + + rc = power_on (slot_cur); + + if (rc) { + err ("something wrong when powering up... please see below for details\n"); + /* need to turn off before on, otherwise, blinking overwrites */ + attn_off(slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + attn_off (slot_cur); + attn_on (slot_cur); + rc = -ENODEV; + goto exit; + } + /* Check to see the error of why it failed */ + if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status))) + err ("power fault occurred trying to power up \n"); + else if (SLOT_BUS_SPEED (slot_cur->status)) { + err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + } else if (SLOT_BUS_MODE (slot_cur->ext_status)) { + err ("bus mode mismatch occurred. please check current bus mode and card capability \n"); + print_card_capability (slot_cur); + } + ibmphp_update_slot_info (slot_cur); + goto exit; + } + debug ("after power_on\n"); + /*-----------------------debugging---------------------------*/ + get_cur_bus_info (&slot_cur); + debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed); + /*----------------------------------------------------------*/ + + rc = slot_update (&slot_cur); + if (rc) + goto error_power; + + rc = -EINVAL; + if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) { + err ("power fault occurred trying to power up... \n"); + goto error_power; + } + if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) { + err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + goto error_power; + } + /* Don't think this case will happen after above checks... but just in case, for paranoia sake */ + if (!(SLOT_POWER (slot_cur->status))) { + err ("power on failed... \n"); + goto error_power; + } + + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { + /* We cannot do update_slot_info here, since no memory for + * kmalloc n.e.ways, and update_slot_info allocates some */ + err ("out of system memory \n"); + rc = -ENOMEM; + goto error_power; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + for (i = 0; i < 4; i++) + slot_cur->func->irq[i] = slot_cur->irq[i]; + + debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device); + + if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) { + err ("configure_card was unsuccessful... \n"); + ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */ + debug ("after unconfigure_card\n"); + slot_cur->func = NULL; + rc = -ENOMEM; + goto error_power; + } + + function = 0x00; + do { + tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++); + if (tmp_func && !(tmp_func->dev)) + ibm_configure_device (tmp_func); + } while (tmp_func); + + attn_off (slot_cur); + if (slot_update (&slot_cur)) { + rc = -EFAULT; + goto exit; + } + ibmphp_print_test (); + rc = ibmphp_update_slot_info (slot_cur); +exit: + ibmphp_unlock_operations(); + return rc; + +error_nopower: + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); +error_cont: + rcpr = slot_update (&slot_cur); + if (rcpr) { + rc = rcpr; + goto exit; + } + ibmphp_update_slot_info (slot_cur); + goto exit; + +error_power: + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + rc = rcpr; + goto exit; + } + goto error_cont; +} + +/************************************************************** +* HOT REMOVING ADAPTER CARD * +* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * +* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * + DISABLE POWER , * +**************************************************************/ +int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot->private; + int rc; + + ibmphp_lock_operations(); + rc = ibmphp_do_disable_slot(slot); + ibmphp_unlock_operations(); + return rc; +} + +int ibmphp_do_disable_slot (struct slot *slot_cur) +{ + int rc; + u8 flag; + int parm = 0; + + debug ("DISABLING SLOT... \n"); + + if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) { + return -ENODEV; + } + + flag = slot_cur->flag; + slot_cur->flag = TRUE; + + if (flag == TRUE) { + rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */ + if (rc) + goto error; + } + attn_LED_blink (slot_cur); + + if (slot_cur->func == NULL) { + /* We need this for fncs's that were there on bootup */ + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { + err ("out of system memory \n"); + rc = -ENOMEM; + goto error; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + } + + if ((rc = ibm_unconfigure_device (slot_cur->func))) { + err ("removing from kernel failed... \n"); + err ("Please check to see if it was statically linked or is " + "in use otherwise. (perhaps the driver is not 'hot-removable')\n"); + goto error; + } + + /* If we got here from latch suddenly opening on operating card or + a power fault, there's no power to the card, so cannot + read from it to determine what resources it occupied. This operation + is forbidden anyhow. The best we can do is remove it from kernel + lists at least */ + + if (!flag) { + attn_off (slot_cur); + return 0; + } + + rc = ibmphp_unconfigure_card (&slot_cur, parm); + slot_cur->func = NULL; + debug ("in disable_slot. after unconfigure_card\n"); + if (rc) { + err ("could not unconfigure card.\n"); + goto error; + } + + rc = ibmphp_hpc_writeslot (slot_cur, HPC_SLOT_OFF); + if (rc) + goto error; + + attn_off (slot_cur); + rc = slot_update (&slot_cur); + if (rc) + goto exit; + + rc = ibmphp_update_slot_info (slot_cur); + ibmphp_print_test (); +exit: + return rc; + +error: + /* Need to turn off if was blinking b4 */ + attn_off (slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + rc = -EFAULT; + goto exit; + } + if (flag) + ibmphp_update_slot_info (slot_cur); + goto exit; +} + +struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .set_attention_status = set_attention_status, + .enable_slot = enable_slot, + .disable_slot = ibmphp_disable_slot, + .hardware_test = NULL, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_present, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +/* .get_max_adapter_speed = get_max_adapter_speed, + .get_bus_name_status = get_bus_name, +*/ +}; + +static void ibmphp_unload (void) +{ + free_slots (); + debug ("after slots \n"); + ibmphp_free_resources (); + debug ("after resources \n"); + ibmphp_free_bus_info_queue (); + debug ("after bus info \n"); + ibmphp_free_ebda_hpc_queue (); + debug ("after ebda hpc \n"); + ibmphp_free_ebda_pci_rsrc_queue (); + debug ("after ebda pci rsrc \n"); + kfree (ibmphp_pci_bus); +} + +static int __init ibmphp_init (void) +{ + struct pci_bus *bus; + int i = 0; + int rc = 0; + + init_flag = 1; + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + ibmphp_pci_bus = kmalloc (sizeof (*ibmphp_pci_bus), GFP_KERNEL); + if (!ibmphp_pci_bus) { + err ("out of memory\n"); + rc = -ENOMEM; + goto exit; + } + + bus = pci_find_bus(0); + if (!bus) { + err ("Can't find the root pci bus, can not continue\n"); + rc = -ENODEV; + goto error; + } + memcpy (ibmphp_pci_bus, bus, sizeof (*ibmphp_pci_bus)); + + ibmphp_debug = debug; + + ibmphp_hpc_initvars (); + + for (i = 0; i < 16; i++) + irqs[i] = 0; + + if ((rc = ibmphp_access_ebda ())) + goto error; + debug ("after ibmphp_access_ebda ()\n"); + + if ((rc = ibmphp_rsrc_init ())) + goto error; + debug ("AFTER Resource & EBDA INITIALIZATIONS\n"); + + max_slots = get_max_slots (); + + if ((rc = ibmphp_register_pci ())) + goto error; + + if (init_ops ()) { + rc = -ENODEV; + goto error; + } + + ibmphp_print_test (); + if ((rc = ibmphp_hpc_start_poll_thread ())) { + goto error; + } + + /* lock ourselves into memory with a module + * count of -1 so that no one can unload us. */ + module_put(THIS_MODULE); + +exit: + return rc; + +error: + ibmphp_unload (); + goto exit; +} + +static void __exit ibmphp_exit (void) +{ + ibmphp_hpc_stop_poll_thread (); + debug ("after polling\n"); + ibmphp_unload (); + debug ("done\n"); +} + +module_init (ibmphp_init); +module_exit (ibmphp_exit); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_ebda.c linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_ebda.c --- linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_ebda.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_ebda.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1228 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Tong Yu, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ibmphp.h" + +/* + * POST builds data blocks(in this data block definition, a char-1 + * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended + * BIOS Data Area which describe the configuration of the hot-plug + * controllers and resources used by the PCI Hot-Plug devices. + * + * This file walks EBDA, maps data block from physical addr, + * reconstruct linked lists about all system resource(MEM, PFM, IO) + * already assigned by POST, as well as linked lists about hot plug + * controllers (ctlr#, slot#, bus&slot features...) + */ + +/* Global lists */ +LIST_HEAD (ibmphp_ebda_pci_rsrc_head); +LIST_HEAD (ibmphp_slot_head); + +/* Local variables */ +static struct ebda_hpc_list *hpc_list_ptr; +static struct ebda_rsrc_list *rsrc_list_ptr; +static struct rio_table_hdr *rio_table_ptr = NULL; +static LIST_HEAD (ebda_hpc_head); +static LIST_HEAD (bus_info_head); +static LIST_HEAD (rio_vg_head); +static LIST_HEAD (rio_lo_head); +static LIST_HEAD (opt_vg_head); +static LIST_HEAD (opt_lo_head); +static void *io_mem; + +/* Local functions */ +static int ebda_rsrc_controller (void); +static int ebda_rsrc_rsrc (void); +static int ebda_rio_table (void); + +static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void) +{ + struct ebda_hpc_list *list; + + list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) +{ + struct controller *controller; + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + + controller = kmalloc (sizeof (struct controller), GFP_KERNEL); + if (!controller) + return NULL; + memset (controller, 0, sizeof (*controller)); + + slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); + if (!slots) { + kfree (controller); + return NULL; + } + memset (slots, 0, sizeof (*slots) * slot_count); + controller->slots = slots; + + buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); + if (!buses) { + kfree (controller->slots); + kfree (controller); + return NULL; + } + memset (buses, 0, sizeof (*buses) * bus_count); + controller->buses = buses; + + return controller; +} + +static void free_ebda_hpc (struct controller *controller) +{ + kfree (controller->slots); + controller->slots = NULL; + kfree (controller->buses); + controller->buses = NULL; + controller->ctrl_dev = NULL; + kfree (controller); +} + +static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void) +{ + struct ebda_rsrc_list *list; + + list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *resource; + + resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); + if (!resource) + return NULL; + memset (resource, 0, sizeof (*resource)); + return resource; +} + +static void __init print_bus_info (void) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); + debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); + debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); + debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); + debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); + debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); + + debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv); + debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv); + debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix); + debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix); + debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix); + + } +} + +static void print_lo_info (void) +{ + struct rio_detail *ptr; + struct list_head *ptr1; + debug ("print_lo_info ---- \n"); + list_for_each (ptr1, &rio_lo_head) { + ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); + debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); + debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); + debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); + debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); + debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); + debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); + + } +} + +static void print_vg_info (void) +{ + struct rio_detail *ptr; + struct list_head *ptr1; + debug ("%s --- \n", __FUNCTION__); + list_for_each (ptr1, &rio_vg_head) { + ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); + debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); + debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); + debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); + debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); + debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); + debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); + + } +} + +static void __init print_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { + ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); + } +} + +static void __init print_ibm_slot (void) +{ + struct slot *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &ibmphp_slot_head) { + ptr = list_entry (ptr1, struct slot, ibm_slot_list); + debug ("%s - slot_number: %x \n", __FUNCTION__, ptr->number); + } +} + +static void __init print_opt_vg (void) +{ + struct opt_rio *ptr; + struct list_head *ptr1; + debug ("%s --- \n", __FUNCTION__); + list_for_each (ptr1, &opt_vg_head) { + ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); + debug ("%s - rio_type %x \n", __FUNCTION__, ptr->rio_type); + debug ("%s - chassis_num: %x \n", __FUNCTION__, ptr->chassis_num); + debug ("%s - first_slot_num: %x \n", __FUNCTION__, ptr->first_slot_num); + debug ("%s - middle_num: %x \n", __FUNCTION__, ptr->middle_num); + } +} + +static void __init print_ebda_hpc (void) +{ + struct controller *hpc_ptr; + struct list_head *ptr1; + u16 index; + + list_for_each (ptr1, &ebda_hpc_head) { + + hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); + + for (index = 0; index < hpc_ptr->slot_count; index++) { + debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); + debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); + debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); + debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); + } + + for (index = 0; index < hpc_ptr->bus_count; index++) { + debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); + } + + debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); + switch (hpc_ptr->ctlr_type) { + case 1: + debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); + debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 0: + debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); + debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 2: + case 4: + debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); + debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + } + } +} + +int __init ibmphp_access_ebda (void) +{ + u8 format, num_ctlrs, rio_complete, hs_complete; + u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; + + + rio_complete = 0; + hs_complete = 0; + + io_mem = ioremap ((0x40 << 4) + 0x0e, 2); + if (!io_mem ) + return -ENOMEM; + ebda_seg = readw (io_mem); + iounmap (io_mem); + debug ("returned ebda segment: %x\n", ebda_seg); + + io_mem = ioremap (ebda_seg<<4, 65000); + if (!io_mem ) + return -ENOMEM; + next_offset = 0x180; + + for (;;) { + offset = next_offset; + next_offset = readw (io_mem + offset); /* offset of next blk */ + + offset += 2; + if (next_offset == 0) /* 0 indicate it's last blk */ + break; + blk_id = readw (io_mem + offset); /* this blk id */ + + offset += 2; + /* check if it is hot swap block or rio block */ + if (blk_id != 0x4853 && blk_id != 0x4752) + continue; + /* found hs table */ + if (blk_id == 0x4853) { + debug ("now enter hot swap block---\n"); + debug ("hot blk id: %x\n", blk_id); + format = readb (io_mem + offset); + + offset += 1; + if (format != 4) { + iounmap (io_mem); + return -ENODEV; + } + debug ("hot blk format: %x\n", format); + /* hot swap sub blk */ + base = offset; + + sub_addr = base; + re = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + rc_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (rc_id != 0x5243) { + iounmap (io_mem); + return -ENODEV; + } + /* rc sub blk signature */ + num_ctlrs = readb (io_mem + sub_addr); + + sub_addr += 1; + hpc_list_ptr = alloc_ebda_hpc_list (); + if (!hpc_list_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + hpc_list_ptr->format = format; + hpc_list_ptr->num_ctlrs = num_ctlrs; + hpc_list_ptr->phys_addr = sub_addr; /* offset of RSRC_CONTROLLER blk */ + debug ("info about hpc descriptor---\n"); + debug ("hot blk format: %x\n", format); + debug ("num of controller: %x\n", num_ctlrs); + debug ("offset of hpc data structure enteries: %x\n ", sub_addr); + + sub_addr = base + re; /* re sub blk */ + rc = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + re_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (re_id != 0x5245) { + iounmap (io_mem); + return -ENODEV; + } + + /* signature of re */ + num_entries = readw (io_mem + sub_addr); + + sub_addr += 2; /* offset of RSRC_ENTRIES blk */ + rsrc_list_ptr = alloc_ebda_rsrc_list (); + if (!rsrc_list_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_list_ptr->format = format; + rsrc_list_ptr->num_entries = num_entries; + rsrc_list_ptr->phys_addr = sub_addr; + + debug ("info about rsrc descriptor---\n"); + debug ("format: %x\n", format); + debug ("num of rsrc: %x\n", num_entries); + debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); + + hs_complete = 1; + } + /* found rio table */ + else if (blk_id == 0x4752) { + debug ("now enter io table ---\n"); + debug ("rio blk id: %x\n", blk_id); + + rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); + if (!rio_table_ptr) + return -ENOMEM; + memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); + rio_table_ptr->ver_num = readb (io_mem + offset); + rio_table_ptr->scal_count = readb (io_mem + offset + 1); + rio_table_ptr->riodev_count = readb (io_mem + offset + 2); + rio_table_ptr->offset = offset +3 ; + + debug ("info about rio table hdr ---\n"); + debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset); + + rio_complete = 1; + } + } + + if (!hs_complete && !rio_complete) { + iounmap (io_mem); + return -ENODEV; + } + + if (rio_table_ptr) { + if (rio_complete == 1 && rio_table_ptr->ver_num == 3) { + rc = ebda_rio_table (); + if (rc) { + iounmap (io_mem); + return rc; + } + } + } + rc = ebda_rsrc_controller (); + if (rc) { + iounmap (io_mem); + return rc; + } + + rc = ebda_rsrc_rsrc (); + if (rc) { + iounmap (io_mem); + return rc; + } + + iounmap (io_mem); + return 0; +} + +/* + * map info of scalability details and rio details from physical address + */ +static int __init ebda_rio_table (void) +{ + u16 offset; + u8 i; + struct rio_detail *rio_detail_ptr; + + offset = rio_table_ptr->offset; + offset += 12 * rio_table_ptr->scal_count; + + // we do concern about rio details + for (i = 0; i < rio_table_ptr->riodev_count; i++) { + rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL); + if (!rio_detail_ptr) + return -ENOMEM; + memset (rio_detail_ptr, 0, sizeof (struct rio_detail)); + rio_detail_ptr->rio_node_id = readb (io_mem + offset); + rio_detail_ptr->bbar = readl (io_mem + offset + 1); + rio_detail_ptr->rio_type = readb (io_mem + offset + 5); + rio_detail_ptr->owner_id = readb (io_mem + offset + 6); + rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7); + rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8); + rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9); + rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10); + rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11); + rio_detail_ptr->status = readb (io_mem + offset + 12); + rio_detail_ptr->wpindex = readb (io_mem + offset + 13); + rio_detail_ptr->chassis_num = readb (io_mem + offset + 14); +// debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); + //create linked list of chassis + if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) + list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head); + //create linked list of expansion box + else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) + list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head); + else + // not in my concern + kfree (rio_detail_ptr); + offset += 15; + } + print_lo_info (); + print_vg_info (); + return 0; +} + +/* + * reorganizing linked list of chassis + */ +static struct opt_rio *search_opt_vg (u8 chassis_num) +{ + struct opt_rio *ptr; + struct list_head *ptr1; + list_for_each (ptr1, &opt_vg_head) { + ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); + if (ptr->chassis_num == chassis_num) + return ptr; + } + return NULL; +} + +static int __init combine_wpg_for_chassis (void) +{ + struct opt_rio *opt_rio_ptr = NULL; + struct rio_detail *rio_detail_ptr = NULL; + struct list_head *list_head_ptr = NULL; + + list_for_each (list_head_ptr, &rio_vg_head) { + rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); + opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num); + if (!opt_rio_ptr) { + opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL); + if (!opt_rio_ptr) + return -ENOMEM; + memset (opt_rio_ptr, 0, sizeof (struct opt_rio)); + opt_rio_ptr->rio_type = rio_detail_ptr->rio_type; + opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num; + opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num; + opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num; + list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head); + } else { + opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num); + opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num); + } + } + print_opt_vg (); + return 0; +} + +/* + * reorgnizing linked list of expansion box + */ +static struct opt_rio_lo *search_opt_lo (u8 chassis_num) +{ + struct opt_rio_lo *ptr; + struct list_head *ptr1; + list_for_each (ptr1, &opt_lo_head) { + ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list); + if (ptr->chassis_num == chassis_num) + return ptr; + } + return NULL; +} + +static int combine_wpg_for_expansion (void) +{ + struct opt_rio_lo *opt_rio_lo_ptr = NULL; + struct rio_detail *rio_detail_ptr = NULL; + struct list_head *list_head_ptr = NULL; + + list_for_each (list_head_ptr, &rio_lo_head) { + rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); + opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num); + if (!opt_rio_lo_ptr) { + opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL); + if (!opt_rio_lo_ptr) + return -ENOMEM; + memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo)); + opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type; + opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num; + opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num; + opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num; + opt_rio_lo_ptr->pack_count = 1; + + list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head); + } else { + opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num); + opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num); + opt_rio_lo_ptr->pack_count = 2; + } + } + return 0; +} + + +/* Since we don't know the max slot number per each chassis, hence go + * through the list of all chassis to find out the range + * Arguments: slot_num, 1st slot number of the chassis we think we are on, + * var (0 = chassis, 1 = expansion box) + */ +static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) +{ + struct opt_rio *opt_vg_ptr = NULL; + struct opt_rio_lo *opt_lo_ptr = NULL; + struct list_head *ptr = NULL; + int rc = 0; + + if (!var) { + list_for_each (ptr, &opt_vg_head) { + opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); + if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { + rc = -ENODEV; + break; + } + } + } else { + list_for_each (ptr, &opt_lo_head) { + opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); + if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) { + rc = -ENODEV; + break; + } + } + } + return rc; +} + +static struct opt_rio_lo * find_rxe_num (u8 slot_num) +{ + struct opt_rio_lo *opt_lo_ptr; + struct list_head *ptr; + + list_for_each (ptr, &opt_lo_head) { + opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); + //check to see if this slot_num belongs to expansion box + if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) + return opt_lo_ptr; + } + return NULL; +} + +static struct opt_rio * find_chassis_num (u8 slot_num) +{ + struct opt_rio *opt_vg_ptr; + struct list_head *ptr; + + list_for_each (ptr, &opt_vg_head) { + opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); + //check to see if this slot_num belongs to chassis + if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) + return opt_vg_ptr; + } + return NULL; +} + +/* This routine will find out how many slots are in the chassis, so that + * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc + */ +static u8 calculate_first_slot (u8 slot_num) +{ + u8 first_slot = 1; + struct list_head * list; + struct slot * slot_cur; + + list_for_each (list, &ibmphp_slot_head) { + slot_cur = list_entry (list, struct slot, ibm_slot_list); + if (slot_cur->ctrl) { + if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) + first_slot = slot_cur->ctrl->ending_slot_num; + } + } + return first_slot + 1; + +} +static char *create_file_name (struct slot * slot_cur) +{ + struct opt_rio *opt_vg_ptr = NULL; + struct opt_rio_lo *opt_lo_ptr = NULL; + static char str[30]; + int which = 0; /* rxe = 1, chassis = 0 */ + u8 number = 1; /* either chassis or rxe # */ + u8 first_slot = 1; + u8 slot_num; + u8 flag = 0; + + if (!slot_cur) { + err ("Structure passed is empty \n"); + return NULL; + } + + slot_num = slot_cur->number; + + memset (str, 0, sizeof(str)); + + if (rio_table_ptr) { + if (rio_table_ptr->ver_num == 3) { + opt_vg_ptr = find_chassis_num (slot_num); + opt_lo_ptr = find_rxe_num (slot_num); + } + } + if (opt_vg_ptr) { + if (opt_lo_ptr) { + if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) { + number = opt_lo_ptr->chassis_num; + first_slot = opt_lo_ptr->first_slot_num; + which = 1; /* it is RXE */ + } else { + first_slot = opt_vg_ptr->first_slot_num; + number = opt_vg_ptr->chassis_num; + which = 0; + } + } else { + first_slot = opt_vg_ptr->first_slot_num; + number = opt_vg_ptr->chassis_num; + which = 0; + } + ++flag; + } else if (opt_lo_ptr) { + number = opt_lo_ptr->chassis_num; + first_slot = opt_lo_ptr->first_slot_num; + which = 1; + ++flag; + } else if (rio_table_ptr) { + if (rio_table_ptr->ver_num == 3) { + /* if both NULL and we DO have correct RIO table in BIOS */ + return NULL; + } + } + if (!flag) { + if (slot_cur->ctrl->ctlr_type == 4) { + first_slot = calculate_first_slot (slot_num); + which = 1; + } else { + which = 0; + } + } + + sprintf(str, "%s%dslot%d", + which == 0 ? "chassis" : "rxe", + number, slot_num - first_slot + 1); + return str; +} + +static struct pci_driver ibmphp_driver; + +/* + * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of + * each hpc from physical address to a list of hot plug controllers based on + * hpc descriptors. + */ +static int __init ebda_rsrc_controller (void) +{ + u16 addr, addr_slot, addr_bus; + u8 ctlr_id, temp, bus_index; + u16 ctlr, slot, bus; + u16 slot_num, bus_num, index; + struct hotplug_slot *hp_slot_ptr; + struct controller *hpc_ptr; + struct ebda_hpc_bus *bus_ptr; + struct ebda_hpc_slot *slot_ptr; + struct bus_info *bus_info_ptr1, *bus_info_ptr2; + int rc; + struct slot *tmp_slot; + struct list_head *list; + + addr = hpc_list_ptr->phys_addr; + for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { + bus_index = 1; + ctlr_id = readb (io_mem + addr); + addr += 1; + slot_num = readb (io_mem + addr); + + addr += 1; + addr_slot = addr; /* offset of slot structure */ + addr += (slot_num * 4); + + bus_num = readb (io_mem + addr); + + addr += 1; + addr_bus = addr; /* offset of bus */ + addr += (bus_num * 9); /* offset of ctlr_type */ + temp = readb (io_mem + addr); + + addr += 1; + /* init hpc structure */ + hpc_ptr = alloc_ebda_hpc (slot_num, bus_num); + if (!hpc_ptr ) { + rc = -ENOMEM; + goto error_no_hpc; + } + hpc_ptr->ctlr_id = ctlr_id; + hpc_ptr->ctlr_relative_id = ctlr; + hpc_ptr->slot_count = slot_num; + hpc_ptr->bus_count = bus_num; + debug ("now enter ctlr data struture ---\n"); + debug ("ctlr id: %x\n", ctlr_id); + debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); + debug ("count of slots controlled by this ctlr: %x\n", slot_num); + debug ("count of buses controlled by this ctlr: %x\n", bus_num); + + /* init slot structure, fetch slot, bus, cap... */ + slot_ptr = hpc_ptr->slots; + for (slot = 0; slot < slot_num; slot++) { + slot_ptr->slot_num = readb (io_mem + addr_slot); + slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num); + slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); + slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); + + // create bus_info lined list --- if only one slot per bus: slot_min = slot_max + + bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); + if (!bus_info_ptr2) { + bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); + if (!bus_info_ptr1) { + rc = -ENOMEM; + goto error_no_hp_slot; + } + memset (bus_info_ptr1, 0, sizeof (struct bus_info)); + bus_info_ptr1->slot_min = slot_ptr->slot_num; + bus_info_ptr1->slot_max = slot_ptr->slot_num; + bus_info_ptr1->slot_count += 1; + bus_info_ptr1->busno = slot_ptr->slot_bus_num; + bus_info_ptr1->index = bus_index++; + bus_info_ptr1->current_speed = 0xff; + bus_info_ptr1->current_bus_mode = 0xff; + + bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; + + list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); + + } else { + bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num); + bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num); + bus_info_ptr2->slot_count += 1; + + } + + // end of creating the bus_info linked list + + slot_ptr++; + addr_slot += 1; + } + + /* init bus structure */ + bus_ptr = hpc_ptr->buses; + for (bus = 0; bus < bus_num; bus++) { + bus_ptr->bus_num = readb (io_mem + addr_bus + bus); + bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus); + bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1); + + bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2); + + bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3); + + bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4); + + bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num); + if (bus_info_ptr2) { + bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv; + bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv; + bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix; + bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix; + bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; + } + bus_ptr++; + } + + hpc_ptr->ctlr_type = temp; + + switch (hpc_ptr->ctlr_type) { + case 1: + hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr); + hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); + hpc_ptr->irq = readb (io_mem + addr + 2); + addr += 3; + debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", + hpc_ptr->u.pci_ctlr.bus, + hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq); + break; + + case 0: + hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr); + hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2); + if (!request_region (hpc_ptr->u.isa_ctlr.io_start, + (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), + "ibmphp")) { + rc = -ENODEV; + goto error_no_hp_slot; + } + hpc_ptr->irq = readb (io_mem + addr + 4); + addr += 5; + break; + + case 2: + case 4: + hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); + hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); + hpc_ptr->irq = readb (io_mem + addr + 5); + addr += 6; + break; + default: + rc = -ENODEV; + goto error_no_hp_slot; + } + + //reorganize chassis' linked list + combine_wpg_for_chassis (); + combine_wpg_for_expansion (); + hpc_ptr->revision = 0xff; + hpc_ptr->options = 0xff; + hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num; + hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num; + + // register slots with hpc core as well as create linked list of ibm slot + for (index = 0; index < hpc_ptr->slot_count; index++) { + + hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hp_slot_ptr) { + rc = -ENOMEM; + goto error_no_hp_slot; + } + memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot)); + + hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!hp_slot_ptr->info) { + rc = -ENOMEM; + goto error_no_hp_info; + } + memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info)); + + hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL); + if (!hp_slot_ptr->name) { + rc = -ENOMEM; + goto error_no_hp_name; + } + + tmp_slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!tmp_slot) { + rc = -ENOMEM; + goto error_no_slot; + } + memset (tmp_slot, 0, sizeof (*tmp_slot)); + + tmp_slot->flag = TRUE; + + tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap; + if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX) + tmp_slot->supported_speed = 3; + else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX) + tmp_slot->supported_speed = 2; + else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX) + tmp_slot->supported_speed = 1; + + if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP) + tmp_slot->supported_bus_mode = 1; + else + tmp_slot->supported_bus_mode = 0; + + + tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num; + + bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); + if (!bus_info_ptr1) { + rc = -ENODEV; + goto error; + } + tmp_slot->bus_on = bus_info_ptr1; + bus_info_ptr1 = NULL; + tmp_slot->ctrl = hpc_ptr; + + tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index; + tmp_slot->number = hpc_ptr->slots[index].slot_num; + tmp_slot->hotplug_slot = hp_slot_ptr; + + hp_slot_ptr->private = tmp_slot; + + rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr); + if (rc) + goto error; + + rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private); + if (rc) + goto error; + hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; + + // end of registering ibm slot with hotplug core + + list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); + } + + print_bus_info (); + list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head ); + + } /* each hpc */ + + list_for_each (list, &ibmphp_slot_head) { + tmp_slot = list_entry (list, struct slot, ibm_slot_list); + + snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); + pci_hp_register (tmp_slot->hotplug_slot); + } + + print_ebda_hpc (); + print_ibm_slot (); + return 0; + +error: + kfree (hp_slot_ptr->private); +error_no_slot: + kfree (hp_slot_ptr->name); +error_no_hp_name: + kfree (hp_slot_ptr->info); +error_no_hp_info: + kfree (hp_slot_ptr); +error_no_hp_slot: + free_ebda_hpc (hpc_ptr); +error_no_hpc: + iounmap (io_mem); + return rc; +} + +/* + * map info (bus, devfun, start addr, end addr..) of i/o, memory, + * pfm from the physical addr to a list of resource. + */ +static int __init ebda_rsrc_rsrc (void) +{ + u16 addr; + short rsrc; + u8 type, rsrc_type; + struct ebda_pci_rsrc *rsrc_ptr; + + addr = rsrc_list_ptr->phys_addr; + debug ("now entering rsrc land\n"); + debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr); + + for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) { + type = readb (io_mem + addr); + + addr += 1; + rsrc_type = type & EBDA_RSRC_TYPE_MASK; + + if (rsrc_type == EBDA_IO_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readw (io_mem + addr + 2); + rsrc_ptr->end_addr = readw (io_mem + addr + 4); + addr += 6; + + debug ("rsrc from io type ----\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + + if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readl (io_mem + addr + 2); + rsrc_ptr->end_addr = readl (io_mem + addr + 6); + addr += 10; + + debug ("rsrc from mem or pfm ---\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + } + kfree (rsrc_list_ptr); + rsrc_list_ptr = NULL; + print_ebda_pci_rsrc (); + return 0; +} + +u16 ibmphp_get_total_controllers (void) +{ + return hpc_list_ptr->num_ctlrs; +} + +struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) +{ + struct slot *slot; + struct list_head *list; + + list_for_each (list, &ibmphp_slot_head) { + slot = list_entry (list, struct slot, ibm_slot_list); + if (slot->number == physical_num) + return slot; + } + return NULL; +} + +/* To find: + * - the smallest slot number + * - the largest slot number + * - the total number of the slots based on each bus + * (if only one slot per bus slot_min = slot_max ) + */ +struct bus_info *ibmphp_find_same_bus_num (u32 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr; + } + return NULL; +} + +/* Finding relative bus number, in order to map corresponding + * bus register + */ +int ibmphp_get_bus_index (u8 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr->index; + } + return -ENODEV; +} + +void ibmphp_free_bus_info_queue (void) +{ + struct bus_info *bus_info; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &bus_info_head ) { + bus_info = list_entry (list, struct bus_info, bus_info_list); + kfree (bus_info); + } +} + +void ibmphp_free_ebda_hpc_queue (void) +{ + struct controller *controller = NULL; + struct list_head *list; + struct list_head *next; + int pci_flag = 0; + + list_for_each_safe (list, next, &ebda_hpc_head) { + controller = list_entry (list, struct controller, ebda_hpc_list); + if (controller->ctlr_type == 0) + release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1)); + else if ((controller->ctlr_type == 1) && (!pci_flag)) { + ++pci_flag; + pci_unregister_driver (&ibmphp_driver); + } + free_ebda_hpc (controller); + } +} + +void ibmphp_free_ebda_pci_rsrc_queue (void) +{ + struct ebda_pci_rsrc *resource; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) { + resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + kfree (resource); + resource = NULL; + } +} + +static struct pci_device_id id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_IBM, + .device = HPC_DEVICE_ID, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = HPC_SUBSYSTEM_ID, + .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), + }, {} +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *); +static struct pci_driver ibmphp_driver = { + .name = "ibmphp", + .id_table = id_table, + .probe = ibmphp_probe, +}; + +int ibmphp_register_pci (void) +{ + struct controller *ctrl; + struct list_head *tmp; + int rc = 0; + + list_for_each (tmp, &ebda_hpc_head) { + ctrl = list_entry (tmp, struct controller, ebda_hpc_list); + if (ctrl->ctlr_type == 1) { + rc = pci_module_init (&ibmphp_driver); + break; + } + } + return rc; +} +static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) +{ + struct controller *ctrl; + struct list_head *tmp; + + debug ("inside ibmphp_probe \n"); + + list_for_each (tmp, &ebda_hpc_head) { + ctrl = list_entry (tmp, struct controller, ebda_hpc_list); + if (ctrl->ctlr_type == 1) { + if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) { + ctrl->ctrl_dev = dev; + debug ("found device!!! \n"); + debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device); + return 0; + } + } + } + return -ENODEV; +} + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_hpc.c linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_hpc.c --- linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_hpc.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_hpc.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1228 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, IBM Corporation + * + * Copyright (c) 2001-2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + * + */ + +#include +#include +#include +#include +#include +#include +#include "ibmphp.h" + +static int to_debug = FALSE; +#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) + +//---------------------------------------------------------------------------- +// timeout values +//---------------------------------------------------------------------------- +#define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd +#define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd +#define HPC_GETACCESS_TIMEOUT 60 // seconds +#define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds +#define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots + +//---------------------------------------------------------------------------- +// Winnipeg Architected Register Offsets +//---------------------------------------------------------------------------- +#define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low +#define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg +#define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register +#define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register +#define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register + +//---------------------------------------------------------------------------- +// Winnipeg Store Type commands (Add this commands to the register offset) +//---------------------------------------------------------------------------- +#define WPG_I2C_AND 0x1000 // I2C AND operation +#define WPG_I2C_OR 0x2000 // I2C OR operation + +//---------------------------------------------------------------------------- +// Command set for I2C Master Operation Setup Regisetr +//---------------------------------------------------------------------------- +#define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index +#define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index +#define WPG_READDIRECT_MASK 0x10010000 +#define WPG_WRITEDIRECT_MASK 0x60010000 + + +//---------------------------------------------------------------------------- +// bit masks for I2C Master Control Register +//---------------------------------------------------------------------------- +#define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- +#define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval + +//---------------------------------------------------------------------------- +// command index +//---------------------------------------------------------------------------- +#define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr +#define WPG_CTLR_INDEX 0x0F // index - ctlr +#define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr +#define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr + +//---------------------------------------------------------------------------- +// macro utilities +//---------------------------------------------------------------------------- +// if bits 20,22,25,26,27,29,30 are OFF return TRUE +#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) + +//---------------------------------------------------------------------------- +// global variables +//---------------------------------------------------------------------------- +static int ibmphp_shutdown; +static int tid_poll; +static struct semaphore sem_hpcaccess; // lock access to HPC +static struct semaphore semOperations; // lock all operations and + // access to data structures +static struct semaphore sem_exit; // make sure polling thread goes away +//---------------------------------------------------------------------------- +// local function prototypes +//---------------------------------------------------------------------------- +static u8 i2c_ctrl_read (struct controller *, void *, u8); +static u8 i2c_ctrl_write (struct controller *, void *, u8, u8); +static u8 hpc_writecmdtoindex (u8, u8); +static u8 hpc_readcmdtoindex (u8, u8); +static void get_hpc_access (void); +static void free_hpc_access (void); +static void poll_hpc (void); +static int update_slot (struct slot *, u8); +static int process_changeinstatus (struct slot *, struct slot *); +static int process_changeinlatch (u8, u8, struct controller *); +static int hpc_poll_thread (void *); +static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); +//---------------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_initvars +* +* Action: initialize semaphores and variables +*---------------------------------------------------------------------*/ +void __init ibmphp_hpc_initvars (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + + init_MUTEX (&sem_hpcaccess); + init_MUTEX (&semOperations); + init_MUTEX_LOCKED (&sem_exit); + to_debug = FALSE; + ibmphp_shutdown = FALSE; + tid_poll = 0; + + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: i2c_ctrl_read +* +* Action: read from HPC over I2C +* +*---------------------------------------------------------------------*/ +static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) +{ + u8 status; + int i; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index); + + //-------------------------------------------------------------------- + // READ - step 1 + // read at address, byte length, I2C address (shifted), index + // or read direct, byte length, index + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_READATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_READDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 2 : clear the message buffer + data = 0x00000000; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 3 : issue start operation, I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Error : WPG timeout\n", __FUNCTION__); + return HPC_ERROR; + } + //-------------------------------------------------------------------- + // READ - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Exit Error:I2C timeout\n"); + return HPC_ERROR; + } + + //-------------------------------------------------------------------- + // READ - step 6 : get DATA + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + + status = (u8) data; + + debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); + + return (status); +} + +/*---------------------------------------------------------------------- +* Name: i2c_ctrl_write +* +* Action: write to HPC over I2C +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd) +{ + u8 rc; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + int i; + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd); + + rc = 0; + //-------------------------------------------------------------------- + // WRITE - step 1 + // write at address, byte length, I2C address (shifted), index + // or write direct, byte length, index + data = 0x00000000; + + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_WRITEATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_WRITEDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 2 : clear the message buffer + data = 0x00000000 | (ulong) cmd; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 3 : issue start operation,I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); + rc = HPC_ERROR; + } + + //-------------------------------------------------------------------- + // WRITE - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Error : I2C timeout\n"); + rc = HPC_ERROR; + } + + debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); + return (rc); +} + +//------------------------------------------------------------ +// Read from ISA type HPC +//------------------------------------------------------------ +static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset) +{ + u16 start_address; + u16 end_address; + u8 data; + + start_address = ctlr_ptr->u.isa_ctlr.io_start; + end_address = ctlr_ptr->u.isa_ctlr.io_end; + data = inb (start_address + offset); + return data; +} + +//-------------------------------------------------------------- +// Write to ISA type HPC +//-------------------------------------------------------------- +static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data) +{ + u16 start_address; + u16 port_address; + + start_address = ctlr_ptr->u.isa_ctlr.io_start; + port_address = start_address + (u16) offset; + outb (data, port_address); +} + +static u8 pci_ctrl_read (struct controller *ctrl, u8 offset) +{ + u8 data = 0x00; + debug ("inside pci_ctrl_read\n"); + if (ctrl->ctrl_dev) + pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data); + return data; +} + +static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data) +{ + u8 rc = -ENODEV; + debug ("inside pci_ctrl_write\n"); + if (ctrl->ctrl_dev) { + pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data); + rc = 0; + } + return rc; +} + +static u8 ctrl_read (struct controller *ctlr, void *base, u8 offset) +{ + u8 rc; + switch (ctlr->ctlr_type) { + case 0: + rc = isa_ctrl_read (ctlr, offset); + break; + case 1: + rc = pci_ctrl_read (ctlr, offset); + break; + case 2: + case 4: + rc = i2c_ctrl_read (ctlr, base, offset); + break; + default: + return -ENODEV; + } + return rc; +} + +static u8 ctrl_write (struct controller *ctlr, void *base, u8 offset, u8 data) +{ + u8 rc = 0; + switch (ctlr->ctlr_type) { + case 0: + isa_ctrl_write(ctlr, offset, data); + break; + case 1: + rc = pci_ctrl_write (ctlr, offset, data); + break; + case 2: + case 4: + rc = i2c_ctrl_write(ctlr, base, offset, data); + break; + default: + return -ENODEV; + } + return rc; +} +/*---------------------------------------------------------------------- +* Name: hpc_writecmdtoindex() +* +* Action: convert a write command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_writecmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 + case HPC_CTLR_CLEARIRQ: // 0x06.N.15 + case HPC_CTLR_RESET: // 0x07.N.15 + case HPC_CTLR_IRQSTEER: // 0x08.N.15 + case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 + case HPC_ALLSLOT_ON: // 0x11.N.15 + case HPC_ALLSLOT_OFF: // 0x12.N.15 + rc = 0x0F; + break; + + case HPC_SLOT_OFF: // 0x02.Y.0-14 + case HPC_SLOT_ON: // 0x03.Y.0-14 + case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 + case HPC_SLOT_ATTNON: // 0x05.N.0-14 + case HPC_SLOT_BLINKLED: // 0x13.N.0-14 + rc = index; + break; + + case HPC_BUS_33CONVMODE: + case HPC_BUS_66CONVMODE: + case HPC_BUS_66PCIXMODE: + case HPC_BUS_100PCIXMODE: + case HPC_BUS_133PCIXMODE: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + + default: + err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); + rc = HPC_ERROR; + } + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_readcmdtoindex() +* +* Action: convert a read command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_readcmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case READ_CTLRSTATUS: + rc = 0x0F; + break; + case READ_SLOTSTATUS: + case READ_ALLSTAT: + rc = index; + break; + case READ_EXTSLOTSTATUS: + rc = index + WPG_1ST_EXTSLOT_INDEX; + break; + case READ_BUSSTATUS: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + case READ_SLOTLATCHLOWREG: + rc = 0x28; + break; + case READ_REVLEVEL: + rc = 0x25; + break; + case READ_HPCOPTIONS: + rc = 0x27; + break; + default: + rc = HPC_ERROR; + } + return rc; +} + +/*---------------------------------------------------------------------- +* Name: HPCreadslot() +* +* Action: issue a READ command to HPC +* +* Input: pslot - can not be NULL for READ_ALLSTAT +* pstatus - can be NULL for READ_ALLSTAT +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) +{ + void *wpg_bbar = NULL; + struct controller *ctlr_ptr; + struct list_head *pslotlist; + u8 index, status; + int rc = 0; + int busindex; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus); + + if ((pslot == NULL) + || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { + rc = -EINVAL; + err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if (cmd == READ_BUSSTATUS) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_readcmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + //-------------------------------------------------------------------- + // check controller status before reading + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + switch (cmd) { + case READ_ALLSTAT: + // update the slot structure + pslot->ctrl->status = status; + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) + pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); + + break; + + case READ_SLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_EXTSLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_CTLRSTATUS: + // DO NOT update the slot structure + *pstatus = status; + break; + + case READ_BUSSTATUS: + pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_REVLEVEL: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_HPCOPTIONS: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_SLOTLATCHLOWREG: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + // Not used + case READ_ALLSLOT: + list_for_each (pslotlist, &ibmphp_slot_head) { + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + index = pslot->ctlr_index; + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, + wpg_bbar, &status); + if (!rc) { + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, + ctlr_ptr, wpg_bbar, &status); + if (!rc) + pslot->ext_status = + ctrl_read (ctlr_ptr, wpg_bbar, + index + WPG_1ST_EXTSLOT_INDEX); + } else { + err ("%s - Error ctrl_read failed\n", __FUNCTION__); + rc = -EINVAL; + break; + } + } + break; + default: + rc = -EINVAL; + break; + } + } + //-------------------------------------------------------------------- + // cleanup + //-------------------------------------------------------------------- + + // remove physical to logical address mapping + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) + iounmap (wpg_bbar); + + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_writeslot() +* +* Action: issue a WRITE command to HPC +*---------------------------------------------------------------------*/ +int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) +{ + void *wpg_bbar = NULL; + struct controller *ctlr_ptr; + u8 index, status; + int busindex; + u8 done; + int rc = 0; + int timeout; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd); + if (pslot == NULL) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) || + (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) || + (cmd == HPC_BUS_133PCIXMODE)) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_writecmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) { + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, + ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, + ctlr_ptr->u.wpeg_ctlr.i2c_addr); + } + //-------------------------------------------------------------------- + // check controller status before writing + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + + ctrl_write (ctlr_ptr, wpg_bbar, index, cmd); + + //-------------------------------------------------------------------- + // check controller is still not working on the command + //-------------------------------------------------------------------- + timeout = CMD_COMPLETE_TOUT_SEC; + done = FALSE; + while (!done) { + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) { + if (NEEDTOCHECK_CMDSTATUS (cmd)) { + if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) + done = TRUE; + } else + done = TRUE; + } + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("%s - Error command complete timeout\n", __FUNCTION__); + rc = -EFAULT; + } else + timeout--; + } + } + ctlr_ptr->status = status; + } + // cleanup + + // remove physical to logical address mapping + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) + iounmap (wpg_bbar); + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: get_hpc_access() +* +* Action: make sure only one process can access HPC at one time +*---------------------------------------------------------------------*/ +static void get_hpc_access (void) +{ + down (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: free_hpc_access() +*---------------------------------------------------------------------*/ +void free_hpc_access (void) +{ + up (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_lock_operations() +* +* Action: make sure only one process can change the data structure +*---------------------------------------------------------------------*/ +void ibmphp_lock_operations (void) +{ + down (&semOperations); + to_debug = TRUE; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_unlock_operations() +*---------------------------------------------------------------------*/ +void ibmphp_unlock_operations (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + up (&semOperations); + to_debug = FALSE; + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: poll_hpc() +*---------------------------------------------------------------------*/ +#define POLL_LATCH_REGISTER 0 +#define POLL_SLOTS 1 +#define POLL_SLEEP 2 +static void poll_hpc (void) +{ + struct slot myslot; + struct slot *pslot = NULL; + struct list_head *pslotlist; + int rc; + int poll_state = POLL_LATCH_REGISTER; + u8 oldlatchlow = 0x00; + u8 curlatchlow = 0x00; + int poll_count = 0; + u8 ctrl_count = 0x00; + + debug ("%s - Entry\n", __FUNCTION__); + + while (!ibmphp_shutdown) { + if (ibmphp_shutdown) + break; + + /* try to get the lock to do some kind of harware access */ + down (&semOperations); + + switch (poll_state) { + case POLL_LATCH_REGISTER: + oldlatchlow = curlatchlow; + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) { + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + if (oldlatchlow != curlatchlow) + process_changeinlatch (oldlatchlow, + curlatchlow, + pslot->ctrl); + } + } + } + ++poll_count; + poll_state = POLL_SLEEP; + break; + case POLL_SLOTS: + list_for_each (pslotlist, &ibmphp_slot_head) { + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + // make a copy of the old status + memcpy ((void *) &myslot, (void *) pslot, + sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + if ((myslot.status != pslot->status) + || (myslot.ext_status != pslot->ext_status)) + process_changeinstatus (pslot, &myslot); + } + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + } + } + ++poll_count; + poll_state = POLL_SLEEP; + break; + case POLL_SLEEP: + /* don't sleep with a lock on the hardware */ + up (&semOperations); + long_delay (POLL_INTERVAL_SEC * HZ); + + if (ibmphp_shutdown) + break; + + down (&semOperations); + + if (poll_count >= POLL_LATCH_CNT) { + poll_count = 0; + poll_state = POLL_SLOTS; + } else + poll_state = POLL_LATCH_REGISTER; + break; + } + /* give up the harware semaphore */ + up (&semOperations); + /* sleep for a short time just for good measure */ + set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout (HZ/10); + } + up (&sem_exit); + debug ("%s - Exit\n", __FUNCTION__); +} + + +/* ---------------------------------------------------------------------- + * Name: ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot) + * + * Action: fill out the hotplug_slot info + * + * Input: pointer to hotplug_slot + * + * Return + * Value: 0 or error codes + *-----------------------------------------------------------------------*/ +int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot) +{ + int rc = 0; + struct slot *pslot; + + if (phpslot && phpslot->private) { + pslot = (struct slot *) phpslot->private; + rc = update_slot (pslot, (u8) TRUE); + if (!rc) { + + // power - enabled:1 not:0 + phpslot->info->power_status = SLOT_POWER (pslot->status); + + // attention - off:0, on:1, blinking:2 + phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status); + + // latch - open:1 closed:0 + phpslot->info->latch_status = SLOT_LATCH (pslot->status); + + // pci board - present:1 not:0 + if (SLOT_PRESENT (pslot->status)) + phpslot->info->adapter_status = 1; + else + phpslot->info->adapter_status = 0; +/* + if (pslot->bus_on->supported_bus_mode + && (pslot->bus_on->supported_speed == BUS_SPEED_66)) + phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX; + else + phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed; +*/ } else + rc = -EINVAL; + } else + rc = -EINVAL; + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: update_slot +* +* Action: fill out slot status and extended status, controller status +* +* Input: pointer to slot struct +*---------------------------------------------------------------------*/ +static int update_slot (struct slot *pslot, u8 update) +{ + int rc = 0; + + debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinstatus +* +* Action: compare old and new slot status, process the change in status +* +* Input: pointer to slot struct, old slot struct +* +* Return 0 or error codes +* Value: +* +* Side +* Effects: None. +* +* Notes: +*---------------------------------------------------------------------*/ +static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) +{ + u8 status; + int rc = 0; + u8 disable = FALSE; + u8 update = FALSE; + + debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot, + (ulong) poldslot); + + // bit 0 - HPC_SLOT_POWER + if ((pslot->status & 0x01) != (poldslot->status & 0x01)) + update = TRUE; + + // bit 1 - HPC_SLOT_CONNECT + // ignore + + // bit 2 - HPC_SLOT_ATTN + if ((pslot->status & 0x04) != (poldslot->status & 0x04)) + update = TRUE; + + // bit 3 - HPC_SLOT_PRSNT2 + // bit 4 - HPC_SLOT_PRSNT1 + if (((pslot->status & 0x08) != (poldslot->status & 0x08)) + || ((pslot->status & 0x10) != (poldslot->status & 0x10))) + update = TRUE; + + // bit 5 - HPC_SLOT_PWRGD + if ((pslot->status & 0x20) != (poldslot->status & 0x20)) + // OFF -> ON: ignore, ON -> OFF: disable slot + if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) + disable = TRUE; + + // bit 6 - HPC_SLOT_BUS_SPEED + // ignore + + // bit 7 - HPC_SLOT_LATCH + if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { + update = TRUE; + // OPEN -> CLOSE + if (pslot->status & 0x80) { + if (SLOT_PWRGD (pslot->status)) { + // power goes on and off after closing latch + // check again to make sure power is still ON + long_delay (1 * HZ); + rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); + if (SLOT_PWRGD (status)) + update = TRUE; + else // overwrite power in pslot to OFF + pslot->status &= ~HPC_SLOT_POWER; + } + } + // CLOSE -> OPEN + else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD) + && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) { + disable = TRUE; + } + // else - ignore + } + // bit 4 - HPC_SLOT_BLINK_ATTN + if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) + update = TRUE; + + if (disable) { + debug ("process_changeinstatus - disable slot\n"); + pslot->flag = FALSE; + rc = ibmphp_do_disable_slot (pslot); + } + + if (update || disable) { + ibmphp_update_slot_info (pslot); + } + + debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinlatch +* +* Action: compare old and new latch reg status, process the change +* +* Input: old and current latch register status +* +* Return 0 or error codes +* Value: +*---------------------------------------------------------------------*/ +static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) +{ + struct slot myslot, *pslot; + u8 i; + u8 mask; + int rc = 0; + + debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); + // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots + + for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) { + mask = 0x01 << i; + if ((mask & old) != (mask & new)) { + pslot = ibmphp_get_slot_from_physical_num (i); + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); + process_changeinstatus (pslot, &myslot); + } else { + rc = -EINVAL; + err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); + } + } + } + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_poll_thread +* +* Action: polling +* +* Return 0 +* Value: +*---------------------------------------------------------------------*/ +static int hpc_poll_thread (void *data) +{ + debug ("%s - Entry\n", __FUNCTION__); + + daemonize("hpc_poll"); + allow_signal(SIGKILL); + + poll_hpc (); + + tid_poll = 0; + debug ("%s - Exit\n", __FUNCTION__); + return 0; +} + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_start_poll_thread +* +* Action: start polling thread +*---------------------------------------------------------------------*/ +int __init ibmphp_hpc_start_poll_thread (void) +{ + int rc = 0; + + debug ("%s - Entry\n", __FUNCTION__); + + tid_poll = kernel_thread (hpc_poll_thread, 0, 0); + if (tid_poll < 0) { + err ("%s - Error, thread not started\n", __FUNCTION__); + rc = -1; + } + + debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_stop_poll_thread +* +* Action: stop polling thread and cleanup +*---------------------------------------------------------------------*/ +void __exit ibmphp_hpc_stop_poll_thread (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + + ibmphp_shutdown = TRUE; + debug ("before locking operations \n"); + ibmphp_lock_operations (); + debug ("after locking operations \n"); + + // wait for poll thread to exit + debug ("before sem_exit down \n"); + down (&sem_exit); + debug ("after sem_exit down \n"); + + // cleanup + debug ("before free_hpc_access \n"); + free_hpc_access (); + debug ("after free_hpc_access \n"); + ibmphp_unlock_operations (); + debug ("after unlock operations \n"); + up (&sem_exit); + debug ("after sem exit up\n"); + + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: hpc_wait_ctlr_notworking +* +* Action: wait until the controller is in a not working state +* +* Return 0, HPC_ERROR +* Value: +*---------------------------------------------------------------------*/ +static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar, + u8 * pstatus) +{ + int rc = 0; + u8 done = FALSE; + + debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); + + while (!done) { + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); + if (*pstatus == HPC_ERROR) { + rc = HPC_ERROR; + done = TRUE; + } + if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) + done = TRUE; + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("HPCreadslot - Error ctlr timeout\n"); + rc = HPC_ERROR; + } else + timeout--; + } + } + debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); + return rc; +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_pci.c linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_pci.c --- linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_pci.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_pci.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,1758 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include "ibmphp.h" + + +static int configure_device(struct pci_func *); +static int configure_bridge(struct pci_func **, u8); +static struct res_needed *scan_behind_bridge(struct pci_func *, u8); +static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); +static u8 find_sec_number (u8 primary_busno, u8 slotno); + +/* + * NOTE..... If BIOS doesn't provide default routing, we assign: + * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. + * If adapter is bridged, then we assign 11 to it and devices behind it. + * We also assign the same irq numbers for multi function devices. + * These are PIC mode, so shouldn't matter n.e.ways (hopefully) + */ +static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) +{ + int j = 0; + for (j = 0; j < 4; j++) { + if (cur_func->irq[j] == 0xff) { + switch (class_code) { + case PCI_BASE_CLASS_STORAGE: + cur_func->irq[j] = SCSI_IRQ; + break; + case PCI_BASE_CLASS_NETWORK: + cur_func->irq[j] = LAN_IRQ; + break; + default: + cur_func->irq[j] = OTHER_IRQ; + break; + } + } + } +} + +/* + * Configures the device to be added (will allocate needed resources if it + * can), the device can be a bridge or a regular pci device, can also be + * multi-functional + * + * Input: function to be added + * + * TO DO: The error case with Multifunction device or multi function bridge, + * if there is an error, will need to go through all previous functions and + * unconfigure....or can add some code into unconfigure_card.... + */ +int ibmphp_configure_card (struct pci_func *func, u8 slotno) +{ + u16 vendor_id; + u32 class; + u8 class_code; + u8 hdr_type, device, sec_number; + u8 function; + struct pci_func *newfunc; /* for multi devices */ + struct pci_func *cur_func, *prev_func; + int rc, i, j; + int cleanup_count; + u8 flag; + u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ + + debug ("inside configure_card, func->busno = %x \n", func->busno); + + device = func->device; + cur_func = func; + + /* We only get bus and device from IRQ routing table. So at this point, + * func->busno is correct, and func->device contains only device (at the 5 + * highest bits) + */ + + /* For every function on the card */ + for (function = 0x00; function < 0x08; function++) { + unsigned int devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = cur_func->busno; + + cur_func->function = function; + + debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", + cur_func->busno, cur_func->device, cur_func->function); + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + debug ("vendor_id is %x\n", vendor_id); + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + debug ("found valid device, vendor_id = %x\n", vendor_id); + + ++valid_device; + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); + + class_code = class >> 24; + debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x. \n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + cur_func->next = NULL; + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x...bailing out\n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + cur_func->next = newfunc; + cur_func = newfunc; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + assign_alt_irq (cur_func, class_code); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to hot-add PPB properly.\n"); + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + /* This could only happen if kmalloc failed */ + if (rc) { + /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + cur_func = newfunc; + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + debug ("class now is %x\n", class); + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + + assign_alt_irq (cur_func, class_code); + + debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + err ("was not able to hot-add PPB properly.\n"); + cleanup_count = 2; + goto error; + } + debug ("cur_func->busno = %x, device = %x, function = %x\n", + cur_func->busno, device, function); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + debug ("after configuring bridge..., sec_number = %x\n", sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + debug ("inside for loop, device is %x\n", i); + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err (" out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + + /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + function = 0x8; + break; + default: + err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); + return -ENXIO; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Cannot find any valid devices on the card. Or unable to read from card.\n"); + return -ENODEV; + } + + return 0; + +error: + for (i = 0; i < cleanup_count; i++) { + if (cur_func->io[i]) { + ibmphp_remove_resource (cur_func->io[i]); + cur_func->io[i] = NULL; + } else if (cur_func->pfmem[i]) { + ibmphp_remove_resource (cur_func->pfmem[i]); + cur_func->pfmem[i] = NULL; + } else if (cur_func->mem[i]) { + ibmphp_remove_resource (cur_func->mem[i]); + cur_func->mem[i] = NULL; + } + } + return rc; +} + +/* + * This function configures the pci BARs of a single device. + * Input: pointer to the pci_func + * Output: configured PCI, 0, or error + */ +static int configure_device (struct pci_func *func) +{ + u32 bar[6]; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + u8 irq; + int count; + int len[6]; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *mem_tmp; + struct resource_node *pfmem[6]; + unsigned int devfn; + + debug ("%s - inside\n", __FUNCTION__); + + devfn = PCI_DEVFN(func->device, func->function); + ibmphp_pci_bus->number = func->busno; + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + + /* not sure if i need this. per scott, said maybe need smth like this + if devices don't adhere 100% to the spec, so don't want to write + to the reserved bits + + pcibios_read_config_byte(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, &tmp); + if (tmp & 0x01) // IO + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); + else // Memory + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); + */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + debug ("inside IO SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO %x, count %d\n", len[count], count); + + io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io[count], 0, sizeof (struct resource_node)); + io[count]->type = IO; + io[count]->busno = func->busno; + io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + io[count]->len = len[count]; + if (ibmphp_check_resource(io[count], 0) == 0) { + ibmphp_add_resource (io[count]); + func->io[count] = io[count]; + } else { + err ("cannot allocate requested io for bus %x device %x function %x len %x\n", + func->busno, func->device, func->function, len[count]); + kfree (io[count]); + return -EIO; + } + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); + + /* _______________This is for debugging purposes only_____________________ */ + debug ("b4 writing, the IO address is %x\n", func->io[count]->start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + debug ("after writing.... the start address is %x\n", bar[count]); + /* _________________________________________________________________________*/ + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + debug ("PFMEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM %x, count %d\n", len[count], count); + + pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem[count], 0, sizeof (struct resource_node)); + pfmem[count]->type = PFMEM; + pfmem[count]->busno = func->busno; + pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem[count]->len = len[count]; + pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (pfmem[count], 0) == 0) { + ibmphp_add_resource (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + kfree (pfmem[count]); + return -ENOMEM; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem[count]->busno; + mem_tmp->devfunc = pfmem[count]->devfunc; + mem_tmp->len = pfmem[count]->len; + debug ("there's no pfmem... going into mem.\n"); + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem[count]->fromMem = TRUE; + pfmem[count]->rangeno = mem_tmp->rangeno; + pfmem[count]->start = mem_tmp->start; + pfmem[count]->end = mem_tmp->end; + ibmphp_add_pfmem_from_mem (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (pfmem[count]); + return -EIO; + } + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); + + /*_______________This is for debugging purposes only______________________________*/ + debug ("b4 writing, start address is %x\n", func->pfmem[count]->start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + debug ("after writing, start address is %x\n", bar[count]); + /*_________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + debug ("inside the mem 64 case, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + } + } else { + /* regular memory */ + debug ("REGULAR MEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Mem %x, count %d\n", len[count], count); + + mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem[count], 0, sizeof (struct resource_node)); + mem[count]->type = MEM; + mem[count]->busno = func->busno; + mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem[count]->len = len[count]; + if (ibmphp_check_resource (mem[count], 0) == 0) { + ibmphp_add_resource (mem[count]); + func->mem[count] = mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem[count]); + return -EIO; + } + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); + /* _______________________This is for debugging purposes only _______________________*/ + debug ("b4 writing, start address is %x\n", func->mem[count]->start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + debug ("after writing, the address is %x\n", bar[count]); + /* __________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + debug ("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + } + } + } /* end of mem */ + } /* end of for */ + + func->bus = 0; /* To indicate that this is not a PPB */ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); + + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); + + return 0; +} + +/****************************************************************************** + * This routine configures a PCI-2-PCI bridge and the functions behind it + * Parameters: pci_func + * Returns: + ******************************************************************************/ +static int configure_bridge (struct pci_func **func_passed, u8 slotno) +{ + int count; + int i; + int rc; + u8 sec_number; + u8 io_base; + u16 pfmem_base; + u32 bar[2]; + u32 len[2]; + u8 flag_io = FALSE; + u8 flag_mem = FALSE; + u8 flag_pfmem = FALSE; + u8 need_io_upper = FALSE; + u8 need_pfmem_upper = FALSE; + struct res_needed *amount_needed = NULL; + struct resource_node *io = NULL; + struct resource_node *bus_io[2] = {NULL, NULL}; + struct resource_node *mem = NULL; + struct resource_node *bus_mem[2] = {NULL, NULL}; + struct resource_node *mem_tmp = NULL; + struct resource_node *pfmem = NULL; + struct resource_node *bus_pfmem[2] = {NULL, NULL}; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + struct pci_func *func = *func_passed; + unsigned int devfn; + u8 irq; + int retval; + + debug ("%s - enter\n", __FUNCTION__); + + devfn = PCI_DEVFN(func->function, func->device); + ibmphp_pci_bus->number = func->busno; + + /* Configuring necessary info for the bridge so that we could see the devices + * behind it + */ + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno); + + /* _____________________For debugging purposes only __________________________ + pci_bus_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); + debug ("primary # written into the bridge is %x\n", pri_number); + ___________________________________________________________________________*/ + + /* in EBDA, only get allocated 1 additional bus # per slot */ + sec_number = find_sec_number (func->busno, slotno); + if (sec_number == 0xff) { + err ("cannot allocate secondary bus number for the bridged device \n"); + return -EINVAL; + } + + debug ("after find_sec_number, the number we got is %x\n", sec_number); + debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number); + + /* __________________For debugging purposes only __________________________________ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number after write/read is %x\n", sec_number); + ________________________________________________________________________________*/ + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number); + + /* __________________For debugging purposes only ____________________________________ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number); + debug ("subordinate number after write/read is %x\n", sec_number); + __________________________________________________________________________________*/ + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY); + + debug ("func->busno is %x\n", func->busno); + debug ("sec_number after writing is %x\n", sec_number); + + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + /* First we need to allocate mem/io for the bridge itself in case it needs it */ + for (count = 0; address[count]; count++) { /* for 2 BARs */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + + if (!bar[count]) { + /* This BAR is not implemented */ + debug ("so we come here then, eh?, count = %d\n", count); + continue; + } + // tmp_bar = bar[count]; + + debug ("Bar %d wants %x\n", count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO = %x\n", len[count]); + + bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!bus_io[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_io[count], 0, sizeof (struct resource_node)); + bus_io[count]->type = IO; + bus_io[count]->busno = func->busno; + bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_io[count]->len = len[count]; + if (ibmphp_check_resource (bus_io[count], 0) == 0) { + ibmphp_add_resource (bus_io[count]); + func->io[count] = bus_io[count]; + } else { + err ("cannot allocate requested io for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_io[count]); + return -EIO; + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM = %x\n", len[count]); + + bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_pfmem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_pfmem[count], 0, sizeof (struct resource_node)); + bus_pfmem[count]->type = PFMEM; + bus_pfmem[count]->busno = func->busno; + bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_pfmem[count]->len = len[count]; + bus_pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { + ibmphp_add_resource (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = bus_pfmem[count]->busno; + mem_tmp->devfunc = bus_pfmem[count]->devfunc; + mem_tmp->len = bus_pfmem[count]->len; + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + bus_pfmem[count]->fromMem = TRUE; + bus_pfmem[count]->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (bus_pfmem[count]); + return -EIO; + } + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + + } + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Memory is %x\n", len[count]); + + bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_mem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_mem[count], 0, sizeof (struct resource_node)); + bus_mem[count]->type = MEM; + bus_mem[count]->busno = func->busno; + bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_mem[count]->len = len[count]; + if (ibmphp_check_resource (bus_mem[count], 0) == 0) { + ibmphp_add_resource (bus_mem[count]); + func->mem[count] = bus_mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_mem[count]); + return -EIO; + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + + } + } + } /* end of mem */ + } /* end of for */ + + /* Now need to see how much space the devices behind the bridge needed */ + amount_needed = scan_behind_bridge (func, sec_number); + if (amount_needed == NULL) + return -ENOMEM; + + ibmphp_pci_bus->number = func->busno; + debug ("after coming back from scan_behind_bridge\n"); + debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct); + debug ("amount_needed->io = %x\n", amount_needed->io); + debug ("amount_needed->mem = %x\n", amount_needed->mem); + debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); + + if (amount_needed->not_correct) { + debug ("amount_needed is not correct \n"); + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + if (bus_io[count]) { + ibmphp_remove_resource (bus_io[count]); + func->io[count] = NULL; + } else if (bus_pfmem[count]) { + ibmphp_remove_resource (bus_pfmem[count]); + func->pfmem[count] = NULL; + } else if (bus_mem[count]) { + ibmphp_remove_resource (bus_mem[count]); + func->mem[count] = NULL; + } + } + kfree (amount_needed); + return -ENODEV; + } + + if (!amount_needed->io) { + debug ("it doesn't want IO?\n"); + flag_io = TRUE; + } else { + debug ("it wants %x IO behind the bridge \n", amount_needed->io); + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = func->busno; + io->devfunc = ((func->device << 3) | (func->function & 0x7)); + io->len = amount_needed->io; + if (ibmphp_check_resource (io, 1) == 0) { + debug ("were we able to add io\n"); + ibmphp_add_resource (io); + flag_io = TRUE; + } + } + + if (!amount_needed->mem) { + debug ("it doesn't want n.e.memory?\n"); + flag_mem = TRUE; + } else { + debug ("it wants %x memory behind the bridge\n", amount_needed->mem); + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = func->busno; + mem->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem->len = amount_needed->mem; + if (ibmphp_check_resource (mem, 1) == 0) { + ibmphp_add_resource (mem); + flag_mem = TRUE; + debug ("were we able to add mem\n"); + } + } + + if (!amount_needed->pfmem) { + debug ("it doesn't want n.e.pfmem mem?\n"); + flag_pfmem = TRUE; + } else { + debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = func->busno; + pfmem->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem->len = amount_needed->pfmem; + pfmem->fromMem = FALSE; + if (ibmphp_check_resource (pfmem, 1) == 0) { + ibmphp_add_resource (pfmem); + flag_pfmem = TRUE; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem->busno; + mem_tmp->devfunc = pfmem->devfunc; + mem_tmp->len = pfmem->len; + if (ibmphp_check_resource (mem_tmp, 1) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem->fromMem = TRUE; + pfmem->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (pfmem); + flag_pfmem = TRUE; + } + } + } + + debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n"); + debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem); + + if (flag_io && flag_mem && flag_pfmem) { + /* If on bootup, there was a bridged card in this slot, + * then card was removed and ibmphp got unloaded and loaded + * back again, there's no way for us to remove the bus + * struct, so no need to kmalloc, can use existing node + */ + bus = ibmphp_find_res_bus (sec_number); + if (!bus) { + bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!bus) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus, 0, sizeof (struct bus_node)); + bus->busno = sec_number; + debug ("b4 adding new bus\n"); + rc = add_new_bus (bus, io, mem, pfmem, func->busno); + } else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem)) + rc = add_new_bus (bus, io, mem, pfmem, 0xFF); + else { + err ("expected bus structure not empty? \n"); + retval = -EIO; + goto error; + } + if (rc) { + if (rc == -ENOMEM) { + ibmphp_remove_bus (bus, func->busno); + kfree (amount_needed); + return rc; + } + retval = rc; + goto error; + } + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base); + + if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + debug ("io 32\n"); + need_io_upper = TRUE; + } + if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + debug ("pfmem 64\n"); + need_pfmem_upper = TRUE; + } + + if (bus->noIORanges) { + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); + + /* _______________This is for debugging purposes only ____________________ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp); + debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp); + debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + ________________________________________________________________________*/ + + if (need_io_upper) { /* since can't support n.e.ways */ + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000); + } + } else { + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00); + } + + if (bus->noMemRanges) { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); + + /* ____________________This is for debugging purposes only ________________________ + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp); + debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp); + debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + __________________________________________________________________________________*/ + + } else { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000); + } + if (bus->noPFMemRanges) { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16); + + /* __________________________This is for debugging purposes only _______________________ + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp); + debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp); + debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + ______________________________________________________________________________________*/ + + if (need_pfmem_upper) { /* since can't support n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000); + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000); + } + } else { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000); + } + + debug ("b4 writing control information\n"); + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + /* + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); + */ + + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07); + for (i = 0; i < 32; i++) { + if (amount_needed->devices[i]) { + debug ("device where devices[i] is 1 = %x\n", i); + func->devices[i] = 1; + } + } + func->bus = 1; /* For unconfiguring, to indicate it's PPB */ + func_passed = &func; + debug ("func->busno b4 returning is %x\n", func->busno); + debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno); + kfree (amount_needed); + return 0; + } else { + err ("Configuring bridge was unsuccessful... \n"); + mem_tmp = NULL; + retval = -EIO; + goto error; + } + +error: + if (amount_needed) + kfree (amount_needed); + if (pfmem) + ibmphp_remove_resource (pfmem); + if (io) + ibmphp_remove_resource (io); + if (mem) + ibmphp_remove_resource (mem); + for (i = 0; i < 2; i++) { /* for 2 BARs */ + if (bus_io[i]) { + ibmphp_remove_resource (bus_io[i]); + func->io[i] = NULL; + } else if (bus_pfmem[i]) { + ibmphp_remove_resource (bus_pfmem[i]); + func->pfmem[i] = NULL; + } else if (bus_mem[i]) { + ibmphp_remove_resource (bus_mem[i]); + func->mem[i] = NULL; + } + } + return retval; +} + +/***************************************************************************** + * This function adds up the amount of resources needed behind the PPB bridge + * and passes it to the configure_bridge function + * Input: bridge function + * Ouput: amount of resources needed + *****************************************************************************/ +static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) +{ + int count, len[6]; + u16 vendor_id; + u8 hdr_type; + u8 device, function; + unsigned int devfn; + int howmany = 0; /*this is to see if there are any devices behind the bridge */ + + u32 bar[6], class; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + struct res_needed *amount; + + amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL); + if (amount == NULL) + return NULL; + memset (amount, 0, sizeof (struct res_needed)); + + ibmphp_pci_bus->number = busno; + + debug ("the bus_no behind the bridge is %x\n", busno); + debug ("scanning devices behind the bridge...\n"); + for (device = 0; device < 32; device++) { + amount->devices[device] = 0; + for (function = 0; function < 8; function++) { + devfn = PCI_DEVFN(device, function); + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + howmany++; + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); + + debug ("hdr_type behind the bridge is %x\n", hdr_type); + if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { + err ("embedded bridges not supported for hot-plugging.\n"); + amount->not_correct = TRUE; + return amount; + } + + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } + + amount->devices[device] = 1; + + for (count = 0; address[count]; count++) { + /* for 6 BARs */ + /* + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, address[count], &tmp); + if (tmp & 0x01) // IO + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD); + else // MEMORY + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + + debug ("what is bar[count]? %x, count = %d\n", bar[count], count); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + //tmp_bar = bar[count]; + + debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + amount->io += len[count]; + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->pfmem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) + /* takes up another dword */ + count += 1; + + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->mem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } + } /* end for */ + } /* end if (valid) */ + } /* end for */ + } /* end for */ + + if (!howmany) + amount->not_correct = TRUE; + else + amount->not_correct = FALSE; + if ((amount->io) && (amount->io < IOBRIDGE)) + amount->io = IOBRIDGE; + if ((amount->mem) && (amount->mem < MEMBRIDGE)) + amount->mem = MEMBRIDGE; + if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE)) + amount->pfmem = MEMBRIDGE; + return amount; +} + +/* The following 3 unconfigure_boot_ routines deal with the case when we had the card + * upon bootup in the system, since we don't allocate func to such case, we need to read + * the start addresses from pci config space and then find the corresponding entries in + * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) + * Change: we also call these functions even if we configured the card ourselves (i.e., not + * the bootup case), since it should work same way + */ +static int unconfigure_boot_device (u8 busno, u8 device, u8 function) +{ + u32 start_address; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct bus_node *bus; + u32 end_address; + u32 temp_end; + u32 size; + u32 tmp_address; + unsigned int devfn; + + debug ("%s - enter\n", __FUNCTION__); + + bus = ibmphp_find_res_bus (busno); + if (!bus) { + debug ("cannot find corresponding bus.\n"); + return -EINVAL; + } + + devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = busno; + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); + + /* We can do this here, b/c by that time the device driver of the card has been stopped */ + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &size); + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], start_address); + + debug ("start_address is %x\n", start_address); + debug ("busno, device, function %x %x %x\n", busno, device, function); + if (!size) { + /* This BAR is not implemented */ + debug ("is this bar no implemented?, count = %d\n", count); + continue; + } + tmp_address = start_address; + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + size = size & 0xFFFFFFFC; + size = ~size + 1; + end_address = start_address + size - 1; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + /* This is needed b/c of the old I/O restrictions in the BIOS */ + while (temp_end < end_address) { + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + } + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of pfmem is %x\n", start_address); + + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EIO; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of mem is %x\n", start_address); + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EIO; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + + return 0; +} + +static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) +{ + int count; + int bus_no, pri_no, sub_no, sec_no = 0; + u32 start_address, tmp_address; + u8 sec_number, sub_number, pri_number; + struct resource_node *io = NULL; + struct resource_node *mem = NULL; + struct resource_node *pfmem = NULL; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + unsigned int devfn; + + devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = busno; + bus_no = (int) busno; + debug ("busno is %x\n", busno); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); + debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number is %x\n", sec_number); + sec_no = (int) sec_number; + pri_no = (int) pri_number; + if (pri_no != bus_no) { + err ("primary numbers in our structures and pci config space don't match.\n"); + return -EINVAL; + } + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + sec_no = (int) sec_no; + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number); + sub_no = (int) sub_number; + debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); + if (sec_no != sub_number) { + err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); + return -ENODEV; + } + + bus = ibmphp_find_res_bus (sec_number); + debug ("bus->busno is %x\n", bus->busno); + debug ("sec_number is %x\n", sec_number); + if (!bus) { + err ("cannot find Bus structure for the bridged device\n"); + return -EINVAL; + } + + ibmphp_remove_bus (bus, busno); + + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); + + if (!start_address) { + /* This BAR is not implemented */ + continue; + } + + tmp_address = start_address; + + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + if (io) + debug ("io->start = %x\n", io->start); + + ibmphp_remove_resource (io); + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EINVAL; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EINVAL; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + debug ("%s - exiting, returning success\n", __FUNCTION__); + return 0; +} + +static int unconfigure_boot_card (struct slot *slot_cur) +{ + u16 vendor_id; + u32 class; + u8 hdr_type; + u8 device; + u8 busno; + u8 function; + int rc; + unsigned int devfn; + u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ + + debug ("%s - enter\n", __FUNCTION__); + + device = slot_cur->device; + busno = slot_cur->bus; + + debug ("b4 for loop, device is %x\n", device); + /* For every function on the card */ + for (function = 0x0; function < 0x08; function++) { + devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = busno; + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + ++valid_device; + + debug ("%s - found correct device\n", __FUNCTION__); + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); + + debug ("hdr_type %x, class %x\n", hdr_type, class); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x function %x is VGA compatible and is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x function %x is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + break; + default: + err ("MAJOR PROBLEM!!!! Cannot read device's header \n"); + return -1; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Could not find device to unconfigure. Or could not read the card. \n"); + return -1; + } + return 0; +} + +/* + * free the resources of the card (multi, single, or bridged) + * Parameters: slot, flag to say if this is for removing entire module or just + * unconfiguring the device + * TO DO: will probably need to add some code in case there was some resource, + * to remove it... this is from when we have errors in the configure_card... + * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! + * Returns: 0, -1, -ENODEV + */ +int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) +{ + int i; + int count; + int rc; + struct slot *sl = *slot_cur; + struct pci_func *cur_func = NULL; + struct pci_func *temp_func; + + debug ("%s - enter\n", __FUNCTION__); + + if (!the_end) { + /* Need to unconfigure the card */ + rc = unconfigure_boot_card (sl); + if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { + /* In all other cases, will still need to get rid of func structure if it exists */ + return rc; + } + } + + if (sl->func) { + cur_func = sl->func; + while (cur_func) { + /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ + if (cur_func->bus) { + /* in other words, it's a PPB */ + count = 2; + } else { + count = 6; + } + + for (i = 0; i < count; i++) { + if (cur_func->io[i]) { + debug ("io[%d] exists \n", i); + if (the_end > 0) + ibmphp_remove_resource (cur_func->io[i]); + cur_func->io[i] = NULL; + } + if (cur_func->mem[i]) { + debug ("mem[%d] exists \n", i); + if (the_end > 0) + ibmphp_remove_resource (cur_func->mem[i]); + cur_func->mem[i] = NULL; + } + if (cur_func->pfmem[i]) { + debug ("pfmem[%d] exists \n", i); + if (the_end > 0) + ibmphp_remove_resource (cur_func->pfmem[i]); + cur_func->pfmem[i] = NULL; + } + } + + temp_func = cur_func->next; + kfree (cur_func); + cur_func = temp_func; + } + } + + sl->func = NULL; + *slot_cur = sl; + debug ("%s - exit\n", __FUNCTION__); + return 0; +} + +/* + * add a new bus resulting from hot-plugging a PPB bridge with devices + * + * Input: bus and the amount of resources needed (we know we can assign those, + * since they've been checked already + * Output: bus added to the correct spot + * 0, -1, error + */ +static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) +{ + struct range_node *io_range = NULL; + struct range_node *mem_range = NULL; + struct range_node *pfmem_range = NULL; + struct bus_node *cur_bus = NULL; + + /* Trying to find the parent bus number */ + if (parent_busno != 0xFF) { + cur_bus = ibmphp_find_res_bus (parent_busno); + if (!cur_bus) { + err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); + return -ENODEV; + } + + list_add (&bus->bus_list, &cur_bus->bus_list); + } + if (io) { + io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!io_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io_range, 0, sizeof (struct range_node)); + io_range->start = io->start; + io_range->end = io->end; + io_range->rangeno = 1; + bus->noIORanges = 1; + bus->rangeIO = io_range; + } + if (mem) { + mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!mem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem_range, 0, sizeof (struct range_node)); + mem_range->start = mem->start; + mem_range->end = mem->end; + mem_range->rangeno = 1; + bus->noMemRanges = 1; + bus->rangeMem = mem_range; + } + if (pfmem) { + pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!pfmem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem_range, 0, sizeof (struct range_node)); + pfmem_range->start = pfmem->start; + pfmem_range->end = pfmem->end; + pfmem_range->rangeno = 1; + bus->noPFMemRanges = 1; + bus->rangePFMem = pfmem_range; + } + return 0; +} + +/* + * find the 1st available bus number for PPB to set as its secondary bus + * Parameters: bus_number of the primary bus + * Returns: bus_number of the secondary bus or 0xff in case of failure + */ +static u8 find_sec_number (u8 primary_busno, u8 slotno) +{ + int min, max; + u8 busno; + struct bus_info *bus; + struct bus_node *bus_cur; + + bus = ibmphp_find_same_bus_num (primary_busno); + if (!bus) { + err ("cannot get slot range of the bus from the BIOS\n"); + return 0xff; + } + max = bus->slot_max; + min = bus->slot_min; + if ((slotno > max) || (slotno < min)) { + err ("got the wrong range\n"); + return 0xff; + } + busno = (u8) (slotno - (u8) min); + busno += primary_busno + 0x01; + bus_cur = ibmphp_find_res_bus (busno); + /* either there is no such bus number, or there are no ranges, which + * can only happen if we removed the bridged device in previous load + * of the driver, and now only have the skeleton bus struct + */ + if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem))) + return busno; + return 0xff; +} + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_res.c linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_res.c --- linux-2.5.70-bk9/drivers/pci/hotplug/ibmphp_res.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/ibmphp_res.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,2157 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include "ibmphp.h" + +static int flags = 0; /* for testing */ + +static void update_resources (struct bus_node *bus_cur, int type, int rangeno); +static int once_over (void); +static int remove_ranges (struct bus_node *, struct bus_node *); +static int update_bridge_ranges (struct bus_node **); +static int add_range (int type, struct range_node *, struct bus_node *); +static void fix_resources (struct bus_node *); +static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); + +static LIST_HEAD(gbuses); +LIST_HEAD(ibmphp_res_head); + +static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag) +{ + struct bus_node * newbus; + + if (!(curr) && !(flag)) { + err ("NULL pointer passed \n"); + return NULL; + } + + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory \n"); + return NULL; + } + + memset (newbus, 0, sizeof (struct bus_node)); + if (flag) + newbus->busno = busno; + else + newbus->busno = curr->bus_num; + list_add_tail (&newbus->bus_list, &gbuses); + return newbus; +} + +static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr) +{ + struct resource_node *rs; + + if (!curr) { + err ("NULL passed to allocate \n"); + return NULL; + } + + rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!rs) { + err ("out of system memory \n"); + return NULL; + } + memset (rs, 0, sizeof (struct resource_node)); + rs->busno = curr->bus_num; + rs->devfunc = curr->dev_fun; + rs->start = curr->start_addr; + rs->end = curr->end_addr; + rs->len = curr->end_addr - curr->start_addr + 1; + return rs; +} + +static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) +{ + struct bus_node * newbus; + struct range_node *newrange; + u8 num_ranges = 0; + + if (first_bus) { + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory. \n"); + return -ENOMEM; + } + memset (newbus, 0, sizeof (struct bus_node)); + newbus->busno = curr->bus_num; + } else { + newbus = *new_bus; + switch (flag) { + case MEM: + num_ranges = newbus->noMemRanges; + break; + case PFMEM: + num_ranges = newbus->noPFMemRanges; + break; + case IO: + num_ranges = newbus->noIORanges; + break; + } + } + + newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!newrange) { + if (first_bus) + kfree (newbus); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newrange, 0, sizeof (struct range_node)); + newrange->start = curr->start_addr; + newrange->end = curr->end_addr; + + if (first_bus || (!num_ranges)) + newrange->rangeno = 1; + else { + /* need to insert our range */ + add_range (flag, newrange, newbus); + debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); + } + + switch (flag) { + case MEM: + newbus->rangeMem = newrange; + if (first_bus) + newbus->noMemRanges = 1; + else { + debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noMemRanges; + fix_resources (newbus); + } + break; + case IO: + newbus->rangeIO = newrange; + if (first_bus) + newbus->noIORanges = 1; + else { + debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noIORanges; + fix_resources (newbus); + } + break; + case PFMEM: + newbus->rangePFMem = newrange; + if (first_bus) + newbus->noPFMemRanges = 1; + else { + debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noPFMemRanges; + fix_resources (newbus); + } + + break; + } + + *new_bus = newbus; + *new_range = newrange; + return 0; +} + + +/* Notes: + * 1. The ranges are ordered. The buses are not ordered. (First come) + * + * 2. If cannot allocate out of PFMem range, allocate from Mem ranges. PFmemFromMem + * are not sorted. (no need since use mem node). To not change the entire code, we + * also add mem node whenever this case happens so as not to change + * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) + */ + +/***************************************************************************** + * This is the Resource Management initialization function. It will go through + * the Resource list taken from EBDA and fill in this module's data structures + * + * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, + * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW + * + * Input: ptr to the head of the resource list from EBDA + * Output: 0, -1 or error codes + ***************************************************************************/ +int __init ibmphp_rsrc_init (void) +{ + struct ebda_pci_rsrc *curr; + struct range_node *newrange = NULL; + struct bus_node *newbus = NULL; + struct bus_node *bus_cur; + struct bus_node *bus_prev; + struct list_head *tmp; + struct resource_node *new_io = NULL; + struct resource_node *new_mem = NULL; + struct resource_node *new_pfmem = NULL; + int rc; + struct list_head *tmp_ebda; + + list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) { + curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + if (!(curr->rsrc_type & PCIDEVMASK)) { + /* EBDA still lists non PCI devices, so ignore... */ + debug ("this is not a PCI DEVICE in rsrc_init, please take care\n"); + // continue; + } + + /* this is a primary bus resource */ + if (curr->rsrc_type & PRIMARYBUSMASK) { + /* memory */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* no bus structure exists in place yet */ + if (list_empty (&gbuses)) { + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + /* found our bus */ + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + + list_add_tail (&newbus->bus_list, &gbuses); + debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* prefetchable memory */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + /* found our bus */ + rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + + } else { + ; /* type is reserved WHAT TO DO IN THIS CASE??? + NOTHING TO DO??? */ + } + } else { + /* regular pci device resource */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* Memory resource */ + new_mem = alloc_resources (curr); + if (!new_mem) + return -ENOMEM; + new_mem->type = MEM; + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * assign a -1 and then update once the range + * actually appears... + */ + if (ibmphp_add_resource (new_mem) < 0) { + newbus = alloc_error_bus (curr, 0, 0); + if (!newbus) + return -ENOMEM; + newbus->firstMem = new_mem; + ++newbus->needMemUpdate; + new_mem->rangeno = -1; + } + debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end); + + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* PFMemory resource */ + new_pfmem = alloc_resources (curr); + if (!new_pfmem) + return -ENOMEM; + new_pfmem->type = PFMEM; + new_pfmem->fromMem = FALSE; + if (ibmphp_add_resource (new_pfmem) < 0) { + newbus = alloc_error_bus (curr, 0, 0); + if (!newbus) + return -ENOMEM; + newbus->firstPFMem = new_pfmem; + ++newbus->needPFMemUpdate; + new_pfmem->rangeno = -1; + } + + debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end); + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO resource */ + new_io = alloc_resources (curr); + if (!new_io) + return -ENOMEM; + new_io->type = IO; + + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * Can assign a -1 and then update once the + * range actually appears... + */ + if (ibmphp_add_resource (new_io) < 0) { + newbus = alloc_error_bus (curr, 0, 0); + if (!newbus) + return -ENOMEM; + newbus->firstIO = new_io; + ++newbus->needIOUpdate; + new_io->rangeno = -1; + } + debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end); + } + } + } + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */ + rc = update_bridge_ranges (&bus_cur); + if (rc) + return rc; + } + rc = once_over (); /* This is to align ranges (so no -1) */ + if (rc) + return rc; + return 0; +} + +/******************************************************************************** + * This function adds a range into a sorted list of ranges per bus for a particular + * range type, it then calls another routine to update the range numbers on the + * pci devices' resources for the appropriate resource + * + * Input: type of the resource, range to add, current bus + * Output: 0 or -1, bus and range ptrs + ********************************************************************************/ +static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) +{ + struct range_node *range_cur = NULL; + struct range_node *range_prev; + int count = 0, i_init; + int noRanges = 0; + + switch (type) { + case MEM: + range_cur = bus_cur->rangeMem; + noRanges = bus_cur->noMemRanges; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + noRanges = bus_cur->noPFMemRanges; + break; + case IO: + range_cur = bus_cur->rangeIO; + noRanges = bus_cur->noIORanges; + break; + } + + range_prev = NULL; + while (range_cur) { + if (range->start < range_cur->start) + break; + range_prev = range_cur; + range_cur = range_cur->next; + count = count + 1; + } + if (!count) { + /* our range will go at the beginning of the list */ + switch (type) { + case MEM: + bus_cur->rangeMem = range; + break; + case PFMEM: + bus_cur->rangePFMem = range; + break; + case IO: + bus_cur->rangeIO = range; + break; + } + range->next = range_cur; + range->rangeno = 1; + i_init = 0; + } else if (!range_cur) { + /* our range will go at the end of the list */ + range->next = NULL; + range_prev->next = range; + range->rangeno = range_prev->rangeno + 1; + return 0; + } else { + /* the range is in the middle */ + range_prev->next = range; + range->next = range_cur; + range->rangeno = range_cur->rangeno; + i_init = range_prev->rangeno; + } + + for (count = i_init; count < noRanges; ++count) { + ++range_cur->rangeno; + range_cur = range_cur->next; + } + + update_resources (bus_cur, type, i_init + 1); + return 0; +} + +/******************************************************************************* + * This routine goes through the list of resources of type 'type' and updates + * the range numbers that they correspond to. It was called from add_range fnc + * + * Input: bus, type of the resource, the rangeno starting from which to update + ******************************************************************************/ +static void update_resources (struct bus_node *bus_cur, int type, int rangeno) +{ + struct resource_node *res = NULL; + u8 eol = FALSE; /* end of list indicator */ + + switch (type) { + case MEM: + if (bus_cur->firstMem) + res = bus_cur->firstMem; + break; + case PFMEM: + if (bus_cur->firstPFMem) + res = bus_cur->firstPFMem; + break; + case IO: + if (bus_cur->firstIO) + res = bus_cur->firstIO; + break; + } + + if (res) { + while (res) { + if (res->rangeno == rangeno) + break; + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else { + eol = TRUE; + break; + } + } + + if (!eol) { + /* found the range */ + while (res) { + ++res->rangeno; + res = res->next; + } + } + } +} + +static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range) +{ + char * str = ""; + switch (res->type) { + case IO: + str = "io"; + break; + case MEM: + str = "mem"; + break; + case PFMEM: + str = "pfmem"; + break; + } + + while (res) { + if (res->rangeno == -1) { + while (range) { + if ((res->start >= range->start) && (res->end <= range->end)) { + res->rangeno = range->rangeno; + debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno); + switch (res->type) { + case IO: + --bus_cur->needIOUpdate; + break; + case MEM: + --bus_cur->needMemUpdate; + break; + case PFMEM: + --bus_cur->needPFMemUpdate; + break; + } + break; + } + range = range->next; + } + } + if (res->next) + res = res->next; + else + res = res->nextRange; + } + +} + +/***************************************************************************** + * This routine reassigns the range numbers to the resources that had a -1 + * This case can happen only if upon initialization, resources taken by pci dev + * appear in EBDA before the resources allocated for that bus, since we don't + * know the range, we assign -1, and this routine is called after a new range + * is assigned to see the resources with unknown range belong to the added range + * + * Input: current bus + * Output: none, list of resources for that bus are fixed if can be + *******************************************************************************/ +static void fix_resources (struct bus_node *bus_cur) +{ + struct range_node *range; + struct resource_node *res; + + debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); + + if (bus_cur->needIOUpdate) { + res = bus_cur->firstIO; + range = bus_cur->rangeIO; + fix_me (res, bus_cur, range); + } + if (bus_cur->needMemUpdate) { + res = bus_cur->firstMem; + range = bus_cur->rangeMem; + fix_me (res, bus_cur, range); + } + if (bus_cur->needPFMemUpdate) { + res = bus_cur->firstPFMem; + range = bus_cur->rangePFMem; + fix_me (res, bus_cur, range); + } +} + +/******************************************************************************* + * This routine adds a resource to the list of resources to the appropriate bus + * based on their resource type and sorted by their starting addresses. It assigns + * the ptrs to next and nextRange if needed. + * + * Input: resource ptr + * Output: ptrs assigned (to the node) + * 0 or -1 + *******************************************************************************/ +int ibmphp_add_resource (struct resource_node *res) +{ + struct resource_node *res_cur; + struct resource_node *res_prev; + struct bus_node *bus_cur; + struct range_node *range_cur = NULL; + struct resource_node *res_start = NULL; + + debug ("%s - enter\n", __FUNCTION__); + + if (!res) { + err ("NULL passed to add \n"); + return -ENODEV; + } + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + debug ("no bus in the system, either pci_dev's wrong or allocation failed\n"); + return -ENODEV; + } + + /* Normal case */ + switch (res->type) { + case IO: + range_cur = bus_cur->rangeIO; + res_start = bus_cur->firstIO; + break; + case MEM: + range_cur = bus_cur->rangeMem; + res_start = bus_cur->firstMem; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + res_start = bus_cur->firstPFMem; + break; + default: + err ("cannot read the type of the resource to add... problem \n"); + return -EINVAL; + } + while (range_cur) { + if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) { + res->rangeno = range_cur->rangeno; + break; + } + range_cur = range_cur->next; + } + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * this is again the case of rangeno = -1 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + + if (!range_cur) { + switch (res->type) { + case IO: + ++bus_cur->needIOUpdate; + break; + case MEM: + ++bus_cur->needMemUpdate; + break; + case PFMEM: + ++bus_cur->needPFMemUpdate; + break; + } + res->rangeno = -1; + } + + debug ("The range is %d\n", res->rangeno); + if (!res_start) { + /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + res->next = NULL; + res->nextRange = NULL; + } else { + res_cur = res_start; + res_prev = NULL; + + debug ("res_cur->rangeno is %d\n", res_cur->rangeno); + + while (res_cur) { + if (res_cur->rangeno >= res->rangeno) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + /* at the end of the resource list */ + debug ("i should be here, [%x - %x]\n", res->start, res->end); + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = NULL; + } else if (res_cur->rangeno == res->rangeno) { + /* in the same range */ + while (res_cur) { + if (res->start < res_cur->start) + break; + res_prev = res_cur; + res_cur = res_cur->next; + } + if (!res_cur) { + /* the last resource in this range */ + res_prev->next = res; + res->next = NULL; + res->nextRange = res_prev->nextRange; + res_prev->nextRange = NULL; + } else if (res->start < res_cur->start) { + /* at the beginning or middle of the range */ + if (!res_prev) { + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + } else if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res; + else + res_prev->nextRange = res; + + res->next = res_cur; + res->nextRange = NULL; + } + } else { + /* this is the case where it is 1st occurrence of the range */ + if (!res_prev) { + /* at the beginning of the resource list */ + res->next = NULL; + switch (res->type) { + case IO: + res->nextRange = bus_cur->firstIO; + bus_cur->firstIO = res; + break; + case MEM: + res->nextRange = bus_cur->firstMem; + bus_cur->firstMem = res; + break; + case PFMEM: + res->nextRange = bus_cur->firstPFMem; + bus_cur->firstPFMem = res; + break; + } + } else if (res_cur->rangeno > res->rangeno) { + /* in the middle of the resource list */ + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = res_cur; + } + } + } + + debug ("%s - exit\n", __FUNCTION__); + return 0; +} + +/**************************************************************************** + * This routine will remove the resource from the list of resources + * + * Input: io, mem, and/or pfmem resource to be deleted + * Ouput: modified resource list + * 0 or error code + ****************************************************************************/ +int ibmphp_remove_resource (struct resource_node *res) +{ + struct bus_node *bus_cur; + struct resource_node *res_cur = NULL; + struct resource_node *res_prev; + struct resource_node *mem_cur; + char * type = ""; + + if (!res) { + err ("resource to remove is NULL \n"); + return -ENODEV; + } + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find corresponding bus of the io resource to remove " + "bailing out...\n"); + return -ENODEV; + } + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus_cur->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + type = "pfmem"; + break; + default: + err ("unknown type for resource to remove \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + if ((res_cur->start == res->start) && (res_cur->end == res->end)) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (res->type == PFMEM) { + /* + * case where pfmem might be in the PFMemFromMem list + * so will also need to remove the corresponding mem + * entry + */ + res_cur = bus_cur->firstPFMemFromMem; + res_prev = NULL; + + while (res_cur) { + if ((res_cur->start == res->start) && (res_cur->end == res->end)) { + mem_cur = bus_cur->firstMem; + while (mem_cur) { + if ((mem_cur->start == res_cur->start) + && (mem_cur->end == res_cur->end)) + break; + if (mem_cur->next) + mem_cur = mem_cur->next; + else + mem_cur = mem_cur->nextRange; + } + if (!mem_cur) { + err ("cannot find corresponding mem node for pfmem...\n"); + return -EINVAL; + } + + ibmphp_remove_resource (mem_cur); + if (!res_prev) + bus_cur->firstPFMemFromMem = res_cur->next; + else + res_prev->next = res_cur->next; + kfree (res_cur); + return 0; + } + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + if (!res_cur) { + err ("cannot find pfmem to delete...\n"); + return -EINVAL; + } + } else { + err ("the %s resource is not in the list to be deleted...\n", type); + return -EINVAL; + } + } + if (!res_prev) { + /* first device to be deleted */ + if (res_cur->next) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->next; + break; + case MEM: + bus_cur->firstMem = res_cur->next; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->next; + break; + } + } else if (res_cur->nextRange) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->nextRange; + break; + case MEM: + bus_cur->firstMem = res_cur->nextRange; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->nextRange; + break; + } + } else { + switch (res->type) { + case IO: + bus_cur->firstIO = NULL; + break; + case MEM: + bus_cur->firstMem = NULL; + break; + case PFMEM: + bus_cur->firstPFMem = NULL; + break; + } + } + kfree (res_cur); + return 0; + } else { + if (res_cur->next) { + if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res_cur->next; + else + res_prev->nextRange = res_cur->next; + } else if (res_cur->nextRange) { + res_prev->next = NULL; + res_prev->nextRange = res_cur->nextRange; + } else { + res_prev->next = NULL; + res_prev->nextRange = NULL; + } + kfree (res_cur); + return 0; + } + + return 0; +} + +static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) +{ + struct range_node * range = NULL; + + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + default: + err ("cannot read resource type in find_range \n"); + } + + while (range) { + if (res->rangeno == range->rangeno) + break; + range = range->next; + } + return range; +} + +/***************************************************************************** + * This routine will check to make sure the io/mem/pfmem->len that the device asked for + * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, + * otherwise, returns 0 + * + * Input: resource + * Ouput: the correct start and end address are inputted into the resource node, + * 0 or -EINVAL + *****************************************************************************/ +int ibmphp_check_resource (struct resource_node *res, u8 bridge) +{ + struct bus_node *bus_cur; + struct range_node *range = NULL; + struct resource_node *res_prev; + struct resource_node *res_cur = NULL; + u32 len_cur = 0, start_cur = 0, len_tmp = 0; + int noranges = 0; + u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ + u32 tmp_divide; + u8 flag = FALSE; + + if (!res) + return -EINVAL; + + if (bridge) { + /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/ + if (res->type == IO) + tmp_divide = IOBRIDGE; + else + tmp_divide = MEMBRIDGE; + } else + tmp_divide = res->len; + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + debug ("no bus in the system, either pci_dev's wrong or allocation failed \n"); + return -EINVAL; + } + + debug ("%s - enter\n", __FUNCTION__); + debug ("bus_cur->busno is %d\n", bus_cur->busno); + + /* This is a quick fix to not mess up with the code very much. i.e., + * 2000-2fff, len = 1000, but when we compare, we need it to be fff */ + res->len -= 1; + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + noranges = bus_cur->noIORanges; + break; + case MEM: + res_cur = bus_cur->firstMem; + noranges = bus_cur->noMemRanges; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + noranges = bus_cur->noPFMemRanges; + break; + default: + err ("wrong type of resource to check \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + range = find_range (bus_cur, res_cur); + debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); + + if (!range) { + err ("no range for the device exists... bailing out...\n"); + return -EINVAL; + } + + /* found our range */ + if (!res_prev) { + /* first time in the loop */ + if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + debug ("but we are not here, right?\n"); + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + if (!res_cur->next) { + /* last device on the range */ + if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if (((res_cur->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_cur->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_cur->end + 1; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + + if (res_prev) { + if (res_prev->rangeno != res_cur->rangeno) { + /* 1st device on this range */ + if ((res_cur->start != range->start) && + ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } else { + /* in the same range */ + if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if (((res_prev->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_prev->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_prev->end + 1; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + } + /* end if (res_prev) */ + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } /* end of while */ + + + if (!res_prev) { + /* 1st device ever */ + /* need to find appropriate range */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + + if (!res_cur) { + debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); + if (res_prev->rangeno < noranges) { + /* if there're more ranges out there to check */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } else { + /* no more ranges to check on */ + if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } else { + /* have gone through the list of devices and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } + } + } /* end if(!res_cur) */ + return -EINVAL; +} + +/******************************************************************************** + * This routine is called from remove_card if the card contained PPB. + * It will remove all the resources on the bus as well as the bus itself + * Input: Bus + * Ouput: 0, -ENODEV + ********************************************************************************/ +int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) +{ + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct bus_node *prev_bus; + int rc; + + prev_bus = find_bus_wprev (parent_busno, NULL, 0); + + if (!prev_bus) { + debug ("something terribly wrong. Cannot find parent bus to the one to remove\n"); + return -ENODEV; + } + + debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); + + rc = remove_ranges (bus, prev_bus); + if (rc) + return rc; + + if (bus->firstIO) { + res_cur = bus->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstIO = NULL; + } + if (bus->firstMem) { + res_cur = bus->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstMem = NULL; + } + if (bus->firstPFMem) { + res_cur = bus->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMem = NULL; + } + + if (bus->firstPFMemFromMem) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMemFromMem = NULL; + } + + list_del (&bus->bus_list); + kfree (bus); + return 0; +} + +/****************************************************************************** + * This routine deletes the ranges from a given bus, and the entries from the + * parent's bus in the resources + * Input: current bus, previous bus + * Output: 0, -EINVAL + ******************************************************************************/ +static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) +{ + struct range_node *range_cur; + struct range_node *range_tmp; + int i; + struct resource_node *res = NULL; + + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) + return -EINVAL; + ibmphp_remove_resource (res); + + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeIO = NULL; + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeMem = NULL; + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangePFMem = NULL; + } + return 0; +} + +/* + * find the resource node in the bus + * Input: Resource needed, start address of the resource, type of resource + */ +int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) +{ + struct resource_node *res_cur = NULL; + char * type = ""; + + if (!bus) { + err ("The bus passed in NULL to find resource \n"); + return -ENODEV; + } + + switch (flag) { + case IO: + res_cur = bus->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus->firstPFMem; + type = "pfmem"; + break; + default: + err ("wrong type of flag \n"); + return -EINVAL; + } + + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (flag == PFMEM) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + res_cur = res_cur->next; + } + if (!res_cur) { + debug ("SOS...cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } else { + debug ("SOS... cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } + + if (*res) + debug ("*res->start = %x \n", (*res)->start); + + return 0; +} + +/*********************************************************************** + * This routine will free the resource structures used by the + * system. It is called from cleanup routine for the module + * Parameters: none + * Returns: none + ***********************************************************************/ +void ibmphp_free_resources (void) +{ + struct bus_node *bus_cur = NULL; + struct bus_node *bus_tmp; + struct range_node *range_cur; + struct range_node *range_tmp; + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct list_head *tmp; + struct list_head *next; + int i = 0; + flags = 1; + + list_for_each_safe (tmp, next, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + + if (bus_cur->firstIO) { + res_cur = bus_cur->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstIO = NULL; + } + if (bus_cur->firstMem) { + res_cur = bus_cur->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstMem = NULL; + } + if (bus_cur->firstPFMem) { + res_cur = bus_cur->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMem = NULL; + } + + if (bus_cur->firstPFMemFromMem) { + res_cur = bus_cur->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMemFromMem = NULL; + } + + bus_tmp = bus_cur; + list_del (&bus_cur->bus_list); + kfree (bus_tmp); + bus_tmp = NULL; + } +} + +/********************************************************************************* + * This function will go over the PFmem resources to check if the EBDA allocated + * pfmem out of memory buckets of the bus. If so, it will change the range numbers + * and a flag to indicate that this resource is out of memory. It will also move the + * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create + * a new Mem node + * This routine is called right after initialization + *******************************************************************************/ +static int __init once_over (void) +{ + struct resource_node *pfmem_cur; + struct resource_node *pfmem_prev; + struct resource_node *mem; + struct bus_node *bus_cur; + struct list_head *tmp; + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { + for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { + pfmem_cur->fromMem = TRUE; + if (pfmem_prev) + pfmem_prev->next = pfmem_cur->next; + else + bus_cur->firstPFMem = pfmem_cur->next; + + if (!bus_cur->firstPFMemFromMem) + pfmem_cur->next = NULL; + else + /* we don't need to sort PFMemFromMem since we're using mem node for + all the real work anyways, so just insert at the beginning of the + list + */ + pfmem_cur->next = bus_cur->firstPFMemFromMem; + + bus_cur->firstPFMemFromMem = pfmem_cur; + + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = pfmem_cur->busno; + mem->devfunc = pfmem_cur->devfunc; + mem->start = pfmem_cur->start; + mem->end = pfmem_cur->end; + mem->len = pfmem_cur->len; + if (ibmphp_add_resource (mem) < 0) + err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); + pfmem_cur->rangeno = mem->rangeno; + } /* end for pfmem */ + } /* end if */ + } /* end list_for_each bus */ + return 0; +} + +int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) +{ + struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find bus of pfmem to add...\n"); + return -ENODEV; + } + + if (bus_cur->firstPFMemFromMem) + pfmem->next = bus_cur->firstPFMemFromMem; + else + pfmem->next = NULL; + + bus_cur->firstPFMemFromMem = pfmem; + + return 0; +} + +/* This routine just goes through the buses to see if the bus already exists. + * It is called from ibmphp_find_sec_number, to find out a secondary bus number for + * bridged cards + * Parameters: bus_number + * Returns: Bus pointer or NULL + */ +struct bus_node *ibmphp_find_res_bus (u8 bus_number) +{ + return find_bus_wprev (bus_number, NULL, 0); +} + +static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) +{ + struct bus_node *bus_cur; + struct list_head *tmp; + struct list_head *tmp_prev; + + list_for_each (tmp, &gbuses) { + tmp_prev = tmp->prev; + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (flag) + *prev = list_entry (tmp_prev, struct bus_node, bus_list); + if (bus_cur->busno == bus_number) + return bus_cur; + } + + return NULL; +} + +void ibmphp_print_test (void) +{ + int i = 0; + struct bus_node *bus_cur = NULL; + struct range_node *range; + struct resource_node *res; + struct list_head *tmp; + + debug_pci ("*****************START**********************\n"); + + if ((!list_empty(&gbuses)) && flags) { + err ("The GBUSES is not NULL?!?!?!?!?\n"); + return; + } + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + debug_pci ("This is bus # %d. There are \n", bus_cur->busno); + debug_pci ("IORanges = %d\t", bus_cur->noIORanges); + debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges); + debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); + debug_pci ("The IO Ranges are as follows:\n"); + if (bus_cur->rangeIO) { + range = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + debug_pci ("rangeno is %d\n", range->rangeno); + debug_pci ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug_pci ("The Mem Ranges are as follows:\n"); + if (bus_cur->rangeMem) { + range = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + debug_pci ("rangeno is %d\n", range->rangeno); + debug_pci ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug_pci ("The PFMem Ranges are as follows:\n"); + + if (bus_cur->rangePFMem) { + range = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + debug_pci ("rangeno is %d\n", range->rangeno); + debug_pci ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug_pci ("The resources on this bus are as follows\n"); + + debug_pci ("IO...\n"); + if (bus_cur->firstIO) { + res = bus_cur->firstIO; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug_pci ("Mem...\n"); + if (bus_cur->firstMem) { + res = bus_cur->firstMem; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug_pci ("PFMem...\n"); + if (bus_cur->firstPFMem) { + res = bus_cur->firstPFMem; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + + debug_pci ("PFMemFromMem...\n"); + if (bus_cur->firstPFMemFromMem) { + res = bus_cur->firstPFMemFromMem; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + res = res->next; + } + } + } + debug_pci ("***********************END***********************\n"); +} + +static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type) +{ + struct range_node * range_cur = NULL; + switch (type) { + case IO: + range_cur = bus_cur->rangeIO; + break; + case MEM: + range_cur = bus_cur->rangeMem; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + break; + default: + err ("wrong type passed to find out if range already exists \n"); + return -ENODEV; + } + + while (range_cur) { + if ((range_cur->start == range->start) && (range_cur->end == range->end)) + return 1; + range_cur = range_cur->next; + } + + return 0; +} + +/* This routine will read the windows for any PPB we have and update the + * range info for the secondary bus, and will also input this info into + * primary bus, since BIOS doesn't. This is for PPB that are in the system + * on bootup. For bridged cards that were added during previous load of the + * driver, only the ranges and the bus structure are added, the devices are + * added from NVRAM + * Input: primary busno + * Returns: none + * Note: this function doesn't take into account IO restrictions etc, + * so will only work for bridges with no video/ISA devices behind them It + * also will not work for onboard PPB's that can have more than 1 *bus + * behind them All these are TO DO. + * Also need to add more error checkings... (from fnc returns etc) + */ +static int __init update_bridge_ranges (struct bus_node **bus) +{ + u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address; + u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; + u32 start_address, end_address, upper_start, upper_end; + struct bus_node *bus_sec; + struct bus_node *bus_cur; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct range_node *range; + unsigned int devfn; + + bus_cur = *bus; + if (!bus_cur) + return -ENODEV; + ibmphp_pci_bus->number = bus_cur->busno; + + debug ("inside %s \n", __FUNCTION__); + debug ("bus_cur->busno = %x\n", bus_cur->busno); + + for (device = 0; device < 32; device++) { + for (function = 0x00; function < 0x08; function++) { + devfn = PCI_DEVFN(device, function); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + break; + case PCI_HEADER_TYPE_BRIDGE: + function = 0x8; + case PCI_HEADER_TYPE_MULTIBRIDGE: + /* We assume here that only 1 bus behind the bridge + TO DO: add functionality for several: + temp = secondary; + while (temp < subordinate) { + ... + temp++; + } + */ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno); + bus_sec = find_bus_wprev (sec_busno, NULL, 0); + /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */ + if (!bus_sec) { + bus_sec = alloc_error_bus (NULL, sec_busno, 1); + /* the rest will be populated during NVRAM call */ + return 0; + } + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end); + start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; + start_address |= (upper_io_start << 16); + end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; + end_address |= (upper_io_end << 16); + + if ((start_address) && (start_address <= end_address)) { + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfff; + + if (bus_sec->noIORanges > 0) { + if (!range_exists_already (range, bus_sec, IO)) { + add_range (IO, range, bus_sec); + ++bus_sec->noIORanges; + } else { + kfree (range); + range = NULL; + } + } else { + /* 1st IO Range on the bus */ + range->rangeno = 1; + bus_sec->rangeIO = range; + ++bus_sec->noIORanges; + } + fix_resources (bus_sec); + + if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) { + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!io) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = bus_cur->busno; + io->devfunc = ((device << 3) | (function & 0x7)); + io->start = start_address; + io->end = end_address + 0xfff; + io->len = io->end - io->start + 1; + ibmphp_add_resource (io); + } + } + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address); + + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noMemRanges > 0) { + if (!range_exists_already (range, bus_sec, MEM)) { + add_range (MEM, range, bus_sec); + ++bus_sec->noMemRanges; + } else { + kfree (range); + range = NULL; + } + } else { + /* 1st Mem Range on the bus */ + range->rangeno = 1; + bus_sec->rangeMem = range; + ++bus_sec->noMemRanges; + } + + fix_resources (bus_sec); + + if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) { + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = bus_cur->busno; + mem->devfunc = ((device << 3) | (function & 0x7)); + mem->start = start_address; + mem->end = end_address + 0xfffff; + mem->len = mem->end - mem->start + 1; + ibmphp_add_resource (mem); + } + } + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end); + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; +#if BITS_PER_LONG == 64 + start_address |= ((long) upper_start) << 32; + end_address |= ((long) upper_end) << 32; +#endif + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noPFMemRanges > 0) { + if (!range_exists_already (range, bus_sec, PFMEM)) { + add_range (PFMEM, range, bus_sec); + ++bus_sec->noPFMemRanges; + } else { + kfree (range); + range = NULL; + } + } else { + /* 1st PFMem Range on the bus */ + range->rangeno = 1; + bus_sec->rangePFMem = range; + ++bus_sec->noPFMemRanges; + } + + fix_resources (bus_sec); + if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) { + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = bus_cur->busno; + pfmem->devfunc = ((device << 3) | (function & 0x7)); + pfmem->start = start_address; + pfmem->end = end_address + 0xfffff; + pfmem->len = pfmem->end - pfmem->start + 1; + pfmem->fromMem = FALSE; + + ibmphp_add_resource (pfmem); + } + } + break; + } /* end of switch */ + } /* end if vendor */ + } /* end for function */ + } /* end for device */ + + bus = &bus_cur; + return 0; +} diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/pci_hotplug.h linux-2.5.70-bk10/drivers/pci/hotplug/pci_hotplug.h --- linux-2.5.70-bk9/drivers/pci/hotplug/pci_hotplug.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/pci_hotplug.h 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,146 @@ +/* + * PCI HotPlug Core Functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ +#ifndef _PCI_HOTPLUG_H +#define _PCI_HOTPLUG_H + + +/* These values come from the PCI Hotplug Spec */ +enum pci_bus_speed { + PCI_SPEED_33MHz = 0x00, + PCI_SPEED_66MHz = 0x01, + PCI_SPEED_66MHz_PCIX = 0x02, + PCI_SPEED_100MHz_PCIX = 0x03, + PCI_SPEED_133MHz_PCIX = 0x04, + PCI_SPEED_66MHz_PCIX_266 = 0x09, + PCI_SPEED_100MHz_PCIX_266 = 0x0a, + PCI_SPEED_133MHz_PCIX_266 = 0x0b, + PCI_SPEED_66MHz_PCIX_533 = 0x11, + PCI_SPEED_100MHz_PCIX_533 = 0X12, + PCI_SPEED_133MHz_PCIX_533 = 0x13, + PCI_SPEED_UNKNOWN = 0xff, +}; + +struct hotplug_slot; +struct hotplug_slot_attribute { + struct attribute attr; + ssize_t (*show)(struct hotplug_slot *, char *); + ssize_t (*store)(struct hotplug_slot *, const char *, size_t); +}; +/** + * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use + * @owner: The module owner of this structure + * @enable_slot: Called when the user wants to enable a specific pci slot + * @disable_slot: Called when the user wants to disable a specific pci slot + * @set_attention_status: Called to set the specific slot's attention LED to + * the specified value + * @hardware_test: Called to run a specified hardware test on the specified + * slot. + * @get_power_status: Called to get the current power status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_attention_status: Called to get the current attention status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_latch_status: Called to get the current latch status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_adapter_status: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_max_bus_speed: Called to get the max bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_cur_bus_speed: Called to get the current bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * + * The table of function pointers that is passed to the hotplug pci core by a + * hotplug pci driver. These functions are called by the hotplug pci core when + * the user wants to do something to a specific slot (query it for information, + * set an LED, enable / disable power, etc.) + */ +struct hotplug_slot_ops { + struct module *owner; + int (*enable_slot) (struct hotplug_slot *slot); + int (*disable_slot) (struct hotplug_slot *slot); + int (*set_attention_status) (struct hotplug_slot *slot, u8 value); + int (*hardware_test) (struct hotplug_slot *slot, u32 value); + int (*get_power_status) (struct hotplug_slot *slot, u8 *value); + int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); + int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); + int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); + int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); + int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); +}; + +/** + * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot + * @power: if power is enabled or not (1/0) + * @attention_status: if the attention light is enabled or not (1/0) + * @latch_status: if the latch (if any) is open or closed (1/0) + * @adapter_present: if there is a pci board present in the slot or not (1/0) + * + * Used to notify the hotplug pci core of the status of a specific slot. + */ +struct hotplug_slot_info { + u8 power_status; + u8 attention_status; + u8 latch_status; + u8 adapter_status; + enum pci_bus_speed max_bus_speed; + enum pci_bus_speed cur_bus_speed; +}; + +/** + * struct hotplug_slot - used to register a physical slot with the hotplug pci core + * @name: the name of the slot being registered. This string must + * be unique amoung slots registered on this system. + * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @info: pointer to the &struct hotplug_slot_info for the inital values for + * this slot. + * @private: used by the hotplug pci controller driver to store whatever it + * needs. + */ +struct hotplug_slot { + char *name; + struct hotplug_slot_ops *ops; + struct hotplug_slot_info *info; + void *private; + + /* Variables below this are for use only by the hotplug pci core. */ + struct list_head slot_list; + struct kobject kobj; +}; + +extern int pci_hp_register (struct hotplug_slot *slot); +extern int pci_hp_deregister (struct hotplug_slot *slot); +extern int pci_hp_change_slot_info (struct hotplug_slot *slot, + struct hotplug_slot_info *info); + +#endif + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/pci_hotplug_core.c linux-2.5.70-bk10/drivers/pci/hotplug/pci_hotplug_core.c --- linux-2.5.70-bk9/drivers/pci/hotplug/pci_hotplug_core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/pci_hotplug_core.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,666 @@ +/* + * PCI HotPlug Controller Core + * + * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" + + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug; + +#define DRIVER_VERSION "0.5" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Scott Murray " +#define DRIVER_DESC "PCI Hot Plug PCI Core" + + +////////////////////////////////////////////////////////////////// + +static LIST_HEAD(pci_hotplug_slot_list); + +static struct subsystem hotplug_slots_subsys; + +static ssize_t hotplug_slot_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct hotplug_slot *slot=container_of(kobj, + struct hotplug_slot,kobj); + struct hotplug_slot_attribute *attribute = + container_of(attr, struct hotplug_slot_attribute, attr); + return attribute->show ? attribute->show(slot, buf) : 0; +} + +static ssize_t hotplug_slot_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + struct hotplug_slot *slot=container_of(kobj, + struct hotplug_slot,kobj); + struct hotplug_slot_attribute *attribute = + container_of(attr, struct hotplug_slot_attribute, attr); + return attribute->store ? attribute->store(slot, buf, len) : 0; +} + +static struct sysfs_ops hotplug_slot_sysfs_ops = { + .show = hotplug_slot_attr_show, + .store = hotplug_slot_attr_store, +}; + +static struct kobj_type hotplug_slot_ktype = { + .sysfs_ops = &hotplug_slot_sysfs_ops +}; + +static decl_subsys(hotplug_slots, &hotplug_slot_ktype, NULL); + + +/* these strings match up with the values in pci_bus_speed */ +static char *pci_bus_speed_strings[] = { + "33 MHz PCI", /* 0x00 */ + "66 MHz PCI", /* 0x01 */ + "66 MHz PCIX", /* 0x02 */ + "100 MHz PCIX", /* 0x03 */ + "133 MHz PCIX", /* 0x04 */ + NULL, /* 0x05 */ + NULL, /* 0x06 */ + NULL, /* 0x07 */ + NULL, /* 0x08 */ + "66 MHz PCIX 266", /* 0x09 */ + "100 MHz PCIX 266", /* 0x0a */ + "133 MHz PCIX 266", /* 0x0b */ + NULL, /* 0x0c */ + NULL, /* 0x0d */ + NULL, /* 0x0e */ + NULL, /* 0x0f */ + NULL, /* 0x10 */ + "66 MHz PCIX 533", /* 0x11 */ + "100 MHz PCIX 533", /* 0x12 */ + "133 MHz PCIX 533", /* 0x13 */ +}; + +#ifdef CONFIG_HOTPLUG_PCI_CPCI +extern int cpci_hotplug_init(int debug); +extern void cpci_hotplug_exit(void); +#else +static inline int cpci_hotplug_init(int debug) { return 0; } +static inline void cpci_hotplug_exit(void) { } +#endif + +/* Weee, fun with macros... */ +#define GET_STATUS(name,type) \ +static int get_##name (struct hotplug_slot *slot, type *value) \ +{ \ + struct hotplug_slot_ops *ops = slot->ops; \ + int retval = 0; \ + if (try_module_get(ops->owner)) { \ + if (ops->get_##name) \ + retval = ops->get_##name (slot, value); \ + else \ + *value = slot->info->name; \ + module_put(ops->owner); \ + } \ + return retval; \ +} + +GET_STATUS(power_status, u8) +GET_STATUS(attention_status, u8) +GET_STATUS(latch_status, u8) +GET_STATUS(adapter_status, u8) +GET_STATUS(max_bus_speed, enum pci_bus_speed) +GET_STATUS(cur_bus_speed, enum pci_bus_speed) + +static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_power_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); +exit: + return retval; +} + +static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long lpower; + u8 power; + int retval = 0; + + lpower = simple_strtoul (buf, NULL, 10); + power = (u8)(lpower & 0xff); + dbg ("power = %d\n", power); + + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } + switch (power) { + case 0: + if (slot->ops->disable_slot) + retval = slot->ops->disable_slot(slot); + break; + + case 1: + if (slot->ops->enable_slot) + retval = slot->ops->enable_slot(slot); + break; + + default: + err ("Illegal value specified for power\n"); + retval = -EINVAL; + } + module_put(slot->ops->owner); + +exit: + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_power = { + .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = power_read_file, + .store = power_write_file +}; + +static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_attention_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); + +exit: + return retval; +} + +static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long lattention; + u8 attention; + int retval = 0; + + lattention = simple_strtoul (buf, NULL, 10); + attention = (u8)(lattention & 0xff); + dbg (" - attention = %d\n", attention); + + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } + if (slot->ops->set_attention_status) + retval = slot->ops->set_attention_status(slot, attention); + module_put(slot->ops->owner); + +exit: + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_attention = { + .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = attention_read_file, + .store = attention_write_file +}; + +static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_latch_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_latch = { + .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = latch_read_file, +}; + +static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_adapter_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_presence = { + .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = presence_read_file, +}; + +static char *unknown_speed = "Unknown bus speed"; + +static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) +{ + char *speed_string; + int retval; + enum pci_bus_speed value; + + retval = get_max_bus_speed (slot, &value); + if (retval) + goto exit; + + if (value == PCI_SPEED_UNKNOWN) + speed_string = unknown_speed; + else + speed_string = pci_bus_speed_strings[value]; + + retval = sprintf (buf, "%s\n", speed_string); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { + .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = max_bus_speed_read_file, +}; + +static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) +{ + char *speed_string; + int retval; + enum pci_bus_speed value; + + retval = get_cur_bus_speed (slot, &value); + if (retval) + goto exit; + + if (value == PCI_SPEED_UNKNOWN) + speed_string = unknown_speed; + else + speed_string = pci_bus_speed_strings[value]; + + retval = sprintf (buf, "%s\n", speed_string); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { + .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = cur_bus_speed_read_file, +}; + +static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long ltest; + u32 test; + int retval = 0; + + ltest = simple_strtoul (buf, NULL, 10); + test = (u32)(ltest & 0xffffffff); + dbg ("test = %d\n", test); + + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } + if (slot->ops->hardware_test) + retval = slot->ops->hardware_test(slot, test); + module_put(slot->ops->owner); + +exit: + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_test = { + .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .store = test_write_file +}; + +static int has_power_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if ((slot->ops->enable_slot) || + (slot->ops->disable_slot) || + (slot->ops->get_power_status)) + return 0; + return -ENOENT; +} + +static int has_attention_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if ((slot->ops->set_attention_status) || + (slot->ops->get_attention_status)) + return 0; + return -ENOENT; +} + +static int has_latch_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_latch_status) + return 0; + return -ENOENT; +} + +static int has_adapter_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_adapter_status) + return 0; + return -ENOENT; +} + +static int has_max_bus_speed_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_max_bus_speed) + return 0; + return -ENOENT; +} + +static int has_cur_bus_speed_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_cur_bus_speed) + return 0; + return -ENOENT; +} + +static int has_test_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->hardware_test) + return 0; + return -ENOENT; +} + +static int fs_add_slot (struct hotplug_slot *slot) +{ + if (has_power_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); + + if (has_attention_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + + if (has_latch_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + + if (has_adapter_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + + if (has_max_bus_speed_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + + if (has_cur_bus_speed_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + + if (has_test_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); + + return 0; +} + +static void fs_remove_slot (struct hotplug_slot *slot) +{ + if (has_power_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); + + if (has_attention_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + + if (has_latch_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + + if (has_adapter_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + + if (has_max_bus_speed_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + + if (has_cur_bus_speed_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + + if (has_test_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); +} + +static struct hotplug_slot *get_slot_from_name (const char *name) +{ + struct hotplug_slot *slot; + struct list_head *tmp; + + list_for_each (tmp, &pci_hotplug_slot_list) { + slot = list_entry (tmp, struct hotplug_slot, slot_list); + if (strcmp(slot->name, name) == 0) + return slot; + } + return NULL; +} + +/** + * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to register + * + * Registers a hotplug slot with the pci hotplug subsystem, which will allow + * userspace interaction to the slot. + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_register (struct hotplug_slot *slot) +{ + int result; + + if (slot == NULL) + return -ENODEV; + if ((slot->info == NULL) || (slot->ops == NULL)) + return -EINVAL; + + strlcpy(slot->kobj.name, slot->name, KOBJ_NAME_LEN); + kobj_set_kset_s(slot, hotplug_slots_subsys); + + /* this can fail if we have already registered a slot with the same name */ + if (kobject_register(&slot->kobj)) { + err("Unable to register kobject"); + return -EINVAL; + } + + list_add (&slot->slot_list, &pci_hotplug_slot_list); + + result = fs_add_slot (slot); + dbg ("Added slot %s to the list\n", slot->name); + return result; +} + +/** + * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to deregister + * + * The @slot must have been registered with the pci hotplug subsystem + * previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_deregister (struct hotplug_slot *slot) +{ + struct hotplug_slot *temp; + + if (slot == NULL) + return -ENODEV; + + temp = get_slot_from_name (slot->name); + if (temp != slot) { + return -ENODEV; + } + list_del (&slot->slot_list); + + fs_remove_slot (slot); + dbg ("Removed slot %s from the list\n", slot->name); + kobject_unregister(&slot->kobj); + return 0; +} + +/** + * pci_hp_change_slot_info - changes the slot's information structure in the core + * @slot: pointer to the slot whose info has changed + * @info: pointer to the info copy into the slot's info structure + * + * @slot must have been registered with the pci + * hotplug subsystem previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) +{ + if ((slot == NULL) || (info == NULL)) + return -ENODEV; + + /* + * check all fields in the info structure, and update timestamps + * for the files referring to the fields that have now changed. + */ + if ((has_power_file(slot) == 0) && + (slot->info->power_status != info->power_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); + + if ((has_attention_file(slot) == 0) && + (slot->info->attention_status != info->attention_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + + if ((has_latch_file(slot) == 0) && + (slot->info->latch_status != info->latch_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + + if ((has_adapter_file(slot) == 0) && + (slot->info->adapter_status != info->adapter_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + + if ((has_max_bus_speed_file(slot) == 0) && + (slot->info->max_bus_speed != info->max_bus_speed)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + + if ((has_cur_bus_speed_file(slot) == 0) && + (slot->info->cur_bus_speed != info->cur_bus_speed)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + + memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); + + return 0; +} + +static int __init pci_hotplug_init (void) +{ + int result; + + kset_set_kset_s(&hotplug_slots_subsys, pci_bus_type.subsys); + result = subsystem_register(&hotplug_slots_subsys); + if (result) { + err("Register subsys with error %d\n", result); + goto exit; + } + result = cpci_hotplug_init(debug); + if (result) { + err ("cpci_hotplug_init with error %d\n", result); + goto err_subsys; + } + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + goto exit; + +err_subsys: + subsystem_unregister(&hotplug_slots_subsys); +exit: + return result; +} + +static void __exit pci_hotplug_exit (void) +{ + cpci_hotplug_exit(); + subsystem_unregister(&hotplug_slots_subsys); +} + +module_init(pci_hotplug_init); +module_exit(pci_hotplug_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +EXPORT_SYMBOL_GPL(pci_hp_register); +EXPORT_SYMBOL_GPL(pci_hp_deregister); +EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff -urN linux-2.5.70-bk9/drivers/pci/hotplug/pcihp_skeleton.c linux-2.5.70-bk10/drivers/pci/hotplug/pcihp_skeleton.c --- linux-2.5.70-bk9/drivers/pci/hotplug/pcihp_skeleton.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/drivers/pci/hotplug/pcihp_skeleton.c 2003-06-05 04:41:36.000000000 -0700 @@ -0,0 +1,432 @@ +/* + * PCI Hot Plug Controller Skeleton Driver - 0.1 + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver is to be used as a skeleton driver to be show how to interface + * with the pci hotplug core easily. + * + * Send feedback to + * + */ + +#include +#include +#include +#include +#include +#include +#include "pci_hotplug.h" + + +#define SLOT_MAGIC 0x67267322 +struct slot { + u32 magic; + u8 number; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; +}; + +static LIST_HEAD(slot_list); + +#if !defined(CONFIG_HOTPLUG_PCI_SKELETON_MODULE) + #define MY_NAME "pcihp_skeleton" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + + + +/* local variables */ +static int debug; +static int num_slots; + +#define DRIVER_VERSION "0.1" +#define DRIVER_AUTHOR "Greg Kroah-Hartman " +#define DRIVER_DESC "Hot Plug PCI Controller Skeleton Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops skel_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, +}; + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + + +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* + * Fill in code here to enable the specified slot + */ + + return retval; +} + + +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* + * Fill in code here to disable the specified slot + */ + + return retval; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + switch (status) { + case 0: + /* + * Fill in code here to turn light off + */ + break; + + case 1: + default: + /* + * Fill in code here to turn light on + */ + break; + } + + return retval; +} + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + err ("No hardware tests are defined for this driver"); + retval = -ENODEV; + + /* Or you can specify a test if you want to */ + + return retval; +} + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current power status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current attention status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current latch status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current adapter status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +#define SLOT_NAME_SIZE 10 +static void make_slot_name (struct slot *slot) +{ + /* + * Stupid way to make a filename out of the slot name. + * replace this if your hardware provides a better way to name slots. + */ + snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number); +} + +static int init_slots (void) +{ + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *info; + char *name; + int retval = 0; + int i; + + /* + * Create a structure for each slot, and register that slot + * with the pci_hotplug subsystem. + */ + for (i = 0; i < num_slots; ++i) { + slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + memset(slot, 0, sizeof(struct slot)); + + hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) { + kfree (slot); + return -ENOMEM; + } + memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); + slot->hotplug_slot = hotplug_slot; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + kfree (hotplug_slot); + kfree (slot); + return -ENOMEM; + } + memset(info, 0, sizeof (struct hotplug_slot_info)); + hotplug_slot->info = info; + + name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!name) { + kfree (info); + kfree (hotplug_slot); + kfree (slot); + return -ENOMEM; + } + hotplug_slot->name = name; + + slot->magic = SLOT_MAGIC; + slot->number = i; + + hotplug_slot->private = slot; + make_slot_name (slot); + hotplug_slot->ops = &skel_hotplug_slot_ops; + + /* + * Initilize the slot info structure with some known + * good values. + */ + info->power_status = get_skel_power_status(slot); + info->attention_status = get_skel_attention_status(slot); + info->latch_status = get_skel_latch_status(slot); + info->adapter_status = get_skel_adapter_status(slot); + + dbg ("registering slot %d\n", i); + retval = pci_hp_register (slot->hotplug_slot); + if (retval) { + err ("pci_hp_register failed with error %d\n", retval); + kfree (info); + kfree (name); + kfree (hotplug_slot); + kfree (slot); + return retval; + } + + /* add slot to our internal list */ + list_add (&slot->slot_list, &slot_list); + } + + return retval; +} + +static void cleanup_slots (void) +{ + struct list_head *tmp; + struct slot *slot; + + /* + * Unregister all of our slots with the pci_hotplug subsystem, + * and free up all memory that we had allocated. + */ + list_for_each (tmp, &slot_list) { + slot = list_entry (tmp, struct slot, slot_list); + list_del (&slot->slot_list); + pci_hp_deregister (slot->hotplug_slot); + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot->name); + kfree (slot->hotplug_slot); + kfree (slot); + } + + return; +} + +static int __init pcihp_skel_init(void) +{ + int retval; + + /* + * Do specific initialization stuff for your driver here + * Like initilizing your controller hardware (if any) and + * determining the number of slots you have in the system + * right now. + */ + num_slots = 5; + + retval = init_slots(); + if (retval) + return retval; + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + return 0; +} + +static void __exit pcihp_skel_exit(void) +{ + /* + * Clean everything up. + */ + cleanup_slots(); +} + +module_init(pcihp_skel_init); +module_exit(pcihp_skel_exit); + diff -urN linux-2.5.70-bk9/drivers/pci/hotplug.c linux-2.5.70-bk10/drivers/pci/hotplug.c --- linux-2.5.70-bk9/drivers/pci/hotplug.c 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/hotplug.c 2003-06-05 04:41:36.000000000 -0700 @@ -190,9 +190,7 @@ list_del(&dev->bus_list); list_del(&dev->global_list); pci_free_resources(dev); -#ifdef CONFIG_PROC_FS pci_proc_detach_device(dev); -#endif return 0; } EXPORT_SYMBOL(pci_remove_device_safe); @@ -237,10 +235,7 @@ struct pci_bus *b = dev->subordinate; pci_remove_behind_bridge(dev); - -#ifdef CONFIG_PROC_FS pci_proc_detach_bus(b); -#endif list_del(&b->node); kfree(b); @@ -251,10 +246,7 @@ list_del(&dev->bus_list); list_del(&dev->global_list); pci_free_resources(dev); -#ifdef CONFIG_PROC_FS pci_proc_detach_device(dev); -#endif - pci_put_dev(dev); } diff -urN linux-2.5.70-bk9/drivers/pci/pci-driver.c linux-2.5.70-bk10/drivers/pci/pci-driver.c --- linux-2.5.70-bk9/drivers/pci/pci-driver.c 2003-05-26 18:00:44.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/pci-driver.c 2003-06-05 04:41:36.000000000 -0700 @@ -138,10 +138,11 @@ drv = to_pci_driver(dev->driver); pci_dev = to_pci_dev(dev); - if (get_device(dev)) { - error = __pci_device_probe(drv, pci_dev); - put_device(dev); - } + pci_get_dev(pci_dev); + error = __pci_device_probe(drv, pci_dev); + if (error) + pci_put_dev(pci_dev); + return error; } @@ -155,6 +156,7 @@ drv->remove(pci_dev); pci_dev->driver = NULL; } + pci_put_dev(pci_dev); return 0; } @@ -235,7 +237,7 @@ driver_data : 0UL; spin_lock(&pdrv->dynids.lock); - list_add(&pdrv->dynids.list, &dynid->node); + list_add_tail(&pdrv->dynids.list, &dynid->node); spin_unlock(&pdrv->dynids.lock); bus = get_bus(pdrv->driver.bus); @@ -315,6 +317,22 @@ INIT_LIST_HEAD(&dynids->list); } +static void +pci_free_dynids(struct pci_driver *drv) +{ + struct list_head *pos, *n; + struct dynid *dynid; + + spin_lock(&drv->dynids.lock); + list_for_each_safe(pos, n, &drv->dynids.list) { + dynid = list_entry(pos, struct dynid, node); + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + + /** * pci_register_driver - register a new pci driver * @drv: the driver structure to register @@ -363,6 +381,7 @@ pci_unregister_driver(struct pci_driver *drv) { driver_unregister(&drv->driver); + pci_free_dynids(drv); } static struct pci_driver pci_compat_driver = { diff -urN linux-2.5.70-bk9/drivers/pci/pci.c linux-2.5.70-bk10/drivers/pci/pci.c --- linux-2.5.70-bk9/drivers/pci/pci.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/pci.c 2003-06-05 04:41:36.000000000 -0700 @@ -714,9 +714,9 @@ static int __devinit pci_init(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_fixup_device(PCI_FIXUP_FINAL, dev); } return 0; diff -urN linux-2.5.70-bk9/drivers/pci/pci.h linux-2.5.70-bk10/drivers/pci/pci.h --- linux-2.5.70-bk9/drivers/pci/pci.h 2003-05-26 18:00:37.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/pci.h 2003-06-05 04:41:36.000000000 -0700 @@ -3,3 +3,59 @@ extern int pci_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern void pci_create_sysfs_dev_files(struct pci_dev *pdev); +extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, + unsigned long size, unsigned long align, + unsigned long min, unsigned int type_mask, + void (*alignf)(void *, struct resource *, + unsigned long, unsigned long), + void *alignf_data); +/* PCI /proc functions */ +#ifdef CONFIG_PROC_FS +extern int pci_proc_attach_device(struct pci_dev *dev); +extern int pci_proc_detach_device(struct pci_dev *dev); +extern int pci_proc_attach_bus(struct pci_bus *bus); +extern int pci_proc_detach_bus(struct pci_bus *bus); +#else +static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; } +static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; } +static inline int pci_proc_attach_bus(struct pci_bus *bus) { return 0; } +static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } +#endif + +/* Functions for PCI Hotplug drivers to use */ +extern struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); +extern unsigned int pci_do_scan_bus(struct pci_bus *bus); +extern void pci_remove_bus_device(struct pci_dev *dev); +extern int pci_remove_device_safe(struct pci_dev *dev); +extern unsigned char pci_max_busnr(void); +extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); +extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); +extern struct pci_bus *pci_find_bus(unsigned char busnr); + +struct pci_dev_wrapped { + struct pci_dev *dev; + void *data; +}; + +struct pci_bus_wrapped { + struct pci_bus *bus; + void *data; +}; + +struct pci_visit { + int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + int (* post_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + + int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* post_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); +}; + +extern int pci_visit_dev(struct pci_visit *fn, + struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_parent); diff -urN linux-2.5.70-bk9/drivers/pci/pool.c linux-2.5.70-bk10/drivers/pci/pool.c --- linux-2.5.70-bk9/drivers/pci/pool.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/pool.c 2003-06-05 04:41:36.000000000 -0700 @@ -31,7 +31,7 @@ #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) #define POOL_POISON_BYTE 0xa7 -DECLARE_MUTEX (pools_lock); +static DECLARE_MUTEX (pools_lock); static ssize_t show_pools (struct device *dev, char *buf) diff -urN linux-2.5.70-bk9/drivers/pci/probe.c linux-2.5.70-bk10/drivers/pci/probe.c --- linux-2.5.70-bk9/drivers/pci/probe.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/probe.c 2003-06-05 04:41:36.000000000 -0700 @@ -396,7 +396,7 @@ * Returns 0 on success and -1 if unknown type of device (not normal, bridge * or CardBus). */ -int pci_setup_device(struct pci_dev * dev) +static int pci_setup_device(struct pci_dev * dev) { u32 class; @@ -642,7 +642,7 @@ return 0; } -struct pci_bus * __devinit pci_alloc_primary_bus_parented(struct device *parent, int bus) +static struct pci_bus * __devinit pci_alloc_primary_bus_parented(struct device *parent, int bus) { struct pci_bus *b; @@ -693,7 +693,6 @@ EXPORT_SYMBOL(pci_root_buses); #ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pci_setup_device); EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_do_scan_bus); EXPORT_SYMBOL(pci_scan_slot); diff -urN linux-2.5.70-bk9/drivers/pci/proc.c linux-2.5.70-bk10/drivers/pci/proc.c --- linux-2.5.70-bk9/drivers/pci/proc.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/proc.c 2003-06-05 04:41:36.000000000 -0700 @@ -581,13 +581,13 @@ { if (pci_present()) { struct proc_dir_entry *entry; - struct pci_dev *dev; + struct pci_dev *dev = NULL; proc_bus_pci_dir = proc_mkdir("pci", proc_bus); entry = create_proc_entry("devices", 0, proc_bus_pci_dir); if (entry) entry->proc_fops = &proc_bus_pci_dev_operations; proc_initialized = 1; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_proc_attach_device(dev); } legacy_proc_init(); @@ -599,7 +599,6 @@ #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_proc_attach_device); -EXPORT_SYMBOL(pci_proc_detach_device); EXPORT_SYMBOL(pci_proc_attach_bus); EXPORT_SYMBOL(pci_proc_detach_bus); EXPORT_SYMBOL(proc_bus_pci_dir); diff -urN linux-2.5.70-bk9/drivers/pci/search.c linux-2.5.70-bk10/drivers/pci/search.c --- linux-2.5.70-bk9/drivers/pci/search.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/search.c 2003-06-05 04:41:36.000000000 -0700 @@ -55,9 +55,9 @@ struct pci_dev * pci_find_slot(unsigned int bus, unsigned int devfn) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->bus->number == bus && dev->devfn == devfn) return dev; } diff -urN linux-2.5.70-bk9/drivers/pci/setup-irq.c linux-2.5.70-bk10/drivers/pci/setup-irq.c --- linux-2.5.70-bk9/drivers/pci/setup-irq.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/setup-irq.c 2003-06-05 04:41:36.000000000 -0700 @@ -64,8 +64,8 @@ pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), int (*map_irq)(struct pci_dev *, u8, u8)) { - struct pci_dev *dev; - pci_for_each_dev(dev) { + struct pci_dev *dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pdev_fixup_irq(dev, swizzle, map_irq); } } diff -urN linux-2.5.70-bk9/drivers/pci/setup-res.c linux-2.5.70-bk10/drivers/pci/setup-res.c --- linux-2.5.70-bk9/drivers/pci/setup-res.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pci/setup-res.c 2003-06-05 04:41:36.000000000 -0700 @@ -23,7 +23,7 @@ #include #include #include - +#include "pci.h" #define DEBUG_CONFIG 0 #if DEBUG_CONFIG diff -urN linux-2.5.70-bk9/drivers/pnp/pnpbios/proc.c linux-2.5.70-bk10/drivers/pnp/pnpbios/proc.c --- linux-2.5.70-bk9/drivers/pnp/pnpbios/proc.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pnp/pnpbios/proc.c 2003-06-05 04:41:36.000000000 -0700 @@ -29,6 +29,8 @@ #include #include +#include + static struct proc_dir_entry *proc_pnp = NULL; static struct proc_dir_entry *proc_pnp_boot = NULL; @@ -178,18 +180,31 @@ struct pnp_bios_node *node; int boot = (long)data >> 8; u8 nodenum = (long)data; + int ret = count; node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); - if (!node) return -ENOMEM; - if ( pnp_bios_get_dev_node(&nodenum, boot, node) ) - return -EIO; - if (count != node->size - sizeof(struct pnp_bios_node)) - return -EINVAL; - memcpy(node->data, buf, count); - if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) - return -EINVAL; + if (!node) + return -ENOMEM; + if (pnp_bios_get_dev_node(&nodenum, boot, node)) { + ret = -EIO; + goto out; + } + if (count != node->size - sizeof(struct pnp_bios_node)) { + ret = -EINVAL; + goto out; + } + if (copy_from_user(node->data, buf, count)) { + ret = -EFAULT; + goto out; + } + if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) { + ret = -EINVAL; + goto out; + } + ret = count; +out: kfree(node); - return count; + return ret; } int pnpbios_interface_attach_device(struct pnp_bios_node * node) diff -urN linux-2.5.70-bk9/drivers/pnp/resource.c linux-2.5.70-bk10/drivers/pnp/resource.c --- linux-2.5.70-bk9/drivers/pnp/resource.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/drivers/pnp/resource.c 2003-06-05 04:41:36.000000000 -0700 @@ -455,8 +455,8 @@ #ifdef CONFIG_PCI /* check if the resource is being used by a pci device */ if (!pnp_skip_pci_scan) { - struct pci_dev * pci; - pci_for_each_dev(pci) { + struct pci_dev * pci = NULL; + while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { if (pci->irq == *irq) return CONFLICT_TYPE_PCI; } diff -urN linux-2.5.70-bk9/drivers/video/pm2fb.c linux-2.5.70-bk10/drivers/video/pm2fb.c --- linux-2.5.70-bk9/drivers/video/pm2fb.c 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk10/drivers/video/pm2fb.c 2003-06-05 04:41:37.000000000 -0700 @@ -1178,7 +1178,7 @@ static int __init pm2pci_detect(struct pm2fb_info* p) { struct pm2pci_par* pci=&p->board_par.pci; - struct pci_dev* dev; + struct pci_dev* dev = NULL; int i; unsigned char* m; #ifdef __sparc__ @@ -1192,7 +1192,7 @@ } DPRINTK("scanning PCI bus for known chipsets...\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for (i = 0; pm2pci_cards[i].vendor; i++) if (pm2pci_cards[i].vendor == dev->vendor && pm2pci_cards[i].device == dev->device) { diff -urN linux-2.5.70-bk9/drivers/video/sa1100fb.c linux-2.5.70-bk10/drivers/video/sa1100fb.c --- linux-2.5.70-bk9/drivers/video/sa1100fb.c 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk10/drivers/video/sa1100fb.c 2003-06-05 04:41:37.000000000 -0700 @@ -1753,25 +1753,7 @@ return fbi; } -static struct device_driver sa1100fb_driver = { - .name = "sa1100fb", - .bus = &system_bus_type, - .suspend = sa1100fb_suspend, - .resume = sa1100fb_resume, -}; - -static struct sys_device sa1100fb_dev = { - .name = "LCD", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA11x0 [LCD]", - .bus_id = "b0100000", - .driver = &sa1100fb_driver, - }, -}; - -int __init sa1100fb_init(void) +static int __init sa1100fb_probe(struct device *dev) { struct sa1100fb_info *fbi; int ret; @@ -1779,16 +1761,11 @@ if (!request_mem_region(0xb0100000, 0x10000, "LCD")) return -EBUSY; - driver_register(&sa1100fb_driver); - sys_device_register(&sa1100fb_dev); - fbi = sa1100fb_init_fbinfo(); ret = -ENOMEM; if (!fbi) goto failed; - dev_set_drvdata(&sa1100fb_dev.dev, fbi); - /* Initialize video memory */ ret = sa1100fb_map_video_memory(fbi); if (ret) @@ -1822,6 +1799,8 @@ */ sa1100fb_check_var(&fbi->fb.var, &fbi->fb); + dev_set_drvdata(dev, fbi); + ret = register_framebuffer(&fbi->fb); if (ret < 0) goto failed; @@ -1839,14 +1818,26 @@ return 0; failed: - sys_device_unregister(&sa1100fb_dev); - driver_unregister(&sa1100fb_driver); + dev_set_drvdata(dev, NULL); if (fbi) kfree(fbi); release_mem_region(0xb0100000, 0x10000); return ret; } +static struct device_driver sa1100fb_driver = { + .name = "sa11x0-fb", + .bus = &platform_bus_type, + .probe = sa1100fb_probe, + .suspend = sa1100fb_suspend, + .resume = sa1100fb_resume, +}; + +int __init sa1100fb_init(void) +{ + return driver_register(&sa1100fb_driver); +} + int __init sa1100fb_setup(char *options) { #if 0 diff -urN linux-2.5.70-bk9/drivers/video/sis/sis_main.c linux-2.5.70-bk10/drivers/video/sis/sis_main.c --- linux-2.5.70-bk9/drivers/video/sis/sis_main.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/drivers/video/sis/sis_main.c 2003-06-05 04:41:37.000000000 -0700 @@ -134,15 +134,9 @@ if (!init) { init = TRUE; - pci_for_each_dev(pdev) { - DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n", - pdev->device, ivideo.chip_id); - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == ivideo.chip_id)) { - valid_pdev = TRUE; - break; - } - } + pdev = pci_find_device(PCI_VENDOR_ID_SI, ivideo.chip_id, pdev); + if (pdev) + valid_pdev = TRUE; } if (!valid_pdev) { @@ -192,15 +186,9 @@ break; } - pci_for_each_dev(pdev) { - DPRINTK("Current: 0x%x, target: 0x%x\n", - pdev->device, ivideo.chip_id); - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == nbridge_id)) { - valid_pdev = TRUE; - break; - } - } + pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); + if (pdev) + valid_pdev = TRUE; } if (!valid_pdev) { @@ -2117,40 +2105,36 @@ } else { /* 540, 630, 730 */ - pci_for_each_dev(pdev) { - - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == nbridge_id)) { - pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); - pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; - ivideo.video_size = (unsigned int)(1 << (pci_data+21)); - pdev_valid = 1; - - reg = SIS_DATA_BUS_64 << 6; - switch (pci_data) { - case BRI_DRAM_SIZE_2MB: - reg |= SIS_DRAM_SIZE_2MB; - break; - case BRI_DRAM_SIZE_4MB: - reg |= SIS_DRAM_SIZE_4MB; - break; - case BRI_DRAM_SIZE_8MB: - reg |= SIS_DRAM_SIZE_8MB; - break; - case BRI_DRAM_SIZE_16MB: - reg |= SIS_DRAM_SIZE_16MB; - break; - case BRI_DRAM_SIZE_32MB: - reg |= SIS_DRAM_SIZE_32MB; - break; - case BRI_DRAM_SIZE_64MB: - reg |= SIS_DRAM_SIZE_64MB; - break; - } - outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); + pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); + if (pdev) { + pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); + pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; + ivideo.video_size = (unsigned int)(1 << (pci_data+21)); + pdev_valid = 1; + + reg = SIS_DATA_BUS_64 << 6; + switch (pci_data) { + case BRI_DRAM_SIZE_2MB: + reg |= SIS_DRAM_SIZE_2MB; break; - } - } + case BRI_DRAM_SIZE_4MB: + reg |= SIS_DRAM_SIZE_4MB; + break; + case BRI_DRAM_SIZE_8MB: + reg |= SIS_DRAM_SIZE_8MB; + break; + case BRI_DRAM_SIZE_16MB: + reg |= SIS_DRAM_SIZE_16MB; + break; + case BRI_DRAM_SIZE_32MB: + reg |= SIS_DRAM_SIZE_32MB; + break; + case BRI_DRAM_SIZE_64MB: + reg |= SIS_DRAM_SIZE_64MB; + break; + } + outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); + } if (!pdev_valid) return -1; } @@ -2334,12 +2318,10 @@ #ifdef LINUXBIOS - pci_for_each_dev(pdev) { - - if ( (pdev->vendor == PCI_VENDOR_ID_SI) - && ( (pdev->device == PCI_DEVICE_ID_SI_550) || - (pdev->device == PCI_DEVICE_ID_SI_650) || - (pdev->device == PCI_DEVICE_ID_SI_740))) { + while ((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev)) != NULL) { + if ((pdev->device == PCI_DEVICE_ID_SI_550) || + (pdev->device == PCI_DEVICE_ID_SI_650) || + (pdev->device == PCI_DEVICE_ID_SI_740)) { pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; @@ -2408,11 +2390,7 @@ "now reading from PCI config\n"); pdev_valid = 0; - pci_for_each_dev(pdev) { - - if ( (pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == PCI_DEVICE_ID_SI_550) ) { - + while ((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550, pdev)) != NULL) { pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; @@ -2437,7 +2415,6 @@ return -1; } outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); - } } if (!pdev_valid) { printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n"); @@ -3785,7 +3762,7 @@ memset(&sis_disp, 0, sizeof(sis_disp)); #endif - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { for (b = sisdev_list; b->vendor; b++) { if ((b->vendor == pdev->vendor) && (b->device == pdev->device)) { diff -urN linux-2.5.70-bk9/fs/aio.c linux-2.5.70-bk10/fs/aio.c --- linux-2.5.70-bk9/fs/aio.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/fs/aio.c 2003-06-05 04:41:37.000000000 -0700 @@ -252,7 +252,7 @@ return ctx; out_cleanup: - atomic_sub(ctx->max_reqs, &aio_nr); /* undone by __put_ioctx */ + atomic_sub(ctx->max_reqs, &aio_nr); ctx->max_reqs = 0; /* prevent __put_ioctx from sub'ing aio_nr */ __put_ioctx(ctx); return ERR_PTR(-EAGAIN); @@ -405,9 +405,6 @@ list_add(&req->ki_list, &ctx->active_reqs); get_ioctx(ctx); ctx->reqs_active++; - req->ki_user_obj = NULL; - req->ki_ctx = ctx; - req->ki_users = 1; okay = 1; } kunmap_atomic(ring, KM_USER0); @@ -949,7 +946,7 @@ goto out; ret = -EINVAL; - if (unlikely(ctx || !nr_events || (int)nr_events < 0)) { + if (unlikely(ctx || (int)nr_events <= 0)) { pr_debug("EINVAL: io_setup: ctx or nr_events > max\n"); goto out; } @@ -984,9 +981,7 @@ return -EINVAL; } -int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb *user_iocb, - struct iocb *iocb)); -int io_submit_one(struct kioctx *ctx, struct iocb *user_iocb, +int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, struct iocb *iocb) { struct kiocb *req; @@ -1098,7 +1093,7 @@ * fail with -ENOSYS if not implemented. */ asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, - struct iocb **iocbpp) + struct iocb __user **iocbpp) { struct kioctx *ctx; long ret = 0; @@ -1116,8 +1111,13 @@ return -EINVAL; } + /* + * AKPM: should this return a partial result if some of the IOs were + * successfully submitted? + */ for (i=0; iprivate_lock); if (page_has_buffers(page)) { struct buffer_head *head = page_buffers(page); diff -urN linux-2.5.70-bk9/fs/devfs/base.c linux-2.5.70-bk10/fs/devfs/base.c --- linux-2.5.70-bk9/fs/devfs/base.c 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk10/fs/devfs/base.c 2003-06-05 04:41:37.000000000 -0700 @@ -1710,6 +1710,13 @@ if (n < 64 && buf[0]) { devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); + if (!de) { + printk(KERN_ERR "%s: %s not found, cannot remove\n", + __FUNCTION__, buf); + dump_stack(); + return; + } + write_lock(&de->parent->u.dir.lock); _devfs_unregister(de->parent, de); devfs_put(de); diff -urN linux-2.5.70-bk9/fs/hugetlbfs/inode.c linux-2.5.70-bk10/fs/hugetlbfs/inode.c --- linux-2.5.70-bk9/fs/hugetlbfs/inode.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/fs/hugetlbfs/inode.c 2003-06-05 04:41:37.000000000 -0700 @@ -48,9 +48,6 @@ loff_t len; int ret; - if (!capable(CAP_IPC_LOCK)) - return -EPERM; - if (vma->vm_start & ~HPAGE_MASK) return -EINVAL; @@ -231,6 +228,7 @@ spin_unlock(&inode_lock); if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); + clear_inode(inode); destroy_inode(inode); } @@ -317,7 +315,6 @@ struct inode *inode = dentry->d_inode; int error; unsigned int ia_valid = attr->ia_valid; - unsigned long dn_mask; BUG_ON(!inode); @@ -335,26 +332,21 @@ if (error) goto out; attr->ia_valid &= ~ATTR_SIZE; - error = inode_setattr(inode, attr); } - if (error) - goto out; - dn_mask = setattr_mask(ia_valid); - if (dn_mask) - dnotify_parent(dentry, dn_mask); + error = inode_setattr(inode, attr); out: return error; } -static struct inode *hugetlbfs_get_inode(struct super_block *sb, - int mode, dev_t dev) +static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, + gid_t gid, int mode, dev_t dev) { struct inode * inode = new_inode(sb); if (inode) { inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inode->i_uid = uid; + inode->i_gid = gid; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_rdev = NODEV; @@ -391,7 +383,8 @@ static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct inode * inode = hugetlbfs_get_inode(dir->i_sb, mode, dev); + struct inode * inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + current->fsgid, mode, dev); int error = -ENOSPC; if (inode) { @@ -421,7 +414,8 @@ struct inode *inode; int error = -ENOSPC; - inode = hugetlbfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + current->fsgid, S_IFLNK|S_IRWXUGO, 0); if (inode) { int l = strlen(symname)+1; error = page_symlink(inode, symname, l); @@ -478,16 +472,68 @@ }; static int -hugetlbfs_fill_super(struct super_block * sb, void * data, int silent) +hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) +{ + char *opt, *value; + int ret = 0; + + if (!options) + goto out; + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + value = strchr(opt, '='); + if (!value || !*value) { + ret = -EINVAL; + goto out; + } else { + *value++ = '\0'; + } + + if (!strcmp(opt, "uid")) + pconfig->uid = simple_strtoul(value, &value, 0); + else if (!strcmp(opt, "gid")) + pconfig->gid = simple_strtoul(value, &value, 0); + else if (!strcmp(opt, "mode")) + pconfig->mode = simple_strtoul(value,&value,0) & 0777U; + else { + ret = -EINVAL; + goto out; + } + + if (*value) { + ret = -EINVAL; + goto out; + } + } + return 0; +out: + pconfig->uid = current->fsuid; + pconfig->gid = current->fsgid; + pconfig->mode = 0755; + return ret; +} + +static int +hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode * inode; struct dentry * root; + int ret; + struct hugetlbfs_config config; + ret = hugetlbfs_parse_options(data, &config); + if (ret) { + printk("hugetlbfs: invalid mount options: %s.\n", data); + return ret; + } sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; - inode = hugetlbfs_get_inode(sb, S_IFDIR | 0755, 0); + inode = hugetlbfs_get_inode(sb, config.uid, config.gid, + S_IFDIR | config.mode, 0); if (!inode) return -ENOMEM; @@ -548,7 +594,8 @@ goto out_dentry; error = -ENOSPC; - inode = hugetlbfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, + current->fsgid, S_IFREG | S_IRWXUGO, 0); if (!inode) goto out_file; diff -urN linux-2.5.70-bk9/fs/jbd/journal.c linux-2.5.70-bk10/fs/jbd/journal.c --- linux-2.5.70-bk9/fs/jbd/journal.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/fs/jbd/journal.c 2003-06-05 04:41:37.000000000 -0700 @@ -916,7 +916,7 @@ __brelse(bh); } - fsync_bdev(journal->j_dev); + sync_blockdev(journal->j_dev); jbd_debug(1, "JBD: journal cleared.\n"); /* OK, fill in the initial static fields in the new superblock */ diff -urN linux-2.5.70-bk9/fs/reiserfs/file.c linux-2.5.70-bk10/fs/reiserfs/file.c --- linux-2.5.70-bk9/fs/reiserfs/file.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk10/fs/reiserfs/file.c 2003-06-05 04:41:37.000000000 -0700 @@ -736,6 +736,7 @@ struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. __u32 * item=0; // pointer to item we are going to deal with + int item_pos=-1; /* Position in indirect item */ if ( num_pages < 1 ) { @@ -807,7 +808,6 @@ reiserfs_write_lock(inode->i_sb); // We need that for at least search_by_key() for ( i = 0; i < num_pages ; i++ ) { - int item_pos=-1; /* Position in indirect item */ head = page_buffers(prepared_pages[i]); /* For each buffer in the page */ diff -urN linux-2.5.70-bk9/fs/reiserfs/inode.c linux-2.5.70-bk10/fs/reiserfs/inode.c --- linux-2.5.70-bk9/fs/reiserfs/inode.c 2003-05-26 18:00:28.000000000 -0700 +++ linux-2.5.70-bk10/fs/reiserfs/inode.c 2003-06-05 04:41:37.000000000 -0700 @@ -2109,11 +2109,13 @@ * someone else could have locked them and sent them down the * pipe without locking the page */ + bh = head ; do { if (!buffer_uptodate(bh)) { partial = 1; break; } + bh = bh->b_this_page; } while(bh != head); if (!partial) SetPageUptodate(page); diff -urN linux-2.5.70-bk9/fs/reiserfs/journal.c linux-2.5.70-bk10/fs/reiserfs/journal.c --- linux-2.5.70-bk9/fs/reiserfs/journal.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/fs/reiserfs/journal.c 2003-06-05 04:41:37.000000000 -0700 @@ -1368,10 +1368,10 @@ /* compares description block with commit block. returns 1 if they differ, 0 if they are the same */ static int journal_compare_desc_commit(struct super_block *p_s_sb, struct reiserfs_journal_desc *desc, struct reiserfs_journal_commit *commit) { - if (le32_to_cpu(commit->j_trans_id) != le32_to_cpu(desc->j_trans_id) || - le32_to_cpu(commit->j_len) != le32_to_cpu(desc->j_len) || - le32_to_cpu(commit->j_len) > SB_JOURNAL_TRANS_MAX(p_s_sb) || - le32_to_cpu(commit->j_len) <= 0 + if (get_commit_trans_id (commit) != get_desc_trans_id (desc) || + get_commit_trans_len (commit) != get_desc_trans_len (desc) || + get_commit_trans_len (commit) > SB_JOURNAL_TRANS_MAX(p_s_sb) || + get_commit_trans_len (commit) <= 0 ) { return 1 ; } @@ -1391,18 +1391,18 @@ return 0 ; desc = (struct reiserfs_journal_desc *)d_bh->b_data ; - if (le32_to_cpu(desc->j_len) > 0 && !memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8)) { - if (oldest_invalid_trans_id && *oldest_invalid_trans_id && le32_to_cpu(desc->j_trans_id) > *oldest_invalid_trans_id) { + if (get_desc_trans_len(desc) > 0 && !memcmp(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8)) { + if (oldest_invalid_trans_id && *oldest_invalid_trans_id && get_desc_trans_id(desc) > *oldest_invalid_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-986: transaction " "is valid returning because trans_id %d is greater than " - "oldest_invalid %lu\n", le32_to_cpu(desc->j_trans_id), + "oldest_invalid %lu\n", get_desc_trans_id(desc), *oldest_invalid_trans_id); return 0 ; } - if (newest_mount_id && *newest_mount_id > le32_to_cpu(desc->j_mount_id)) { + if (newest_mount_id && *newest_mount_id > get_desc_mount_id (desc)) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1087: transaction " "is valid returning because mount_id %d is less than " - "newest_mount_id %lu\n", desc->j_mount_id, + "newest_mount_id %lu\n", get_desc_mount_id (desc), *newest_mount_id) ; return -1 ; } @@ -1410,7 +1410,7 @@ /* ok, we have a journal description block, lets see if the transaction was valid */ c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - ((offset + le32_to_cpu(desc->j_len) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; + ((offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; if (!c_bh) return 0 ; commit = (struct reiserfs_journal_commit *)c_bh->b_data ; @@ -1419,21 +1419,21 @@ "journal_transaction_is_valid, commit offset %ld had bad " "time %d or length %d\n", c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(commit->j_trans_id), - le32_to_cpu(commit->j_len)); + get_commit_trans_id (commit), + get_commit_trans_len(commit)); brelse(c_bh) ; if (oldest_invalid_trans_id) - *oldest_invalid_trans_id = le32_to_cpu(desc->j_trans_id) ; + *oldest_invalid_trans_id = get_desc_trans_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1004: " "transaction_is_valid setting oldest invalid trans_id " - "to %d\n", le32_to_cpu(desc->j_trans_id)) ; + "to %d\n", get_desc_trans_id(desc)) ; return -1; } brelse(c_bh) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1006: found valid " "transaction start offset %lu, len %d id %d\n", d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_trans_id)) ; + get_desc_trans_len(desc), get_desc_trans_id(desc)) ; return 1 ; } else { return 0 ; @@ -1463,6 +1463,7 @@ struct buffer_head **real_blocks = NULL ; unsigned long trans_offset ; int i; + int trans_half; d_bh = journal_bread(p_s_sb, cur_dblock) ; if (!d_bh) @@ -1472,24 +1473,24 @@ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: " "journal_read_transaction, offset %lu, len %d mount_id %d\n", d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_mount_id)) ; - if (le32_to_cpu(desc->j_trans_id) < oldest_trans_id) { + get_desc_trans_len(desc), get_desc_mount_id(desc)) ; + if (get_desc_trans_id(desc) < oldest_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: " "journal_read_trans skipping because %lu is too old\n", cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ; brelse(d_bh) ; return 1 ; } - if (le32_to_cpu(desc->j_mount_id) != newest_mount_id) { + if (get_desc_mount_id(desc) != newest_mount_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: " "journal_read_trans skipping because %d is != " - "newest_mount_id %lu\n", le32_to_cpu(desc->j_mount_id), + "newest_mount_id %lu\n", get_desc_mount_id(desc), newest_mount_id) ; brelse(d_bh) ; return 1 ; } c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - ((trans_offset + le32_to_cpu(desc->j_len) + 1) % + ((trans_offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; if (!c_bh) { brelse(d_bh) ; @@ -1500,30 +1501,31 @@ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal_read_transaction, " "commit offset %ld had bad time %d or length %d\n", c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(commit->j_trans_id), le32_to_cpu(commit->j_len)); + get_commit_trans_id(commit), get_commit_trans_len(commit)); brelse(c_bh) ; brelse(d_bh) ; return 1; } - trans_id = le32_to_cpu(desc->j_trans_id) ; + trans_id = get_desc_trans_id(desc) ; /* now we know we've got a good transaction, and it was inside the valid time ranges */ - log_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; - real_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; + log_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; + real_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; if (!log_blocks || !real_blocks) { brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_warning("journal-1169: kmalloc failed, unable to mount FS\n") ; return -1 ; } /* get all the buffer heads */ - for(i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + trans_half = journal_trans_half (p_s_sb->s_blocksize) ; + for(i = 0 ; i < get_desc_trans_len(desc) ; i++) { log_blocks[i] = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)); - if (i < JOURNAL_TRANS_HALF) { + if (i < trans_half) { real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ; } else { - real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF])) ; + real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - trans_half])) ; } /* make sure we don't try to replay onto log or reserved area */ if (is_block_in_log_or_reserved_area(p_s_sb, real_blocks[i]->b_blocknr)) { @@ -1532,23 +1534,23 @@ brelse_array(real_blocks, i) ; brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } } /* read in the log blocks, memcpy to the corresponding real block */ - ll_rw_block(READ, le32_to_cpu(desc->j_len), log_blocks) ; - for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + ll_rw_block(READ, get_desc_trans_len(desc), log_blocks) ; + for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { wait_on_buffer(log_blocks[i]) ; if (!buffer_uptodate(log_blocks[i])) { reiserfs_warning("journal-1212: REPLAY FAILURE fsck required! buffer write failed\n") ; - brelse_array(log_blocks + i, le32_to_cpu(desc->j_len) - i) ; - brelse_array(real_blocks, le32_to_cpu(desc->j_len)) ; + brelse_array(log_blocks + i, get_desc_trans_len(desc) - i) ; + brelse_array(real_blocks, get_desc_trans_len(desc)) ; brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ; @@ -1556,24 +1558,24 @@ brelse(log_blocks[i]) ; } /* flush out the real blocks */ - for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { set_buffer_dirty(real_blocks[i]) ; ll_rw_block(WRITE, 1, real_blocks + i) ; } - for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { wait_on_buffer(real_blocks[i]) ; if (!buffer_uptodate(real_blocks[i])) { reiserfs_warning("journal-1226: REPLAY FAILURE, fsck required! buffer write failed\n") ; - brelse_array(real_blocks + i, le32_to_cpu(desc->j_len) - i) ; + brelse_array(real_blocks + i, get_desc_trans_len(desc) - i) ; brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } brelse(real_blocks[i]) ; } - cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ; + cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + get_desc_trans_len(desc) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal " "start to offset %ld\n", cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ; @@ -1716,28 +1718,28 @@ if (ret == 1) { desc = (struct reiserfs_journal_desc *)d_bh->b_data ; if (oldest_start == 0) { /* init all oldest_ values */ - oldest_trans_id = le32_to_cpu(desc->j_trans_id) ; + oldest_trans_id = get_desc_trans_id(desc) ; oldest_start = d_bh->b_blocknr ; - newest_mount_id = le32_to_cpu(desc->j_mount_id) ; + newest_mount_id = get_desc_mount_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1179: Setting " "oldest_start to offset %lu, trans_id %lu\n", oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), oldest_trans_id) ; - } else if (oldest_trans_id > le32_to_cpu(desc->j_trans_id)) { + } else if (oldest_trans_id > get_desc_trans_id(desc)) { /* one we just read was older */ - oldest_trans_id = le32_to_cpu(desc->j_trans_id) ; + oldest_trans_id = get_desc_trans_id(desc) ; oldest_start = d_bh->b_blocknr ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1180: Resetting " "oldest_start to offset %lu, trans_id %lu\n", oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), oldest_trans_id) ; } - if (newest_mount_id < le32_to_cpu(desc->j_mount_id)) { - newest_mount_id = le32_to_cpu(desc->j_mount_id) ; + if (newest_mount_id < get_desc_mount_id(desc)) { + newest_mount_id = get_desc_mount_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " - "newest_mount_id to %d\n", le32_to_cpu(desc->j_mount_id)); + "newest_mount_id to %d\n", get_desc_mount_id(desc)); } - cur_dblock += le32_to_cpu(desc->j_len) + 2 ; + cur_dblock += get_desc_trans_len(desc) + 2 ; } else { cur_dblock++ ; } @@ -1964,13 +1966,6 @@ struct reiserfs_journal *journal; char b[BDEVNAME_SIZE]; - if (sizeof(struct reiserfs_journal_commit) != 4096 || - sizeof(struct reiserfs_journal_desc) != 4096) { - printk("journal-1249: commit or desc struct not 4096 %Zd %Zd\n", sizeof(struct reiserfs_journal_commit), - sizeof(struct reiserfs_journal_desc)) ; - return 1 ; - } - journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof (struct reiserfs_journal)) ; if (!journal) { printk("journal-1256: unable to get memory for journal structure\n") ; @@ -1989,6 +1984,16 @@ SB_BMAP_NR(p_s_sb) + 1 : REISERFS_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + 2); + /* Sanity check to see is the standard journal fitting withing first bitmap + (actual for small blocksizes) */ + if ( !SB_ONDISK_JOURNAL_DEVICE( p_s_sb ) && + (SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb) > p_s_sb->s_blocksize * 8) ) { + printk("journal-1393: journal does not fit for area addressed by first of bitmap blocks. " + "It starts at %u and its size is %u. Block size %ld\n", + SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb), SB_ONDISK_JOURNAL_SIZE(p_s_sb), p_s_sb->s_blocksize) ; + goto free_and_return; + } + if( journal_init_dev( p_s_sb, journal, j_dev_name ) != 0 ) { printk( "sh-462: unable to initialize jornal device\n"); goto free_and_return; @@ -2105,6 +2110,7 @@ SB_JOURNAL(p_s_sb)->j_cnode_free = SB_JOURNAL(p_s_sb)->j_cnode_free_list ? num_cnodes : 0 ; SB_JOURNAL(p_s_sb)->j_cnode_used = 0 ; SB_JOURNAL(p_s_sb)->j_must_wait = 0 ; + init_journal_hash(p_s_sb) ; SB_JOURNAL_LIST(p_s_sb)[0].j_list_bitmap = get_list_bitmap(p_s_sb, SB_JOURNAL_LIST(p_s_sb)) ; if (!(SB_JOURNAL_LIST(p_s_sb)[0].j_list_bitmap)) { @@ -2882,6 +2888,7 @@ int commit_now = flags & COMMIT_NOW ; int wait_on_commit = flags & WAIT ; struct reiserfs_super_block *rs ; + int trans_half ; if (reiserfs_dont_log(th->t_super)) { return 0 ; @@ -2929,16 +2936,16 @@ d_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start) ; set_buffer_uptodate(d_bh) ; desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ; - memset(desc, 0, sizeof(struct reiserfs_journal_desc)) ; - memcpy(desc->j_magic, JOURNAL_DESC_MAGIC, 8) ; - desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ; + memset(d_bh->b_data, 0, d_bh->b_size) ; + memcpy(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8) ; + set_desc_trans_id(desc, SB_JOURNAL(p_s_sb)->j_trans_id) ; /* setup commit block. Don't write (keep it clean too) this one until after everyone else is written */ c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; commit = (struct reiserfs_journal_commit *)c_bh->b_data ; - memset(commit, 0, sizeof(struct reiserfs_journal_commit)) ; - commit->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ; + memset(c_bh->b_data, 0, c_bh->b_size) ; + set_commit_trans_id(commit, SB_JOURNAL(p_s_sb)->j_trans_id) ; set_buffer_uptodate(c_bh) ; /* init this journal list */ @@ -2963,6 +2970,7 @@ /* for each real block, add it to the journal list hash, ** copy into real block index array in the commit or desc block */ + trans_half = journal_trans_half(p_s_sb->s_blocksize) ; for (i = 0, cn = SB_JOURNAL(p_s_sb)->j_first ; cn ; cn = cn->next, i++) { if (test_bit(BH_JDirty, &cn->bh->b_state) ) { jl_cn = get_cnode(p_s_sb) ; @@ -2990,27 +2998,27 @@ jl_cn->bh = cn->bh ; jl_cn->jlist = SB_JOURNAL_LIST(p_s_sb) + SB_JOURNAL_LIST_INDEX(p_s_sb) ; insert_journal_hash(SB_JOURNAL(p_s_sb)->j_list_hash_table, jl_cn) ; - if (i < JOURNAL_TRANS_HALF) { + if (i < trans_half) { desc->j_realblock[i] = cpu_to_le32(cn->bh->b_blocknr) ; } else { - commit->j_realblock[i - JOURNAL_TRANS_HALF] = cpu_to_le32(cn->bh->b_blocknr) ; + commit->j_realblock[i - trans_half] = cpu_to_le32(cn->bh->b_blocknr) ; } } else { i-- ; } } - - desc->j_len = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_len) ; - desc->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ; - desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ; - commit->j_len = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_len) ; + + set_desc_trans_len(desc, SB_JOURNAL(p_s_sb)->j_len) ; + set_desc_mount_id(desc, SB_JOURNAL(p_s_sb)->j_mount_id) ; + set_desc_trans_id(desc, SB_JOURNAL(p_s_sb)->j_trans_id) ; + set_commit_trans_len(commit, SB_JOURNAL(p_s_sb)->j_len); /* special check in case all buffers in the journal were marked for not logging */ if (SB_JOURNAL(p_s_sb)->j_len == 0) { brelse(d_bh) ; brelse(c_bh) ; unlock_journal(p_s_sb) ; -printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ; + printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ; atomic_set(&(SB_JOURNAL(p_s_sb)->j_jlock), 0) ; wake_up(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ; return 0 ; diff -urN linux-2.5.70-bk9/fs/reiserfs/prints.c linux-2.5.70-bk10/fs/reiserfs/prints.c --- linux-2.5.70-bk9/fs/reiserfs/prints.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/fs/reiserfs/prints.c 2003-06-05 04:41:37.000000000 -0700 @@ -546,12 +546,13 @@ { struct reiserfs_journal_desc * desc; - desc = (struct reiserfs_journal_desc *)(bh->b_data); - if (memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8)) + if (memcmp(get_journal_desc_magic (bh), JOURNAL_DESC_MAGIC, 8)) return 1; + desc = (struct reiserfs_journal_desc *)(bh->b_data); printk ("Desc block %llu (j_trans_id %d, j_mount_id %d, j_len %d)", - (unsigned long long)bh->b_blocknr, desc->j_trans_id, desc->j_mount_id, desc->j_len); + (unsigned long long)bh->b_blocknr, get_desc_trans_id (desc), get_desc_mount_id (desc), + get_desc_trans_len (desc)); return 0; } diff -urN linux-2.5.70-bk9/fs/reiserfs/super.c linux-2.5.70-bk10/fs/reiserfs/super.c --- linux-2.5.70-bk9/fs/reiserfs/super.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/fs/reiserfs/super.c 2003-06-05 04:41:37.000000000 -0700 @@ -23,9 +23,6 @@ #include #include -#define REISERFS_OLD_BLOCKSIZE 4096 -#define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 - static struct file_system_type reiserfs_fs_type; const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING; @@ -500,8 +497,11 @@ mount options that have values rather than being toggles. */ typedef struct { char * value; - int bitmask; /* bit which is to be set in mount_options bitmask when this - value is found, 0 is no bits are to be set */ + int setmask; /* bitmask which is to set on mount_options bitmask when this + value is found, 0 is no bits are to be changed. */ + int clrmask; /* bitmask which is to clear on mount_options bitmask when this + value is found, 0 is no bits are to be changed. This is + applied BEFORE setmask */ } arg_desc_t; @@ -511,25 +511,30 @@ char * option_name; int arg_required; /* 0 if argument is not required, not 0 otherwise */ const arg_desc_t * values; /* list of values accepted by an option */ - int bitmask; /* bit which is to be set in mount_options bitmask when this - option is selected, 0 is not bits are to be set */ + int setmask; /* bitmask which is to set on mount_options bitmask when this + value is found, 0 is no bits are to be changed. */ + int clrmask; /* bitmask which is to clear on mount_options bitmask when this + value is found, 0 is no bits are to be changed. This is + applied BEFORE setmask */ } opt_desc_t; /* possible values for "-o block-allocator=" and bits which are to be set in s_mount_opt of reiserfs specific part of in-core super block */ static const arg_desc_t balloc[] = { - {"noborder", REISERFS_NO_BORDER}, - {"no_unhashed_relocation", REISERFS_NO_UNHASHED_RELOCATION}, - {"hashed_relocation", REISERFS_HASHED_RELOCATION}, - {"test4", REISERFS_TEST4}, - {NULL, -1} + {"noborder", 1<option_name; opt ++) { if (!strncmp (p, opt->option_name, strlen (opt->option_name))) { - if (bit_flags && opt->bitmask != -1) - set_bit (opt->bitmask, bit_flags); + if (bit_flags) { + *bit_flags &= ~opt->clrmask; + *bit_flags |= opt->setmask; + } break; } } @@ -620,7 +630,7 @@ } if (!opt->values) { - /* *opt_arg contains pointer to argument */ + /* *=NULLopt_arg contains pointer to argument */ *opt_arg = p; return opt->arg_required; } @@ -628,8 +638,10 @@ /* values possible for this option are listed in opt->values */ for (arg = opt->values; arg->value; arg ++) { if (!strcmp (p, arg->value)) { - if (bit_flags && arg->bitmask != -1 ) - set_bit (arg->bitmask, bit_flags); + if (bit_flags) { + *bit_flags &= ~arg->clrmask; + *bit_flags |= arg->setmask; + } return opt->arg_required; } } @@ -638,7 +650,6 @@ return -1; } - /* returns 0 if something is wrong in option string, 1 - otherwise */ static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */ unsigned long * mount_options, @@ -652,18 +663,18 @@ char * arg = NULL; char * pos; opt_desc_t opts[] = { - {"tails", 't', tails, -1}, - {"notail", 0, 0, -1}, /* Compatibility stuff, so that -o notail -for old setups still work */ - {"conv", 0, 0, REISERFS_CONVERT}, - {"attrs", 0, 0, REISERFS_ATTRS}, - {"nolog", 0, 0, -1}, - {"replayonly", 0, 0, REPLAYONLY}, - {"block-allocator", 'a', balloc, -1}, - {"resize", 'r', 0, -1}, - {"jdev", 'j', 0, -1}, - {"nolargeio", 'w', 0, -1}, - {NULL, 0, 0, -1} + {"tails", 't', tails, 0, 0}, /* Compatibility stuff, so that -o notail for old setups still work */ + {"notail", 0, 0, 0, (1<s_mount_opt; + unsigned long safe_mask = 0; rs = SB_DISK_SUPER_BLOCK (s); if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL)) return -EINVAL; - handle_attrs( s ); + handle_attrs(s); + + /* Add options that are safe here */ + safe_mask |= 1 << REISERFS_SMALLTAIL; + safe_mask |= 1 << REISERFS_LARGETAIL; + safe_mask |= 1 << REISERFS_NO_BORDER; + safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION; + safe_mask |= 1 << REISERFS_HASHED_RELOCATION; + safe_mask |= 1 << REISERFS_TEST4; + safe_mask |= 1 << REISERFS_ATTRS; + + /* Update the bitmask, taking care to keep + * the bits we're not allowed to change here */ + REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask); if(blocks) { int rc = reiserfs_resize(s, blocks); diff -urN linux-2.5.70-bk9/include/asm-alpha/thread_info.h linux-2.5.70-bk10/include/asm-alpha/thread_info.h --- linux-2.5.70-bk9/include/asm-alpha/thread_info.h 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-alpha/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -51,7 +51,7 @@ /* Thread information allocation. */ #define THREAD_SIZE (2*PAGE_SIZE) -#define alloc_thread_info() \ +#define alloc_thread_info(tsk) \ ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-arm/dma-mapping.h linux-2.5.70-bk10/include/asm-arm/dma-mapping.h --- linux-2.5.70-bk9/include/asm-arm/dma-mapping.h 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-arm/dma-mapping.h 2003-06-05 04:41:37.000000000 -0700 @@ -42,12 +42,12 @@ /* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits - * during PCI bus mastering, then you would pass 0x00ffffff as the mask + * during bus mastering, then you would pass 0x00ffffff as the mask * to this function. */ static inline int dma_supported(struct device *dev, u64 mask) { - return 1; + return dev->dma_mask && *dev->dma_mask != 0; } static inline int dma_set_mask(struct device *dev, u64 dma_mask) @@ -81,14 +81,8 @@ * return the CPU-viewed address, and sets @handle to be the * device-viewed address. */ -static inline void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) -{ - if (dev == NULL || dmadev_is_sa1111(dev) || *dev->dma_mask != 0xffffffff) - gfp |= GFP_DMA; - - return consistent_alloc(gfp, size, handle, 0); -} +extern void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp); /** * dma_free_coherent - free memory allocated by dma_alloc_coherent diff -urN linux-2.5.70-bk9/include/asm-arm/hardware.h linux-2.5.70-bk10/include/asm-arm/hardware.h --- linux-2.5.70-bk9/include/asm-arm/hardware.h 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-arm/hardware.h 2003-06-05 04:41:37.000000000 -0700 @@ -15,4 +15,13 @@ #include +#ifndef __ASSEMBLY__ + +struct platform_device; + +extern int platform_add_devices(struct platform_device *, int); +extern int platform_add_device(struct platform_device *); + +#endif + #endif diff -urN linux-2.5.70-bk9/include/asm-arm/thread_info.h linux-2.5.70-bk10/include/asm-arm/thread_info.h --- linux-2.5.70-bk9/include/asm-arm/thread_info.h 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-arm/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -84,7 +84,7 @@ #define THREAD_SIZE (8192) -extern struct thread_info *alloc_thread_info(void); +extern struct thread_info *alloc_thread_info(struct task_struct *task); extern void free_thread_info(struct thread_info *); #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-h8300/thread_info.h linux-2.5.70-bk10/include/asm-h8300/thread_info.h --- linux-2.5.70-bk9/include/asm-h8300/thread_info.h 2003-05-26 18:00:37.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-h8300/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -65,7 +65,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-i386/thread_info.h linux-2.5.70-bk10/include/asm-i386/thread_info.h --- linux-2.5.70-bk9/include/asm-i386/thread_info.h 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-i386/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -87,7 +87,7 @@ /* thread information allocation */ #define THREAD_SIZE (2*PAGE_SIZE) -#define alloc_thread_info() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) +#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-m68k/thread_info.h linux-2.5.70-bk10/include/asm-m68k/thread_info.h --- linux-2.5.70-bk9/include/asm-m68k/thread_info.h 2003-05-26 18:00:42.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-m68k/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -28,10 +28,10 @@ /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */ #if PAGE_SHIFT == 13 /* 8k machines */ -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL,0)) +#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,0)) #define free_thread_info(ti) free_pages((unsigned long)(ti),0) #else /* otherwise assume 4k pages */ -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL,1)) +#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long)(ti),1) #endif /* PAGE_SHIFT == 13 */ diff -urN linux-2.5.70-bk9/include/asm-m68knommu/thread_info.h linux-2.5.70-bk10/include/asm-m68knommu/thread_info.h --- linux-2.5.70-bk9/include/asm-m68knommu/thread_info.h 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-m68knommu/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -65,7 +65,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-parisc/thread_info.h linux-2.5.70-bk10/include/asm-parisc/thread_info.h --- linux-2.5.70-bk9/include/asm-parisc/thread_info.h 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-parisc/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -37,7 +37,7 @@ #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) #define THREAD_SHIFT (PAGE_SHIFT + THREAD_ORDER) -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-ppc/thread_info.h linux-2.5.70-bk10/include/asm-ppc/thread_info.h --- linux-2.5.70-bk9/include/asm-ppc/thread_info.h 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-ppc/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -54,7 +54,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-ppc64/thread_info.h linux-2.5.70-bk10/include/asm-ppc64/thread_info.h --- linux-2.5.70-bk9/include/asm-ppc64/thread_info.h 2003-05-26 18:00:23.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-ppc64/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -52,7 +52,7 @@ #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) #define THREAD_SHIFT (PAGE_SHIFT + THREAD_ORDER) -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-s390/thread_info.h linux-2.5.70-bk10/include/asm-s390/thread_info.h --- linux-2.5.70-bk9/include/asm-s390/thread_info.h 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-s390/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -68,7 +68,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL,THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti),THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-sparc/thread_info.h linux-2.5.70-bk10/include/asm-sparc/thread_info.h --- linux-2.5.70-bk9/include/asm-sparc/thread_info.h 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-sparc/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -78,7 +78,7 @@ #endif BTFIXUPDEF_CALL(struct thread_info *, alloc_thread_info, void) -#define alloc_thread_info() BTFIXUP_CALL(alloc_thread_info)() +#define alloc_thread_info(tsk) BTFIXUP_CALL(alloc_thread_info)() BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *) #define free_thread_info(ti) BTFIXUP_CALL(free_thread_info)(ti) diff -urN linux-2.5.70-bk9/include/asm-sparc64/thread_info.h linux-2.5.70-bk10/include/asm-sparc64/thread_info.h --- linux-2.5.70-bk9/include/asm-sparc64/thread_info.h 2003-05-26 18:00:44.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-sparc64/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -142,10 +142,10 @@ /* thread information allocation */ #if PAGE_SHIFT == 13 -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL, 1)) +#define alloc_thread_info(tsk)((struct thread_info *)__get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long)(ti),1) #else /* PAGE_SHIFT == 13 */ -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL, 0)) +#define alloc_thread_info(tsk)((struct thread_info *)__get_free_pages(GFP_KERNEL, 0)) #define free_thread_info(ti) free_pages((unsigned long)(ti),0) #endif /* PAGE_SHIFT == 13 */ diff -urN linux-2.5.70-bk9/include/asm-um/thread_info.h linux-2.5.70-bk10/include/asm-um/thread_info.h --- linux-2.5.70-bk9/include/asm-um/thread_info.h 2003-05-26 18:00:28.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-um/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -49,7 +49,7 @@ /* thread information allocation */ #define THREAD_SIZE (4*PAGE_SIZE) -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL,2)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 2) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-v850/thread_info.h linux-2.5.70-bk10/include/asm-v850/thread_info.h --- linux-2.5.70-bk9/include/asm-v850/thread_info.h 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-v850/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -54,7 +54,7 @@ */ /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/asm-x86_64/thread_info.h linux-2.5.70-bk10/include/asm-x86_64/thread_info.h --- linux-2.5.70-bk9/include/asm-x86_64/thread_info.h 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk10/include/asm-x86_64/thread_info.h 2003-06-05 04:41:37.000000000 -0700 @@ -73,7 +73,7 @@ } /* thread information allocation */ -#define alloc_thread_info() \ +#define alloc_thread_info(tsk) \ ((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -urN linux-2.5.70-bk9/include/linux/aio.h linux-2.5.70-bk10/include/linux/aio.h --- linux-2.5.70-bk9/include/linux/aio.h 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/aio.h 2003-06-05 04:41:37.000000000 -0700 @@ -41,9 +41,9 @@ #define kiocbClearKicked(iocb) clear_bit(KIF_KICKED, &(iocb)->ki_flags) #define kiocbClearCancelled(iocb) clear_bit(KIF_CANCELLED, &(iocb)->ki_flags) -#define kiocbIsLocked(iocb) test_bit(0, &(iocb)->ki_flags) -#define kiocbIsKicked(iocb) test_bit(1, &(iocb)->ki_flags) -#define kiocbIsCancelled(iocb) test_bit(2, &(iocb)->ki_flags) +#define kiocbIsLocked(iocb) test_bit(KIF_LOCKED, &(iocb)->ki_flags) +#define kiocbIsKicked(iocb) test_bit(KIF_KICKED, &(iocb)->ki_flags) +#define kiocbIsCancelled(iocb) test_bit(KIF_CANCELLED, &(iocb)->ki_flags) struct kiocb { struct list_head ki_run_list; diff -urN linux-2.5.70-bk9/include/linux/device.h linux-2.5.70-bk10/include/linux/device.h --- linux-2.5.70-bk9/include/linux/device.h 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/device.h 2003-06-05 04:41:37.000000000 -0700 @@ -385,6 +385,8 @@ struct resource * resource; }; +#define to_platform_device(x) container_of((x), struct platform_device, dev) + extern int platform_device_register(struct platform_device *); extern void platform_device_unregister(struct platform_device *); diff -urN linux-2.5.70-bk9/include/linux/hugetlb.h linux-2.5.70-bk10/include/linux/hugetlb.h --- linux-2.5.70-bk9/include/linux/hugetlb.h 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/hugetlb.h 2003-06-05 04:41:37.000000000 -0700 @@ -72,6 +72,12 @@ #endif /* !CONFIG_HUGETLB_PAGE */ #ifdef CONFIG_HUGETLBFS +struct hugetlbfs_config { + uid_t uid; + gid_t gid; + umode_t mode; +}; + extern struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; struct file *hugetlb_zero_setup(size_t); diff -urN linux-2.5.70-bk9/include/linux/pci.h linux-2.5.70-bk10/include/linux/pci.h --- linux-2.5.70-bk9/include/linux/pci.h 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/pci.h 2003-06-05 04:41:37.000000000 -0700 @@ -527,8 +527,6 @@ return !list_empty(&pci_devices); } -#define pci_for_each_dev(dev) \ - for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) #define pci_for_each_dev_reverse(dev) \ for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) #define pci_for_each_bus(bus) \ @@ -551,22 +549,12 @@ { return pci_scan_bus_parented(NULL, bus, ops, sysdata); } -struct pci_bus *pci_alloc_primary_bus_parented(struct device * parent, int bus); -static inline struct pci_bus *pci_alloc_primary_bus(int bus) -{ - return pci_alloc_primary_bus_parented(NULL, bus); -} int pci_scan_slot(struct pci_bus *bus, int devfn); void pci_bus_add_devices(struct pci_bus *bus); -int pci_proc_attach_device(struct pci_dev *dev); -int pci_proc_detach_device(struct pci_dev *dev); -int pci_proc_attach_bus(struct pci_bus *bus); -int pci_proc_detach_bus(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); -int pci_setup_device(struct pci_dev *dev); int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); extern struct pci_dev *pci_get_dev(struct pci_dev *dev); extern void pci_put_dev(struct pci_dev *dev); @@ -578,12 +566,8 @@ unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from); struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from); -struct pci_bus *pci_find_bus(unsigned char busnr); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); -unsigned char pci_bus_max_busnr(struct pci_bus* bus); -unsigned char pci_max_busnr(void); int pci_find_capability (struct pci_dev *dev, int cap); -int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val); int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val); @@ -617,8 +601,6 @@ return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val); } -extern spinlock_t pci_lock; - int pci_enable_device(struct pci_dev *dev); int pci_enable_device_bars(struct pci_dev *dev, int mask); void pci_disable_device(struct pci_dev *dev); @@ -638,7 +620,6 @@ int pci_enable_wake(struct pci_dev *dev, u32 state, int enable); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ - void pci_bus_assign_resources(struct pci_bus *bus); void pci_bus_size_bridges(struct pci_bus *bus); int pci_claim_resource(struct pci_dev *, int); @@ -654,24 +635,14 @@ void pci_release_region(struct pci_dev *, int); /* drivers/pci/bus.c */ - -int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, - unsigned long size, unsigned long align, - unsigned long min, unsigned int type_mask, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data); void pci_enable_bridges(struct pci_bus *bus); /* New-style probing supporting hot-pluggable devices */ int pci_register_driver(struct pci_driver *); void pci_unregister_driver(struct pci_driver *); -void pci_remove_bus_device(struct pci_dev *); void pci_remove_behind_bridge(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); -unsigned int pci_do_scan_bus(struct pci_bus *bus); -struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); /* kmem_cache style wrapper around pci_alloc_consistent() */ @@ -686,42 +657,6 @@ extern struct pci_dev *isa_bridge; #endif -/* Some worker functions that PCI Hotplug drivers find useful */ -struct pci_dev_wrapped { - struct pci_dev *dev; - void *data; -}; - -struct pci_bus_wrapped { - struct pci_bus *bus; - void *data; -}; - -struct pci_visit { - int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - int (* post_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - - int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* post_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); -}; - -extern int pci_visit_dev(struct pci_visit *fn, - struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent); -extern int pci_remove_device_safe(struct pci_dev *dev); - -static inline void -pci_dynids_set_use_driver_data(struct pci_driver *pdrv, int val) -{ - pdrv->dynids.use_driver_data = val; -} - #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ @@ -770,7 +705,6 @@ static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } -static inline void pci_dynids_set_use_driver_data(struct pci_driver *pdrv, int val) { } /* Power management related routines */ static inline int pci_save_state(struct pci_dev *dev, u32 *buffer) { return 0; } @@ -778,9 +712,6 @@ static inline int pci_set_power_state(struct pci_dev *dev, int state) { return 0; } static inline int pci_enable_wake(struct pci_dev *dev, u32 state, int enable) { return 0; } -#define pci_for_each_dev(dev) \ - for(dev = NULL; 0; ) - #define isa_bridge ((struct pci_dev *)NULL) #else diff -urN linux-2.5.70-bk9/include/linux/reiserfs_fs.h linux-2.5.70-bk10/include/linux/reiserfs_fs.h --- linux-2.5.70-bk9/include/linux/reiserfs_fs.h 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/reiserfs_fs.h 2003-06-05 04:41:37.000000000 -0700 @@ -1631,29 +1631,43 @@ /***************************************************************************/ /*#ifdef __KERNEL__*/ +#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12) -/* journal.c see journal.c for all the comments here */ - -#define JOURNAL_TRANS_HALF 1018 /* must be correct to keep the desc and commit structs at 4k */ +#define journal_trans_half(blocksize) \ + ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32)) +/* journal.c see journal.c for all the comments here */ /* first block written in a commit. */ struct reiserfs_journal_desc { __u32 j_trans_id ; /* id of commit */ __u32 j_len ; /* length of commit. len +1 is the commit block */ __u32 j_mount_id ; /* mount id of this trans*/ - __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */ - char j_magic[12] ; + __u32 j_realblock[1] ; /* real locations for each block */ } ; +#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) +#define get_desc_trans_len(d) le32_to_cpu((d)->j_len) +#define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id) + +#define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0) +#define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0) + /* last block written in a commit */ struct reiserfs_journal_commit { __u32 j_trans_id ; /* must match j_trans_id from the desc block */ __u32 j_len ; /* ditto */ - __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */ - char j_digest[16] ; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ + __u32 j_realblock[1] ; /* real locations for each block */ } ; +#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) +#define get_commit_trans_len(c) le32_to_cpu((c)->j_len) +#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id) + +#define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0) + /* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the ** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, ** and this transaction does not need to be replayed. diff -urN linux-2.5.70-bk9/include/linux/reiserfs_fs_sb.h linux-2.5.70-bk10/include/linux/reiserfs_fs_sb.h --- linux-2.5.70-bk9/include/linux/reiserfs_fs_sb.h 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/reiserfs_fs_sb.h 2003-06-05 04:41:37.000000000 -0700 @@ -253,6 +253,8 @@ struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for all the real buffer heads in all the transactions */ struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */ + unsigned long j_max_trans_size ; + unsigned long j_max_batch_size ; }; #define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */ diff -urN linux-2.5.70-bk9/include/linux/rtnetlink.h linux-2.5.70-bk10/include/linux/rtnetlink.h --- linux-2.5.70-bk9/include/linux/rtnetlink.h 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/include/linux/rtnetlink.h 2003-06-05 04:41:37.000000000 -0700 @@ -50,7 +50,7 @@ #define RTM_MAX (RTM_BASE+31) /* - Generic structure for encapsulation optional route information. + Generic structure for encapsulation of optional route information. It is reminiscent of sockaddr, but with sa_family replaced with attribute type. */ diff -urN linux-2.5.70-bk9/include/net/ip6_fib.h linux-2.5.70-bk10/include/net/ip6_fib.h --- linux-2.5.70-bk9/include/net/ip6_fib.h 2003-05-26 18:00:45.000000000 -0700 +++ linux-2.5.70-bk10/include/net/ip6_fib.h 2003-06-05 04:41:37.000000000 -0700 @@ -111,9 +111,10 @@ struct rt6_statistics { __u32 fib_nodes; __u32 fib_route_nodes; - __u32 fib_rt_alloc; /* permanet routes */ + __u32 fib_rt_alloc; /* permanent routes */ __u32 fib_rt_entries; /* rt entries in table */ __u32 fib_rt_cache; /* cache routes */ + __u32 fib_discarded_routes; }; #define RTN_TL_ROOT 0x0001 diff -urN linux-2.5.70-bk9/include/net/snmp.h linux-2.5.70-bk10/include/net/snmp.h --- linux-2.5.70-bk9/include/net/snmp.h 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk10/include/net/snmp.h 2003-06-05 04:41:37.000000000 -0700 @@ -42,6 +42,11 @@ */ +/* + * RFC 1213: MIB-II + * RFC 2011 (updates 1213): SNMPv2-MIB-IP + * RFC 2863: Interfaces Group MIB + */ struct ip_mib { unsigned long IpInReceives; @@ -64,6 +69,9 @@ unsigned long __pad[0]; }; +/* + * RFC 2465: IPv6 MIB: General Group + */ struct ipv6_mib { unsigned long Ip6InReceives; @@ -91,6 +99,10 @@ unsigned long __pad[0]; }; +/* + * RFC 1213: MIB-II ICMP Group + * RFC 2011 (updates 1213): SNMPv2 MIB for IP: ICMP group + */ struct icmp_mib { unsigned long IcmpInMsgs; @@ -123,6 +135,9 @@ unsigned long __pad[0]; }; +/* + * RFC 2466: ICMPv6-MIB + */ struct icmpv6_mib { unsigned long Icmp6InMsgs; @@ -161,6 +176,10 @@ unsigned long __pad[0]; }; +/* + * RFC 1213: MIB-II TCP group + * RFC 2012 (updates 1213): SNMPv2-MIB-TCP + */ struct tcp_mib { unsigned long TcpRtoAlgorithm; @@ -180,6 +199,10 @@ unsigned long __pad[0]; }; +/* + * RFC 1213: MIB-II UDP group + * RFC 2013 (updates 1213): SNMPv2-MIB-UDP + */ struct udp_mib { unsigned long UdpInDatagrams; diff -urN linux-2.5.70-bk9/kernel/fork.c linux-2.5.70-bk10/kernel/fork.c --- linux-2.5.70-bk9/kernel/fork.c 2003-05-26 18:00:23.000000000 -0700 +++ linux-2.5.70-bk10/kernel/fork.c 2003-06-05 04:41:37.000000000 -0700 @@ -38,8 +38,6 @@ #include #include -static kmem_cache_t *task_struct_cachep; - extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk); extern void exit_semundo(struct task_struct *tsk); @@ -74,7 +72,13 @@ return total; } -static void free_task_struct(struct task_struct *tsk) +#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR +# define alloc_task_struct() kmem_cache_alloc(task_struct_cachep, GFP_KERNEL) +# define free_task_struct(tsk) kmem_cache_free(task_struct_cachep, (tsk)) +static kmem_cache_t *task_struct_cachep; +#endif + +static void free_task(struct task_struct *tsk) { /* * The task cache is effectively disabled right now. @@ -84,14 +88,14 @@ */ if (tsk != current) { free_thread_info(tsk->thread_info); - kmem_cache_free(task_struct_cachep,tsk); + free_task_struct(tsk); } else { int cpu = get_cpu(); tsk = task_cache[cpu]; if (tsk) { free_thread_info(tsk->thread_info); - kmem_cache_free(task_struct_cachep,tsk); + free_task_struct(tsk); } task_cache[cpu] = current; put_cpu(); @@ -106,7 +110,7 @@ security_task_free(tsk); free_uid(tsk->user); - free_task_struct(tsk); + free_task(tsk); } void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) @@ -186,6 +190,7 @@ void __init fork_init(unsigned long mempages) { +#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR /* create a slab on which task_structs can be allocated */ task_struct_cachep = kmem_cache_create("task_struct", @@ -193,6 +198,7 @@ SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); if (!task_struct_cachep) panic("fork_init(): cannot create task_struct SLAB cache"); +#endif /* * The default maximum number of threads is set to a safe @@ -222,13 +228,13 @@ task_cache[cpu] = NULL; put_cpu(); if (!tsk) { - ti = alloc_thread_info(); - if (!ti) + tsk = alloc_task_struct(); + if (!tsk) return NULL; - tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL); - if (!tsk) { - free_thread_info(ti); + ti = alloc_thread_info(tsk); + if (!ti) { + free_task_struct(tsk); return NULL; } } else @@ -1041,7 +1047,7 @@ atomic_dec(&p->user->processes); free_uid(p->user); bad_fork_free: - free_task_struct(p); + free_task(p); goto fork_out; } diff -urN linux-2.5.70-bk9/kernel/timer.c linux-2.5.70-bk10/kernel/timer.c --- linux-2.5.70-bk9/kernel/timer.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/kernel/timer.c 2003-06-05 04:41:37.000000000 -0700 @@ -1226,47 +1226,36 @@ } #ifdef CONFIG_TIME_INTERPOLATION - volatile unsigned long last_nsec_offset; - -struct time_interpolator *time_interpolator; - #ifndef __HAVE_ARCH_CMPXCHG spinlock_t last_nsec_offset_lock = SPIN_LOCK_UNLOCKED; #endif -static struct { - spinlock_t lock; /* lock protecting list */ - struct time_interpolator *list; /* list of registered interpolators */ -} ti_global = { - .lock = SPIN_LOCK_UNLOCKED -}; +struct time_interpolator *time_interpolator; +struct time_interpolator *time_interpolator_list; +spinlock_t time_interpolator_lock = SPIN_LOCK_UNLOCKED; static inline int is_better_time_interpolator(struct time_interpolator *new) { if (!time_interpolator) return 1; - return new->frequency > 2*time_interpolator->frequency - || (unsigned long) new->drift < (unsigned long) time_interpolator->drift; + return new->frequency > 2*time_interpolator->frequency || + (unsigned long)new->drift < (unsigned long)time_interpolator->drift; } void register_time_interpolator(struct time_interpolator *ti) { - spin_lock(&ti_global.lock); - { - write_seqlock_irq(&xtime_lock); - { - if (is_better_time_interpolator(ti)) - time_interpolator = ti; - } - write_sequnlock_irq(&xtime_lock); - - ti->next = ti_global.list; - ti_global.list = ti; - } - spin_unlock(&ti_global.lock); + spin_lock(&time_interpolator_lock); + write_seqlock_irq(&xtime_lock); + if (is_better_time_interpolator(ti)) + time_interpolator = ti; + write_sequnlock_irq(&xtime_lock); + + ti->next = time_interpolator_list; + time_interpolator_list = ti; + spin_unlock(&time_interpolator_lock); } void @@ -1274,30 +1263,26 @@ { struct time_interpolator *curr, **prev; - spin_lock(&ti_global.lock); - { - prev = &ti_global.list; - for (curr = *prev; curr; curr = curr->next) { - if (curr == ti) { - *prev = curr->next; - break; - } - prev = &curr->next; - } - write_seqlock_irq(&xtime_lock); - { - if (ti == time_interpolator) { - /* we lost the best time-interpolator: */ - time_interpolator = NULL; - /* find the next-best interpolator */ - for (curr = ti_global.list; curr; curr = curr->next) - if (is_better_time_interpolator(curr)) - time_interpolator = curr; - } + spin_lock(&time_interpolator_lock); + prev = &time_interpolator_list; + for (curr = *prev; curr; curr = curr->next) { + if (curr == ti) { + *prev = curr->next; + break; } - write_sequnlock_irq(&xtime_lock); + prev = &curr->next; } - spin_unlock(&ti_global.lock); -} + write_seqlock_irq(&xtime_lock); + if (ti == time_interpolator) { + /* we lost the best time-interpolator: */ + time_interpolator = NULL; + /* find the next-best interpolator */ + for (curr = time_interpolator_list; curr; curr = curr->next) + if (is_better_time_interpolator(curr)) + time_interpolator = curr; + } + write_sequnlock_irq(&xtime_lock); + spin_unlock(&time_interpolator_lock); +} #endif /* CONFIG_TIME_INTERPOLATION */ diff -urN linux-2.5.70-bk9/mm/filemap.c linux-2.5.70-bk10/mm/filemap.c --- linux-2.5.70-bk9/mm/filemap.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/mm/filemap.c 2003-06-05 04:41:37.000000000 -0700 @@ -81,8 +81,6 @@ { struct address_space *mapping = page->mapping; - BUG_ON(PageDirty(page) && !PageSwapCache(page)); - radix_tree_delete(&mapping->page_tree, page->index); list_del(&page->list); page->mapping = NULL; @@ -1410,6 +1408,11 @@ } } +/* + * Copy as much as we can into the page and return the number of bytes which + * were sucessfully copied. If a fault is encountered then clear the page + * out to (offset+bytes) and return the number of bytes which were copied. + */ static inline size_t filemap_copy_from_user(struct page *page, unsigned long offset, const char __user *buf, unsigned bytes) @@ -1427,30 +1430,42 @@ left = __copy_from_user(kaddr + offset, buf, bytes); kunmap(page); } - return left ? 0 : bytes; + return bytes - left; } static size_t __filemap_copy_from_user_iovec(char *vaddr, const struct iovec *iov, size_t base, size_t bytes) { - size_t copied = 0; + size_t copied = 0, left = 0; while (bytes) { char __user *buf = iov->iov_base + base; int copy = min(bytes, iov->iov_len - base); base = 0; - if (__copy_from_user(vaddr, buf, copy)) - break; + left = __copy_from_user(vaddr, buf, copy); copied += copy; bytes -= copy; vaddr += copy; iov++; + + if (unlikely(left)) { + /* zero the rest of the target like __copy_from_user */ + if (bytes) + memset(vaddr, 0, bytes); + break; + } } - return copied; + return copied - left; } +/* + * This has the same sideeffects and return value as filemap_copy_from_user(). + * The difference is that on a fault we need to memset the remainder of the + * page (out to offset+bytes), to emulate filemap_copy_from_user()'s + * single-segment behaviour. + */ static inline size_t filemap_copy_from_user_iovec(struct page *page, unsigned long offset, const struct iovec *iov, size_t base, size_t bytes) @@ -1718,8 +1733,7 @@ copied = filemap_copy_from_user_iovec(page, offset, cur_iov, iov_base, bytes); flush_dcache_page(page); - status = a_ops->commit_write(file, page, offset, - offset + copied); + status = a_ops->commit_write(file, page, offset, offset+bytes); if (likely(copied > 0)) { if (!status) status = copied; diff -urN linux-2.5.70-bk9/net/core/dst.c linux-2.5.70-bk10/net/core/dst.c --- linux-2.5.70-bk9/net/core/dst.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk10/net/core/dst.c 2003-06-05 04:41:37.000000000 -0700 @@ -1,7 +1,7 @@ /* - * net/dst.c Protocol independent destination cache. + * net/core/dst.c Protocol independent destination cache. * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * */ diff -urN linux-2.5.70-bk9/net/core/dv.c linux-2.5.70-bk10/net/core/dv.c --- linux-2.5.70-bk9/net/core/dv.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk10/net/core/dv.c 2003-06-05 04:41:37.000000000 -0700 @@ -5,8 +5,6 @@ * * Generic frame diversion * - * Version: @(#)eth.c 0.41 09/09/2000 - * * Authors: * Benoit LOCHER: initial integration within the kernel with support for ethernet * Dave Miller: improvement on the code (correctness, performance and source files) diff -urN linux-2.5.70-bk9/net/core/filter.c linux-2.5.70-bk10/net/core/filter.c --- linux-2.5.70-bk9/net/core/filter.c 2003-05-26 18:00:28.000000000 -0700 +++ linux-2.5.70-bk10/net/core/filter.c 2003-06-05 04:41:37.000000000 -0700 @@ -36,14 +36,13 @@ #include /* No hurry in this branch */ - static u8 *load_pointer(struct sk_buff *skb, int k) { u8 *ptr = NULL; - if (k>=SKF_NET_OFF) + if (k >= SKF_NET_OFF) ptr = skb->nh.raw + k - SKF_NET_OFF; - else if (k>=SKF_LL_OFF) + else if (k >= SKF_LL_OFF) ptr = skb->mac.raw + k - SKF_LL_OFF; if (ptr >= skb->head && ptr < skb->tail) @@ -80,268 +79,224 @@ /* * Process array of filter instructions. */ - - for(pc = 0; pc < flen; pc++) - { + for (pc = 0; pc < flen; pc++) { fentry = &filter[pc]; - switch(fentry->code) - { - case BPF_ALU|BPF_ADD|BPF_X: - A += X; - continue; - - case BPF_ALU|BPF_ADD|BPF_K: - A += fentry->k; - continue; - - case BPF_ALU|BPF_SUB|BPF_X: - A -= X; - continue; - - case BPF_ALU|BPF_SUB|BPF_K: - A -= fentry->k; - continue; - - case BPF_ALU|BPF_MUL|BPF_X: - A *= X; - continue; - - case BPF_ALU|BPF_MUL|BPF_K: - A *= fentry->k; - continue; - - case BPF_ALU|BPF_DIV|BPF_X: - if(X == 0) - return (0); - A /= X; - continue; - - case BPF_ALU|BPF_DIV|BPF_K: - if(fentry->k == 0) - return (0); - A /= fentry->k; - continue; - - case BPF_ALU|BPF_AND|BPF_X: - A &= X; - continue; - - case BPF_ALU|BPF_AND|BPF_K: - A &= fentry->k; - continue; - - case BPF_ALU|BPF_OR|BPF_X: - A |= X; - continue; - - case BPF_ALU|BPF_OR|BPF_K: - A |= fentry->k; - continue; - - case BPF_ALU|BPF_LSH|BPF_X: - A <<= X; - continue; - - case BPF_ALU|BPF_LSH|BPF_K: - A <<= fentry->k; - continue; - - case BPF_ALU|BPF_RSH|BPF_X: - A >>= X; - continue; - - case BPF_ALU|BPF_RSH|BPF_K: - A >>= fentry->k; - continue; - - case BPF_ALU|BPF_NEG: - A = -A; - continue; - - case BPF_JMP|BPF_JA: - pc += fentry->k; - continue; - - case BPF_JMP|BPF_JGT|BPF_K: - pc += (A > fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JGE|BPF_K: - pc += (A >= fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JEQ|BPF_K: - pc += (A == fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JSET|BPF_K: - pc += (A & fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JGT|BPF_X: - pc += (A > X) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JGE|BPF_X: - pc += (A >= X) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JEQ|BPF_X: - pc += (A == X) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JSET|BPF_X: - pc += (A & X) ? fentry->jt : fentry->jf; + switch (fentry->code) { + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + case BPF_ALU|BPF_ADD|BPF_K: + A += fentry->k; + continue; + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + case BPF_ALU|BPF_SUB|BPF_K: + A -= fentry->k; + continue; + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + case BPF_ALU|BPF_MUL|BPF_K: + A *= fentry->k; + continue; + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + case BPF_ALU|BPF_DIV|BPF_K: + if (fentry->k == 0) + return 0; + A /= fentry->k; + continue; + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + case BPF_ALU|BPF_AND|BPF_K: + A &= fentry->k; + continue; + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + case BPF_ALU|BPF_OR|BPF_K: + A |= fentry->k; + continue; + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + case BPF_ALU|BPF_LSH|BPF_K: + A <<= fentry->k; + continue; + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + case BPF_ALU|BPF_RSH|BPF_K: + A >>= fentry->k; + continue; + case BPF_ALU|BPF_NEG: + A = -A; + continue; + case BPF_JMP|BPF_JA: + pc += fentry->k; + continue; + case BPF_JMP|BPF_JGT|BPF_K: + pc += (A > fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JGE|BPF_K: + pc += (A >= fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JEQ|BPF_K: + pc += (A == fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? fentry->jt : fentry->jf; + continue; + case BPF_LD|BPF_W|BPF_ABS: + k = fentry->k; + load_w: + if (k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) { + A = ntohl(*(u32*)&data[k]); continue; + } + if (k < 0) { + u8 *ptr; - case BPF_LD|BPF_W|BPF_ABS: - k = fentry->k; -load_w: - if(k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) { - A = ntohl(*(u32*)&data[k]); + if (k >= SKF_AD_OFF) + break; + ptr = load_pointer(skb, k); + if (ptr) { + A = ntohl(*(u32*)ptr); continue; } - if (k<0) { - u8 *ptr; - - if (k>=SKF_AD_OFF) - break; - if ((ptr = load_pointer(skb, k)) != NULL) { - A = ntohl(*(u32*)ptr); - continue; - } - } else { - u32 tmp; - if (!skb_copy_bits(skb, k, &tmp, 4)) { - A = ntohl(tmp); - continue; - } + } else { + u32 tmp; + if (!skb_copy_bits(skb, k, &tmp, 4)) { + A = ntohl(tmp); + continue; } - return 0; + } + return 0; + case BPF_LD|BPF_H|BPF_ABS: + k = fentry->k; + load_h: + if (k >= 0 && (unsigned int)(k + sizeof(u16)) <= len) { + A = ntohs(*(u16*)&data[k]); + continue; + } + if (k < 0) { + u8 *ptr; - case BPF_LD|BPF_H|BPF_ABS: - k = fentry->k; -load_h: - if(k >= 0 && (unsigned int) (k + sizeof(u16)) <= len) { - A = ntohs(*(u16*)&data[k]); + if (k >= SKF_AD_OFF) + break; + ptr = load_pointer(skb, k); + if (ptr) { + A = ntohs(*(u16*)ptr); continue; } - if (k<0) { - u8 *ptr; - - if (k>=SKF_AD_OFF) - break; - if ((ptr = load_pointer(skb, k)) != NULL) { - A = ntohs(*(u16*)ptr); - continue; - } - } else { - u16 tmp; - if (!skb_copy_bits(skb, k, &tmp, 2)) { - A = ntohs(tmp); - continue; - } + } else { + u16 tmp; + if (!skb_copy_bits(skb, k, &tmp, 2)) { + A = ntohs(tmp); + continue; } - return 0; - - case BPF_LD|BPF_B|BPF_ABS: - k = fentry->k; + } + return 0; + case BPF_LD|BPF_B|BPF_ABS: + k = fentry->k; load_b: - if(k >= 0 && (unsigned int)k < len) { - A = data[k]; + if (k >= 0 && (unsigned int)k < len) { + A = data[k]; + continue; + } + if (k < 0) { + u8 *ptr; + + if (k >= SKF_AD_OFF) + break; + ptr = load_pointer(skb, k); + if (ptr) { + A = *ptr; continue; } - if (k<0) { - u8 *ptr; - - if (k>=SKF_AD_OFF) - break; - if ((ptr = load_pointer(skb, k)) != NULL) { - A = *ptr; - continue; - } - } else { - u8 tmp; - if (!skb_copy_bits(skb, k, &tmp, 1)) { - A = tmp; - continue; - } + } else { + u8 tmp; + if (!skb_copy_bits(skb, k, &tmp, 1)) { + A = tmp; + continue; } + } + return 0; + case BPF_LD|BPF_W|BPF_LEN: + A = len; + continue; + case BPF_LDX|BPF_W|BPF_LEN: + X = len; + continue; + case BPF_LD|BPF_W|BPF_IND: + k = X + fentry->k; + goto load_w; + case BPF_LD|BPF_H|BPF_IND: + k = X + fentry->k; + goto load_h; + case BPF_LD|BPF_B|BPF_IND: + k = X + fentry->k; + goto load_b; + case BPF_LDX|BPF_B|BPF_MSH: + k = fentry->k; + if (k >= 0 && (unsigned int)k >= len) return 0; - - case BPF_LD|BPF_W|BPF_LEN: - A = len; - continue; - - case BPF_LDX|BPF_W|BPF_LEN: - X = len; - continue; - - case BPF_LD|BPF_W|BPF_IND: - k = X + fentry->k; - goto load_w; - - case BPF_LD|BPF_H|BPF_IND: - k = X + fentry->k; - goto load_h; - - case BPF_LD|BPF_B|BPF_IND: - k = X + fentry->k; - goto load_b; - - case BPF_LDX|BPF_B|BPF_MSH: - k = fentry->k; - if(k >= 0 && (unsigned int)k >= len) - return (0); - X = (data[k] & 0xf) << 2; - continue; - - case BPF_LD|BPF_IMM: - A = fentry->k; - continue; - - case BPF_LDX|BPF_IMM: - X = fentry->k; - continue; - - case BPF_LD|BPF_MEM: - A = mem[fentry->k]; - continue; - - case BPF_LDX|BPF_MEM: - X = mem[fentry->k]; - continue; - - case BPF_MISC|BPF_TAX: - X = A; - continue; - - case BPF_MISC|BPF_TXA: - A = X; - continue; - - case BPF_RET|BPF_K: - return ((unsigned int)fentry->k); - - case BPF_RET|BPF_A: - return ((unsigned int)A); - - case BPF_ST: - mem[fentry->k] = A; - continue; - - case BPF_STX: - mem[fentry->k] = X; - continue; - - default: - /* Invalid instruction counts as RET */ - return (0); + X = (data[k] & 0xf) << 2; + continue; + case BPF_LD|BPF_IMM: + A = fentry->k; + continue; + case BPF_LDX|BPF_IMM: + X = fentry->k; + continue; + case BPF_LD|BPF_MEM: + A = mem[fentry->k]; + continue; + case BPF_LDX|BPF_MEM: + X = mem[fentry->k]; + continue; + case BPF_MISC|BPF_TAX: + X = A; + continue; + case BPF_MISC|BPF_TXA: + A = X; + continue; + case BPF_RET|BPF_K: + return ((unsigned int)fentry->k); + case BPF_RET|BPF_A: + return ((unsigned int)A); + case BPF_ST: + mem[fentry->k] = A; + continue; + case BPF_STX: + mem[fentry->k] = X; + continue; + default: + /* Invalid instruction counts as RET */ + return 0; } - /* Handle ancillary data, which are impossible - (or very difficult) to get parsing packet contents. + /* + * Handle ancillary data, which are impossible + * (or very difficult) to get parsing packet contents. */ switch (k-SKF_AD_OFF) { case SKF_AD_PROTOCOL: @@ -358,7 +313,7 @@ } } - return (0); + return 0; } /** @@ -373,75 +328,55 @@ * * Returns 0 if the rule set is legal or a negative errno code if not. */ - int sk_chk_filter(struct sock_filter *filter, int flen) { struct sock_filter *ftest; - int pc; + int pc; - if ((unsigned int) flen >= (~0U / sizeof(struct sock_filter))) + if ((unsigned int)flen >= (~0U / sizeof(struct sock_filter))) return -EINVAL; - /* - * Check the filter code now. - */ - for(pc = 0; pc < flen; pc++) - { - /* - * All jumps are forward as they are not signed - */ - - ftest = &filter[pc]; - if(BPF_CLASS(ftest->code) == BPF_JMP) - { - /* - * But they mustn't jump off the end. - */ - if(BPF_OP(ftest->code) == BPF_JA) - { - /* Note, the large ftest->k might cause - loops. Compare this with conditional - jumps below, where offsets are limited. --ANK (981016) + /* check the filter code now */ + for (pc = 0; pc < flen; pc++) { + /* all jumps are forward as they are not signed */ + ftest = &filter[pc]; + if (BPF_CLASS(ftest->code) == BPF_JMP) { + /* but they mustn't jump off the end */ + if (BPF_OP(ftest->code) == BPF_JA) { + /* + * Note, the large ftest->k might cause loops. + * Compare this with conditional jumps below, + * where offsets are limited. --ANK (981016) */ if (ftest->k >= (unsigned)(flen-pc-1)) return -EINVAL; - } - else - { - /* - * For conditionals both must be safe - */ - if(pc + ftest->jt +1 >= flen || pc + ftest->jf +1 >= flen) + } else { + /* for conditionals both must be safe */ + if (pc + ftest->jt +1 >= flen || + pc + ftest->jf +1 >= flen) return -EINVAL; } - } + } - /* - * Check that memory operations use valid addresses. - */ - - if (ftest->k >= BPF_MEMWORDS) - { - /* - * But it might not be a memory operation... - */ + /* check that memory operations use valid addresses. */ + if (ftest->k >= BPF_MEMWORDS) { + /* but it might not be a memory operation... */ switch (ftest->code) { case BPF_ST: case BPF_STX: case BPF_LD|BPF_MEM: case BPF_LDX|BPF_MEM: - return -EINVAL; + return -EINVAL; } } - } + } /* - * The program must end with a return. We don't care where they - * jumped within the script (its always forwards) but in the - * end they _will_ hit this. + * The program must end with a return. We don't care where they + * jumped within the script (its always forwards) but in the end + * they _will_ hit this. */ - - return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-EINVAL; + return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL; } /** @@ -454,7 +389,6 @@ * occurs or there is insufficient memory for the filter a negative * errno code is returned. On success the return is zero. */ - int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { struct sk_filter *fp; @@ -463,12 +397,11 @@ /* Make sure new filter is there and in the right amounts. */ if (fprog->filter == NULL || fprog->len > BPF_MAXINSNS) - return (-EINVAL); - - fp = (struct sk_filter *)sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); - if(fp == NULL) - return (-ENOMEM); + return -EINVAL; + fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; if (copy_from_user(fp->insns, fprog->filter, fsize)) { sock_kfree_s(sk, fp, fsize+sizeof(*fp)); return -EFAULT; @@ -477,7 +410,8 @@ atomic_set(&fp->refcnt, 1); fp->len = fprog->len; - if ((err = sk_chk_filter(fp->insns, fp->len))==0) { + err = sk_chk_filter(fp->insns, fp->len); + if (!err) { struct sk_filter *old_fp; spin_lock_bh(&sk->lock.slock); @@ -489,6 +423,5 @@ if (fp) sk_filter_release(sk, fp); - - return (err); + return err; } diff -urN linux-2.5.70-bk9/net/core/iovec.c linux-2.5.70-bk10/net/core/iovec.c --- linux-2.5.70-bk9/net/core/iovec.c 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk10/net/core/iovec.c 2003-06-05 04:41:37.000000000 -0700 @@ -41,35 +41,36 @@ { int size, err, ct; - if(m->msg_namelen) - { - if(mode==VERIFY_READ) - { - err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - if(err<0) - goto out; + if (m->msg_namelen) { + if (mode == VERIFY_READ) { + err = move_addr_to_kernel(m->msg_name, m->msg_namelen, + address); + if (err < 0) + return err; } - m->msg_name = address; - } else + } else { m->msg_name = NULL; + } - err = -EFAULT; size = m->msg_iovlen * sizeof(struct iovec); if (copy_from_user(iov, m->msg_iov, size)) - goto out; - m->msg_iov=iov; + return -EFAULT; - for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) { + m->msg_iov = iov; + err = 0; + + for (ct = 0; ct < m->msg_iovlen; ct++) { err += iov[ct].iov_len; - /* Goal is not to verify user data, but to prevent returning - negative value, which is interpreted as errno. - Overflow is still possible, but it is harmless. + /* + * Goal is not to verify user data, but to prevent returning + * negative value, which is interpreted as errno. + * Overflow is still possible, but it is harmless. */ if (err < 0) return -EMSGSIZE; } -out: + return err; } @@ -81,25 +82,20 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) { - int err = -EFAULT; - - while(len>0) - { - if(iov->iov_len) - { + while (len > 0) { + if (iov->iov_len) { int copy = min_t(unsigned int, iov->iov_len, len); if (copy_to_user(iov->iov_base, kdata, copy)) - goto out; - kdata+=copy; - len-=copy; - iov->iov_len-=copy; - iov->iov_base+=copy; + return -EFAULT; + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; } iov++; } - err = 0; -out: - return err; + + return 0; } /* @@ -110,16 +106,14 @@ void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len) { - while(len>0) - { - if(iov->iov_len) - { + while (len > 0) { + if (iov->iov_len) { int copy = min_t(unsigned int, iov->iov_len, len); memcpy(iov->iov_base, kdata, copy); - kdata+=copy; - len-=copy; - iov->iov_len-=copy; - iov->iov_base+=copy; + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; } iov++; } @@ -134,59 +128,47 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) { - int err = -EFAULT; - - while(len>0) - { - if(iov->iov_len) - { + while (len > 0) { + if (iov->iov_len) { int copy = min_t(unsigned int, len, iov->iov_len); if (copy_from_user(kdata, iov->iov_base, copy)) - goto out; - len-=copy; - kdata+=copy; - iov->iov_base+=copy; - iov->iov_len-=copy; + return -EFAULT; + len -= copy; + kdata += copy; + iov->iov_base += copy; + iov->iov_len -= copy; } iov++; } - err = 0; -out: - return err; -} + return 0; +} /* * For use with ip_build_xmit */ - int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, int len) { - int err = -EFAULT; - /* Skip over the finished iovecs */ - while(offset >= iov->iov_len) - { + while (offset >= iov->iov_len) { offset -= iov->iov_len; iov++; } - while (len > 0) - { + while (len > 0) { u8 *base = iov->iov_base + offset; int copy = min_t(unsigned int, len, iov->iov_len - offset); offset = 0; if (copy_from_user(kdata, base, copy)) - goto out; - len -= copy; + return -EFAULT; + len -= copy; kdata += copy; iov++; } - err = 0; -out: - return err; + + return 0; } /* @@ -197,7 +179,6 @@ * ip_build_xmit must ensure that when fragmenting only the last * call to this function will be unaligned also. */ - int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, unsigned int len, int *csump) { @@ -205,21 +186,19 @@ int partial_cnt = 0, err = 0; /* Skip over the finished iovecs */ - while (offset >= iov->iov_len) - { + while (offset >= iov->iov_len) { offset -= iov->iov_len; iov++; } - while (len > 0) - { + while (len > 0) { u8 *base = iov->iov_base + offset; int copy = min_t(unsigned int, len, iov->iov_len - offset); offset = 0; + /* There is a remnant from previous iov. */ - if (partial_cnt) - { + if (partial_cnt) { int par_len = 4 - partial_cnt; /* iov component is too short ... */ @@ -227,9 +206,9 @@ if (copy_from_user(kdata, base, copy)) goto out_fault; kdata += copy; - base += copy; + base += copy; partial_cnt += copy; - len -= copy; + len -= copy; iov++; if (len) continue; @@ -247,11 +226,9 @@ partial_cnt = 0; } - if (len > copy) - { + if (len > copy) { partial_cnt = copy % 4; - if (partial_cnt) - { + if (partial_cnt) { copy -= partial_cnt; if (copy_from_user(kdata + copy, base + copy, partial_cnt)) diff -urN linux-2.5.70-bk9/net/ipv4/Kconfig linux-2.5.70-bk10/net/ipv4/Kconfig --- linux-2.5.70-bk9/net/ipv4/Kconfig 2003-05-26 18:00:45.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv4/Kconfig 2003-06-05 04:41:37.000000000 -0700 @@ -343,6 +343,10 @@ config INET_AH tristate "IP: AH transformation" + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 ---help--- Support for IPsec AH. @@ -350,6 +354,11 @@ config INET_ESP tristate "IP: ESP transformation" + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_DES ---help--- Support for IPsec ESP. @@ -357,6 +366,8 @@ config INET_IPCOMP tristate "IP: IPComp transformation" + select CRYPTO + select CRYPTO_DEFLATE ---help--- Support for IP Paylod Compression (RFC3173), typically needed for IPsec. diff -urN linux-2.5.70-bk9/net/ipv4/Makefile linux-2.5.70-bk10/net/ipv4/Makefile --- linux-2.5.70-bk9/net/ipv4/Makefile 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv4/Makefile 2003-06-05 04:41:37.000000000 -0700 @@ -16,8 +16,8 @@ obj-$(CONFIG_NET_IPIP) += ipip.o obj-$(CONFIG_NET_IPGRE) += ip_gre.o obj-$(CONFIG_SYN_COOKIES) += syncookies.o -obj-$(CONFIG_INET_AH) += ah.o -obj-$(CONFIG_INET_ESP) += esp.o +obj-$(CONFIG_INET_AH) += ah4.o +obj-$(CONFIG_INET_ESP) += esp4.o obj-$(CONFIG_INET_IPCOMP) += ipcomp.o obj-$(CONFIG_IP_PNP) += ipconfig.o obj-$(CONFIG_NETFILTER) += netfilter/ diff -urN linux-2.5.70-bk9/net/ipv4/ah.c linux-2.5.70-bk10/net/ipv4/ah.c --- linux-2.5.70-bk9/net/ipv4/ah.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv4/ah.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,361 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Clear mutable options and find final destination to substitute - * into IP header for icv calculation. Options are already checked - * for validity, so paranoia is not required. */ - -static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) -{ - unsigned char * optptr = (unsigned char*)(iph+1); - int l = iph->ihl*4 - sizeof(struct iphdr); - int optlen; - - while (l > 0) { - switch (*optptr) { - case IPOPT_END: - return 0; - case IPOPT_NOOP: - l--; - optptr++; - continue; - } - optlen = optptr[1]; - if (optlen<2 || optlen>l) - return -EINVAL; - switch (*optptr) { - case IPOPT_SEC: - case 0x85: /* Some "Extended Security" crap. */ - case 0x86: /* Another "Commercial Security" crap. */ - case IPOPT_RA: - case 0x80|21: /* RFC1770 */ - break; - case IPOPT_LSRR: - case IPOPT_SSRR: - if (optlen < 6) - return -EINVAL; - memcpy(daddr, optptr+optlen-4, 4); - /* Fall through */ - default: - memset(optptr+2, 0, optlen-2); - } - l -= optlen; - optptr += optlen; - } - return 0; -} - -static int ah_output(struct sk_buff *skb) -{ - int err; - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - struct ip_auth_hdr *ah; - struct ah_data *ahp; - union { - struct iphdr iph; - char buf[60]; - } tmp_iph; - - if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { - err = -EINVAL; - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_check_output(x, skb, AF_INET); - if (err) - goto error; - - iph = skb->nh.iph; - if (x->props.mode) { - top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = 0; - top_iph->tot_len = htons(skb->len); - top_iph->frag_off = 0; - if (!(iph->frag_off&htons(IP_DF))) - __ip_select_ident(top_iph, dst, 0); - top_iph->ttl = 0; - top_iph->protocol = IPPROTO_AH; - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - ah = (struct ip_auth_hdr*)(top_iph+1); - ah->nexthdr = IPPROTO_IPIP; - } else { - memcpy(&tmp_iph, skb->data, iph->ihl*4); - top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); - memcpy(top_iph, &tmp_iph, iph->ihl*4); - iph = &tmp_iph.iph; - top_iph->tos = 0; - top_iph->tot_len = htons(skb->len); - top_iph->frag_off = 0; - top_iph->ttl = 0; - top_iph->protocol = IPPROTO_AH; - top_iph->check = 0; - if (top_iph->ihl != 5) { - err = ip_clear_mutable_options(top_iph, &top_iph->daddr); - if (err) - goto error; - } - ah = (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4); - ah->nexthdr = iph->protocol; - } - ahp = x->data; - ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + - ahp->icv_trunc_len) >> 2) - 2; - - ah->reserved = 0; - ah->spi = x->id.spi; - ah->seq_no = htonl(++x->replay.oseq); - ahp->icv(ahp, skb, ah->auth_data); - top_iph->tos = iph->tos; - top_iph->ttl = iph->ttl; - if (x->props.mode) { - top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - } else { - top_iph->frag_off = iph->frag_off; - top_iph->daddr = iph->daddr; - if (iph->ihl != 5) - memcpy(top_iph+1, iph+1, iph->ihl*4 - sizeof(struct iphdr)); - } - ip_send_check(top_iph); - - skb->nh.raw = skb->data; - - x->curlft.bytes += skb->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - if ((skb->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; - -error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(skb); - return err; -} - -int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ - int ah_hlen; - struct iphdr *iph; - struct ip_auth_hdr *ah; - struct ah_data *ahp; - char work_buf[60]; - - if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) - goto out; - - ah = (struct ip_auth_hdr*)skb->data; - ahp = x->data; - ah_hlen = (ah->hdrlen + 2) << 2; - - if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && - ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) - goto out; - - if (!pskb_may_pull(skb, ah_hlen)) - goto out; - - /* We are going to _remove_ AH header to keep sockets happy, - * so... Later this can change. */ - if (skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto out; - - skb->ip_summed = CHECKSUM_NONE; - - ah = (struct ip_auth_hdr*)skb->data; - iph = skb->nh.iph; - - memcpy(work_buf, iph, iph->ihl*4); - - iph->ttl = 0; - iph->tos = 0; - iph->frag_off = 0; - iph->check = 0; - if (iph->ihl != 5) { - u32 dummy; - if (ip_clear_mutable_options(iph, &dummy)) - goto out; - } - { - u8 auth_data[ahp->icv_trunc_len]; - - memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); - skb_push(skb, skb->data - skb->nh.raw); - ahp->icv(ahp, skb, ah->auth_data); - if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { - x->stats.integrity_failed++; - goto out; - } - } - ((struct iphdr*)work_buf)->protocol = ah->nexthdr; - skb->nh.raw = skb_pull(skb, ah_hlen); - memcpy(skb->nh.raw, work_buf, iph->ihl*4); - skb->nh.iph->tot_len = htons(skb->len); - skb_pull(skb, skb->nh.iph->ihl*4); - skb->h.raw = skb->data; - - return 0; - -out: - return -EINVAL; -} - -void ah4_err(struct sk_buff *skb, u32 info) -{ - struct iphdr *iph = (struct iphdr*)skb->data; - struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); - struct xfrm_state *x; - - if (skb->h.icmph->type != ICMP_DEST_UNREACH || - skb->h.icmph->code != ICMP_FRAG_NEEDED) - return; - - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); - if (!x) - return; - printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/%08x\n", - ntohl(ah->spi), ntohl(iph->daddr)); - xfrm_state_put(x); -} - -static int ah_init_state(struct xfrm_state *x, void *args) -{ - struct ah_data *ahp = NULL; - struct xfrm_algo_desc *aalg_desc; - - /* null auth can use a zero length key */ - if (x->aalg->alg_key_len > 512) - goto error; - - ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); - if (ahp == NULL) - return -ENOMEM; - - memset(ahp, 0, sizeof(*ahp)); - - ahp->key = x->aalg->alg_key; - ahp->key_len = (x->aalg->alg_key_len+7)/8; - ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); - if (!ahp->tfm) - goto error; - ahp->icv = ah_hmac_digest; - - /* - * Lookup the algorithm description maintained by xfrm_algo, - * verify crypto transform properties, and store information - * we need for AH processing. This lookup cannot fail here - * after a successful crypto_alloc_tfm(). - */ - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); - BUG_ON(!aalg_desc); - - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(ahp->tfm)) { - printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), - aalg_desc->uinfo.auth.icv_fullbits/8); - goto error; - } - - ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; - ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; - - ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); - if (!ahp->work_icv) - goto error; - - x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); - if (x->props.mode) - x->props.header_len += sizeof(struct iphdr); - x->data = ahp; - - return 0; - -error: - if (ahp) { - if (ahp->work_icv) - kfree(ahp->work_icv); - if (ahp->tfm) - crypto_free_tfm(ahp->tfm); - kfree(ahp); - } - return -EINVAL; -} - -static void ah_destroy(struct xfrm_state *x) -{ - struct ah_data *ahp = x->data; - - if (ahp->work_icv) { - kfree(ahp->work_icv); - ahp->work_icv = NULL; - } - if (ahp->tfm) { - crypto_free_tfm(ahp->tfm); - ahp->tfm = NULL; - } - kfree(ahp); -} - - -static struct xfrm_type ah_type = -{ - .description = "AH4", - .owner = THIS_MODULE, - .proto = IPPROTO_AH, - .init_state = ah_init_state, - .destructor = ah_destroy, - .input = ah_input, - .output = ah_output -}; - -static struct inet_protocol ah4_protocol = { - .handler = xfrm4_rcv, - .err_handler = ah4_err, - .no_policy = 1, -}; - -static int __init ah4_init(void) -{ - if (xfrm_register_type(&ah_type, AF_INET) < 0) { - printk(KERN_INFO "ip ah init: can't add xfrm type\n"); - return -EAGAIN; - } - if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { - printk(KERN_INFO "ip ah init: can't add protocol\n"); - xfrm_unregister_type(&ah_type, AF_INET); - return -EAGAIN; - } - return 0; -} - -static void __exit ah4_fini(void) -{ - if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) - printk(KERN_INFO "ip ah close: can't remove protocol\n"); - if (xfrm_unregister_type(&ah_type, AF_INET) < 0) - printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); -} - -module_init(ah4_init); -module_exit(ah4_fini); -MODULE_LICENSE("GPL"); diff -urN linux-2.5.70-bk9/net/ipv4/ah4.c linux-2.5.70-bk10/net/ipv4/ah4.c --- linux-2.5.70-bk9/net/ipv4/ah4.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/net/ipv4/ah4.c 2003-06-05 04:41:37.000000000 -0700 @@ -0,0 +1,361 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Clear mutable options and find final destination to substitute + * into IP header for icv calculation. Options are already checked + * for validity, so paranoia is not required. */ + +static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +{ + unsigned char * optptr = (unsigned char*)(iph+1); + int l = iph->ihl*4 - sizeof(struct iphdr); + int optlen; + + while (l > 0) { + switch (*optptr) { + case IPOPT_END: + return 0; + case IPOPT_NOOP: + l--; + optptr++; + continue; + } + optlen = optptr[1]; + if (optlen<2 || optlen>l) + return -EINVAL; + switch (*optptr) { + case IPOPT_SEC: + case 0x85: /* Some "Extended Security" crap. */ + case 0x86: /* Another "Commercial Security" crap. */ + case IPOPT_RA: + case 0x80|21: /* RFC1770 */ + break; + case IPOPT_LSRR: + case IPOPT_SSRR: + if (optlen < 6) + return -EINVAL; + memcpy(daddr, optptr+optlen-4, 4); + /* Fall through */ + default: + memset(optptr+2, 0, optlen-2); + } + l -= optlen; + optptr += optlen; + } + return 0; +} + +static int ah_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct iphdr *iph, *top_iph; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { + err = -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err = xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + + iph = skb->nh.iph; + if (x->props.mode) { + top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); + top_iph->ihl = 5; + top_iph->version = 4; + top_iph->tos = 0; + top_iph->tot_len = htons(skb->len); + top_iph->frag_off = 0; + if (!(iph->frag_off&htons(IP_DF))) + __ip_select_ident(top_iph, dst, 0); + top_iph->ttl = 0; + top_iph->protocol = IPPROTO_AH; + top_iph->check = 0; + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + ah = (struct ip_auth_hdr*)(top_iph+1); + ah->nexthdr = IPPROTO_IPIP; + } else { + memcpy(&tmp_iph, skb->data, iph->ihl*4); + top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); + memcpy(top_iph, &tmp_iph, iph->ihl*4); + iph = &tmp_iph.iph; + top_iph->tos = 0; + top_iph->tot_len = htons(skb->len); + top_iph->frag_off = 0; + top_iph->ttl = 0; + top_iph->protocol = IPPROTO_AH; + top_iph->check = 0; + if (top_iph->ihl != 5) { + err = ip_clear_mutable_options(top_iph, &top_iph->daddr); + if (err) + goto error; + } + ah = (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4); + ah->nexthdr = iph->protocol; + } + ahp = x->data; + ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + + ahp->icv_trunc_len) >> 2) - 2; + + ah->reserved = 0; + ah->spi = x->id.spi; + ah->seq_no = htonl(++x->replay.oseq); + ahp->icv(ahp, skb, ah->auth_data); + top_iph->tos = iph->tos; + top_iph->ttl = iph->ttl; + if (x->props.mode) { + top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + } else { + top_iph->frag_off = iph->frag_off; + top_iph->daddr = iph->daddr; + if (iph->ihl != 5) + memcpy(top_iph+1, iph+1, iph->ihl*4 - sizeof(struct iphdr)); + } + ip_send_check(top_iph); + + skb->nh.raw = skb->data; + + x->curlft.bytes += skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst = dst_pop(dst)) == NULL) { + err = -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) +{ + int ah_hlen; + struct iphdr *iph; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + char work_buf[60]; + + if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) + goto out; + + ah = (struct ip_auth_hdr*)skb->data; + ahp = x->data; + ah_hlen = (ah->hdrlen + 2) << 2; + + if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && + ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) + goto out; + + if (!pskb_may_pull(skb, ah_hlen)) + goto out; + + /* We are going to _remove_ AH header to keep sockets happy, + * so... Later this can change. */ + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto out; + + skb->ip_summed = CHECKSUM_NONE; + + ah = (struct ip_auth_hdr*)skb->data; + iph = skb->nh.iph; + + memcpy(work_buf, iph, iph->ihl*4); + + iph->ttl = 0; + iph->tos = 0; + iph->frag_off = 0; + iph->check = 0; + if (iph->ihl != 5) { + u32 dummy; + if (ip_clear_mutable_options(iph, &dummy)) + goto out; + } + { + u8 auth_data[ahp->icv_trunc_len]; + + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); + skb_push(skb, skb->data - skb->nh.raw); + ahp->icv(ahp, skb, ah->auth_data); + if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { + x->stats.integrity_failed++; + goto out; + } + } + ((struct iphdr*)work_buf)->protocol = ah->nexthdr; + skb->nh.raw = skb_pull(skb, ah_hlen); + memcpy(skb->nh.raw, work_buf, iph->ihl*4); + skb->nh.iph->tot_len = htons(skb->len); + skb_pull(skb, skb->nh.iph->ihl*4); + skb->h.raw = skb->data; + + return 0; + +out: + return -EINVAL; +} + +void ah4_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph = (struct iphdr*)skb->data; + struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); + struct xfrm_state *x; + + if (skb->h.icmph->type != ICMP_DEST_UNREACH || + skb->h.icmph->code != ICMP_FRAG_NEEDED) + return; + + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/%08x\n", + ntohl(ah->spi), ntohl(iph->daddr)); + xfrm_state_put(x); +} + +static int ah_init_state(struct xfrm_state *x, void *args) +{ + struct ah_data *ahp = NULL; + struct xfrm_algo_desc *aalg_desc; + + /* null auth can use a zero length key */ + if (x->aalg->alg_key_len > 512) + goto error; + + ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); + if (ahp == NULL) + return -ENOMEM; + + memset(ahp, 0, sizeof(*ahp)); + + ahp->key = x->aalg->alg_key; + ahp->key_len = (x->aalg->alg_key_len+7)/8; + ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + if (!ahp->tfm) + goto error; + ahp->icv = ah_hmac_digest; + + /* + * Lookup the algorithm description maintained by xfrm_algo, + * verify crypto transform properties, and store information + * we need for AH processing. This lookup cannot fail here + * after a successful crypto_alloc_tfm(). + */ + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 != + crypto_tfm_alg_digestsize(ahp->tfm)) { + printk(KERN_INFO "AH: %s digestsize %u != %hu\n", + x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } + + ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; + ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + + ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); + if (!ahp->work_icv) + goto error; + + x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); + if (x->props.mode) + x->props.header_len += sizeof(struct iphdr); + x->data = ahp; + + return 0; + +error: + if (ahp) { + if (ahp->work_icv) + kfree(ahp->work_icv); + if (ahp->tfm) + crypto_free_tfm(ahp->tfm); + kfree(ahp); + } + return -EINVAL; +} + +static void ah_destroy(struct xfrm_state *x) +{ + struct ah_data *ahp = x->data; + + if (ahp->work_icv) { + kfree(ahp->work_icv); + ahp->work_icv = NULL; + } + if (ahp->tfm) { + crypto_free_tfm(ahp->tfm); + ahp->tfm = NULL; + } + kfree(ahp); +} + + +static struct xfrm_type ah_type = +{ + .description = "AH4", + .owner = THIS_MODULE, + .proto = IPPROTO_AH, + .init_state = ah_init_state, + .destructor = ah_destroy, + .input = ah_input, + .output = ah_output +}; + +static struct inet_protocol ah4_protocol = { + .handler = xfrm4_rcv, + .err_handler = ah4_err, + .no_policy = 1, +}; + +static int __init ah4_init(void) +{ + if (xfrm_register_type(&ah_type, AF_INET) < 0) { + printk(KERN_INFO "ip ah init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { + printk(KERN_INFO "ip ah init: can't add protocol\n"); + xfrm_unregister_type(&ah_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit ah4_fini(void) +{ + if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) + printk(KERN_INFO "ip ah close: can't remove protocol\n"); + if (xfrm_unregister_type(&ah_type, AF_INET) < 0) + printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); +} + +module_init(ah4_init); +module_exit(ah4_fini); +MODULE_LICENSE("GPL"); diff -urN linux-2.5.70-bk9/net/ipv4/esp.c linux-2.5.70-bk10/net/ipv4/esp.c --- linux-2.5.70-bk9/net/ipv4/esp.c 2003-06-05 04:41:32.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv4/esp.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,603 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_SG_ONSTACK 4 - -/* decapsulation data for use when post-processing */ -struct esp_decap_data { - xfrm_address_t saddr; - __u16 sport; - __u8 proto; -}; - -int esp_output(struct sk_buff *skb) -{ - int err; - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - struct ip_esp_hdr *esph; - struct crypto_tfm *tfm; - struct esp_data *esp; - struct sk_buff *trailer; - struct udphdr *uh = NULL; - struct xfrm_encap_tmpl *encap = NULL; - int blksize; - int clen; - int alen; - int nfrags; - union { - struct iphdr iph; - char buf[60]; - } tmp_iph; - - /* First, if the skb is not checksummed, complete checksum. */ - if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { - err = -EINVAL; - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_check_output(x, skb, AF_INET); - if (err) - goto error; - err = -ENOMEM; - - /* Strip IP header in transport mode. Save it. */ - if (!x->props.mode) { - iph = skb->nh.iph; - memcpy(&tmp_iph, iph, iph->ihl*4); - __skb_pull(skb, iph->ihl*4); - } - /* Now skb is pure payload to encrypt */ - - /* Round to block size */ - clen = skb->len; - - esp = x->data; - alen = esp->auth.icv_trunc_len; - tfm = esp->conf.tfm; - blksize = (crypto_tfm_alg_blocksize(tfm) + 3) & ~3; - clen = (clen + 2 + blksize-1)&~(blksize-1); - if (esp->conf.padlen) - clen = (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1); - - if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) - goto error; - - /* Fill padding... */ - do { - int i; - for (i=0; ilen - 2; i++) - *(u8*)(trailer->tail + i) = i+1; - } while (0); - *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; - pskb_put(skb, trailer, clen - skb->len); - - encap = x->encap; - - iph = skb->nh.iph; - if (x->props.mode) { - top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); - esph = (struct ip_esp_hdr*)(top_iph+1); - if (encap && encap->encap_type) { - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - uh = (struct udphdr*) esph; - esph = (struct ip_esp_hdr*)(uh+1); - top_iph->protocol = IPPROTO_UDP; - break; - default: - printk(KERN_INFO - "esp_output(): Unhandled encap: %u\n", - encap->encap_type); - top_iph->protocol = IPPROTO_ESP; - break; - } - } else - top_iph->protocol = IPPROTO_ESP; - *(u8*)(trailer->tail - 1) = IPPROTO_IPIP; - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = iph->tos; /* DS disclosed */ - top_iph->tot_len = htons(skb->len + alen); - top_iph->frag_off = iph->frag_off&htons(IP_DF); - if (!(top_iph->frag_off)) - ip_select_ident(top_iph, dst, 0); - top_iph->ttl = iph->ttl; /* TTL disclosed */ - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - } else { - esph = (struct ip_esp_hdr*)skb_push(skb, x->props.header_len); - top_iph = (struct iphdr*)skb_push(skb, iph->ihl*4); - memcpy(top_iph, &tmp_iph, iph->ihl*4); - if (encap && encap->encap_type) { - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - uh = (struct udphdr*) esph; - esph = (struct ip_esp_hdr*)(uh+1); - top_iph->protocol = IPPROTO_UDP; - break; - default: - printk(KERN_INFO - "esp_output(): Unhandled encap: %u\n", - encap->encap_type); - top_iph->protocol = IPPROTO_ESP; - break; - } - } else - top_iph->protocol = IPPROTO_ESP; - iph = &tmp_iph.iph; - top_iph->tot_len = htons(skb->len + alen); - top_iph->check = 0; - top_iph->frag_off = iph->frag_off; - *(u8*)(trailer->tail - 1) = iph->protocol; - } - - /* this is non-NULL only with UDP Encapsulation */ - if (encap && uh) { - uh->source = encap->encap_sport; - uh->dest = encap->encap_dport; - uh->len = htons(skb->len + alen - sizeof(struct iphdr)); - uh->check = 0; - } - - esph->spi = x->id.spi; - esph->seq_no = htonl(++x->replay.oseq); - - if (esp->conf.ivlen) - crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); - - do { - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; - - if (unlikely(nfrags > MAX_SG_ONSTACK)) { - sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); - if (!sg) - goto error; - } - skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); - crypto_cipher_encrypt(tfm, sg, sg, clen); - if (unlikely(sg != sgbuf)) - kfree(sg); - } while (0); - - if (esp->conf.ivlen) { - memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); - crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); - } - - if (esp->auth.icv_full_len) { - esp->auth.icv(esp, skb, (u8*)esph-skb->data, - sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); - pskb_put(skb, trailer, alen); - } - - ip_send_check(top_iph); - - skb->nh.raw = skb->data; - - x->curlft.bytes += skb->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - if ((skb->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; - -error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(skb); - return err; -} - -/* - * Note: detecting truncated vs. non-truncated authentication data is very - * expensive, so we only support truncated data, which is the recommended - * and common case. - */ -int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ - struct iphdr *iph; - struct ip_esp_hdr *esph; - struct esp_data *esp = x->data; - struct sk_buff *trailer; - int blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); - int alen = esp->auth.icv_trunc_len; - int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; - int nfrags; - int encap_len = 0; - - if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) - goto out; - - if (elen <= 0 || (elen & (blksize-1))) - goto out; - - /* If integrity check is required, do this. */ - if (esp->auth.icv_full_len) { - u8 sum[esp->auth.icv_full_len]; - u8 sum1[alen]; - - esp->auth.icv(esp, skb, 0, skb->len-alen, sum); - - if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) - BUG(); - - if (unlikely(memcmp(sum, sum1, alen))) { - x->stats.integrity_failed++; - goto out; - } - } - - if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) - goto out; - - skb->ip_summed = CHECKSUM_NONE; - - esph = (struct ip_esp_hdr*)skb->data; - iph = skb->nh.iph; - - /* Get ivec. This can be wrong, check against another impls. */ - if (esp->conf.ivlen) - crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); - - { - u8 nexthdr[2]; - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; - u8 workbuf[60]; - int padlen; - - if (unlikely(nfrags > MAX_SG_ONSTACK)) { - sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); - if (!sg) - goto out; - } - skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); - crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); - if (unlikely(sg != sgbuf)) - kfree(sg); - - if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) - BUG(); - - padlen = nexthdr[0]; - if (padlen+2 >= elen) - goto out; - - /* ... check padding bits here. Silly. :-) */ - - if (x->encap && decap && decap->decap_type) { - struct esp_decap_data *encap_data; - struct udphdr *uh = (struct udphdr *) (iph+1); - - encap_data = (struct esp_decap_data *) (decap->decap_data); - encap_data->proto = 0; - - switch (decap->decap_type) { - case UDP_ENCAP_ESPINUDP: - - if ((void*)uh == (void*)esph) { - printk(KERN_DEBUG - "esp_input(): Got ESP; expecting ESPinUDP\n"); - break; - } - - encap_data->proto = AF_INET; - encap_data->saddr.a4 = iph->saddr; - encap_data->sport = uh->source; - encap_len = (void*)esph - (void*)uh; - if (encap_len != sizeof(*uh)) - printk(KERN_DEBUG - "esp_input(): UDP -> ESP: too much room: %d\n", - encap_len); - break; - - default: - printk(KERN_INFO - "esp_input(): processing unknown encap type: %u\n", - decap->decap_type); - break; - } - } - - iph->protocol = nexthdr[1]; - pskb_trim(skb, skb->len - alen - padlen - 2); - memcpy(workbuf, skb->nh.raw, iph->ihl*4); - skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); - skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; - memcpy(skb->nh.raw, workbuf, iph->ihl*4); - skb->nh.iph->tot_len = htons(skb->len); - } - - return 0; - -out: - return -EINVAL; -} - -int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ - - if (x->encap) { - struct xfrm_encap_tmpl *encap; - struct esp_decap_data *decap_data; - - encap = x->encap; - decap_data = (struct esp_decap_data *)(decap->decap_data); - - /* first, make sure that the decap type == the encap type */ - if (encap->encap_type != decap->decap_type) - return -EINVAL; - - /* Next, if we don't have an encap type, then ignore it */ - if (!encap->encap_type) - return 0; - - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - /* - * 1) if the NAT-T peer's IP or port changed then - * advertize the change to the keying daemon. - * This is an inbound SA, so just compare - * SRC ports. - */ - if (decap_data->proto == AF_INET && - (decap_data->saddr.a4 != x->props.saddr.a4 || - decap_data->sport != encap->encap_sport)) { - xfrm_address_t ipaddr; - - ipaddr.a4 = decap_data->saddr.a4; - km_new_mapping(x, &ipaddr, decap_data->sport); - - /* XXX: perhaps add an extra - * policy check here, to see - * if we should allow or - * reject a packet from a - * different source - * address/port. - */ - } - - /* - * 2) ignore UDP/TCP checksums in case - * of NAT-T in Transport Mode, or - * perform other post-processing fixes - * as per * draft-ietf-ipsec-udp-encaps-06, - * section 3.1.2 - */ - if (!x->props.mode) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - break; - default: - printk(KERN_INFO - "esp4_post_input(): Unhandled encap type: %u\n", - encap->encap_type); - break; - } - } - return 0; -} - -static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) -{ - struct esp_data *esp = x->data; - u32 blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); - - if (x->props.mode) { - mtu = (mtu + 2 + blksize-1)&~(blksize-1); - } else { - /* The worst case. */ - mtu += 2 + blksize; - } - if (esp->conf.padlen) - mtu = (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1); - - return mtu + x->props.header_len + esp->auth.icv_trunc_len; -} - -void esp4_err(struct sk_buff *skb, u32 info) -{ - struct iphdr *iph = (struct iphdr*)skb->data; - struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); - struct xfrm_state *x; - - if (skb->h.icmph->type != ICMP_DEST_UNREACH || - skb->h.icmph->code != ICMP_FRAG_NEEDED) - return; - - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); - if (!x) - return; - printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/%08x\n", - ntohl(esph->spi), ntohl(iph->daddr)); - xfrm_state_put(x); -} - -void esp_destroy(struct xfrm_state *x) -{ - struct esp_data *esp = x->data; - - if (esp->conf.tfm) { - crypto_free_tfm(esp->conf.tfm); - esp->conf.tfm = NULL; - } - if (esp->conf.ivec) { - kfree(esp->conf.ivec); - esp->conf.ivec = NULL; - } - if (esp->auth.tfm) { - crypto_free_tfm(esp->auth.tfm); - esp->auth.tfm = NULL; - } - if (esp->auth.work_icv) { - kfree(esp->auth.work_icv); - esp->auth.work_icv = NULL; - } - kfree(esp); -} - -int esp_init_state(struct xfrm_state *x, void *args) -{ - struct esp_data *esp = NULL; - - /* null auth and encryption can have zero length keys */ - if (x->aalg) { - if (x->aalg->alg_key_len > 512) - goto error; - } - if (x->ealg == NULL) - goto error; - - esp = kmalloc(sizeof(*esp), GFP_KERNEL); - if (esp == NULL) - return -ENOMEM; - - memset(esp, 0, sizeof(*esp)); - - if (x->aalg) { - struct xfrm_algo_desc *aalg_desc; - - esp->auth.key = x->aalg->alg_key; - esp->auth.key_len = (x->aalg->alg_key_len+7)/8; - esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); - if (esp->auth.tfm == NULL) - goto error; - esp->auth.icv = esp_hmac_digest; - - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); - BUG_ON(!aalg_desc); - - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(esp->auth.tfm)) { - printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", - x->aalg->alg_name, - crypto_tfm_alg_digestsize(esp->auth.tfm), - aalg_desc->uinfo.auth.icv_fullbits/8); - goto error; - } - - esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; - esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; - - esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL); - if (!esp->auth.work_icv) - goto error; - } - esp->conf.key = x->ealg->alg_key; - esp->conf.key_len = (x->ealg->alg_key_len+7)/8; - esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC); - if (esp->conf.tfm == NULL) - goto error; - esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm); - esp->conf.padlen = 0; - if (esp->conf.ivlen) { - esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); - get_random_bytes(esp->conf.ivec, esp->conf.ivlen); - } - crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len); - x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; - if (x->props.mode) - x->props.header_len += sizeof(struct iphdr); - if (x->encap) { - struct xfrm_encap_tmpl *encap = x->encap; - - if (encap->encap_type) { - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - x->props.header_len += sizeof(struct udphdr); - break; - default: - printk (KERN_INFO - "esp_init_state(): Unhandled encap type: %u\n", - encap->encap_type); - break; - } - } - } - x->data = esp; - x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len; - return 0; - -error: - if (esp) { - if (esp->auth.tfm) - crypto_free_tfm(esp->auth.tfm); - if (esp->auth.work_icv) - kfree(esp->auth.work_icv); - if (esp->conf.tfm) - crypto_free_tfm(esp->conf.tfm); - kfree(esp); - } - return -EINVAL; -} - -static struct xfrm_type esp_type = -{ - .description = "ESP4", - .owner = THIS_MODULE, - .proto = IPPROTO_ESP, - .init_state = esp_init_state, - .destructor = esp_destroy, - .get_max_size = esp4_get_max_size, - .input = esp_input, - .post_input = esp_post_input, - .output = esp_output -}; - -static struct inet_protocol esp4_protocol = { - .handler = xfrm4_rcv, - .err_handler = esp4_err, - .no_policy = 1, -}; - -static int __init esp4_init(void) -{ - struct xfrm_decap_state decap; - - if (sizeof(struct esp_decap_data) < - sizeof(decap.decap_data)) { - extern void decap_data_too_small(void); - - decap_data_too_small(); - } - - if (xfrm_register_type(&esp_type, AF_INET) < 0) { - printk(KERN_INFO "ip esp init: can't add xfrm type\n"); - return -EAGAIN; - } - if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { - printk(KERN_INFO "ip esp init: can't add protocol\n"); - xfrm_unregister_type(&esp_type, AF_INET); - return -EAGAIN; - } - return 0; -} - -static void __exit esp4_fini(void) -{ - if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) - printk(KERN_INFO "ip esp close: can't remove protocol\n"); - if (xfrm_unregister_type(&esp_type, AF_INET) < 0) - printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); -} - -module_init(esp4_init); -module_exit(esp4_fini); -MODULE_LICENSE("GPL"); diff -urN linux-2.5.70-bk9/net/ipv4/esp4.c linux-2.5.70-bk10/net/ipv4/esp4.c --- linux-2.5.70-bk9/net/ipv4/esp4.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk10/net/ipv4/esp4.c 2003-06-05 04:41:37.000000000 -0700 @@ -0,0 +1,603 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SG_ONSTACK 4 + +/* decapsulation data for use when post-processing */ +struct esp_decap_data { + xfrm_address_t saddr; + __u16 sport; + __u8 proto; +}; + +int esp_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct iphdr *iph, *top_iph; + struct ip_esp_hdr *esph; + struct crypto_tfm *tfm; + struct esp_data *esp; + struct sk_buff *trailer; + struct udphdr *uh = NULL; + struct xfrm_encap_tmpl *encap = NULL; + int blksize; + int clen; + int alen; + int nfrags; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + /* First, if the skb is not checksummed, complete checksum. */ + if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { + err = -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err = xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + err = -ENOMEM; + + /* Strip IP header in transport mode. Save it. */ + if (!x->props.mode) { + iph = skb->nh.iph; + memcpy(&tmp_iph, iph, iph->ihl*4); + __skb_pull(skb, iph->ihl*4); + } + /* Now skb is pure payload to encrypt */ + + /* Round to block size */ + clen = skb->len; + + esp = x->data; + alen = esp->auth.icv_trunc_len; + tfm = esp->conf.tfm; + blksize = (crypto_tfm_alg_blocksize(tfm) + 3) & ~3; + clen = (clen + 2 + blksize-1)&~(blksize-1); + if (esp->conf.padlen) + clen = (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) + goto error; + + /* Fill padding... */ + do { + int i; + for (i=0; ilen - 2; i++) + *(u8*)(trailer->tail + i) = i+1; + } while (0); + *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; + pskb_put(skb, trailer, clen - skb->len); + + encap = x->encap; + + iph = skb->nh.iph; + if (x->props.mode) { + top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); + esph = (struct ip_esp_hdr*)(top_iph+1); + if (encap && encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + uh = (struct udphdr*) esph; + esph = (struct ip_esp_hdr*)(uh+1); + top_iph->protocol = IPPROTO_UDP; + break; + default: + printk(KERN_INFO + "esp_output(): Unhandled encap: %u\n", + encap->encap_type); + top_iph->protocol = IPPROTO_ESP; + break; + } + } else + top_iph->protocol = IPPROTO_ESP; + *(u8*)(trailer->tail - 1) = IPPROTO_IPIP; + top_iph->ihl = 5; + top_iph->version = 4; + top_iph->tos = iph->tos; /* DS disclosed */ + top_iph->tot_len = htons(skb->len + alen); + top_iph->frag_off = iph->frag_off&htons(IP_DF); + if (!(top_iph->frag_off)) + ip_select_ident(top_iph, dst, 0); + top_iph->ttl = iph->ttl; /* TTL disclosed */ + top_iph->check = 0; + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + } else { + esph = (struct ip_esp_hdr*)skb_push(skb, x->props.header_len); + top_iph = (struct iphdr*)skb_push(skb, iph->ihl*4); + memcpy(top_iph, &tmp_iph, iph->ihl*4); + if (encap && encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + uh = (struct udphdr*) esph; + esph = (struct ip_esp_hdr*)(uh+1); + top_iph->protocol = IPPROTO_UDP; + break; + default: + printk(KERN_INFO + "esp_output(): Unhandled encap: %u\n", + encap->encap_type); + top_iph->protocol = IPPROTO_ESP; + break; + } + } else + top_iph->protocol = IPPROTO_ESP; + iph = &tmp_iph.iph; + top_iph->tot_len = htons(skb->len + alen); + top_iph->check = 0; + top_iph->frag_off = iph->frag_off; + *(u8*)(trailer->tail - 1) = iph->protocol; + } + + /* this is non-NULL only with UDP Encapsulation */ + if (encap && uh) { + uh->source = encap->encap_sport; + uh->dest = encap->encap_dport; + uh->len = htons(skb->len + alen - sizeof(struct iphdr)); + uh->check = 0; + } + + esph->spi = x->id.spi; + esph->seq_no = htonl(++x->replay.oseq); + + if (esp->conf.ivlen) + crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + + do { + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg = sgbuf; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto error; + } + skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); + crypto_cipher_encrypt(tfm, sg, sg, clen); + if (unlikely(sg != sgbuf)) + kfree(sg); + } while (0); + + if (esp->conf.ivlen) { + memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + } + + if (esp->auth.icv_full_len) { + esp->auth.icv(esp, skb, (u8*)esph-skb->data, + sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); + pskb_put(skb, trailer, alen); + } + + ip_send_check(top_iph); + + skb->nh.raw = skb->data; + + x->curlft.bytes += skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst = dst_pop(dst)) == NULL) { + err = -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +/* + * Note: detecting truncated vs. non-truncated authentication data is very + * expensive, so we only support truncated data, which is the recommended + * and common case. + */ +int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) +{ + struct iphdr *iph; + struct ip_esp_hdr *esph; + struct esp_data *esp = x->data; + struct sk_buff *trailer; + int blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); + int alen = esp->auth.icv_trunc_len; + int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; + int nfrags; + int encap_len = 0; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) + goto out; + + if (elen <= 0 || (elen & (blksize-1))) + goto out; + + /* If integrity check is required, do this. */ + if (esp->auth.icv_full_len) { + u8 sum[esp->auth.icv_full_len]; + u8 sum1[alen]; + + esp->auth.icv(esp, skb, 0, skb->len-alen, sum); + + if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) + BUG(); + + if (unlikely(memcmp(sum, sum1, alen))) { + x->stats.integrity_failed++; + goto out; + } + } + + if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + + skb->ip_summed = CHECKSUM_NONE; + + esph = (struct ip_esp_hdr*)skb->data; + iph = skb->nh.iph; + + /* Get ivec. This can be wrong, check against another impls. */ + if (esp->conf.ivlen) + crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); + + { + u8 nexthdr[2]; + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg = sgbuf; + u8 workbuf[60]; + int padlen; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto out; + } + skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); + crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); + if (unlikely(sg != sgbuf)) + kfree(sg); + + if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) + BUG(); + + padlen = nexthdr[0]; + if (padlen+2 >= elen) + goto out; + + /* ... check padding bits here. Silly. :-) */ + + if (x->encap && decap && decap->decap_type) { + struct esp_decap_data *encap_data; + struct udphdr *uh = (struct udphdr *) (iph+1); + + encap_data = (struct esp_decap_data *) (decap->decap_data); + encap_data->proto = 0; + + switch (decap->decap_type) { + case UDP_ENCAP_ESPINUDP: + + if ((void*)uh == (void*)esph) { + printk(KERN_DEBUG + "esp_input(): Got ESP; expecting ESPinUDP\n"); + break; + } + + encap_data->proto = AF_INET; + encap_data->saddr.a4 = iph->saddr; + encap_data->sport = uh->source; + encap_len = (void*)esph - (void*)uh; + if (encap_len != sizeof(*uh)) + printk(KERN_DEBUG + "esp_input(): UDP -> ESP: too much room: %d\n", + encap_len); + break; + + default: + printk(KERN_INFO + "esp_input(): processing unknown encap type: %u\n", + decap->decap_type); + break; + } + } + + iph->protocol = nexthdr[1]; + pskb_trim(skb, skb->len - alen - padlen - 2); + memcpy(workbuf, skb->nh.raw, iph->ihl*4); + skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); + skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; + memcpy(skb->nh.raw, workbuf, iph->ihl*4); + skb->nh.iph->tot_len = htons(skb->len); + } + + return 0; + +out: + return -EINVAL; +} + +int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) +{ + + if (x->encap) { + struct xfrm_encap_tmpl *encap; + struct esp_decap_data *decap_data; + + encap = x->encap; + decap_data = (struct esp_decap_data *)(decap->decap_data); + + /* first, make sure that the decap type == the encap type */ + if (encap->encap_type != decap->decap_type) + return -EINVAL; + + /* Next, if we don't have an encap type, then ignore it */ + if (!encap->encap_type) + return 0; + + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + /* + * 1) if the NAT-T peer's IP or port changed then + * advertize the change to the keying daemon. + * This is an inbound SA, so just compare + * SRC ports. + */ + if (decap_data->proto == AF_INET && + (decap_data->saddr.a4 != x->props.saddr.a4 || + decap_data->sport != encap->encap_sport)) { + xfrm_address_t ipaddr; + + ipaddr.a4 = decap_data->saddr.a4; + km_new_mapping(x, &ipaddr, decap_data->sport); + + /* XXX: perhaps add an extra + * policy check here, to see + * if we should allow or + * reject a packet from a + * different source + * address/port. + */ + } + + /* + * 2) ignore UDP/TCP checksums in case + * of NAT-T in Transport Mode, or + * perform other post-processing fixes + * as per * draft-ietf-ipsec-udp-encaps-06, + * section 3.1.2 + */ + if (!x->props.mode) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + break; + default: + printk(KERN_INFO + "esp4_post_input(): Unhandled encap type: %u\n", + encap->encap_type); + break; + } + } + return 0; +} + +static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) +{ + struct esp_data *esp = x->data; + u32 blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); + + if (x->props.mode) { + mtu = (mtu + 2 + blksize-1)&~(blksize-1); + } else { + /* The worst case. */ + mtu += 2 + blksize; + } + if (esp->conf.padlen) + mtu = (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + return mtu + x->props.header_len + esp->auth.icv_trunc_len; +} + +void esp4_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph = (struct iphdr*)skb->data; + struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); + struct xfrm_state *x; + + if (skb->h.icmph->type != ICMP_DEST_UNREACH || + skb->h.icmph->code != ICMP_FRAG_NEEDED) + return; + + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/%08x\n", + ntohl(esph->spi), ntohl(iph->daddr)); + xfrm_state_put(x); +} + +void esp_destroy(struct xfrm_state *x) +{ + struct esp_data *esp = x->data; + + if (esp->conf.tfm) { + crypto_free_tfm(esp->conf.tfm); + esp->conf.tfm = NULL; + } + if (esp->conf.ivec) { + kfree(esp->conf.ivec); + esp->conf.ivec = NULL; + } + if (esp->auth.tfm) { + crypto_free_tfm(esp->auth.tfm); + esp->auth.tfm = NULL; + } + if (esp->auth.work_icv) { + kfree(esp->auth.work_icv); + esp->auth.work_icv = NULL; + } + kfree(esp); +} + +int esp_init_state(struct xfrm_state *x, void *args) +{ + struct esp_data *esp = NULL; + + /* null auth and encryption can have zero length keys */ + if (x->aalg) { + if (x->aalg->alg_key_len > 512) + goto error; + } + if (x->ealg == NULL) + goto error; + + esp = kmalloc(sizeof(*esp), GFP_KERNEL); + if (esp == NULL) + return -ENOMEM; + + memset(esp, 0, sizeof(*esp)); + + if (x->aalg) { + struct xfrm_algo_desc *aalg_desc; + + esp->auth.key = x->aalg->alg_key; + esp->auth.key_len = (x->aalg->alg_key_len+7)/8; + esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + if (esp->auth.tfm == NULL) + goto error; + esp->auth.icv = esp_hmac_digest; + + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 != + crypto_tfm_alg_digestsize(esp->auth.tfm)) { + printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", + x->aalg->alg_name, + crypto_tfm_alg_digestsize(esp->auth.tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } + + esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; + esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + + esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL); + if (!esp->auth.work_icv) + goto error; + } + esp->conf.key = x->ealg->alg_key; + esp->conf.key_len = (x->ealg->alg_key_len+7)/8; + esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC); + if (esp->conf.tfm == NULL) + goto error; + esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm); + esp->conf.padlen = 0; + if (esp->conf.ivlen) { + esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); + get_random_bytes(esp->conf.ivec, esp->conf.ivlen); + } + crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len); + x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; + if (x->props.mode) + x->props.header_len += sizeof(struct iphdr); + if (x->encap) { + struct xfrm_encap_tmpl *encap = x->encap; + + if (encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + x->props.header_len += sizeof(struct udphdr); + break; + default: + printk (KERN_INFO + "esp_init_state(): Unhandled encap type: %u\n", + encap->encap_type); + break; + } + } + } + x->data = esp; + x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len; + return 0; + +error: + if (esp) { + if (esp->auth.tfm) + crypto_free_tfm(esp->auth.tfm); + if (esp->auth.work_icv) + kfree(esp->auth.work_icv); + if (esp->conf.tfm) + crypto_free_tfm(esp->conf.tfm); + kfree(esp); + } + return -EINVAL; +} + +static struct xfrm_type esp_type = +{ + .description = "ESP4", + .owner = THIS_MODULE, + .proto = IPPROTO_ESP, + .init_state = esp_init_state, + .destructor = esp_destroy, + .get_max_size = esp4_get_max_size, + .input = esp_input, + .post_input = esp_post_input, + .output = esp_output +}; + +static struct inet_protocol esp4_protocol = { + .handler = xfrm4_rcv, + .err_handler = esp4_err, + .no_policy = 1, +}; + +static int __init esp4_init(void) +{ + struct xfrm_decap_state decap; + + if (sizeof(struct esp_decap_data) < + sizeof(decap.decap_data)) { + extern void decap_data_too_small(void); + + decap_data_too_small(); + } + + if (xfrm_register_type(&esp_type, AF_INET) < 0) { + printk(KERN_INFO "ip esp init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { + printk(KERN_INFO "ip esp init: can't add protocol\n"); + xfrm_unregister_type(&esp_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit esp4_fini(void) +{ + if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) + printk(KERN_INFO "ip esp close: can't remove protocol\n"); + if (xfrm_unregister_type(&esp_type, AF_INET) < 0) + printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); +} + +module_init(esp4_init); +module_exit(esp4_fini); +MODULE_LICENSE("GPL"); diff -urN linux-2.5.70-bk9/net/ipv6/Kconfig linux-2.5.70-bk10/net/ipv6/Kconfig --- linux-2.5.70-bk9/net/ipv6/Kconfig 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/Kconfig 2003-06-05 04:41:37.000000000 -0700 @@ -4,6 +4,8 @@ config IPV6_PRIVACY bool "IPv6: Privacy Extensions (RFC 3041) support" depends on IPV6 + select CRYPTO + select CRYPTO_MD5 ---help--- Privacy Extensions for Stateless Address Autoconfiguration in IPv6 support. With this option, additional periodically-alter @@ -20,6 +22,10 @@ config INET6_AH tristate "IPv6: AH transformation" depends on IPV6 + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 ---help--- Support for IPsec AH. @@ -28,6 +34,11 @@ config INET6_ESP tristate "IPv6: ESP transformation" depends on IPV6 + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_DES ---help--- Support for IPsec ESP. @@ -36,6 +47,8 @@ config INET6_IPCOMP tristate "IPv6: IPComp transformation" depends on IPV6 + select CRYPTO + select CRYPTO_DEFLATE ---help--- Support for IP Paylod Compression (RFC3173), typically needed for IPsec. diff -urN linux-2.5.70-bk9/net/ipv6/addrconf.c linux-2.5.70-bk10/net/ipv6/addrconf.c --- linux-2.5.70-bk9/net/ipv6/addrconf.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/addrconf.c 2003-06-05 04:41:37.000000000 -0700 @@ -19,7 +19,7 @@ * * Janos Farkas : delete timer on ifdown * - * Andi Kleen : kill doube kfree on module + * Andi Kleen : kill double kfree on module * unload. * Maciej W. Rozycki : FDDI support * sekiya@USAGI : Don't send too many RS @@ -343,6 +343,7 @@ "%s(): cannot create /proc/net/dev_snmp6/%s\n", __FUNCTION__, dev->name)); neigh_parms_release(&nd_tbl, ndev->nd_parms); + ndev->dead = 1; in6_dev_finish_destroy(ndev); return NULL; } @@ -1256,7 +1257,7 @@ rtmsg.rtmsg_type = RTMSG_NEWROUTE; rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; - /* prefix length - 96 bytes "::d.d.d.d" */ + /* prefix length - 96 bits "::d.d.d.d" */ rtmsg.rtmsg_dst_len = 96; rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; rtmsg.rtmsg_ifindex = dev->ifindex; diff -urN linux-2.5.70-bk9/net/ipv6/af_inet6.c linux-2.5.70-bk10/net/ipv6/af_inet6.c --- linux-2.5.70-bk9/net/ipv6/af_inet6.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/af_inet6.c 2003-06-05 04:41:37.000000000 -0700 @@ -310,7 +310,7 @@ } else { if (addr_type != IPV6_ADDR_ANY) { /* ipv4 addr of the socket is invalid. Only the - * unpecified and mapped address have a v4 equivalent. + * unspecified and mapped address have a v4 equivalent. */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { diff -urN linux-2.5.70-bk9/net/ipv6/ip6_fib.c linux-2.5.70-bk10/net/ipv6/ip6_fib.c --- linux-2.5.70-bk9/net/ipv6/ip6_fib.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/ip6_fib.c 2003-06-05 04:41:37.000000000 -0700 @@ -40,7 +40,6 @@ #include #define RT6_DEBUG 2 -#undef CONFIG_IPV6_SUBTREES #if RT6_DEBUG >= 3 #define RT6_TRACE(x...) printk(KERN_DEBUG x) @@ -594,8 +593,8 @@ is orphan. If it is, shoot it. */ st_failure: - if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT)) - fib_repair_tree(fn); + if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) + fib6_repair_tree(fn); dst_free(&rt->u.dst); return err; #endif @@ -896,6 +895,7 @@ *rtp = rt->u.next; rt->rt6i_node = NULL; rt6_stats.fib_rt_entries--; + rt6_stats.fib_discarded_routes++; /* Adjust walkers */ read_lock(&fib6_walker_lock); diff -urN linux-2.5.70-bk9/net/ipv6/route.c linux-2.5.70-bk10/net/ipv6/route.c --- linux-2.5.70-bk9/net/ipv6/route.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/route.c 2003-06-05 04:41:37.000000000 -0700 @@ -336,7 +336,7 @@ return err; } -/* No rt6_lock! If COW faild, the function returns dead route entry +/* No rt6_lock! If COW failed, the function returns dead route entry with dst->error set to errno value. */ @@ -1786,11 +1786,12 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) { - seq_printf(seq, "%04x %04x %04x %04x %04x %04x\n", + seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", rt6_stats.fib_nodes, rt6_stats.fib_route_nodes, rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries, rt6_stats.fib_rt_cache, - atomic_read(&ip6_dst_ops.entries)); + atomic_read(&ip6_dst_ops.entries), + rt6_stats.fib_discarded_routes); return 0; } diff -urN linux-2.5.70-bk9/net/ipv6/udp.c linux-2.5.70-bk10/net/ipv6/udp.c --- linux-2.5.70-bk9/net/ipv6/udp.c 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/udp.c 2003-06-05 04:41:38.000000000 -0700 @@ -254,7 +254,6 @@ struct inet_opt *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct in6_addr *daddr; - struct in6_addr saddr; struct dst_entry *dst; struct flowi fl; struct ip6_flowlabel *flowlabel = NULL; @@ -355,7 +354,7 @@ fl.proto = IPPROTO_UDP; ipv6_addr_copy(&fl.fl6_dst, &np->daddr); - ipv6_addr_copy(&fl.fl6_src, &saddr); + ipv6_addr_copy(&fl.fl6_src, &np->saddr); fl.oif = sk->bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -381,20 +380,23 @@ return err; } - ip6_dst_store(sk, dst, &fl.fl6_dst); - /* get the source address used in the appropriate device */ - err = ipv6_get_saddr(dst, daddr, &saddr); + err = ipv6_get_saddr(dst, daddr, &fl.fl6_src); if (err == 0) { if (ipv6_addr_any(&np->saddr)) - ipv6_addr_copy(&np->saddr, &saddr); + ipv6_addr_copy(&np->saddr, &fl.fl6_src); if (ipv6_addr_any(&np->rcv_saddr)) { - ipv6_addr_copy(&np->rcv_saddr, &saddr); + ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); inet->rcv_saddr = LOOPBACK4_IPV6; } + + ip6_dst_store(sk, dst, + !ipv6_addr_cmp(&fl.fl6_dst, &np->daddr) ? + &np->daddr : NULL); + sk->state = TCP_ESTABLISHED; } fl6_sock_release(flowlabel); diff -urN linux-2.5.70-bk9/net/ipv6/xfrm6_policy.c linux-2.5.70-bk10/net/ipv6/xfrm6_policy.c --- linux-2.5.70-bk9/net/ipv6/xfrm6_policy.c 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk10/net/ipv6/xfrm6_policy.c 2003-06-05 04:41:38.000000000 -0700 @@ -146,7 +146,7 @@ memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics)); dst_prev->path = &rt->u.dst; - /* Copy neighbout for reachability confirmation */ + /* Copy neighbour for reachability confirmation */ dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); dst_prev->input = rt->u.dst.input; dst_prev->output = dst_prev->xfrm->type->output; diff -urN linux-2.5.70-bk9/scripts/Makefile.build linux-2.5.70-bk10/scripts/Makefile.build --- linux-2.5.70-bk9/scripts/Makefile.build 2003-05-26 18:00:46.000000000 -0700 +++ linux-2.5.70-bk10/scripts/Makefile.build 2003-06-05 04:41:38.000000000 -0700 @@ -71,55 +71,7 @@ quiet_cmd_checksrc = CHECK $< cmd_checksrc = $(CHECK) $(c_flags) $< ; endif - -# Module versioning -# --------------------------------------------------------------------------- -ifdef CONFIG_MODVERSIONS - -# $(call if_changed_rule,vcc_o_c) does essentially the same as the -# normal $(call if_changed_dep,cc_o_c), i.e. compile an object file -# from a C file, keeping track of the command line and dependencies. -# -# However, actually it does: -# o compile a .tmp_.o from .c -# o if .tmp_.o doesn't contain a __ksymtab version, i.e. does -# not export symbols, we just rename .tmp_.o to .o and -# are done. -# o otherwise, we calculate symbol versions using the good old -# genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate .o from .tmp_.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms - -quiet_cmd_vcc_o_c = CC $(quiet_modtag) $@ -cmd_vcc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< - -define rule_vcc_o_c - $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ - $(cmd_checksrc) \ - $(if $($(quiet)cmd_vcc_o_c),echo ' $($(quiet)cmd_vcc_o_c)';) \ - $(cmd_vcc_o_c); \ - \ - if ! $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - mv $(@D)/.tmp_$(@F) $@; \ - else \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ - fi; - \ - scripts/fixdep $(depfile) $@ '$(cmd_vcc_o_c)' > $(@D)/.$(@F).tmp; \ - rm -f $(depfile); \ - mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd -endef - -endif # Compile C sources (.c) # --------------------------------------------------------------------------- @@ -164,35 +116,63 @@ %.i: %.c FORCE $(call if_changed_dep,cc_i_c) +# C (.c) files +# The C file is compiled and updated dependency information is generated. +# (See cmd_cc_o_c + relevant part of rule_cc_o_c) + quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ -cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + +ifndef CONFIG_MODVERSIONS +cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + +else +# When module versioning is enabled the following steps are executed: +# o compile a .tmp_.o from .c +# o if .tmp_.o doesn't contain a __ksymtab version, i.e. does +# not export symbols, we just rename .tmp_.o to .o and +# are done. +# o otherwise, we calculate symbol versions using the good old +# genksyms on the preprocessed source and postprocess them in a way +# that they are usable as a linker script +# o generate .o from .tmp_.o using the linker to +# replace the unresolved symbols __crc_exported_symbol with +# the actual value of the checksum generated by genksyms + +cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< +cmd_modversions = \ + if ! $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ + mv $(@D)/.tmp_$(@F) $@; \ + else \ + $(CPP) -D__GENKSYMS__ $(c_flags) $< \ + | $(GENKSYMS) \ + > $(@D)/.tmp_$(@F:.o=.ver); \ + \ + $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ + -T $(@D)/.tmp_$(@F:.o=.ver); \ + rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ + fi; +endif + define rule_cc_o_c - $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ - $(cmd_checksrc) \ - $(if $($(quiet)cmd_cc_o_c),echo ' $($(quiet)cmd_cc_o_c)';) \ - $(cmd_cc_o_c); \ - scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp; \ - rm -f $(depfile); \ + $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ + $(cmd_checksrc) \ + $(if $($(quiet)cmd_cc_o_c),echo ' $($(quiet)cmd_cc_o_c)';) \ + $(cmd_cc_o_c); \ + $(cmd_modversions) \ + scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp; \ + rm -f $(depfile); \ mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd endef # Built-in and composite module parts %.o: %.c FORCE -ifdef CONFIG_MODVERSIONS - $(call if_changed_rule,vcc_o_c) -else $(call if_changed_rule,cc_o_c) -endif # Single-part modules are special since we need to mark them in $(MODVERDIR) $(single-used-m): %.o: %.c FORCE -ifdef CONFIG_MODVERSIONS - $(call if_changed_rule,vcc_o_c) -else $(call if_changed_rule,cc_o_c) -endif $(touch-module) quiet_cmd_cc_lst_c = MKLST $@ diff -urN linux-2.5.70-bk9/scripts/kconfig/conf.c linux-2.5.70-bk10/scripts/kconfig/conf.c --- linux-2.5.70-bk9/scripts/kconfig/conf.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/scripts/kconfig/conf.c 2003-06-05 04:41:38.000000000 -0700 @@ -286,10 +286,14 @@ break; } } else { - sym->user = sym->curr; - if (sym->curr.tri == mod) { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); return 0; + case yes: + break; } } diff -urN linux-2.5.70-bk9/scripts/kconfig/confdata.c linux-2.5.70-bk10/scripts/kconfig/confdata.c --- linux-2.5.70-bk9/scripts/kconfig/confdata.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/scripts/kconfig/confdata.c 2003-06-05 04:41:38.000000000 -0700 @@ -243,7 +243,8 @@ prop = sym_get_choice_prop(sym); sym->flags &= ~SYMBOL_NEW; for (e = prop->expr; e; e = e->left.expr) - sym->flags |= e->right.sym->flags & SYMBOL_NEW; + if (e->right.sym->visible != no) + sym->flags |= e->right.sym->flags & SYMBOL_NEW; } sym_change_count = 1; diff -urN linux-2.5.70-bk9/scripts/kconfig/menu.c linux-2.5.70-bk10/scripts/kconfig/menu.c --- linux-2.5.70-bk9/scripts/kconfig/menu.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/scripts/kconfig/menu.c 2003-06-05 04:41:38.000000000 -0700 @@ -221,11 +221,18 @@ for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym) { menu->sym->flags |= SYMBOL_CHOICEVAL; + if (!menu->prompt) + fprintf(stderr, "%s:%d:warning: choice value must have a prompt\n", + menu->file->name, menu->lineno); for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->type != P_DEFAULT) - continue; - fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n", - prop->file->name, prop->lineno); + if (prop->type == P_PROMPT && prop->menu != menu) { + fprintf(stderr, "%s:%d:warning: choice values currently only support a single prompt\n", + prop->file->name, prop->lineno); + + } + if (prop->type == P_DEFAULT) + fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n", + prop->file->name, prop->lineno); } current_entry = menu; menu_set_type(sym->type); @@ -311,14 +318,6 @@ } else visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); - if (sym && sym_is_choice(sym)) { - for (child = menu->list; child; child = child->next) - if (menu_is_visible(child)) - break; - if (!child) - return false; - } - if (visible != no) return true; if (!sym || sym_get_tristate_value(menu->sym) == no) diff -urN linux-2.5.70-bk9/scripts/kconfig/symbol.c linux-2.5.70-bk10/scripts/kconfig/symbol.c --- linux-2.5.70-bk9/scripts/kconfig/symbol.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/scripts/kconfig/symbol.c 2003-06-05 04:41:38.000000000 -0700 @@ -201,6 +201,9 @@ if (def_sym->visible != no) return def_sym; } + + /* no choice? reset tristate value */ + sym->curr.tri = no; return NULL; } diff -urN linux-2.5.70-bk9/sound/core/memalloc.c linux-2.5.70-bk10/sound/core/memalloc.c --- linux-2.5.70-bk9/sound/core/memalloc.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/sound/core/memalloc.c 2003-06-05 04:41:38.000000000 -0700 @@ -823,12 +823,12 @@ static void __init preallocate_cards(void) { - struct pci_dev *pci; + struct pci_dev *pci = NULL; int card; card = 0; - pci_for_each_dev(pci) { + while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { struct prealloc_dev *dev; if (card >= SNDRV_CARDS) break; diff -urN linux-2.5.70-bk9/sound/oss/cmpci.c linux-2.5.70-bk10/sound/oss/cmpci.c --- linux-2.5.70-bk9/sound/oss/cmpci.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk10/sound/oss/cmpci.c 2003-06-05 04:41:38.000000000 -0700 @@ -580,15 +580,17 @@ spin_unlock_irqrestore(&s->lock, flags); } -static void trans_ac3(struct cm_state *s, void *dest, const char *source, int size) +static int trans_ac3(struct cm_state *s, void *dest, const char *source, int size) { int i = size / 2; + int err; unsigned long data; unsigned long *dst = (unsigned long *) dest; unsigned short *src = (unsigned short *)source; do { - data = (unsigned long) *src++; + if ((err = __get_user(data, src++))) + return err; data <<= 12; // ok for 16-bit data if (s->spdif_counter == 2 || s->spdif_counter == 3) data |= 0x40000000; // indicate AC-3 raw data @@ -605,6 +607,8 @@ if (s->spdif_counter == 384) s->spdif_counter = 0; } while (--i); + + return 0; } static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate) @@ -1655,13 +1659,16 @@ continue; } if (s->status & DO_AC3_SW) { + int err; + // clip exceeded data, caught by 033 and 037 if (swptr + 2 * cnt > s->dma_dac.dmasize) cnt = (s->dma_dac.dmasize - swptr) / 2; - trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt); + if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) + return err; swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; } else if (s->status & DO_DUAL_DAC) { - int i; + int i, err; unsigned long *src, *dst0, *dst1; src = (unsigned long *) buffer; @@ -1669,8 +1676,10 @@ dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time for (i = 0; i <= cnt / 4; i++) { - *dst0++ = *src++; - *dst1++ = *src++; + if ((err = __get_user(*dst0++, src++))) + return err; + if ((err = __get_user(*dst1++, src++))) + return err; } swptr = (swptr + cnt) % s->dma_dac.dmasize; } else { diff -urN linux-2.5.70-bk9/sound/oss/esssolo1.c linux-2.5.70-bk10/sound/oss/esssolo1.c --- linux-2.5.70-bk9/sound/oss/esssolo1.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk10/sound/oss/esssolo1.c 2003-06-05 04:41:38.000000000 -0700 @@ -915,9 +915,9 @@ { unsigned int minor = minor(inode->i_rdev); struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver (pci_dev); if (drvr != &solo1_driver) @@ -1597,9 +1597,9 @@ unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver(pci_dev); @@ -1888,9 +1888,9 @@ DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver(pci_dev); @@ -2113,9 +2113,9 @@ unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver(pci_dev); diff -urN linux-2.5.70-bk9/sound/oss/maestro.c linux-2.5.70-bk10/sound/oss/maestro.c --- linux-2.5.70-bk9/sound/oss/maestro.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk10/sound/oss/maestro.c 2003-06-05 04:41:38.000000000 -0700 @@ -2132,10 +2132,10 @@ { unsigned int minor = minor(inode->i_rdev); struct ess_card *card = NULL; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct pci_driver *drvr; - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { drvr = pci_dev_driver (pdev); if (drvr == &maestro_pci_driver) { card = (struct ess_card*)pci_get_drvdata (pdev); @@ -2978,13 +2978,13 @@ unsigned int minor = minor(inode->i_rdev); struct ess_state *s = NULL; unsigned char fmtm = ~0, fmts = 0; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; /* * Scan the cards and find the channel. We only * do this at open time so it is ok */ - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { struct ess_card *c; struct pci_driver *drvr; diff -urN linux-2.5.70-bk9/sound/oss/via82cxxx_audio.c linux-2.5.70-bk10/sound/oss/via82cxxx_audio.c --- linux-2.5.70-bk9/sound/oss/via82cxxx_audio.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk10/sound/oss/via82cxxx_audio.c 2003-06-05 04:41:38.000000000 -0700 @@ -1357,12 +1357,12 @@ { int minor = minor(inode->i_rdev); struct via_info *card; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct pci_driver *drvr; DPRINTK ("ENTER\n"); - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { drvr = pci_dev_driver (pdev); if (drvr == &via_driver) { assert (pci_get_drvdata (pdev) != NULL); @@ -2982,8 +2982,8 @@ static int via_dsp_open (struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - struct via_info *card; - struct pci_dev *pdev; + struct via_info *card = NULL; + struct pci_dev *pdev = NULL; struct via_channel *chan; struct pci_driver *drvr; int nonblock = (file->f_flags & O_NONBLOCK); @@ -2995,8 +2995,7 @@ return -EINVAL; } - card = NULL; - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { drvr = pci_dev_driver (pdev); if (drvr == &via_driver) { assert (pci_get_drvdata (pdev) != NULL); diff -urN linux-2.5.70-bk9/sound/pci/rme9652/hammerfall_mem.c linux-2.5.70-bk10/sound/pci/rme9652/hammerfall_mem.c --- linux-2.5.70-bk9/sound/pci/rme9652/hammerfall_mem.c 2003-06-05 04:41:33.000000000 -0700 +++ linux-2.5.70-bk10/sound/pci/rme9652/hammerfall_mem.c 2003-06-05 04:41:38.000000000 -0700 @@ -185,7 +185,7 @@ static int __init alsa_hammerfall_mem_init(void) { int i; - struct pci_dev *pci; + struct pci_dev *pci = NULL; hammerfall_buf_t *rbuf; /* make sure our buffer records are clean */ @@ -205,12 +205,12 @@ i = 0; /* card number */ rbuf = hammerfall_buffers; - pci_for_each_dev(pci) { + while ((pci = pci_find_device(PCI_VENDOR_ID_XILINX, PCI_ANY_ID, pci)) != NULL) { int k; /* check for Hammerfall and Hammerfall DSP cards */ - if (pci->vendor != 0x10ee || (pci->device != 0x3fc4 && pci->device != 0x3fc5)) + if (pci->device != 0x3fc4 && pci->device != 0x3fc5) continue; if (!enable[i])