Commit 5b17082f authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.20

parent 433b8708
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -59,29 +59,30 @@ comment 'General setup'
bool 'BIGMEM support' CONFIG_BIGMEM
bool 'Networking support' CONFIG_NET
bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
choice 'PCI access mode' \
"BIOS CONFIG_PCI_GOBIOS \
Direct CONFIG_PCI_GODIRECT \
Any CONFIG_PCI_GOANY" Any
if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
define_bool CONFIG_PCI_BIOS y
fi
if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
define_bool CONFIG_PCI_DIRECT y
fi
fi
bool 'MCA support' CONFIG_MCA
bool 'SGI Visual Workstation support' CONFIG_VISWS
if [ "$CONFIG_VISWS" = "y" ]; then
define_bool CONFIG_X86_VISWS_APIC y
define_bool CONFIG_X86_LOCAL_APIC y
define_bool CONFIG_PCI y
else
if [ "$CONFIG_SMP" = "y" ]; then
define_bool CONFIG_X86_IO_APIC y
define_bool CONFIG_X86_LOCAL_APIC y
fi
bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
choice 'PCI access mode' \
"BIOS CONFIG_PCI_GOBIOS \
Direct CONFIG_PCI_GODIRECT \
Any CONFIG_PCI_GOANY" Any
if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
define_bool CONFIG_PCI_BIOS y
fi
if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
define_bool CONFIG_PCI_DIRECT y
fi
fi
bool 'MCA support' CONFIG_MCA
fi
source drivers/pcmcia/Config.in
......
......@@ -19,7 +19,12 @@ OX_OBJS := i386_ksyms.o
MX_OBJS :=
ifdef CONFIG_PCI
O_OBJS += bios32.o
O_OBJS += pci-i386.o
ifdef CONFIG_VISWS
O_OBJS += pci-visws.o
else
O_OBJS += pci-pc.o
endif
endif
ifdef CONFIG_MCA
......
......@@ -223,6 +223,8 @@
19990819 Alan Cox <alan@redhat.com>
Tested Zoltan's changes on a pre production Athlon - 100%
success.
19991008 Manfred Spraul <manfreds@colorfullife.com>
replaced spin_lock_reschedule() with a normal semaphore.
*/
#include <linux/types.h>
#include <linux/errno.h>
......@@ -303,8 +305,6 @@ typedef u8 mtrr_type;
TRUE)
#endif
#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule ();
#ifndef CONFIG_PROC_FS
# define compute_ascii() while (0)
#endif
......@@ -314,7 +314,7 @@ static char *ascii_buffer = NULL;
static unsigned int ascii_buf_bytes = 0;
#endif
static unsigned int *usage_table = NULL;
static spinlock_t main_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_MUTEX(main_lock);
/* Private functions */
#ifdef CONFIG_PROC_FS
......@@ -1172,7 +1172,7 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
increment = increment ? 1 : 0;
max = get_num_var_ranges ();
/* Search for existing MTRR */
spin_lock_reschedule (&main_lock);
down(&main_lock);
for (i = 0; i < max; ++i)
{
(*get_mtrr) (i, &lbase, &lsize, &ltype);
......@@ -1181,7 +1181,7 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
/* At this point we know there is some kind of overlap/enclosure */
if ( (base < lbase) || (base + size > lbase + lsize) )
{
spin_unlock (&main_lock);
up(&main_lock);
printk ("mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n",
base, size, lbase, lsize);
return -EINVAL;
......@@ -1190,14 +1190,14 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
if (ltype != type)
{
if (type == MTRR_TYPE_UNCACHABLE) continue;
spin_unlock (&main_lock);
up(&main_lock);
printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n",
base, size, attrib_to_str (ltype), attrib_to_str (type) );
return -EINVAL;
}
if (increment) ++usage_table[i];
compute_ascii ();
spin_unlock (&main_lock);
up(&main_lock);
return i;
}
/* Search for an empty MTRR */
......@@ -1211,7 +1211,7 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
set_mtrr (i, base, size, type);
usage_table[i] = 1;
compute_ascii ();
spin_unlock (&main_lock);
up(&main_lock);
return i;
} /* End Function mtrr_add */
......@@ -1232,7 +1232,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
max = get_num_var_ranges ();
spin_lock_reschedule (&main_lock);
down(&main_lock);
if (reg < 0)
{
/* Search for existing MTRR */
......@@ -1247,14 +1247,14 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
}
if (reg < 0)
{
spin_unlock (&main_lock);
up(&main_lock);
printk ("mtrr: no MTRR for %lx,%lx found\n", base, size);
return -EINVAL;
}
}
if (reg >= max)
{
spin_unlock (&main_lock);
up(&main_lock);
printk ("mtrr: register: %d too big\n", reg);
return -EINVAL;
}
......@@ -1262,7 +1262,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
{
if ((reg == 3) && arr3_protected)
{
spin_unlock (&main_lock);
up(&main_lock);
printk ("mtrr: ARR3 cannot be changed\n");
return -EINVAL;
}
......@@ -1270,19 +1270,19 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
(*get_mtrr) (reg, &lbase, &lsize, &ltype);
if (lsize < 1)
{
spin_unlock (&main_lock);
up(&main_lock);
printk ("mtrr: MTRR %d not used\n", reg);
return -EINVAL;
}
if (usage_table[reg] < 1)
{
spin_unlock (&main_lock);
up(&main_lock);
printk ("mtrr: reg: %d has count=0\n", reg);
return -EINVAL;
}
if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0);
compute_ascii ();
spin_unlock (&main_lock);
up(&main_lock);
return reg;
} /* End Function mtrr_del */
......
/*
* Low-Level PCI Access for i386 machines
*
* Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* Drew@Colorado.EDU
* +1 (303) 786-7975
*
* Drew's work was sponsored by:
* iX Multiuser Multitasking Magazine
* Hannover, Germany
* hm@ix.de
*
* Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
*
* PCI BIOS Specification
* PCI Local Bus Specification
* PCI to PCI Bridge Specification
* PCI System Design Guide
*
*
* CHANGELOG :
* Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
* Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
*
* Jan 5, 1995 : Modified to probe PCI hardware at boot time by Frederic
* Potter, potter@cao-vlsi.ibp.fr
*
* Jan 10, 1995 : Modified to store the information about configured pci
* devices into a list, which can be accessed via /proc/pci by
* Curtis Varner, cvarner@cs.ucr.edu
*
* Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
* Alpha version. Intel & UMC chipset support only.
*
* Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
* moved to drivers/pci/pci.c.
*
* Dec 7, 1996 : Added support for direct configuration access of boards
* with Intel compatible access schemes (tsbogend@alpha.franken.de)
*
* Feb 3, 1997 : Set internal functions to static, save/restore flags
* avoid dead locks reading broken PCI BIOS, werner@suse.de
*
* Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
* (mj@atrey.karlin.mff.cuni.cz)
*
* May 7, 1997 : Added some missing cli()'s. [mj]
*
* Jun 20, 1997 : Corrected problems in "conf1" type accesses.
* (paubert@iram.es)
*
* Aug 2, 1997 : Split to PCI BIOS handling and direct PCI access parts
* and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj]
*
* May 1, 1998 : Support for peer host bridges. [mj]
*
* Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
* can be accessed from interrupts even on SMP systems. [mj]
*
* August 1998 : Better support for peer host bridges and more paranoid
* checks for direct hardware access. Ugh, this file starts to look as
* a large gallery of common hardware bug workarounds (watch the comments)
* -- the PCI specs themselves are sane, but most implementors should be
* hit hard with \hammer scaled \magstep5. [mj]
*
* Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
*
* Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj]
*
* August 1999 : New resource management and configuration access stuff. [mj]
*
* Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
* Based on ideas by Chris Frantz and David Hinds. [mj]
*
* Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi
* for a lot of patience during testing. [mj]
*
* Oct 8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj]
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include "pci-i386.h"
/*
* Assign new address to PCI resource. We hope our resource information
* is complete. On the PC, we don't re-assign resources unless we are
* forced to do so.
*
* Expects start=0, end=size-1, flags=resource type.
*/
static int __init pcibios_assign_resource(struct pci_dev *dev, int i)
{
struct resource *r = &dev->resource[i];
struct resource *pr = pci_find_parent_resource(dev, r);
unsigned long size = r->end + 1;
u32 new, check;
if (!pr) {
printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO) {
/*
* We need to avoid collisions with `mirrored' VGA ports and other strange
* ISA hardware, so we always want the addresses kilobyte aligned.
*/
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size);
return -EFBIG;
}
if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) {
printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
} else {
if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) {
printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
}
if (i < 6) {
int reg = PCI_BASE_ADDRESS_0 + 4*i;
new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if (new != check)
printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
} else if (i == PCI_ROM_RESOURCE) {
r->flags |= PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
}
printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
return 0;
}
/*
* Handle resources of PCI devices. If the world were perfect, we could
* just allocate all the resource regions and do nothing more. It isn't.
* On the other hand, we cannot just re-allocate all devices, as it would
* require us to know lots of host bridge internals. So we attempt to
* keep as much of the original configuration as possible, but tweak it
* when it's found to be wrong.
*
* Known BIOS problems we have to work around:
* - I/O or memory regions not configured
* - regions configured, but not enabled in the command register
* - bogus I/O addresses above 64K used
* - expansion ROMs left enabled (this may sound harmless, but given
* the fact the PCI specs explicitly allow address decoders to be
* shared between expansion ROMs and other resource regions, it's
* at least dangerous)
*
* Our solution:
* (1) Allocate resources for all buses behind PCI-to-PCI bridges.
* This gives us fixed barriers on where we can allocate.
* (2) Allocate resources for all enabled devices. If there is
* a collision, just mark the resource as unallocated. Also
* disable expansion ROMs during this step.
* (3) Try to allocate resources for disabled devices. If the
* resources were assigned correctly, everything goes well,
* if they weren't, they won't disturb allocation of other
* resources.
* (4) Assign new addresses to resources which were either
* not configured at all or misconfigured. If explicitly
* requested by the user, configure expansion ROM address
* as well. Finally enable the I/O and Memory bits.
*/
static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
{
struct pci_dev *dev;
int idx;
struct resource *r, *pr;
/* Depth-First Search on bus tree */
while (bus) {
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
if (!r->start)
continue;
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0)
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
}
}
if (bus->children)
pcibios_allocate_bus_resources(bus->children);
bus = bus->next;
}
}
static void __init pcibios_allocate_resources(int pass)
{
struct pci_dev *dev;
int idx, disabled;
u16 command;
struct resource *r, *pr;
for(dev=pci_devices; dev; dev=dev->next) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (r->parent) /* Already allocated */
continue;
if (!r->start) /* Address not assigned at all */
continue;
if (r->flags & IORESOURCE_IO)
disabled = !(command & PCI_COMMAND_IO);
else
disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) {
DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
/* We'll assign a new address later */
r->start -= r->end;
r->start = 0;
}
}
}
if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
/* Turn the ROM off, leave the resource region, but keep it unregistered. */
u32 reg;
DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
}
}
}
}
static void __init pcibios_assign_resources(void)
{
struct pci_dev *dev;
u16 cmd, old_cmd;
int idx;
int fault = 0;
struct resource *r;
for(dev=pci_devices; dev; dev=dev->next) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for(idx=0; idx<6; idx++) {
r = &dev->resource[idx];
if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
/*
* Don't touch IDE controllers and I/O ports of video cards!
* Neither enable anything in their command registers.
*/
continue;
if (!r->start && r->end) {
/*
* We shall assign a new address to this resource, either because
* the BIOS forgot to do so or because we have decided the old
* address was unusable for some reason.
*/
if (pcibios_assign_resource(dev, idx) < 0)
fault = 1;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
if (fault)
printk("PCI: Not enabling device %s because of resource collisions\n", dev->slot_name);
else {
printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
}
if (pci_probe & PCI_ASSIGN_ROMS) {
r = &dev->resource[PCI_ROM_RESOURCE];
r->end -= r->start;
r->start = 0;
if (r->end)
pcibios_assign_resource(dev, PCI_ROM_RESOURCE);
}
}
}
void __init pcibios_resource_survey(void)
{
pcibios_allocate_bus_resources(pci_root);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
}
/*
* Low-Level PCI Access for i386 machines.
*
* (c) 1999 Martin Mares <mj@ucw.cz>
*/
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#define PCI_PROBE_BIOS 1
#define PCI_PROBE_CONF1 2
#define PCI_PROBE_CONF2 4
#define PCI_NO_SORT 0x100
#define PCI_BIOS_SORT 0x200
#define PCI_NO_CHECKS 0x400
#define PCI_NO_PEER_FIXUP 0x800
#define PCI_ASSIGN_ROMS 0x1000
#define PCI_NO_IRQ_SCAN 0x2000
extern unsigned int pci_probe;
/* pci-i386.c */
void pcibios_resource_survey(void);
/*
* bios32.c - Low-Level PCI Access
* Low-Level PCI Support for PC
*
* $Id: bios32.c,v 1.48 1998/09/26 08:06:55 mj Exp $
*
* Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* Drew@Colorado.EDU
* +1 (303) 786-7975
*
* Drew's work was sponsored by:
* iX Multiuser Multitasking Magazine
* Hannover, Germany
* hm@ix.de
*
* Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
*
* PCI BIOS Specification
* PCI Local Bus Specification
* PCI to PCI Bridge Specification
* PCI System Design Guide
*
*
* CHANGELOG :
* Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
* Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
*
* Jan 5, 1995 : Modified to probe PCI hardware at boot time by Frederic
* Potter, potter@cao-vlsi.ibp.fr
*
* Jan 10, 1995 : Modified to store the information about configured pci
* devices into a list, which can be accessed via /proc/pci by
* Curtis Varner, cvarner@cs.ucr.edu
*
* Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter.
* Alpha version. Intel & UMC chipset support only.
*
* Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
* moved to drivers/pci/pci.c.
*
* Dec 7, 1996 : Added support for direct configuration access of boards
* with Intel compatible access schemes (tsbogend@alpha.franken.de)
*
* Feb 3, 1997 : Set internal functions to static, save/restore flags
* avoid dead locks reading broken PCI BIOS, werner@suse.de
*
* Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS
* (mj@atrey.karlin.mff.cuni.cz)
*
* May 7, 1997 : Added some missing cli()'s. [mj]
*
* Jun 20, 1997 : Corrected problems in "conf1" type accesses.
* (paubert@iram.es)
*
* Aug 2, 1997 : Split to PCI BIOS handling and direct PCI access parts
* and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj]
*
* May 1, 1998 : Support for peer host bridges. [mj]
*
* Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
* can be accessed from interrupts even on SMP systems. [mj]
*
* August 1998 : Better support for peer host bridges and more paranoid
* checks for direct hardware access. Ugh, this file starts to look as
* a large gallery of common hardware bug workarounds (watch the comments)
* -- the PCI specs themselves are sane, but most implementors should be
* hit hard with \hammer scaled \magstep5. [mj]
*
* Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
*
* Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj]
*
* August 1999 : New resource management and configuration access stuff. [mj]
*
* Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges.
* Based on ideas by Chris Frantz and David Hinds. [mj]
* (c) 1999 Martin Mares <mj@ucw.cz>
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/smp.h>
#undef DEBUG
#include "pci-i386.h"
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#define PCI_PROBE_BIOS 1
#define PCI_PROBE_CONF1 2
#define PCI_PROBE_CONF2 4
#define PCI_NO_SORT 0x100
#define PCI_BIOS_SORT 0x200
#define PCI_NO_CHECKS 0x400
#define PCI_NO_PEER_FIXUP 0x800
#define PCI_ASSIGN_ROMS 0x1000
#define PCI_NO_IRQ_SCAN 0x2000
static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
/*
* IRQ routing table provided by the BIOS
......@@ -161,55 +63,55 @@ struct irq_routing_table {
static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inb(0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inb(0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inw(0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inw(0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inl(0xCFC);
return PCIBIOS_SUCCESSFUL;
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inl(0xCFC);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outb(value, 0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
outl(CONFIG_CMD(dev,where), 0xCF8);
outb(value, 0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outw(value, 0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
outl(CONFIG_CMD(dev,where), 0xCF8);
outw(value, 0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outl(value, 0xCFC);
return PCIBIOS_SUCCESSFUL;
outl(CONFIG_CMD(dev,where), 0xCF8);
outl(value, 0xCFC);
return PCIBIOS_SUCCESSFUL;
}
#undef CONFIG_CMD
static struct pci_ops pci_direct_conf1 = {
pci_conf1_read_config_byte,
pci_conf1_read_config_word,
pci_conf1_read_config_dword,
pci_conf1_write_config_byte,
pci_conf1_write_config_word,
pci_conf1_write_config_dword
pci_conf1_read_config_byte,
pci_conf1_read_config_word,
pci_conf1_read_config_dword,
pci_conf1_write_config_byte,
pci_conf1_write_config_word,
pci_conf1_write_config_dword
};
/*
......@@ -224,50 +126,50 @@ static struct pci_ops pci_direct_conf1 = {
static int pci_conf2_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
SET(dev);
*value = inb(IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
SET(dev);
*value = inb(IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
SET(dev);
*value = inw(IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
SET(dev);
*value = inw(IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
SET(dev);
*value = inl (IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
SET(dev);
*value = inl (IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
SET(dev);
outb (value, IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
SET(dev);
outb (value, IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_write_config_word(struct pci_dev *dev, int where, u16 value)
{
SET(dev);
outw (value, IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
SET(dev);
outw (value, IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
SET(dev);
outl (value, IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
SET(dev);
outl (value, IOADDR(dev->devfn,where));
outb (0, 0xCF8);
return PCIBIOS_SUCCESSFUL;
}
#undef SET
......@@ -275,12 +177,12 @@ static int pci_conf2_write_config_dword(struct pci_dev *dev, int where, u32 valu
#undef FUNC
static struct pci_ops pci_direct_conf2 = {
pci_conf2_read_config_byte,
pci_conf2_read_config_word,
pci_conf2_read_config_dword,
pci_conf2_write_config_byte,
pci_conf2_write_config_word,
pci_conf2_write_config_dword
pci_conf2_read_config_byte,
pci_conf2_read_config_word,
pci_conf2_read_config_dword,
pci_conf2_write_config_byte,
pci_conf2_write_config_word,
pci_conf2_write_config_dword
};
/*
......@@ -299,10 +201,6 @@ static int __init pci_sanity_check(struct pci_ops *o)
struct pci_bus bus; /* Fake bus and device */
struct pci_dev dev;
#ifdef CONFIG_VISWS
return 1; /* Lithium PCI Bridges are non-standard */
#endif
if (pci_probe & PCI_NO_CHECKS)
return 1;
bus.number = 0;
......@@ -461,7 +359,7 @@ static unsigned long bios32_service(unsigned long service)
printk("bios32_service(0x%lx): not present\n", service);
return 0;
default: /* Shouldn't happen */
printk("bios32_service(0x%lx): returned 0x%x, report to <mj@ucw.cz>.\n",
printk("bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n",
service, return_code);
return 0;
}
......@@ -829,59 +727,6 @@ static struct irq_routing_table * __init pcibios_get_irq_routing_table(void)
#endif
/*
* Assign new address to PCI resource. We hope our resource information
* is complete. On the PC, we don't re-assign resources unless we are
* forced to do so.
*
* Expects start=0, end=size-1, flags=resource type.
*/
static int __init pcibios_assign_resource(struct pci_dev *dev, int i)
{
struct resource *r = &dev->resource[i];
struct resource *pr = pci_find_parent_resource(dev, r);
unsigned long size = r->end + 1;
u32 new, check;
if (!pr) {
printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO) {
/*
* We need to avoid collisions with `mirrored' VGA ports and other strange
* ISA hardware, so we always want the addresses kilobyte aligned.
*/
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size);
return -EFBIG;
}
if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) {
printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
} else {
if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) {
printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
return -EBUSY;
}
}
if (i < 6) {
int reg = PCI_BASE_ADDRESS_0 + 4*i;
new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if (new != check)
printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
} else if (i == PCI_ROM_RESOURCE) {
r->flags |= PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
}
printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
return 0;
}
/*
* Several buggy motherboards address only 16 devices and mirror
* them to next 16 IDs. We try to detect this `feature' on all
......@@ -943,11 +788,6 @@ static void __init pcibios_fixup_peer_bridges(void)
struct pci_dev *d;
struct pci_ops *ops = pci_root->ops;
#ifdef CONFIG_VISWS
pci_scan_bus(1, ops, NULL);
return;
#endif
#ifdef CONFIG_PCI_DIRECT
/*
* Don't search for peer host bridges if we use config type 2
......@@ -1053,17 +893,14 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
*/
if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
/* This just can't be right even with the fixes */
#if 0
DBG("PCI: IDE base address fixup for %s\n", d->slot_name);
for(i=0; i<4; i++) {
struct resource *r = &d->resource[i];
if ((r->start & ~0x80) == 0x374) {
r->start += 2;
r->start |= 2;
r->end = r->start;
}
}
#endif
}
struct pci_fixup pcibios_fixups[] = {
......@@ -1073,170 +910,6 @@ struct pci_fixup pcibios_fixups[] = {
{ 0 }
};
/*
* Handle resources of PCI devices. If the world were perfect, we could
* just allocate all the resource regions and do nothing more. It isn't.
* On the other hand, we cannot just re-allocate all devices, as it would
* require us to know lots of host bridge internals. So we attempt to
* keep as much of the original configuration as possible, but tweak it
* when it's found to be wrong.
*
* Known BIOS problems we have to work around:
* - I/O or memory regions not configured
* - regions configured, but not enabled in the command register
* - bogus I/O addresses above 64K used
* - expansion ROMs left enabled (this may sound harmless, but given
* the fact the PCI specs explicitly allow address decoders to be
* shared between expansion ROMs and other resource regions, it's
* at least dangerous)
*
* Our solution:
* (1) Allocate resources for all buses behind PCI-to-PCI bridges.
* This gives us fixed barriers on where we can allocate.
* (2) Allocate resources for all enabled devices. If there is
* a collision, just mark the resource as unallocated. Also
* disable expansion ROMs during this step.
* (3) Try to allocate resources for disabled devices. If the
* resources were assigned correctly, everything goes well,
* if they weren't, they won't disturb allocation of other
* resources.
* (4) Assign new addresses to resources which were either
* not configured at all or misconfigured. If explicitly
* requested by the user, configure expansion ROM address
* as well. Finally enable the I/O and Memory bits.
*/
static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
{
struct pci_dev *dev;
int idx;
struct resource *r, *pr;
/* Depth-First Search on bus tree */
while (bus) {
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
if (!r->start)
continue;
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0)
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
}
}
if (bus->children)
pcibios_allocate_bus_resources(bus->children);
bus = bus->next;
}
}
static void __init pcibios_allocate_resources(int pass)
{
struct pci_dev *dev;
int idx, disabled;
u16 command;
struct resource *r, *pr;
for(dev=pci_devices; dev; dev=dev->next) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (r->parent) /* Already allocated */
continue;
if (!r->start) /* Address not assigned at all */
continue;
if (r->flags & IORESOURCE_IO)
disabled = !(command & PCI_COMMAND_IO);
else
disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) {
DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
/* We'll assign a new address later */
r->start -= r->end;
r->start = 0;
}
}
}
if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
/* Turn the ROM off, leave the resource region, but keep it unregistered. */
u32 reg;
DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
}
}
}
}
static void __init pcibios_assign_resources(void)
{
struct pci_dev *dev;
u16 cmd, old_cmd;
int idx;
int fault = 0;
struct resource *r;
for(dev=pci_devices; dev; dev=dev->next) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for(idx=0; idx<6; idx++) {
r = &dev->resource[idx];
if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
/*
* Don't touch IDE controllers and I/O ports of video cards!
* Neither enable anything in their command registers.
*/
continue;
if (!r->start && r->end) {
/*
* We shall assign a new address to this resource, either because
* the BIOS forgot to do so or because we have decided the old
* address was unusable for some reason.
*/
if (pcibios_assign_resource(dev, idx) < 0)
fault = 1;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
if (fault)
printk("PCI: Not enabling device %s because of resource collisions\n", dev->slot_name);
else {
printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
}
if (pci_probe & PCI_ASSIGN_ROMS) {
r = &dev->resource[PCI_ROM_RESOURCE];
r->end -= r->start;
r->start = 0;
if (r->end)
pcibios_assign_resource(dev, PCI_ROM_RESOURCE);
}
}
}
static void __init pcibios_resource_survey(void)
{
pcibios_allocate_bus_resources(pci_root);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
}
/*
* Fix up IRQs of all PCI devices.
*/
......@@ -1309,7 +982,7 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
* table, but unfortunately we have to know the interrupt router chip.
*/
static int __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin)
static char * __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin)
{
struct irq_info *q;
struct pci_dev *router;
......@@ -1330,13 +1003,13 @@ static int __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_tab
;
if (!i) {
DBG(" -> not found in routing table\n");
return 0;
return NULL;
}
pirq = q->irq[pin].link;
mask = q->irq[pin].bitmap;
if (!pirq) {
DBG(" -> not routed\n");
return 0;
return NULL;
}
DBG(" -> PIRQ %02x, mask %04x", pirq, mask);
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
......@@ -1345,7 +1018,7 @@ static int __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_tab
;
if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
DBG(" -> router not found\n");
return 0;
return NULL;
}
#define ID(x,y) ((x << 16) | y)
rtrid = ID(rt->rtr_vendor, rt->rtr_device);
......@@ -1367,17 +1040,24 @@ static int __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_tab
pci_read_config_byte(router, pirq, &x);
if (x < 16) {
DBG(" -> [PIIX] %02x\n", x);
return x;
dev->irq = x;
return "PIIX";
} else if (newirq) {
DBG(" -> [PIIX] set to %02x\n", newirq);
pci_write_config_byte(router, pirq, newirq);
return newirq;
dev->irq = newirq;
return "PIIX-NEW";
}
DBG(" -> [PIIX] sink\n");
return 0;
return NULL;
default:
DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
return 0;
if (newirq && mask == (1 << newirq)) {
/* Only one IRQ available -> use it */
dev->irq = newirq;
return "guess";
}
return NULL;
}
#undef ID
}
......@@ -1435,9 +1115,9 @@ static void __init pcibios_fixup_irqs(void)
if (dev->irq >= NR_IRQS)
dev->irq = 0;
if (pin && !dev->irq && rtable && rtable->version) {
dev->irq = pcibios_lookup_irq(dev, rtable, pin);
if (dev->irq)
printk("PCI: Assigned IRQ %d to device %s\n", dev->irq, dev->slot_name);
char *msg = pcibios_lookup_irq(dev, rtable, pin);
if (msg)
printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg);
}
}
......
/*
* Low-Level PCI Support for SGI Visual Workstation
*
* (c) 1999 Martin Mares <mj@ucw.cz>
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/smp.h>
#include <asm/lithium.h>
#include "pci-i386.h"
unsigned int pci_probe = 0;
/*
* The VISWS uses configuration access type 1 only.
*/
#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inb(0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inw(0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
*value = inl(0xCFC);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outb(value, 0xCFC + (where&3));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outw(value, 0xCFC + (where&2));
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
outl(CONFIG_CMD(dev,where), 0xCF8);
outl(value, 0xCFC);
return PCIBIOS_SUCCESSFUL;
}
#undef CONFIG_CMD
static struct pci_ops visws_pci_ops = {
pci_conf1_read_config_byte,
pci_conf1_read_config_word,
pci_conf1_read_config_dword,
pci_conf1_write_config_byte,
pci_conf1_write_config_word,
pci_conf1_write_config_dword
};
static void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev, *p;
u8 pin;
int irq;
for(dev=pci_devices; dev; dev=dev->next) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
dev->irq = 0;
if (!pin)
continue;
pin--;
if (dev->bus->parent) {
p = dev->bus->parent->self;
pin = (pin + PCI_SLOT(dev->devfn)) % 4;
} else
p = dev;
irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
if (irq >= 0)
dev->irq = irq;
DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
}
}
void __init pcibios_fixup_bus(struct pci_bus *b)
{
pci_read_bridge_bases(b);
}
#if 0
static struct resource visws_pci_bus_resources[2] = {
{ "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
{ "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
};
#endif
void __init pcibios_init(void)
{
unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
pci_scan_bus(0, &visws_pci_ops, NULL);
pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
pcibios_fixup_irqs();
pcibios_resource_survey();
}
char * __init pcibios_setup(char *str)
{
return str;
}
......@@ -507,7 +507,7 @@ static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *
if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
continue; /* no room in ide_hwifs[] */
if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
ide_init_hwif_ports(&hwif->hw, base, (ctl + 2), NULL);
ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
}
......
......@@ -22,6 +22,7 @@
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodev.h>
......
......@@ -51,6 +51,10 @@
static struct acpi_facp *acpi_facp = NULL;
static unsigned long acpi_facp_addr = 0;
static unsigned long acpi_dsdt_addr = 0;
static volatile u32 acpi_pm1_status = 0;
static volatile u32 acpi_gpe_status = 0;
static volatile u32 acpi_gpe_level = 0;
static DECLARE_WAIT_QUEUE_HEAD(acpi_wait_event);
/*
......@@ -77,6 +81,19 @@ static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
}
}
/*
* Get the value of the fixed event enable register
*/
static u32 acpi_read_pm1_enable(struct acpi_facp *facp)
{
int offset = facp->pm1_evt_len >> 1;
u32 value = inw(facp->pm1a_evt + offset);
if (facp->pm1b_evt) {
value |= inw(facp->pm1b_evt + offset);
}
return value;
}
/*
* Set the value of the fixed event enable register (enable events)
*/
......@@ -132,6 +149,28 @@ static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value)
}
}
/*
* Get the value of the general-purpose event enable register
*/
static u32 acpi_read_gpe_enable(struct acpi_facp *facp)
{
u32 value = 0;
int i, size, offset;
offset = facp->gpe0_len >> 1;
if (facp->gpe1) {
size = facp->gpe1_len >> 1;
for (i = size - 1; i >= 0; i--) {
value = (value << 8) | inb(facp->gpe1 + offset + i);
}
}
size = facp->gpe0_len >> 1;
for (i = size - 1; i >= 0; i--) {
value = (value << 8) | inb(facp->gpe0 + offset + i);
}
return value;
}
/*
* Set the value of the general-purpose event enable register (enable events)
*/
......@@ -162,7 +201,8 @@ static struct acpi_table *__init acpi_map_table(u32 addr)
if (addr) {
// map table header to determine size
table = (struct acpi_table *)
ioremap_nocache((unsigned long) addr, sizeof(struct acpi_table));
ioremap_nocache((unsigned long) addr,
sizeof(struct acpi_table));
if (table) {
unsigned long table_size = table->length;
iounmap(table);
......@@ -206,10 +246,13 @@ static int __init acpi_map_tables(void)
// strip trailing space and print OEM identifier
memcpy_fromio(oem, rsdp->oem, 6);
oem[6] = '\0';
for (j = 5; j > 0 && (oem[j] == '\0' || oem[j] == ' '); j--) {
for (j = 5;
j > 0 && (oem[j] == '\0' || oem[j] == ' ');
j--) {
oem[j] = '\0';
}
printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n", oem, (void *) i);
printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n",
oem, (void *) i);
break;
}
......@@ -269,17 +312,32 @@ static void acpi_unmap_tables(void)
*/
static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
{
u32 status;
// detect and disable any fixed events
status = acpi_read_pm1_status(acpi_facp);
acpi_write_pm1_enable(acpi_facp, ~status);
// detect and disable any general-purpose events
status = acpi_read_gpe_status(acpi_facp);
acpi_write_gpe_enable(acpi_facp, ~status);
u32 pm1_status, gpe_status, gpe_level, gpe_edge;
// detect and clear fixed events
pm1_status = (acpi_read_pm1_status(acpi_facp)
& acpi_read_pm1_enable(acpi_facp));
acpi_write_pm1_status(acpi_facp, pm1_status);
// detect and handle general-purpose events
gpe_status = (acpi_read_gpe_status(acpi_facp)
& acpi_read_gpe_enable(acpi_facp));
gpe_level = gpe_status & acpi_gpe_level;
if (gpe_level) {
// disable level-triggered events
acpi_write_gpe_enable(
acpi_facp,
acpi_read_gpe_enable(acpi_facp) & ~gpe_level);
}
gpe_edge = gpe_status & ~gpe_level;
if (gpe_edge) {
// clear edge-triggered events
while (acpi_read_gpe_status(acpi_facp) & gpe_edge)
acpi_write_gpe_status(acpi_facp, gpe_edge);
}
// notify process reading /dev/acpi
acpi_pm1_status |= pm1_status;
acpi_gpe_status |= gpe_status;
wake_up_interruptible(&acpi_wait_event);
}
......@@ -317,17 +375,79 @@ static int acpi_ioctl(struct inode *inode,
(void *) arg,
sizeof(struct acpi_find_tables));
if (!status) {
struct acpi_find_tables *rqst = (struct acpi_find_tables *) arg;
struct acpi_find_tables *rqst
= (struct acpi_find_tables *) arg;
put_user(acpi_facp_addr, &rqst->facp);
put_user(acpi_dsdt_addr, &rqst->dsdt);
status = 0;
}
break;
case ACPI_ENABLE_EVENT:
status = verify_area(VERIFY_READ,
(void *) arg,
sizeof(struct acpi_enable_event));
if (!status) {
struct acpi_enable_event *rqst
= (struct acpi_enable_event *) arg;
u32 pm1_enable, gpe_enable, gpe_level;
u32 pm1_enabling, gpe_enabling;
get_user(pm1_enable, &rqst->pm1_enable);
get_user(gpe_enable, &rqst->gpe_enable);
get_user(gpe_level, &rqst->gpe_level);
gpe_level &= gpe_enable;
// clear previously disabled events before enabling
pm1_enabling = (pm1_enable
& ~acpi_read_pm1_enable(acpi_facp));
acpi_write_pm1_status(acpi_facp, pm1_enabling);
gpe_enabling = (gpe_enable &
~acpi_read_gpe_enable(acpi_facp));
while (acpi_read_gpe_status(acpi_facp) & gpe_enabling)
acpi_write_gpe_status(acpi_facp, gpe_enabling);
acpi_write_pm1_enable(acpi_facp, pm1_enable);
acpi_write_gpe_enable(acpi_facp, gpe_enable);
acpi_gpe_level = gpe_level;
status = 0;
}
break;
case ACPI_WAIT_EVENT:
interruptible_sleep_on(&acpi_wait_event);
if (signal_pending(current))
return -ERESTARTSYS;
status = 0;
status = verify_area(VERIFY_WRITE,
(void *) arg,
sizeof(struct acpi_wait_event));
if (!status) {
struct acpi_wait_event *rqst
= (struct acpi_wait_event *) arg;
u32 pm1_status = 0;
u32 gpe_status = 0;
for (;;) {
unsigned long flags;
// we need an atomic exchange here
save_flags(flags);
cli();
pm1_status = acpi_pm1_status;
acpi_pm1_status = 0;
gpe_status = acpi_gpe_status;
acpi_gpe_status = 0;
restore_flags(flags);
if (pm1_status || gpe_status)
break;
// wait for an event to arrive
interruptible_sleep_on(&acpi_wait_event);
if (signal_pending(current))
return -ERESTARTSYS;
}
put_user(pm1_status, &rqst->pm1_status);
put_user(gpe_status, &rqst->gpe_status);
status = 0;
}
break;
}
return status;
......@@ -448,7 +568,8 @@ static void __exit acpi_exit(void)
// disable and clear any pending events
acpi_write_gpe_enable(acpi_facp, 0);
while (acpi_read_gpe_status(acpi_facp)) {
acpi_write_gpe_status(acpi_facp, acpi_read_gpe_status(acpi_facp));
acpi_write_gpe_status(acpi_facp,
acpi_read_gpe_status(acpi_facp));
}
acpi_write_pm1_enable(acpi_facp, 0);
acpi_write_pm1_status(acpi_facp, acpi_read_pm1_status(acpi_facp));
......@@ -464,6 +585,7 @@ static void __exit acpi_exit(void)
module_init(acpi_init)
module_exit(acpi_exit)
#else
__initcall(acpi_init);
......
......@@ -151,8 +151,6 @@ static void parport_ieee1284_terminate (struct parport *port)
{
port = port->physport;
port->ieee1284.phase = IEEE1284_PH_TERMINATE;
/* EPP terminates differently. */
switch (port->ieee1284.mode) {
case IEEE1284_MODE_EPP:
......@@ -171,7 +169,32 @@ static void parport_ieee1284_terminate (struct parport *port)
PARPORT_CONTROL_SELECT
| PARPORT_CONTROL_INIT);
break;
case IEEE1284_MODE_ECP:
case IEEE1284_MODE_ECPRLE:
case IEEE1284_MODE_ECPSWE:
/* In ECP we can only terminate from fwd idle phase. */
if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
/* Event 47: Set nInit high */
parport_frob_control (port,
PARPORT_CONTROL_INIT
| PARPORT_CONTROL_AUTOFD,
PARPORT_CONTROL_INIT
| PARPORT_CONTROL_AUTOFD);
/* Event 49: PError goes high */
parport_wait_peripheral (port,
PARPORT_STATUS_PAPEROUT,
PARPORT_STATUS_PAPEROUT);
parport_data_forward (port);
DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
port->name);
port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
}
/* fall-though.. */
default:
/* Terminate from all other modes. */
......
......@@ -1758,6 +1758,8 @@ static int __init parport_pc_init_pci (int irq, int dma)
{ { 0, -1 }, } },
{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
{ { 0, -1 }, } },
{ PCI_VENDOR_ID_EXSYS, PCI_DEVICE_ID_EXSYS_4014, 2,
{ { 2, -1 }, { 3, -1 }, } },
{ 0, }
};
......
......@@ -989,6 +989,10 @@ VENDOR( ATRONICS, "Atronics" )
DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL")
ENDVENDOR()
VENDOR( EXSYS, "Exsys" )
DEVICE( EXSYS, EXSYS_4014, "EX-4014")
ENDVENDOR()
VENDOR( TIGERJET, "TigerJet" )
DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN")
ENDVENDOR()
......
......@@ -176,10 +176,38 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
}
/*
* This interface is depreciated - users should use the scsi generics
* This interface is depreciated - users should use the scsi generic (sg)
* interface instead, as this is a more flexible approach to performing
* generic SCSI commands on a device.
*
* The structure that we are passed should look like:
*
* struct sdata {
* unsigned int inlen; [i] Length of data to be written to device
* unsigned int outlen; [i] Length of data to be read from device
* unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12).
* [o] Data read from device starts here.
* [o] On error, sense buffer starts here.
* unsigned char wdata[y]; [i] Data written to device starts here.
* };
* Notes:
* - The SCSI command length is determined by examining the 1st byte
* of the given command. There is no way to override this.
* - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
* - The length (x + y) must be at least OMAX_SB_LEN bytes long to
* accomodate the sense buffer when an error occurs.
* The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
* old code will not be surprised.
* - If a Unix error occurs (e.g. ENOMEM) then the user will receive
* a negative return and the Unix error code in 'errno'.
* If the SCSI command succeeds then 0 is returned.
* Positive numbers returned are the compacted SCSI error codes (4
* bytes in one int) where the lowest byte is the SCSI status.
* See the drivers/scsi/scsi.h file for more information on this.
*
*/
#define OMAX_SB_LEN 16 /* Old sense buffer length */
int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
{
unsigned long flags;
......@@ -195,8 +223,6 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
if (!sic)
return -EINVAL;
/*
* Verify that we can read at least this much.
*/
......@@ -204,23 +230,13 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
if (result)
return result;
/*
* The structure that we are passed should look like:
*
* struct sdata {
* unsigned int inlen;
* unsigned int outlen;
* unsigned char cmd[]; # However many bytes are used for cmd.
* unsigned char data[];
* };
*/
get_user(inlen, &sic->inlen);
get_user(outlen, &sic->outlen);
/*
* We do not transfer more than MAX_BUF with this interface.
* If the user needs to transfer more data than this, they
* should use scsi_generics instead.
* should use scsi_generics (sg) instead.
*/
if (inlen > MAX_BUF)
return -EINVAL;
......@@ -249,19 +265,16 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
*/
cmdlen = COMMAND_SIZE(opcode);
result = verify_area(VERIFY_READ, cmd_in,
cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
result = verify_area(VERIFY_READ, cmd_in, cmdlen + inlen);
if (result)
return result;
copy_from_user((void *) cmd, cmd_in, cmdlen);
copy_from_user(cmd, cmd_in, cmdlen);
/*
* Obtain the data to be sent to the device (if any).
*/
copy_from_user((void *) buf,
(void *) (cmd_in + cmdlen),
inlen);
copy_from_user(buf, cmd_in + cmdlen, inlen);
/*
* Set the lun field to the correct value.
......@@ -311,19 +324,18 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
* If there was an error condition, pass the info back to the user.
*/
if (SCpnt->result) {
result = verify_area(VERIFY_WRITE,
cmd_in,
sizeof(SCpnt->sense_buffer));
int sb_len = sizeof(SCpnt->sense_buffer);
sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
result = verify_area(VERIFY_WRITE, cmd_in, sb_len);
if (result)
return result;
copy_to_user((void *) cmd_in,
SCpnt->sense_buffer,
sizeof(SCpnt->sense_buffer));
copy_to_user(cmd_in, SCpnt->sense_buffer, sb_len);
} else {
result = verify_area(VERIFY_WRITE, cmd_in, outlen);
if (result)
return result;
copy_to_user((void *) cmd_in, buf, outlen);
copy_to_user(cmd_in, buf, outlen);
}
result = SCpnt->result;
......
......@@ -815,7 +815,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
/* Now wake up any sg_read() that is waiting for this packet. */
wake_up_interruptible(&sfp->read_wait);
if ((sfp->async_qp) && (! closed))
kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN);
kill_fasync(sfp->async_qp, SIGPOLL);
}
static void sg_debug_all(const Sg_fd * sfp)
......
......@@ -44,7 +44,7 @@ comment 'USB Devices'
dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
dep_tristate ' USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
if [ "$CONFIG_USB_SCSI" != "n" ]; then
dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
bool ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG
fi
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
fi
......
......@@ -6,6 +6,8 @@ int usb_printer_init(void);
void usb_hub_cleanup(void);
void usb_mouse_cleanup(void);
int usb_scsi_init(void);
int usb_hp_scanner_init(void);
void usb_hp_scanner_cleanup(void);
int proc_usb_init (void);
void proc_usb_cleanup (void);
int usb_serial_init (void);
......@@ -120,7 +120,7 @@ static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
wake_up_interruptible(&mouse->wait);
if (mouse->fasync)
kill_fasync(mouse->fasync, SIGIO, POLL_IN);
kill_fasync(mouse->fasync, SIGIO);
return 1;
}
......
......@@ -286,9 +286,12 @@ static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len)
static int usb_hcd_bandwidth (const struct usb_device *dev, char *buf, int *len)
{
*len += sprintf (buf + *len, format_bandwidth,
dev->bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
100 * dev->bus->bandwidth_allocated / FRAME_TIME_MAX_USECS_ALLOC,
dev->bus->bandwidth_int_reqs, dev->bus->bandwidth_isoc_reqs
dev->bus->bandwidth_allocated,
FRAME_TIME_MAX_USECS_ALLOC,
(100 * dev->bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) /
FRAME_TIME_MAX_USECS_ALLOC,
dev->bus->bandwidth_int_reqs,
dev->bus->bandwidth_isoc_reqs
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
......@@ -360,12 +363,12 @@ static int usb_device_dump (char *buf, int *len,
if (*len >= DUMP_LIMIT)
return -1;
if (usbdev->devnum > 0) { /* for any except root hub */
if (usb_dump_desc (usbdev, buf, len) < 0)
if ((level == 0) && (usbdev->devnum < 0)) { /* for root hub */
if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
return -1;
}
else { /* for a host controller */
if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
else { /* for anything but a root hub */
if (usb_dump_desc (usbdev, buf, len) < 0)
return -1;
}
......
......@@ -683,7 +683,7 @@ int init_module(void)
void cleanup_module(void)
{
tty_unregister_driver(&acm_tty_driver);
tty_unregister_driver(&serial_tty_driver);
usb_deregister(&usb_serial_driver);
}
......
......@@ -2,16 +2,16 @@
* driver/usb/usb-core.c
*
* (C) Copyright David Waite 1999
* based on code from usb.c, by Linus Torvolds
* based on code from usb.c, by Linus Torvalds
*
* The purpose of this file is to pull any and all generic modular code from
* usb.c and put it in a separate file. This way usb.c is kept as a generic
* library, while this file handles starting drivers, etc.
*
*/
#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/module.h>
#include "inits.h"
#include "usb.h"
......@@ -28,7 +28,6 @@
# endif
#endif
int usb_init(void)
{
#ifdef CONFIG_USB_PROC
......@@ -77,6 +76,7 @@ int usb_init(void)
#endif
return 0;
}
/*
* Clean up when unloading the module
*/
......@@ -103,10 +103,9 @@ int init_module(void)
{
return usb_init();
}
void cleanup_module(void)
{
cleanup_drivers();
}
#endif
......@@ -13,9 +13,14 @@
* are evil.
*/
#ifndef EXPORT_SYMTAB
#define EXPORT_SYMTAB
#endif
#define USB_DEBUG 1
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/malloc.h>
......@@ -177,7 +182,7 @@ static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount
* However, this first cut at USB bandwidth allocation does not
* contain any frame allocation tracking.
*/
int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
static int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
{
unsigned int new_alloc;
......@@ -269,6 +274,7 @@ static void usb_check_support(struct usb_device *dev)
if (!dev->driver && dev->devnum > 0)
usb_find_driver(dev);
}
/*
* This entrypoint gets called for each new device.
*
......@@ -996,7 +1002,6 @@ int usb_get_configuration(struct usb_device *dev)
return 0;
}
char *usb_string(struct usb_device *dev, int index)
{
int len, i;
......@@ -1153,9 +1158,10 @@ int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq ha
if (!ret) {
dev->bus->bandwidth_allocated += bustime;
dev->bus->bandwidth_int_reqs++;
PRINTD ("bw_alloc bumped to %d for %d requesters\n",
PRINTD ("bw_alloc bumped to %d for %d requesters",
dev->bus->bandwidth_allocated,
dev->bus->bandwidth_int_reqs);
dev->bus->bandwidth_int_reqs +
dev->bus->bandwidth_isoc_reqs);
}
return ret;
......@@ -1185,9 +1191,10 @@ int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe)
bustime = NS_TO_US(bustime);
dev->bus->bandwidth_allocated -= bustime;
dev->bus->bandwidth_int_reqs--;
PRINTD ("bw_alloc reduced to %d for %d requesters\n",
PRINTD ("bw_alloc reduced to %d for %d requesters",
dev->bus->bandwidth_allocated,
dev->bus->bandwidth_int_reqs);
dev->bus->bandwidth_int_reqs +
dev->bus->bandwidth_isoc_reqs);
}
return err;
......@@ -1213,11 +1220,14 @@ int usb_init_isoc (struct usb_device *usb_dev,
long bustime;
int err;
if (frame_count <= 0)
return -EINVAL;
/* Check host controller's bandwidth for this Isoc. request. */
/* TBD: some way to factor in frame_spacing ??? */
bustime = calc_bus_time (0, usb_pipein(pipe), 1,
usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)));
bustime = NS_TO_US(bustime); /* work in microseconds */
bustime = NS_TO_US(bustime) / frame_count; /* work in microseconds */
if (check_bandwidth_alloc (usb_dev->bus->bandwidth_allocated, bustime))
return USB_ST_BANDWIDTH_ERROR;
......@@ -1227,8 +1237,9 @@ int usb_init_isoc (struct usb_device *usb_dev,
if (!err) {
usb_dev->bus->bandwidth_allocated += bustime;
usb_dev->bus->bandwidth_isoc_reqs++;
PRINTD ("bw_alloc bumped to %d for %d requesters\n",
PRINTD ("bw_alloc bumped to %d for %d requesters",
usb_dev->bus->bandwidth_allocated,
usb_dev->bus->bandwidth_int_reqs +
usb_dev->bus->bandwidth_isoc_reqs);
}
......@@ -1243,11 +1254,12 @@ void usb_free_isoc (struct usb_isoc_desc *isocdesc)
bustime = calc_bus_time (0, usb_pipein(isocdesc->pipe), 1,
usb_maxpacket(isocdesc->usb_dev, isocdesc->pipe,
usb_pipeout(isocdesc->pipe)));
bustime = NS_TO_US(bustime);
bustime = NS_TO_US(bustime) / isocdesc->frame_count;
isocdesc->usb_dev->bus->bandwidth_allocated -= bustime;
isocdesc->usb_dev->bus->bandwidth_isoc_reqs--;
PRINTD ("bw_alloc reduced to %d for %d requesters\n",
PRINTD ("bw_alloc reduced to %d for %d requesters",
isocdesc->usb_dev->bus->bandwidth_allocated,
isocdesc->usb_dev->bus->bandwidth_int_reqs +
isocdesc->usb_dev->bus->bandwidth_isoc_reqs);
isocdesc->usb_dev->bus->op->free_isoc (isocdesc);
......@@ -1276,3 +1288,49 @@ struct list_head *usb_bus_get_list(void)
}
#endif
/*
* USB may be built into the kernel or be built as modules.
* If the USB core [and maybe a host controller driver] is built
* into the kernel, and other device drivers are built as modules,
* then these symbols need to be exported for the modules to use.
*/
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_alloc_bus);
EXPORT_SYMBOL(usb_free_bus);
EXPORT_SYMBOL(usb_register_bus);
EXPORT_SYMBOL(usb_deregister_bus);
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_free_dev);
EXPORT_SYMBOL(usb_inc_dev_use);
EXPORT_SYMBOL(usb_init_root_hub);
EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
EXPORT_SYMBOL(usb_set_address);
EXPORT_SYMBOL(usb_get_descriptor);
EXPORT_SYMBOL(usb_get_string);
EXPORT_SYMBOL(usb_string);
EXPORT_SYMBOL(usb_get_protocol);
EXPORT_SYMBOL(usb_set_protocol);
EXPORT_SYMBOL(usb_get_report);
EXPORT_SYMBOL(usb_set_idle);
EXPORT_SYMBOL(usb_clear_halt);
EXPORT_SYMBOL(usb_set_interface);
EXPORT_SYMBOL(usb_get_configuration);
EXPORT_SYMBOL(usb_set_configuration);
EXPORT_SYMBOL(usb_control_msg);
EXPORT_SYMBOL(usb_request_irq);
EXPORT_SYMBOL(usb_release_irq);
/* EXPORT_SYMBOL(usb_bulk_msg); */
EXPORT_SYMBOL(usb_request_bulk);
EXPORT_SYMBOL(usb_terminate_bulk);
EXPORT_SYMBOL(usb_get_current_frame_number);
EXPORT_SYMBOL(usb_init_isoc);
EXPORT_SYMBOL(usb_free_isoc);
EXPORT_SYMBOL(usb_run_isoc);
EXPORT_SYMBOL(usb_kill_isoc);
......@@ -49,6 +49,15 @@
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
/*
* USB Packet IDs (PIDs)
*/
......@@ -706,7 +715,7 @@ void usb_show_string(struct usb_device *dev, char *id, int index);
#ifdef USB_DEBUG
#define PRINTD(format, args...) printk("usb: " format "\n" , ## args);
#else /* NOT DEBUGGING */
#define PRINTD(fmt, arg...) do {} while (0) /**/
#define PRINTD(fmt, arg...) do {} while (0)
#endif /* USB_DEBUG */
/* A simple way to change one line from DEBUG to NOT DEBUG: */
#define XPRINTD(fmt, arg...) do {} while (0)
......
......@@ -5,7 +5,6 @@
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
......
......@@ -1512,8 +1512,8 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
char * target_buf, *target_data;
unsigned long data_offset = offset;
offset = page->offset-inode->i_size;
if (offset < 0)
offset = inode->i_size - page->offset;
if (page->offset>inode->i_size)
offset = 0;
else if (offset >= data_offset)
offset = data_offset;
......
......@@ -60,7 +60,7 @@ struct inode_operations fat_file_inode_operations = {
fat_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
block_flushpage, /* flushpage */
fat_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
......@@ -118,7 +118,7 @@ static int fat_write_partial_page(struct file *file, struct page *page, unsigned
unsigned long page_cache = 0;
long status;
pgpos = inode->i_size & PAGE_CACHE_MASK;
pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
while (pgpos < page->offset) {
hash = page_hash(inode, pgpos);
repeat_find: new_page = __find_lock_page(inode, pgpos, hash);
......
......@@ -183,22 +183,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
}
}
/*
* Generate a unique inode number.
*/
ino_t ncp_invent_inos(unsigned long n)
{
static ino_t ino = 2;
if (ino + 2*n < ino)
{
/* wrap around */
ino = 2;
}
ino += n;
return ino;
}
static inline int
ncp_single_volume(struct ncp_server *server)
{
......@@ -449,7 +433,7 @@ ncp_do_simple_filldir(struct file *filp, char* name, int len,
ino = find_inode_number(dentry, &qname);
if (!ino)
ino = ncp_invent_inos(1);
ino = iunique(2);
result = filldir(dirent, name, len, filp->f_pos, ino);
if (!result)
......@@ -494,7 +478,7 @@ ncp_do_filldir(struct file *filp, struct ncp_entry_info *entry, void *dirent,
if (!newdent->d_inode) {
entry->opened = 0;
entry->ino = ncp_invent_inos(1);
entry->ino = iunique(2);
newino = ncp_iget(inode->i_sb, entry);
if (newino) {
newdent->d_op = &ncp_dentry_operations;
......@@ -517,7 +501,7 @@ ncp_do_filldir(struct file *filp, struct ncp_entry_info *entry, void *dirent,
ino = find_inode_number(dentry, &qname);
if (!ino)
ino = ncp_invent_inos(1);
ino = iunique(2);
result = filldir(dirent, entry->i.entryName, entry->i.nameLen,
filp->f_pos, ino);
......@@ -810,7 +794,7 @@ dentry->d_parent->d_name.name, __name, res);
* Create an inode for the entry.
*/
finfo.opened = 0;
finfo.ino = ncp_invent_inos(1);
finfo.ino = iunique(2);
error = -EACCES;
inode = ncp_iget(dir->i_sb, &finfo);
......@@ -838,7 +822,7 @@ static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
struct inode *inode;
int error = -EINVAL;
finfo->ino = ncp_invent_inos(1);
finfo->ino = iunique(2);
inode = ncp_iget(dir->i_sb, finfo);
if (!inode)
goto out_close;
......
......@@ -31,7 +31,6 @@
#include "ncplib_kernel.h"
static void ncp_read_inode(struct inode *);
static void ncp_put_inode(struct inode *);
static void ncp_delete_inode(struct inode *);
static void ncp_put_super(struct super_block *);
......@@ -39,7 +38,7 @@ static int ncp_statfs(struct super_block *, struct statfs *, int);
static struct super_operations ncp_sops =
{
ncp_read_inode, /* read inode */
NULL, /* read inode */
NULL, /* write inode */
ncp_put_inode, /* put inode */
ncp_delete_inode, /* delete inode */
......@@ -56,9 +55,6 @@ extern struct inode_operations ncp_symlink_inode_operations;
extern int ncp_symlink(struct inode*, struct dentry*, const char*);
#endif
static struct ncp_entry_info *read_nwinfo = NULL;
static DECLARE_MUTEX(read_sem);
/*
* Fill in the ncpfs-specific information in the inode.
*/
......@@ -216,33 +212,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
}
/*
* This is called from iget() with the read semaphore held.
* The global ncp_entry_info structure has been set up by ncp_iget.
*/
static void ncp_read_inode(struct inode *inode)
{
if (read_nwinfo == NULL) {
printk(KERN_ERR "ncp_read_inode: invalid call\n");
return;
}
ncp_set_attr(inode, read_nwinfo);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ncp_file_inode_operations;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ncp_dir_inode_operations;
#ifdef CONFIG_NCPFS_EXTRAS
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ncp_symlink_inode_operations;
#endif
} else {
inode->i_op = NULL;
}
}
/*
* Set up the ncp_entry_info pointer and get a new inode.
* Get a new inode.
*/
struct inode *
ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
......@@ -254,12 +224,23 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
return NULL;
}
down(&read_sem);
read_nwinfo = info;
inode = iget(sb, info->ino);
read_nwinfo = NULL;
up(&read_sem);
if (!inode)
inode = get_empty_inode();
if (inode) {
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_ino = info->ino;
ncp_set_attr(inode, info);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ncp_file_inode_operations;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ncp_dir_inode_operations;
#ifdef CONFIG_NCPFS_EXTRAS
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ncp_symlink_inode_operations;
#endif
}
insert_inode_hash(inode);
} else
printk(KERN_ERR "ncp_iget: iget failed!\n");
return inode;
}
......@@ -710,9 +691,6 @@ int init_module(void)
{
DPRINTK(KERN_DEBUG "ncpfs: init_module called\n");
init_MUTEX(&read_sem);
read_nwinfo = NULL;
#ifdef DEBUG_NCP_MALLOC
ncp_malloced = 0;
ncp_current_malloced = 0;
......
......@@ -38,21 +38,14 @@
#define ACPI_FACP_SIG 0x50434146 /* 'FACP' */
#define ACPI_DSDT_SIG 0x54445344 /* 'DSDT' */
/* PM1_STS flags */
#define ACPI_TMR_STS 0x0001
#define ACPI_BM_STS 0x0010
#define ACPI_GBL_STS 0x0020
#define ACPI_PWRBTN_STS 0x0100
#define ACPI_SLPBTN_STS 0x0200
#define ACPI_RTC_STS 0x0400
#define ACPI_WAK_STS 0x8000
/* PM1_EN flags */
#define ACPI_TMR_EN 0x0001
#define ACPI_GBL_EN 0x0020
#define ACPI_PWRBTN_EN 0x0100
#define ACPI_SLPBTN_EN 0x0200
#define ACPI_RTC_EN 0x0400
/* PM1_STS/EN flags */
#define ACPI_TMR 0x0001
#define ACPI_BM 0x0010
#define ACPI_GBL 0x0020
#define ACPI_PWRBTN 0x0100
#define ACPI_SLPBTN 0x0200
#define ACPI_RTC 0x0400
#define ACPI_WAK 0x8000
/* PM1_CNT flags */
#define ACPI_SCI_EN 0x0001
......@@ -150,11 +143,23 @@ struct acpi_facp {
};
#define ACPI_FIND_TABLES _IOR('A', 1, struct acpi_find_tables)
#define ACPI_WAIT_EVENT _IO('A', 2)
#define ACPI_ENABLE_EVENT _IOW('A', 2, struct acpi_enable_event)
#define ACPI_WAIT_EVENT _IOR('A', 3, struct acpi_wait_event)
struct acpi_find_tables {
unsigned long facp;
unsigned long dsdt;
unsigned long facp; /* FACP physical address */
unsigned long dsdt; /* DSDT physical address */
};
struct acpi_enable_event {
__u32 pm1_enable; /* fixed events */
__u32 gpe_enable; /* general-purpose events (GPEs) */
__u32 gpe_level; /* level-triggered GPEs */
};
struct acpi_wait_event {
__u32 pm1_status; /* fixed events */
__u32 gpe_status; /* general-purpose events */
};
#ifdef __KERNEL__
......
......@@ -1073,6 +1073,9 @@
#define PCI_VENDOR_ID_HOLTEK 0x9412
#define PCI_DEVICE_ID_HOLTEK_6565 0x6565
#define PCI_VENDOR_ID_EXSYS 0xd84d
#define PCI_DEVICE_ID_EXSYS_4014 0x4014
#define PCI_VENDOR_ID_TIGERJET 0xe159
#define PCI_DEVICE_ID_TIGERJET_300 0x0001
......
......@@ -7,6 +7,7 @@
*
* /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
* BIGMEM support, Andrea Arcangeli <andrea@suse.de>
* SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
*/
#include <linux/config.h>
......@@ -41,11 +42,13 @@ static int shm_tot = 0; /* total number of shared memory pages */
static int shm_rss = 0; /* number of shared memory pages that are in memory */
static int shm_swp = 0; /* number of shared memory pages that are in swap */
static int max_shmid = 0; /* every used id is <= max_shmid */
static DECLARE_WAIT_QUEUE_HEAD(shm_lock); /* calling findkey() may need to wait */
static DECLARE_WAIT_QUEUE_HEAD(shm_wait); /* calling findkey() may need to wait */
static struct shmid_kernel *shm_segs[SHMMNI];
static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
spinlock_t shm_lock = SPIN_LOCK_UNLOCKED;
/* some statistics */
static ulong swap_attempts = 0;
static ulong swap_successes = 0;
......@@ -61,7 +64,7 @@ void __init shm_init (void)
for (id = 0; id < SHMMNI; id++)
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
init_waitqueue_head(&shm_lock);
init_waitqueue_head(&shm_wait);
#ifdef CONFIG_PROC_FS
ent = create_proc_entry("sysvipc/shm", 0, 0);
ent->read_proc = sysvipc_shm_read_proc;
......@@ -75,8 +78,21 @@ static int findkey (key_t key)
struct shmid_kernel *shp;
for (id = 0; id <= max_shmid; id++) {
while ((shp = shm_segs[id]) == IPC_NOID)
sleep_on (&shm_lock);
if ((shp = shm_segs[id]) == IPC_NOID) {
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&shm_wait, &wait);
for(;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if ((shp = shm_segs[id]) != IPC_NOID)
break;
spin_unlock(&shm_lock);
schedule();
spin_lock(&shm_lock);
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&shm_wait, &wait);
}
if (shp == IPC_UNUSED)
continue;
if (key == shp->u.shm_perm.key)
......@@ -106,28 +122,30 @@ static int newseg (key_t key, int shmflg, int size)
return -ENOSPC;
found:
spin_unlock(&shm_lock);
shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
if (!shp) {
spin_lock(&shm_lock);
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
wake_up (&shm_lock);
wake_up (&shm_wait);
return -ENOMEM;
}
lock_kernel();
shp->shm_pages = (ulong *) vmalloc (numpages*sizeof(ulong));
unlock_kernel();
if (!shp->shm_pages) {
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
wake_up (&shm_lock);
kfree(shp);
spin_lock(&shm_lock);
shm_segs[id] = (struct shmid_kernel *) IPC_UNUSED;
wake_up (&shm_wait);
return -ENOMEM;
}
for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
shm_tot += numpages;
shp->u.shm_perm.key = key;
shp->u.shm_perm.mode = (shmflg & S_IRWXUGO);
shp->u.shm_perm.cuid = shp->u.shm_perm.uid = current->euid;
shp->u.shm_perm.cgid = shp->u.shm_perm.gid = current->egid;
shp->u.shm_perm.seq = shm_seq;
shp->u.shm_segsz = size;
shp->u.shm_cpid = current->pid;
shp->attaches = NULL;
......@@ -136,11 +154,16 @@ static int newseg (key_t key, int shmflg, int size)
shp->u.shm_ctime = CURRENT_TIME;
shp->shm_npages = numpages;
spin_lock(&shm_lock);
shm_tot += numpages;
shp->u.shm_perm.seq = shm_seq;
if (id > max_shmid)
max_shmid = id;
shm_segs[id] = shp;
used_segs++;
wake_up (&shm_lock);
wake_up (&shm_wait);
return (unsigned int) shp->u.shm_perm.seq * SHMMNI + id;
}
......@@ -152,7 +175,7 @@ asmlinkage long sys_shmget (key_t key, int size, int shmflg)
int err, id = 0;
down(&current->mm->mmap_sem);
lock_kernel();
spin_lock(&shm_lock);
if (size < 0 || size > shmmax) {
err = -EINVAL;
} else if (key == IPC_PRIVATE) {
......@@ -175,7 +198,7 @@ asmlinkage long sys_shmget (key_t key, int size, int shmflg)
else
err = (int) shp->u.shm_perm.seq * SHMMNI + id;
}
unlock_kernel();
spin_unlock(&shm_lock);
up(&current->mm->mmap_sem);
return err;
}
......@@ -188,6 +211,7 @@ static void killseg (int id)
{
struct shmid_kernel *shp;
int i, numpages;
int rss, swp;
shp = shm_segs[id];
if (shp == IPC_NOID || shp == IPC_UNUSED) {
......@@ -204,23 +228,31 @@ static void killseg (int id)
printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
return;
}
spin_unlock(&shm_lock);
numpages = shp->shm_npages;
for (i = 0; i < numpages ; i++) {
for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
pte_t pte;
pte = __pte(shp->shm_pages[i]);
if (pte_none(pte))
continue;
if (pte_present(pte)) {
free_page (pte_page(pte));
shm_rss--;
rss++;
} else {
lock_kernel();
swap_free(pte_val(pte));
shm_swp--;
unlock_kernel();
swp++;
}
}
lock_kernel();
vfree(shp->shm_pages);
shm_tot -= numpages;
unlock_kernel();
kfree(shp);
spin_lock(&shm_lock);
shm_rss -= rss;
shm_swp -= swp;
shm_tot -= numpages;
return;
}
......@@ -231,14 +263,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
struct ipc_perm *ipcp;
int id, err = -EINVAL;
lock_kernel();
if (cmd < 0 || shmid < 0)
goto out;
goto out_unlocked;
if (cmd == IPC_SET) {
err = -EFAULT;
if(copy_from_user (&tbuf, buf, sizeof (*buf)))
goto out;
goto out_unlocked;
}
spin_lock(&shm_lock);
switch (cmd) { /* replace with proc interface ? */
case IPC_INFO:
......@@ -252,8 +284,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shminfo.shmmin = SHMMIN;
shminfo.shmall = SHMALL;
shminfo.shmseg = SHMSEG;
spin_unlock(&shm_lock);
if(copy_to_user (buf, &shminfo, sizeof(struct shminfo)))
goto out;
goto out_unlocked;
spin_lock(&shm_lock);
err = max_shmid;
goto out;
}
......@@ -267,8 +301,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shm_info.shm_swp = shm_swp;
shm_info.swap_attempts = swap_attempts;
shm_info.swap_successes = swap_successes;
spin_unlock(&shm_lock);
if(copy_to_user (buf, &shm_info, sizeof(shm_info)))
goto out;
goto out_unlocked;
spin_lock(&shm_lock);
err = max_shmid;
goto out;
}
......@@ -283,8 +319,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
goto out;
id = (unsigned int) shp->u.shm_perm.seq * SHMMNI + shmid;
err = -EFAULT;
spin_unlock(&shm_lock);
if(copy_to_user (buf, &shp->u, sizeof(*buf)))
goto out;
goto out_unlocked;
spin_lock(&shm_lock);
err = id;
goto out;
}
......@@ -325,8 +363,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
if (ipcperms (ipcp, S_IRUGO))
goto out;
err = -EFAULT;
spin_unlock(&shm_lock);
if(copy_to_user (buf, &shp->u, sizeof(shp->u)))
goto out;
goto out_unlocked;
spin_lock(&shm_lock);
break;
case IPC_SET:
if (current->euid == shp->u.shm_perm.uid ||
......@@ -358,7 +398,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
}
err = 0;
out:
unlock_kernel();
spin_unlock(&shm_lock);
out_unlocked:
return err;
}
......@@ -440,7 +481,7 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
unsigned long len;
down(&current->mm->mmap_sem);
lock_kernel();
spin_lock(&shm_lock);
if (shmid < 0) {
/* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */
goto out;
......@@ -501,8 +542,10 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI)
goto out;
spin_unlock(&shm_lock);
err = -ENOMEM;
shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
spin_lock(&shm_lock);
if (!shmd)
goto out;
if ((shp != shm_segs[id]) || (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
......@@ -524,12 +567,11 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
shmd->vm_ops = &shm_vm_ops;
shp->u.shm_nattch++; /* prevent destruction */
if ((err = shm_map (shmd))) {
if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
killseg(id);
kmem_cache_free(vm_area_cachep, shmd);
goto out;
}
spin_unlock(&shm_lock);
err = shm_map (shmd);
spin_lock(&shm_lock);
if (err)
goto failed_shm_map;
insert_attach(shp,shmd); /* insert shmd into shp->attaches */
......@@ -539,9 +581,17 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
*raddr = addr;
err = 0;
out:
unlock_kernel();
spin_unlock(&shm_lock);
up(&current->mm->mmap_sem);
return err;
failed_shm_map:
if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
killseg(id);
spin_unlock(&shm_lock);
up(&current->mm->mmap_sem);
kmem_cache_free(vm_area_cachep, shmd);
return err;
}
/* This is called by fork, once for every shm attach. */
......@@ -549,13 +599,13 @@ static void shm_open (struct vm_area_struct *shmd)
{
struct shmid_kernel *shp;
lock_kernel();
spin_lock(&shm_lock);
shp = *(struct shmid_kernel **) shmd->vm_private_data;
insert_attach(shp,shmd); /* insert shmd into shp->attaches */
shp->u.shm_nattch++;
shp->u.shm_atime = CURRENT_TIME;
shp->u.shm_lpid = current->pid;
unlock_kernel();
spin_unlock(&shm_lock);
}
/*
......@@ -568,7 +618,7 @@ static void shm_close (struct vm_area_struct *shmd)
{
struct shmid_kernel *shp;
lock_kernel();
spin_lock(&shm_lock);
/* remove from the list of attaches of the shm segment */
shp = *(struct shmid_kernel **) shmd->vm_private_data;
remove_attach(shp,shmd); /* remove from shp->attaches */
......@@ -578,7 +628,7 @@ static void shm_close (struct vm_area_struct *shmd)
unsigned int id = (struct shmid_kernel **)shmd->vm_private_data - shm_segs;
killseg (id);
}
unlock_kernel();
spin_unlock(&shm_lock);
}
/*
......@@ -590,14 +640,12 @@ asmlinkage long sys_shmdt (char *shmaddr)
struct vm_area_struct *shmd, *shmdnext;
down(&current->mm->mmap_sem);
lock_kernel();
for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
shmdnext = shmd->vm_next;
if (shmd->vm_ops == &shm_vm_ops
&& shmd->vm_start - shmd->vm_offset == (ulong) shmaddr)
do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
}
unlock_kernel();
up(&current->mm->mmap_sem);
return 0;
}
......@@ -640,36 +688,43 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
}
#endif
lock_kernel();
spin_lock(&shm_lock);
again:
pte = __pte(shp->shm_pages[idx]);
if (!pte_present(pte)) {
if (pte_none(pte)) {
spin_unlock(&shm_lock);
page = __get_free_page(GFP_BIGUSER);
if (!page)
goto oom;
clear_bigpage(page);
spin_lock(&shm_lock);
if (pte_val(pte) != shp->shm_pages[idx])
goto changed;
} else {
unsigned long entry = pte_val(pte);
spin_unlock(&shm_lock);
page_map = lookup_swap_cache(entry);
if (!page_map) {
lock_kernel();
swapin_readahead(entry);
page_map = read_swap_cache(entry);
unlock_kernel();
if (!page_map)
goto oom;
}
pte = __pte(shp->shm_pages[idx]);
page = page_address(page_map);
if (pte_present(pte))
goto present;
if (!page_map)
goto oom;
delete_from_swap_cache(page_map);
page_map = replace_with_bigmem(page_map);
page = page_address(page_map);
lock_kernel();
swap_free(entry);
unlock_kernel();
spin_lock(&shm_lock);
shm_swp--;
pte = __pte(shp->shm_pages[idx]);
if (pte_present(pte))
goto present;
}
shm_rss++;
pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
......@@ -679,7 +734,7 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
done: /* pte_val(pte) == shp->shm_pages[idx] */
get_page(mem_map + MAP_NR(pte_page(pte)));
unlock_kernel();
spin_unlock(&shm_lock);
current->min_flt++;
return pte_page(pte);
......@@ -687,11 +742,9 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
free_page(page);
goto again;
present:
if (page_map)
free_page_and_swap_cache(page);
free_page(page);
goto done;
oom:
unlock_kernel();
return -1;
}
......@@ -710,17 +763,20 @@ int shm_swap (int prio, int gfp_mask)
int loop = 0;
int counter;
struct page * page_map;
int ret = 0;
lock_kernel();
counter = shm_rss >> prio;
if (!counter || !(swap_nr = get_swap_page()))
goto out_unlock;
lock_kernel();
if (!counter || !(swap_nr = get_swap_page())) {
unlock_kernel();
return 0;
}
unlock_kernel();
spin_lock(&shm_lock);
check_id:
shp = shm_segs[swap_id];
if (shp == IPC_UNUSED || shp == IPC_NOID || shp->u.shm_perm.mode & SHM_LOCKED ) {
next_id:
next_id:
swap_idx = 0;
if (++swap_id > max_shmid) {
swap_id = 0;
......@@ -748,27 +804,30 @@ int shm_swap (int prio, int gfp_mask)
swap_attempts++;
if (--counter < 0) { /* failed */
failed:
failed:
spin_unlock(&shm_lock);
lock_kernel();
swap_free (swap_nr);
goto out_unlock;
unlock_kernel();
return 0;
}
if (page_count(mem_map + MAP_NR(pte_page(page))) != 1)
goto check_table;
if (!(page_map = prepare_bigmem_swapout(page_map)))
goto check_table;
shp->shm_pages[idx] = swap_nr;
swap_successes++;
shm_swp++;
shm_rss--;
spin_unlock(&shm_lock);
lock_kernel();
swap_duplicate(swap_nr);
add_to_swap_cache(page_map, swap_nr);
rw_swap_page(WRITE, page_map, 0);
unlock_kernel();
__free_page(page_map);
swap_successes++;
shm_swp++;
shm_rss--;
ret = 1;
out_unlock:
unlock_kernel();
return ret;
return 1;
}
/*
......@@ -784,8 +843,12 @@ static void shm_unuse_page(struct shmid_kernel *shp, unsigned long idx,
get_page(mem_map + MAP_NR(page));
shm_rss++;
swap_free(entry);
shm_swp--;
spin_unlock(&shm_lock);
lock_kernel();
swap_free(entry);
unlock_kernel();
}
/*
......@@ -795,6 +858,7 @@ void shm_unuse(unsigned long entry, unsigned long page)
{
int i, n;
spin_lock(&shm_lock);
for (i = 0; i < SHMMNI; i++)
if (shm_segs[i] != IPC_UNUSED && shm_segs[i] != IPC_NOID)
for (n = 0; n < shm_segs[i]->shm_npages; n++)
......@@ -804,6 +868,7 @@ void shm_unuse(unsigned long entry, unsigned long page)
page, entry);
return;
}
spin_unlock(&shm_lock);
}
#ifdef CONFIG_PROC_FS
......@@ -815,6 +880,7 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n");
spin_lock(&shm_lock);
for(i = 0; i < SHMMNI; i++)
if(shm_segs[i] != IPC_UNUSED) {
len += sprintf(buffer + len, "%10d %10d %4o %10d %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n",
......@@ -849,6 +915,7 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
len = length;
if(len < 0)
len = 0;
spin_unlock(&shm_lock);
return len;
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment