Commit 40437f0c authored by Anton Blanchard's avatar Anton Blanchard

Merge samba.org:/home/anton/linux-2.5

into samba.org:/home/anton/ppc64tree
parents 9fd1db0a b2fd37fa
...@@ -1132,7 +1132,6 @@ NETWORKING [GENERAL] ...@@ -1132,7 +1132,6 @@ NETWORKING [GENERAL]
P: Networking Team P: Networking Team
M: netdev@oss.sgi.com M: netdev@oss.sgi.com
L: linux-net@vger.kernel.org L: linux-net@vger.kernel.org
W: http://www.uk.linux.org/NetNews.html (2.0 only)
S: Maintained S: Maintained
NETWORKING [IPv4/IPv6] NETWORKING [IPv4/IPv6]
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 5 PATCHLEVEL = 5
SUBLEVEL = 38 SUBLEVEL = 39
EXTRAVERSION = EXTRAVERSION =
# *DOCUMENTATION* # *DOCUMENTATION*
...@@ -173,6 +173,9 @@ noconfig_targets := xconfig menuconfig config oldconfig randconfig \ ...@@ -173,6 +173,9 @@ noconfig_targets := xconfig menuconfig config oldconfig randconfig \
help tags TAGS sgmldocs psdocs pdfdocs htmldocs \ help tags TAGS sgmldocs psdocs pdfdocs htmldocs \
checkconfig checkhelp checkincludes checkconfig checkhelp checkincludes
RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \) -prune -o
RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS
# Helpers built in scripts/ # Helpers built in scripts/
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
...@@ -581,13 +584,13 @@ spec: ...@@ -581,13 +584,13 @@ spec:
# will become invalid # will become invalid
rpm: clean spec rpm: clean spec
find . -name SCCS -prune -o -name BitKeeper -prune -o \ find . $(RCS_FIND_IGNORE) \
\( -size 0 -o -name .depend -o -name .hdepend \) \ \( -size 0 -o -name .depend -o -name .hdepend \) \
-type f -print | xargs rm -f -type f -print | xargs rm -f
set -e; \ set -e; \
cd $(TOPDIR)/.. ; \ cd $(TOPDIR)/.. ; \
ln -sf $(TOPDIR) $(KERNELPATH) ; \ ln -sf $(TOPDIR) $(KERNELPATH) ; \
tar -cvz --exclude CVS -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \ tar -cvz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \
rm $(KERNELPATH) ; \ rm $(KERNELPATH) ; \
cd $(TOPDIR) ; \ cd $(TOPDIR) ; \
. scripts/mkversion > .version ; \ . scripts/mkversion > .version ; \
...@@ -717,7 +720,7 @@ include arch/$(ARCH)/Makefile ...@@ -717,7 +720,7 @@ include arch/$(ARCH)/Makefile
clean: archclean clean: archclean
@echo 'Cleaning up' @echo 'Cleaning up'
@find . -name SCCS -prune -o -name BitKeeper -prune -o \ @find . $(RCS_FIND_IGNORE) \
\( -name \*.[oas] -o -name core -o -name .\*.cmd -o \ \( -name \*.[oas] -o -name core -o -name .\*.cmd -o \
-name .\*.tmp -o -name .\*.d \) -type f -print \ -name .\*.tmp -o -name .\*.d \) -type f -print \
| grep -v lxdialog/ | xargs rm -f | grep -v lxdialog/ | xargs rm -f
...@@ -726,7 +729,7 @@ clean: archclean ...@@ -726,7 +729,7 @@ clean: archclean
mrproper: clean archmrproper mrproper: clean archmrproper
@echo 'Making mrproper' @echo 'Making mrproper'
@find . -name SCCS -prune -o -name BitKeeper -prune -o \ @find . $(RCS_FIND_IGNORE) \
\( -name .depend -o -name .\*.cmd \) \ \( -name .depend -o -name .\*.cmd \) \
-type f -print | xargs rm -f -type f -print | xargs rm -f
@rm -f $(MRPROPER_FILES) @rm -f $(MRPROPER_FILES)
...@@ -736,7 +739,7 @@ mrproper: clean archmrproper ...@@ -736,7 +739,7 @@ mrproper: clean archmrproper
distclean: mrproper distclean: mrproper
@echo 'Making distclean' @echo 'Making distclean'
@find . -name SCCS -prune -o -name BitKeeper -prune -o \ @find . $(RCS_FIND_IGNORE) \
\( -not -type d \) -and \ \( -not -type d \) -and \
\( -name '*.orig' -o -name '*.rej' -o -name '*~' \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
...@@ -747,18 +750,18 @@ distclean: mrproper ...@@ -747,18 +750,18 @@ distclean: mrproper
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
define all-sources define all-sources
( find . \( -name SCCS -o -name BitKeeper -o -name include -o \ ( find . $(RCS_FIND_IGNORE) \
-name arch \) -prune \ \( -name include -o -name arch \) -prune -o \
-o -name '*.[chS]' -print; \ -name '*.[chS]' -print; \
find arch/$(ARCH) \( -name SCCS -o -name BitKeeper \) -prune \ find arch/$(ARCH) $(RCS_FIND_IGNORE) \
-o -name '*.[chS]' -print; \ -name '*.[chS]' -print; \
find include \( -name SCCS -o -name BitKeeper -o -name config -o \ find include $(RCS_FIND_IGNORE) \
-name 'asm-*' \) -prune \ \( -name config -o -name 'asm-*' \) -prune -o \
-o -name '*.[chS]' -print; \
find include/asm-$(ARCH) \( -name SCCS -o -name BitKeeper \) -prune \
-o -name '*.[chS]' -print; \ -o -name '*.[chS]' -print; \
find include/asm-generic \( -name SCCS -o -name BitKeeper \) -prune \ find include/asm-$(ARCH) $(RCS_FIND_IGNORE) \
-o -name '*.[chS]' -print ) -name '*.[chS]' -print; \
find include/asm-generic $(RCS_FIND_IGNORE) \
-name '*.[chS]' -print )
endef endef
quiet_cmd_TAGS = MAKE $@ quiet_cmd_TAGS = MAKE $@
...@@ -825,17 +828,17 @@ sgmldocs psdocs pdfdocs htmldocs: scripts ...@@ -825,17 +828,17 @@ sgmldocs psdocs pdfdocs htmldocs: scripts
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
checkconfig: checkconfig:
find * -name SCCS -prune -o -name BitKeeper -prune -o \ find * $(RCS_FIND_IGNORE) \
-name '*.[hcS]' -type f -print | sort \ -name '*.[hcS]' -type f -print | sort \
| xargs $(PERL) -w scripts/checkconfig.pl | xargs $(PERL) -w scripts/checkconfig.pl
checkhelp: checkhelp:
find * -name SCCS -prune -o -name BitKeeper -prune -o \ find * $(RCS_FIND_IGNORE) \
-name [cC]onfig.in -print | sort \ -name [cC]onfig.in -print | sort \
| xargs $(PERL) -w scripts/checkhelp.pl | xargs $(PERL) -w scripts/checkhelp.pl
checkincludes: checkincludes:
find * -name SCCS -prune -o -name BitKeeper -prune -o \ find * $(RCS_FIND_IGNORE) \
-name '*.[hcS]' -type f -print | sort \ -name '*.[hcS]' -type f -print | sort \
| xargs $(PERL) -w scripts/checkincludes.pl | xargs $(PERL) -w scripts/checkincludes.pl
......
...@@ -34,6 +34,7 @@ if [ "$CONFIG_X86" = "y" ]; then ...@@ -34,6 +34,7 @@ if [ "$CONFIG_X86" = "y" ]; then
define_bool CONFIG_ACPI_EC y define_bool CONFIG_ACPI_EC y
define_bool CONFIG_ACPI_POWER y define_bool CONFIG_ACPI_POWER y
define_bool CONFIG_ACPI_PCI $CONFIG_PCI define_bool CONFIG_ACPI_PCI $CONFIG_PCI
define_bool CONFIG_ACPI_SLEEP $CONFIG_SOFTWARE_SUSPEND
define_bool CONFIG_ACPI_SYSTEM y define_bool CONFIG_ACPI_SYSTEM y
fi fi
fi fi
......
...@@ -55,7 +55,8 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { ...@@ -55,7 +55,8 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
[ACPI_SPCR] = "SPCR", [ACPI_SPCR] = "SPCR",
[ACPI_SRAT] = "SRAT", [ACPI_SRAT] = "SRAT",
[ACPI_SSDT] = "SSDT", [ACPI_SSDT] = "SSDT",
[ACPI_SPMI] = "SPMI" [ACPI_SPMI] = "SPMI",
[ACPI_HPET] = "HPET"
}; };
/* System Description Table (RSDT/XSDT) */ /* System Description Table (RSDT/XSDT) */
...@@ -320,7 +321,7 @@ acpi_table_parse_madt_family ( ...@@ -320,7 +321,7 @@ acpi_table_parse_madt_family (
handler(entry); handler(entry);
} }
entry = (acpi_table_entry_header *) entry = (acpi_table_entry_header *)
((unsigned long) entry += entry->length); ((unsigned long) entry + entry->length);
} }
return count; return count;
......
...@@ -6,6 +6,8 @@ obj-y := core.o sys.o interface.o power.o bus.o \ ...@@ -6,6 +6,8 @@ obj-y := core.o sys.o interface.o power.o bus.o \
obj-y += fs/ obj-y += fs/
obj-$(CONFIG_HOTPLUG) += hotplug.o
export-objs := core.o power.o sys.o bus.o driver.o \ export-objs := core.o power.o sys.o bus.o driver.o \
class.o intf.o platform.o cpu.o class.o intf.o platform.o cpu.o
......
...@@ -50,3 +50,13 @@ extern void interface_remove(struct device_class *, struct device *); ...@@ -50,3 +50,13 @@ extern void interface_remove(struct device_class *, struct device *);
extern int driver_attach(struct device_driver * drv); extern int driver_attach(struct device_driver * drv);
extern void driver_detach(struct device_driver * drv); extern void driver_detach(struct device_driver * drv);
#ifdef CONFIG_HOTPLUG
extern int dev_hotplug(struct device *dev, const char *action);
#else
static inline int dev_hotplug(struct device *dev, const char *action)
{
return 0;
}
#endif
...@@ -200,6 +200,9 @@ int device_register(struct device *dev) ...@@ -200,6 +200,9 @@ int device_register(struct device *dev)
if (platform_notify) if (platform_notify)
platform_notify(dev); platform_notify(dev);
/* notify userspace of device entry */
dev_hotplug(dev, "add");
register_done: register_done:
if (error) { if (error) {
spin_lock(&device_lock); spin_lock(&device_lock);
...@@ -255,6 +258,9 @@ void put_device(struct device * dev) ...@@ -255,6 +258,9 @@ void put_device(struct device * dev)
if (platform_notify_remove) if (platform_notify_remove)
platform_notify_remove(dev); platform_notify_remove(dev);
/* notify userspace that this device is about to disappear */
dev_hotplug (dev, "remove");
device_detach(dev); device_detach(dev);
bus_remove_device(dev); bus_remove_device(dev);
......
/*
* drivers/base/hotplug.c - hotplug call code
*
* Copyright (c) 2000-2001 David Brownell
* Copyright (c) 2002 Greg Kroah-Hartman
* Copyright (c) 2002 IBM Corp.
*
* Based off of drivers/usb/core/usb.c:call_agent(), which was
* written by David Brownell.
*
*/
#define DEBUG 0
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/kmod.h>
#include <linux/interrupt.h>
#include "base.h"
/*
* hotplugging invokes what /proc/sys/kernel/hotplug says (normally
* /sbin/hotplug) when devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*/
#define BUFFER_SIZE 1024 /* should be enough memory for the env */
#define NUM_ENVP 32 /* number of env pointers */
int dev_hotplug (struct device *dev, const char *action)
{
char *argv [3], **envp, *buffer, *scratch;
int retval;
int i = 0;
pr_debug ("%s\n", __FUNCTION__);
if (!dev)
return -ENODEV;
if (!dev->bus || !dev->bus->hotplug)
return -ENODEV;
if (!hotplug_path [0])
return -ENODEV;
if (in_interrupt ()) {
pr_debug ("%s - in_interrupt, not allowed!", __FUNCTION__);
return -EIO;
}
if (!current->fs->root) {
/* don't try to do anything unless we have a root partition */
pr_debug ("%s - %s -- no FS yet\n", __FUNCTION__, action);
return -EIO;
}
envp = (char **) kmalloc (NUM_ENVP * sizeof (char *), GFP_KERNEL);
if (!envp)
return -ENOMEM;
buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
if (!buffer) {
kfree (envp);
return -ENOMEM;
}
/* only one standardized param to hotplug command: the bus name */
argv [0] = hotplug_path;
argv [1] = dev->bus->name;
argv [2] = 0;
/* minimal command environment */
envp [i++] = "HOME=/";
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
scratch = buffer;
/* action: add, remove */
envp [i++] = scratch;
scratch += sprintf (scratch, "ACTION=%s", action) + 1;
/* have the bus specific function set up the rest of the environment */
retval = dev->bus->hotplug (dev, &envp[i], NUM_ENVP - i,
scratch, BUFFER_SIZE - (scratch - buffer));
if (retval) {
pr_debug ("%s - hotplug() returned %d\n", __FUNCTION__, retval);
goto exit;
}
pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv [0], argv[1],
action, envp[0], envp[1], envp[2]);
retval = call_usermodehelper (argv [0], argv, envp);
if (retval)
pr_debug ("%s - call_usermodehelper returned %d\n",
__FUNCTION__, retval);
exit:
kfree (buffer);
kfree (envp);
return retval;
}
...@@ -137,8 +137,24 @@ deadline_find_hash(struct deadline_data *dd, sector_t offset) ...@@ -137,8 +137,24 @@ deadline_find_hash(struct deadline_data *dd, sector_t offset)
return rq; return rq;
} }
static sector_t deadline_get_last_sector(struct deadline_data *dd)
{
sector_t last_sec = dd->last_sector;
/*
* if dispatch is non-empty, disregard last_sector and check last one
*/
if (!list_empty(dd->dispatch)) {
struct request *__rq = list_entry_rq(dd->dispatch->prev);
last_sec = __rq->sector + __rq->nr_sectors;
}
return last_sec;
}
static int static int
deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) deadline_merge(request_queue_t *q, struct list_head **insert, struct bio *bio)
{ {
struct deadline_data *dd = q->elevator.elevator_data; struct deadline_data *dd = q->elevator.elevator_data;
const int data_dir = bio_data_dir(bio); const int data_dir = bio_data_dir(bio);
...@@ -150,9 +166,11 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) ...@@ -150,9 +166,11 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
/* /*
* try last_merge to avoid going to hash * try last_merge to avoid going to hash
*/ */
ret = elv_try_last_merge(q, req, bio); ret = elv_try_last_merge(q, bio);
if (ret != ELEVATOR_NO_MERGE) if (ret != ELEVATOR_NO_MERGE) {
*insert = q->last_merge;
goto out; goto out;
}
/* /*
* see if the merge hash can satisfy a back merge * see if the merge hash can satisfy a back merge
...@@ -161,12 +179,15 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) ...@@ -161,12 +179,15 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
if (elv_rq_merge_ok(__rq, bio)) { if (elv_rq_merge_ok(__rq, bio)) {
*req = __rq; *insert = &__rq->queuelist;
ret = ELEVATOR_BACK_MERGE; ret = ELEVATOR_BACK_MERGE;
goto out; goto out;
} }
} }
/*
* scan list from back to find insertion point.
*/
entry = sort_list = &dd->sort_list[data_dir]; entry = sort_list = &dd->sort_list[data_dir];
while ((entry = entry->prev) != sort_list) { while ((entry = entry->prev) != sort_list) {
__rq = list_entry_rq(entry); __rq = list_entry_rq(entry);
...@@ -177,8 +198,8 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) ...@@ -177,8 +198,8 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
if (!(__rq->flags & REQ_CMD)) if (!(__rq->flags & REQ_CMD))
continue; continue;
if (!*req && bio_rq_in_between(bio, __rq, sort_list)) if (!*insert && bio_rq_in_between(bio, __rq, sort_list))
*req = __rq; *insert = &__rq->queuelist;
if (__rq->flags & REQ_BARRIER) if (__rq->flags & REQ_BARRIER)
break; break;
...@@ -189,12 +210,23 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) ...@@ -189,12 +210,23 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
if (__rq->sector - bio_sectors(bio) == bio->bi_sector) { if (__rq->sector - bio_sectors(bio) == bio->bi_sector) {
ret = elv_try_merge(__rq, bio); ret = elv_try_merge(__rq, bio);
if (ret != ELEVATOR_NO_MERGE) { if (ret != ELEVATOR_NO_MERGE) {
*req = __rq; *insert = &__rq->queuelist;
break; break;
} }
} }
} }
/*
* no insertion point found, check the very front
*/
if (!*insert && !list_empty(sort_list)) {
__rq = list_entry_rq(sort_list->next);
if (bio->bi_sector + bio_sectors(bio) < __rq->sector &&
bio->bi_sector > deadline_get_last_sector(dd))
*insert = sort_list;
}
out: out:
return ret; return ret;
} }
...@@ -254,18 +286,9 @@ deadline_move_to_dispatch(struct deadline_data *dd, struct request *rq) ...@@ -254,18 +286,9 @@ deadline_move_to_dispatch(struct deadline_data *dd, struct request *rq)
static void deadline_move_requests(struct deadline_data *dd, struct request *rq) static void deadline_move_requests(struct deadline_data *dd, struct request *rq)
{ {
struct list_head *sort_head = &dd->sort_list[rq_data_dir(rq)]; struct list_head *sort_head = &dd->sort_list[rq_data_dir(rq)];
sector_t last_sec = dd->last_sector; sector_t last_sec = deadline_get_last_sector(dd);
int batch_count = dd->fifo_batch; int batch_count = dd->fifo_batch;
/*
* if dispatch is non-empty, disregard last_sector and check last one
*/
if (!list_empty(dd->dispatch)) {
struct request *__rq = list_entry_rq(dd->dispatch->prev);
last_sec = __rq->sector + __rq->nr_sectors;
}
do { do {
struct list_head *nxt = rq->queuelist.next; struct list_head *nxt = rq->queuelist.next;
int this_rq_cost; int this_rq_cost;
......
...@@ -136,8 +136,7 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio) ...@@ -136,8 +136,7 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio)
return ret; return ret;
} }
inline int elv_try_last_merge(request_queue_t *q, struct request **req, inline int elv_try_last_merge(request_queue_t *q, struct bio *bio)
struct bio *bio)
{ {
int ret = ELEVATOR_NO_MERGE; int ret = ELEVATOR_NO_MERGE;
...@@ -150,8 +149,8 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req, ...@@ -150,8 +149,8 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req,
if (!rq_mergeable(__rq)) if (!rq_mergeable(__rq))
q->last_merge = NULL; q->last_merge = NULL;
else if ((ret = elv_try_merge(__rq, bio))) else
*req = __rq; ret = elv_try_merge(__rq, bio);
} }
return ret; return ret;
...@@ -162,15 +161,17 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req, ...@@ -162,15 +161,17 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req,
* *
* See if we can find a request that this buffer can be coalesced with. * See if we can find a request that this buffer can be coalesced with.
*/ */
int elevator_noop_merge(request_queue_t *q, struct request **req, int elevator_noop_merge(request_queue_t *q, struct list_head **insert,
struct bio *bio) struct bio *bio)
{ {
struct list_head *entry = &q->queue_head; struct list_head *entry = &q->queue_head;
struct request *__rq; struct request *__rq;
int ret; int ret;
if ((ret = elv_try_last_merge(q, req, bio))) if ((ret = elv_try_last_merge(q, bio))) {
*insert = q->last_merge;
return ret; return ret;
}
while ((entry = entry->prev) != &q->queue_head) { while ((entry = entry->prev) != &q->queue_head) {
__rq = list_entry_rq(entry); __rq = list_entry_rq(entry);
...@@ -182,7 +183,7 @@ int elevator_noop_merge(request_queue_t *q, struct request **req, ...@@ -182,7 +183,7 @@ int elevator_noop_merge(request_queue_t *q, struct request **req,
continue; continue;
if ((ret = elv_try_merge(__rq, bio))) { if ((ret = elv_try_merge(__rq, bio))) {
*req = __rq; *insert = &__rq->queuelist;
q->last_merge = &__rq->queuelist; q->last_merge = &__rq->queuelist;
return ret; return ret;
} }
...@@ -240,12 +241,12 @@ int elevator_global_init(void) ...@@ -240,12 +241,12 @@ int elevator_global_init(void)
return 0; return 0;
} }
int elv_merge(request_queue_t *q, struct request **rq, struct bio *bio) int elv_merge(request_queue_t *q, struct list_head **entry, struct bio *bio)
{ {
elevator_t *e = &q->elevator; elevator_t *e = &q->elevator;
if (e->elevator_merge_fn) if (e->elevator_merge_fn)
return e->elevator_merge_fn(q, rq, bio); return e->elevator_merge_fn(q, entry, bio);
return ELEVATOR_NO_MERGE; return ELEVATOR_NO_MERGE;
} }
......
...@@ -1583,7 +1583,6 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1583,7 +1583,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
again: again:
req = NULL;
insert_here = NULL; insert_here = NULL;
if (blk_queue_empty(q)) { if (blk_queue_empty(q)) {
...@@ -1593,10 +1592,13 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1593,10 +1592,13 @@ static int __make_request(request_queue_t *q, struct bio *bio)
if (barrier) if (barrier)
goto get_rq; goto get_rq;
el_ret = elv_merge(q, &req, bio); el_ret = elv_merge(q, &insert_here, bio);
switch (el_ret) { switch (el_ret) {
case ELEVATOR_BACK_MERGE: case ELEVATOR_BACK_MERGE:
req = list_entry_rq(insert_here);
BUG_ON(!rq_mergeable(req)); BUG_ON(!rq_mergeable(req));
if (!q->back_merge_fn(q, req, bio)) { if (!q->back_merge_fn(q, req, bio)) {
insert_here = &req->queuelist; insert_here = &req->queuelist;
break; break;
...@@ -1611,7 +1613,10 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1611,7 +1613,10 @@ static int __make_request(request_queue_t *q, struct bio *bio)
goto out; goto out;
case ELEVATOR_FRONT_MERGE: case ELEVATOR_FRONT_MERGE:
req = list_entry_rq(insert_here);
BUG_ON(!rq_mergeable(req)); BUG_ON(!rq_mergeable(req));
if (!q->front_merge_fn(q, req, bio)) { if (!q->front_merge_fn(q, req, bio)) {
insert_here = req->queuelist.prev; insert_here = req->queuelist.prev;
break; break;
...@@ -1638,13 +1643,6 @@ static int __make_request(request_queue_t *q, struct bio *bio) ...@@ -1638,13 +1643,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
* elevator says don't/can't merge. get new request * elevator says don't/can't merge. get new request
*/ */
case ELEVATOR_NO_MERGE: case ELEVATOR_NO_MERGE:
/*
* use elevator hints as to where to insert the
* request. if no hints, just add it to the back
* of the queue
*/
if (req)
insert_here = &req->queuelist;
break; break;
default: default:
......
dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
if [ "$CONFIG_GART_IOMMU" = "y" ]; then
dep_bool '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
else
dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
fi
if [ "$CONFIG_AGP" != "n" ]; then if [ "$CONFIG_AGP" != "n" ]; then
bool ' Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL bool ' Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
bool ' Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810 bool ' Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
...@@ -7,6 +12,9 @@ if [ "$CONFIG_AGP" != "n" ]; then ...@@ -7,6 +12,9 @@ if [ "$CONFIG_AGP" != "n" ]; then
bool ' Generic SiS support' CONFIG_AGP_SIS bool ' Generic SiS support' CONFIG_AGP_SIS
bool ' ALI chipset support' CONFIG_AGP_ALI bool ' ALI chipset support' CONFIG_AGP_ALI
bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS
if [ "$CONFIG_GART_IOMMU" != "y" ]; then
bool ' AMD 8151 support' CONFIG_AGP_AMD_8151
fi
if [ "$CONFIG_IA64" = "y" ]; then if [ "$CONFIG_IA64" = "y" ]; then
bool ' Intel 460GX support' CONFIG_AGP_I460 bool ' Intel 460GX support' CONFIG_AGP_I460
bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
......
...@@ -16,6 +16,7 @@ agpgart-$(CONFIG_AGP_ALI) += ali-agp.o ...@@ -16,6 +16,7 @@ agpgart-$(CONFIG_AGP_ALI) += ali-agp.o
agpgart-$(CONFIG_AGP_SWORKS) += sworks-agp.o agpgart-$(CONFIG_AGP_SWORKS) += sworks-agp.o
agpgart-$(CONFIG_AGP_I460) += i460-agp.o agpgart-$(CONFIG_AGP_I460) += i460-agp.o
agpgart-$(CONFIG_AGP_HP_ZX1) += hp-agp.o agpgart-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
agpgart-$(CONFIG_AGP_AMD_8151) += k8-agp.o
agpgart-objs := $(agpgart-y) agpgart-objs := $(agpgart-y)
obj-$(CONFIG_AGP) += agpgart.o obj-$(CONFIG_AGP) += agpgart.o
......
...@@ -50,6 +50,9 @@ EXPORT_SYMBOL(agp_backend_release); ...@@ -50,6 +50,9 @@ EXPORT_SYMBOL(agp_backend_release);
struct agp_bridge_data agp_bridge = { type: NOT_SUPPORTED }; struct agp_bridge_data agp_bridge = { type: NOT_SUPPORTED };
static int agp_try_unsupported __initdata = 0; static int agp_try_unsupported __initdata = 0;
int agp_memory_reserved;
__u32 *agp_gatt_table;
int agp_backend_acquire(void) int agp_backend_acquire(void)
{ {
if (agp_bridge.type == NOT_SUPPORTED) if (agp_bridge.type == NOT_SUPPORTED)
...@@ -243,7 +246,7 @@ static int agp_return_size(void) ...@@ -243,7 +246,7 @@ static int agp_return_size(void)
/* Routine to copy over information structure */ /* Routine to copy over information structure */
void agp_copy_info(agp_kern_info * info) int agp_copy_info(agp_kern_info * info)
{ {
unsigned long page_mask = 0; unsigned long page_mask = 0;
int i; int i;
...@@ -251,7 +254,7 @@ void agp_copy_info(agp_kern_info * info) ...@@ -251,7 +254,7 @@ void agp_copy_info(agp_kern_info * info)
memset(info, 0, sizeof(agp_kern_info)); memset(info, 0, sizeof(agp_kern_info));
if (agp_bridge.type == NOT_SUPPORTED) { if (agp_bridge.type == NOT_SUPPORTED) {
info->chipset = agp_bridge.type; info->chipset = agp_bridge.type;
return; return -EIO;
} }
info->version.major = agp_bridge.version->major; info->version.major = agp_bridge.version->major;
info->version.minor = agp_bridge.version->minor; info->version.minor = agp_bridge.version->minor;
...@@ -268,6 +271,7 @@ void agp_copy_info(agp_kern_info * info) ...@@ -268,6 +271,7 @@ void agp_copy_info(agp_kern_info * info)
page_mask |= agp_bridge.mask_memory(page_mask, i); page_mask |= agp_bridge.mask_memory(page_mask, i);
info->page_mask = ~page_mask; info->page_mask = ~page_mask;
return 0;
} }
/* End - Routine to copy over information structure */ /* End - Routine to copy over information structure */
...@@ -518,6 +522,7 @@ int agp_generic_create_gatt_table(void) ...@@ -518,6 +522,7 @@ int agp_generic_create_gatt_table(void)
SetPageReserved(page); SetPageReserved(page);
agp_bridge.gatt_table_real = (unsigned long *) table; agp_bridge.gatt_table_real = (unsigned long *) table;
agp_gatt_table = (void *)table;
CACHE_FLUSH(); CACHE_FLUSH();
agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table), agp_bridge.gatt_table = ioremap_nocache(virt_to_phys(table),
(PAGE_SIZE * (1 << page_order))); (PAGE_SIZE * (1 << page_order)));
...@@ -625,6 +630,9 @@ int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type) ...@@ -625,6 +630,9 @@ int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type)
break; break;
} }
num_entries -= agp_memory_reserved/PAGE_SIZE;
if (num_entries < 0) num_entries = 0;
if (type != 0 || mem->type != 0) { if (type != 0 || mem->type != 0) {
/* The generic routines know nothing of memory types */ /* The generic routines know nothing of memory types */
return -EINVAL; return -EINVAL;
...@@ -824,6 +832,17 @@ static struct { ...@@ -824,6 +832,17 @@ static struct {
}, },
#endif /* CONFIG_AGP_ALI */ #endif /* CONFIG_AGP_ALI */
#ifdef CONFIG_AGP_AMD_8151
{
.device_id = PCI_DEVICE_ID_AMD_8151_0,
.vendor_id = PCI_VENDOR_ID_AMD,
.chipset = AMD_8151,
.vendor_name = "AMD",
.chipset_name = "8151",
.chipset_setup = amd_8151_setup
},
#endif /* CONFIG_AGP_AMD */
#ifdef CONFIG_AGP_AMD #ifdef CONFIG_AGP_AMD
{ {
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006,
...@@ -858,7 +877,6 @@ static struct { ...@@ -858,7 +877,6 @@ static struct {
.chipset_setup = amd_irongate_setup, .chipset_setup = amd_irongate_setup,
}, },
#endif /* CONFIG_AGP_AMD */ #endif /* CONFIG_AGP_AMD */
#ifdef CONFIG_AGP_INTEL #ifdef CONFIG_AGP_INTEL
{ {
.device_id = PCI_DEVICE_ID_INTEL_82443LX_0, .device_id = PCI_DEVICE_ID_INTEL_82443LX_0,
...@@ -1632,7 +1650,7 @@ static struct pci_driver agp_pci_driver = { ...@@ -1632,7 +1650,7 @@ static struct pci_driver agp_pci_driver = {
.probe = agp_probe, .probe = agp_probe,
}; };
static int __init agp_init(void) int __init agp_init(void)
{ {
int ret_val; int ret_val;
...@@ -1658,5 +1676,7 @@ static void __exit agp_cleanup(void) ...@@ -1658,5 +1676,7 @@ static void __exit agp_cleanup(void)
} }
} }
#ifndef CONFIG_GART_IOMMU
module_init(agp_init); module_init(agp_init);
module_exit(agp_cleanup); module_exit(agp_cleanup);
#endif
...@@ -49,6 +49,7 @@ void agp_free_key(int key); ...@@ -49,6 +49,7 @@ void agp_free_key(int key);
/* chipset specific init routines. */ /* chipset specific init routines. */
int __init ali_generic_setup (struct pci_dev *pdev); int __init ali_generic_setup (struct pci_dev *pdev);
int __init amd_irongate_setup (struct pci_dev *pdev); int __init amd_irongate_setup (struct pci_dev *pdev);
int __init amd_8151_setup (struct pci_dev *pdev);
int __init hp_zx1_setup (struct pci_dev *pdev); int __init hp_zx1_setup (struct pci_dev *pdev);
int __init intel_i460_setup (struct pci_dev *pdev); int __init intel_i460_setup (struct pci_dev *pdev);
int __init intel_generic_setup (struct pci_dev *pdev); int __init intel_generic_setup (struct pci_dev *pdev);
...@@ -319,6 +320,22 @@ struct agp_bridge_data { ...@@ -319,6 +320,22 @@ struct agp_bridge_data {
#define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */ #define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */
#define AMD_CACHEENTRY 0x10 /* In mmio region (32-bit register) */ #define AMD_CACHEENTRY 0x10 /* In mmio region (32-bit register) */
#define AMD_8151_APSIZE 0xb4
#define AMD_8151_GARTBLOCK 0xb8
#define AMD_X86_64_GARTAPERTURECTL 0x90
#define AMD_X86_64_GARTAPERTUREBASE 0x94
#define AMD_X86_64_GARTTABLEBASE 0x98
#define AMD_X86_64_GARTCACHECTL 0x9c
#define AMD_X86_64_GARTEN 1<<0
#define AMD_8151_VMAPERTURE 0x10
#define AMD_8151_AGP_CTL 0xb0
#define AMD_8151_APERTURESIZE 0xb4
#define AMD_8151_GARTPTR 0xb8
#define AMD_8151_GTLBEN 1<<7
#define AMD_8151_APEREN 1<<8
/* ALi registers */ /* ALi registers */
#define ALI_APBASE 0x10 #define ALI_APBASE 0x10
#define ALI_AGPCTRL 0xb8 #define ALI_AGPCTRL 0xb8
......
This diff is collapsed.
...@@ -121,6 +121,8 @@ extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */ ...@@ -121,6 +121,8 @@ extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */ extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */
#endif #endif
extern void disable_early_printk(void);
/* /*
* redirect is the pseudo-tty that console output * redirect is the pseudo-tty that console output
* is redirected to if asked by TIOCCONS. * is redirected to if asked by TIOCCONS.
...@@ -2185,6 +2187,9 @@ void __init console_init(void) ...@@ -2185,6 +2187,9 @@ void __init console_init(void)
* set up the console device so that later boot sequences can * set up the console device so that later boot sequences can
* inform about problems etc.. * inform about problems etc..
*/ */
#ifdef CONFIG_EARLY_PRINTK
disable_early_printk();
#endif
#ifdef CONFIG_VT #ifdef CONFIG_VT
con_init(); con_init();
#endif #endif
......
...@@ -36,14 +36,11 @@ ...@@ -36,14 +36,11 @@
* This driver has been tested SUCCESSFULLY with the following drivers : * This driver has been tested SUCCESSFULLY with the following drivers :
* o usb-uhci-hcd (For Intel/Via USB controllers) * o usb-uhci-hcd (For Intel/Via USB controllers)
* o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers) * o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers)
* o ohci-hcd (For other USB controllers)
* *
* This driver has NOT been tested with the following drivers : * This driver has NOT been tested with the following drivers :
* o ehci-hcd (USB 2.0 controllers) * o ehci-hcd (USB 2.0 controllers)
* *
* This driver DOESN'T SEEM TO WORK with the following drivers :
* o ohci-hcd (For other USB controllers)
* The first outgoing URB never calls its completion/failure callback.
*
* Note that all HCD drivers do USB_ZERO_PACKET and timeout properly, * Note that all HCD drivers do USB_ZERO_PACKET and timeout properly,
* so we don't have to worry about that anymore. * so we don't have to worry about that anymore.
* One common problem is the failure to set the address on the dongle, * One common problem is the failure to set the address on the dongle,
...@@ -104,8 +101,8 @@ MODULE_DEVICE_TABLE(usb, dongles); ...@@ -104,8 +101,8 @@ MODULE_DEVICE_TABLE(usb, dongles);
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum); static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf);
static void irda_usb_disconnect(struct usb_device *dev, void *ptr); static void irda_usb_disconnect(struct usb_interface *intf);
static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev); static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
static int irda_usb_open(struct irda_usb_cb *self); static int irda_usb_open(struct irda_usb_cb *self);
...@@ -1340,7 +1337,7 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) ...@@ -1340,7 +1337,7 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Function irda_usb_find_class_desc(dev, ifnum) * Function irda_usb_find_class_desc(intf)
* *
* Returns instance of IrDA class descriptor, or NULL if not found * Returns instance of IrDA class descriptor, or NULL if not found
* *
...@@ -1348,8 +1345,9 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) ...@@ -1348,8 +1345,9 @@ static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
* offer to us, describing their IrDA characteristics. We will use that in * offer to us, describing their IrDA characteristics. We will use that in
* irda_usb_init_qos() * irda_usb_init_qos()
*/ */
static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf)
{ {
struct usb_device *dev = interface_to_usbdev (intf);
struct irda_class_desc *desc; struct irda_class_desc *desc;
int ret; int ret;
...@@ -1368,7 +1366,8 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device ...@@ -1368,7 +1366,8 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
IU_REQ_GET_CLASS_DESC, IU_REQ_GET_CLASS_DESC,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); 0, intf->altsetting->bInterfaceNumber, desc,
sizeof(*desc), MSECS_TO_JIFFIES(500));
IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret); IRDA_DEBUG(1, "%s(), ret=%d\n", __FUNCTION__, ret);
if (ret < sizeof(*desc)) { if (ret < sizeof(*desc)) {
...@@ -1403,9 +1402,10 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device ...@@ -1403,9 +1402,10 @@ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device
* Note : it might be worth protecting this function by a global * Note : it might be worth protecting this function by a global
* spinlock... Or not, because maybe USB already deal with that... * spinlock... Or not, because maybe USB already deal with that...
*/ */
static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, static int irda_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf);
struct irda_usb_cb *self = NULL; struct irda_usb_cb *self = NULL;
struct usb_interface_descriptor *interface; struct usb_interface_descriptor *interface;
struct irda_class_desc *irda_desc; struct irda_class_desc *irda_desc;
...@@ -1430,7 +1430,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1430,7 +1430,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
(irda->present == 0) && (irda->present == 0) &&
(irda->netopen == 0)) { (irda->netopen == 0)) {
IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), found a zombie instance !!!\n", __FUNCTION__);
irda_usb_disconnect(irda->usbdev, (void *) irda); irda_usb_disconnect(irda->usbintf);
} }
} }
...@@ -1445,7 +1445,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1445,7 +1445,7 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
if(self == NULL) { if(self == NULL) {
WARNING("Too many USB IrDA devices !!! (max = %d)\n", WARNING("Too many USB IrDA devices !!! (max = %d)\n",
NIRUSB); NIRUSB);
return NULL; return -ENFILE;
} }
/* Reset the instance */ /* Reset the instance */
...@@ -1459,35 +1459,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1459,35 +1459,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
int j; int j;
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
usb_free_urb(self->rx_urb[j]); usb_free_urb(self->rx_urb[j]);
return NULL; return -ENOMEM;
} }
} }
self->tx_urb = usb_alloc_urb(0, GFP_KERNEL); self->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!self->tx_urb) { if (!self->tx_urb) {
for (i = 0; i < IU_MAX_RX_URBS; i++) for (i = 0; i < IU_MAX_RX_URBS; i++)
usb_free_urb(self->rx_urb[i]); usb_free_urb(self->rx_urb[i]);
return NULL; return -ENOMEM;
} }
self->speed_urb = usb_alloc_urb(0, GFP_KERNEL); self->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!self->speed_urb) { if (!self->speed_urb) {
for (i = 0; i < IU_MAX_RX_URBS; i++) for (i = 0; i < IU_MAX_RX_URBS; i++)
usb_free_urb(self->rx_urb[i]); usb_free_urb(self->rx_urb[i]);
usb_free_urb(self->tx_urb); usb_free_urb(self->tx_urb);
return NULL; return -ENOMEM;
} }
/* Is this really necessary? */ /* Is this really necessary? */
if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) { if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
err("set_configuration failed"); err("set_configuration failed");
return NULL; return -EIO;
} }
/* Is this really necessary? */ /* Is this really necessary? */
/* Note : some driver do hardcode the interface number, some others /* Note : some driver do hardcode the interface number, some others
* specify an alternate, but very few driver do like this. * specify an alternate, but very few driver do like this.
* Jean II */ * Jean II */
ret = usb_set_interface(dev, ifnum, 0); ret = usb_set_interface(dev, intf->altsetting->bInterfaceNumber, 0);
IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", ifnum, ret); IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", intf->altsetting->bInterfaceNumber, ret);
switch (ret) { switch (ret) {
case 0: case 0:
break; break;
...@@ -1497,33 +1497,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1497,33 +1497,35 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
break; break;
default: default:
IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret); IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret);
return NULL; return -EIO;
break; break;
} }
/* Find our endpoints */ /* Find our endpoints */
interface = &dev->actconfig->interface[ifnum].altsetting[0]; interface = &intf->altsetting[0];
if(!irda_usb_parse_endpoints(self, interface->endpoint, if(!irda_usb_parse_endpoints(self, interface->endpoint,
interface->bNumEndpoints)) { interface->bNumEndpoints)) {
ERROR("%s(), Bogus endpoints...\n", __FUNCTION__); ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
return NULL; return -EIO;
} }
/* Find IrDA class descriptor */ /* Find IrDA class descriptor */
irda_desc = irda_usb_find_class_desc(dev, ifnum); irda_desc = irda_usb_find_class_desc(intf);
if (irda_desc == NULL) if (irda_desc == NULL)
return NULL; return -ENODEV;
self->irda_desc = irda_desc; self->irda_desc = irda_desc;
self->present = 1; self->present = 1;
self->netopen = 0; self->netopen = 0;
self->capability = id->driver_info; self->capability = id->driver_info;
self->usbdev = dev; self->usbdev = dev;
self->usbintf = intf;
ret = irda_usb_open(self); ret = irda_usb_open(self);
if (ret) if (ret)
return NULL; return -ENOMEM;
return self; dev_set_drvdata(&intf->dev, self);
return 0;
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -1538,14 +1540,18 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -1538,14 +1540,18 @@ static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
* So, we must make bloody sure that everything gets deactivated. * So, we must make bloody sure that everything gets deactivated.
* Jean II * Jean II
*/ */
static void irda_usb_disconnect(struct usb_device *dev, void *ptr) static void irda_usb_disconnect(struct usb_interface *intf)
{ {
unsigned long flags; unsigned long flags;
struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; struct irda_usb_cb *self = dev_get_drvdata (&intf->dev);
int i; int i;
IRDA_DEBUG(1, "%s()\n", __FUNCTION__); IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
dev_set_drvdata(&intf->dev, NULL);
if (!self)
return;
/* Make sure that the Tx path is not executing. - Jean II */ /* Make sure that the Tx path is not executing. - Jean II */
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
...@@ -1577,6 +1583,7 @@ static void irda_usb_disconnect(struct usb_device *dev, void *ptr) ...@@ -1577,6 +1583,7 @@ static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
irda_usb_close(self); irda_usb_close(self);
/* No longer attached to USB bus */ /* No longer attached to USB bus */
self->usbdev = NULL; self->usbdev = NULL;
self->usbintf = NULL;
/* Clean up our urbs */ /* Clean up our urbs */
for (i = 0; i < IU_MAX_RX_URBS; i++) for (i = 0; i < IU_MAX_RX_URBS; i++)
...@@ -1635,7 +1642,7 @@ void __exit usb_irda_cleanup(void) ...@@ -1635,7 +1642,7 @@ void __exit usb_irda_cleanup(void)
/* If the Device is zombie */ /* If the Device is zombie */
if((irda->usbdev != NULL) && (irda->present == 0)) { if((irda->usbdev != NULL) && (irda->present == 0)) {
IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__); IRDA_DEBUG(0, "%s(), disconnect zombie now !\n", __FUNCTION__);
irda_usb_disconnect(irda->usbdev, (void *) irda); irda_usb_disconnect(irda->usbintf);
} }
} }
......
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kmod.h> /* for hotplug_path */ #include "pci.h"
#ifndef FALSE
#define FALSE (0)
#define TRUE (!FALSE)
#endif
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
static void run_sbin_hotplug(struct pci_dev *pdev, int insert) int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{ {
int i; struct pci_dev *pdev;
char *argv[3], *envp[8]; char *scratch;
char id[20], sub_id[24], bus_id[24], class_id[20]; int i = 0;
int length = 0;
if (!hotplug_path[0])
return; if (!dev)
return -ENODEV;
sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device); pdev = to_pci_dev(dev);
sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device); if (!pdev)
sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name); return -ENODEV;
i = 0; scratch = buffer;
argv[i++] = hotplug_path;
argv[i++] = "pci"; /* stuff we want to pass to /sbin/hotplug */
argv[i] = 0; envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
i = 0; pdev->class);
/* minimal command environment */ if ((buffer_size - length <= 0) || (i >= num_envp))
envp[i++] = "HOME=/"; return -ENOMEM;
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++length;
scratch += length;
/* other stuff we want to pass to /sbin/hotplug */
envp[i++] = class_id; envp[i++] = scratch;
envp[i++] = id; length += snprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
envp[i++] = sub_id; pdev->vendor, pdev->device);
envp[i++] = bus_id; if ((buffer_size - length <= 0) || (i >= num_envp))
if (insert) return -ENOMEM;
envp[i++] = "ACTION=add"; ++length;
else scratch += length;
envp[i++] = "ACTION=remove";
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp[i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
pdev->slot_name);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
envp[i] = 0; envp[i] = 0;
call_usermodehelper (argv [0], argv, envp); return 0;
} }
#else #else
static void run_sbin_hotplug(struct pci_dev *pdev, int insert) { } int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif #endif
/** /**
...@@ -66,8 +82,6 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) ...@@ -66,8 +82,6 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
pci_proc_attach_device(dev); pci_proc_attach_device(dev);
#endif #endif
/* notify userspace of new hotplug device */
run_sbin_hotplug(dev, TRUE);
} }
static void static void
...@@ -99,8 +113,6 @@ pci_remove_device(struct pci_dev *dev) ...@@ -99,8 +113,6 @@ pci_remove_device(struct pci_dev *dev)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
pci_proc_detach_device(dev); pci_proc_detach_device(dev);
#endif #endif
/* notify userspace of hotplug device removal */
run_sbin_hotplug(dev, FALSE);
} }
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include "pci.h"
/* /*
* Registration of PCI drivers and handling of hot-pluggable devices. * Registration of PCI drivers and handling of hot-pluggable devices.
...@@ -199,8 +200,9 @@ static int pci_bus_match(struct device * dev, struct device_driver * drv) ...@@ -199,8 +200,9 @@ static int pci_bus_match(struct device * dev, struct device_driver * drv)
} }
struct bus_type pci_bus_type = { struct bus_type pci_bus_type = {
name: "pci", name: "pci",
match: pci_bus_match, match: pci_bus_match,
hotplug: pci_hotplug,
}; };
static int __init pci_driver_init(void) static int __init pci_driver_init(void)
......
/* Functions internal to the PCI core code */
extern int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "i82092aa.h" #include "i82092aa.h"
#include "i82365.h" #include "i82365.h"
MODULE_LICENSE("GPL");
/* PCI core routines */ /* PCI core routines */
static struct pci_device_id i82092aa_pci_ids[] = { static struct pci_device_id i82092aa_pci_ids[] = {
{ {
......
...@@ -1048,11 +1048,19 @@ int isapnp_cfg_begin(int csn, int logdev) ...@@ -1048,11 +1048,19 @@ int isapnp_cfg_begin(int csn, int logdev)
isapnp_wait(); isapnp_wait();
isapnp_key(); isapnp_key();
isapnp_wake(csn); isapnp_wake(csn);
#if 1 /* to avoid malfunction when the isapnptools package is used */ #if 1
isapnp_set_rdp(); /* to avoid malfunction when the isapnptools package is used */
udelay(1000); /* delay 1000us */ /* we must set RDP to our value again */
write_address(0x01); /* it is possible to set RDP only in the isolation phase */
udelay(1000); /* delay 1000us */ /* Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
isapnp_write_byte(0x02, 0x04); /* clear CSN of card */
mdelay(2); /* is this necessary? */
isapnp_wake(csn); /* bring card into sleep state */
isapnp_wake(0); /* bring card into isolation state */
isapnp_set_rdp(); /* reset the RDP port */
udelay(1000); /* delay 1000us */
isapnp_write_byte(0x06, csn); /* reset CSN to previous value */
udelay(250); /* is this necessary? */
#endif #endif
if (logdev >= 0) if (logdev >= 0)
isapnp_device(logdev); isapnp_device(logdev);
......
...@@ -510,57 +510,42 @@ static int usb_device_match (struct device *dev, struct device_driver *drv) ...@@ -510,57 +510,42 @@ static int usb_device_match (struct device *dev, struct device_driver *drv)
* cases, we know no other thread can recycle our address, since we must * cases, we know no other thread can recycle our address, since we must
* already have been serialized enough to prevent that. * already have been serialized enough to prevent that.
*/ */
static void call_policy (char *verb, struct usb_device *dev) static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{ {
char *argv [3], **envp, *buf, *scratch; struct usb_interface *intf;
int i = 0, value; struct usb_device *usb_dev;
char *scratch;
int i = 0;
int length = 0;
if (!hotplug_path [0]) dbg ("%s", __FUNCTION__);
return;
if (in_interrupt ()) {
dbg ("In_interrupt");
return;
}
if (!current->fs->root) {
/* statically linked USB is initted rather early */
dbg ("call_policy %s, num %d -- no FS yet", verb, dev->devnum);
return;
}
if (dev->devnum < 0) {
dbg ("device already deleted ??");
return;
}
if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
dbg ("enomem");
return;
}
if (!(buf = kmalloc (256, GFP_KERNEL))) {
kfree (envp);
dbg ("enomem2");
return;
}
/* only one standardized param to hotplug command: type */ if (!dev)
argv [0] = hotplug_path; return -ENODEV;
argv [1] = "usb";
argv [2] = 0;
/* minimal command environment */ /* check for generic driver, we do not call do hotplug calls for it */
envp [i++] = "HOME=/"; if (dev->driver == &usb_generic_driver)
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; return -ENODEV;
#ifdef DEBUG intf = to_usb_interface(dev);
/* hint that policy agent should enter no-stdout debug mode */ if (!intf)
envp [i++] = "DEBUG=kernel"; return -ENODEV;
#endif
/* extensible set of named bus-specific parameters,
* supporting multiple driver selection algorithms.
*/
scratch = buf;
/* action: add, remove */ usb_dev = interface_to_usbdev (intf);
envp [i++] = scratch; if (!usb_dev)
scratch += sprintf (scratch, "ACTION=%s", verb) + 1; return -ENODEV;
if (usb_dev->devnum < 0) {
dbg ("device already deleted ??");
return -ENODEV;
}
if (!usb_dev->bus) {
dbg ("bus already removed?");
return -ENODEV;
}
scratch = buffer;
#ifdef CONFIG_USB_DEVICEFS #ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read /* If this is available, userspace programs can directly read
...@@ -569,27 +554,48 @@ static void call_policy (char *verb, struct usb_device *dev) ...@@ -569,27 +554,48 @@ static void call_policy (char *verb, struct usb_device *dev)
* *
* FIXME reduce hardwired intelligence here * FIXME reduce hardwired intelligence here
*/ */
envp [i++] = "DEVFS=/proc/bus/usb";
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d", length += snprintf (scratch, buffer_size - length,
dev->bus->busnum, dev->devnum) + 1; "%s", "DEVFS=/proc/bus/usb");
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
#endif #endif
/* per-device configuration hacks are common */ /* per-device configuration hacks are common */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "PRODUCT=%x/%x/%x", length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
dev->descriptor.idVendor, usb_dev->descriptor.idVendor,
dev->descriptor.idProduct, usb_dev->descriptor.idProduct,
dev->descriptor.bcdDevice) + 1; usb_dev->descriptor.bcdDevice);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
/* class-based driver binding models */ /* class-based driver binding models */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "TYPE=%d/%d/%d", length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceClass,
dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceSubClass,
dev->descriptor.bDeviceProtocol) + 1; usb_dev->descriptor.bDeviceProtocol);
if (dev->descriptor.bDeviceClass == 0) { if ((buffer_size - length <= 0) || (i >= num_envp))
int alt = dev->actconfig->interface [0].act_altsetting; return -ENOMEM;
++length;
scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
/* a simple/common case: one config, one interface, one driver /* a simple/common case: one config, one interface, one driver
* with current altsetting being a reasonable setting. * with current altsetting being a reasonable setting.
...@@ -597,31 +603,29 @@ static void call_policy (char *verb, struct usb_device *dev) ...@@ -597,31 +603,29 @@ static void call_policy (char *verb, struct usb_device *dev)
* device-specific binding policies. * device-specific binding policies.
*/ */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "INTERFACE=%d/%d/%d", length += snprintf (scratch, buffer_size - length,
dev->actconfig->interface [0].altsetting [alt].bInterfaceClass, "INTERFACE=%d/%d/%d",
dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass, intf->altsetting[alt].bInterfaceClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol) intf->altsetting[alt].bInterfaceSubClass,
+ 1; intf->altsetting[alt].bInterfaceProtocol);
/* INTERFACE-0, INTERFACE-1, ... ? */ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
} }
envp [i++] = 0; envp [i++] = 0;
/* assert: (scratch - buf) < sizeof buf */
/* NOTE: user mode daemons can call the agents too */ return 0;
dbg ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
value = call_usermodehelper (argv [0], argv, envp);
kfree (buf);
kfree (envp);
if (value != 0)
dbg ("kusbd policy returned 0x%x", value);
} }
#else #else
static inline void static int usb_hotplug (struct device *dev, char **envp,
call_policy (char *verb, struct usb_device *dev) char *buffer, int buffer_size)
{ } {
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */ #endif /* CONFIG_HOTPLUG */
...@@ -894,9 +898,6 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -894,9 +898,6 @@ void usb_disconnect(struct usb_device **pdev)
put_device(&dev->dev); put_device(&dev->dev);
} }
/* Let policy agent unload modules etc */
call_policy ("remove", dev);
/* Decrement the reference count, it'll auto free everything when */ /* Decrement the reference count, it'll auto free everything when */
/* it hits 0 which could very well be now */ /* it hits 0 which could very well be now */
usb_put_dev(dev); usb_put_dev(dev);
...@@ -1174,9 +1175,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1174,9 +1175,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
/* add a /proc/bus/usb entry */ /* add a /proc/bus/usb entry */
usbfs_add_device(dev); usbfs_add_device(dev);
/* userspace may load modules and/or configure further */
call_policy ("add", dev);
return 0; return 0;
} }
...@@ -1439,6 +1437,7 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1439,6 +1437,7 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
.name = "usb", .name = "usb",
.match = usb_device_match, .match = usb_device_match,
.hotplug = usb_hotplug,
}; };
/* /*
......
...@@ -788,7 +788,7 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -788,7 +788,7 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us)
/* only check card status if the map isn't allocated, ie no card seen yet /* only check card status if the map isn't allocated, ie no card seen yet
* or if it's been over half a second since we last accessed it * or if it's been over half a second since we last accessed it
*/ */
if (info->lba_to_pba == NULL || jiffies > (info->last_access + HZ/2)) { if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) {
/* check to see if a card is fitted */ /* check to see if a card is fitted */
result = sddr55_status (us); result = sddr55_status (us);
......
...@@ -859,6 +859,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -859,6 +859,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
* This must be called with scsi_lock(us->srb->host) held */ * This must be called with scsi_lock(us->srb->host) held */
void usb_stor_abort_transport(struct us_data *us) void usb_stor_abort_transport(struct us_data *us)
{ {
struct Scsi_Host *host;
int state = atomic_read(&us->sm_state); int state = atomic_read(&us->sm_state);
US_DEBUGP("usb_stor_abort_transport called\n"); US_DEBUGP("usb_stor_abort_transport called\n");
...@@ -870,7 +871,8 @@ void usb_stor_abort_transport(struct us_data *us) ...@@ -870,7 +871,8 @@ void usb_stor_abort_transport(struct us_data *us)
/* set state to abort and release the lock */ /* set state to abort and release the lock */
atomic_set(&us->sm_state, US_STATE_ABORTING); atomic_set(&us->sm_state, US_STATE_ABORTING);
scsi_unlock(us->srb->host); host = us->srb->host;
scsi_unlock(host);
/* If the state machine is blocked waiting for an URB or an IRQ, /* If the state machine is blocked waiting for an URB or an IRQ,
* let's wake it up */ * let's wake it up */
...@@ -892,8 +894,8 @@ void usb_stor_abort_transport(struct us_data *us) ...@@ -892,8 +894,8 @@ void usb_stor_abort_transport(struct us_data *us)
/* Wait for the aborted command to finish */ /* Wait for the aborted command to finish */
wait_for_completion(&us->notify); wait_for_completion(&us->notify);
/* Reacquire the lock */ /* Reacquire the lock: note that us->srb is now NULL */
scsi_lock(us->srb->host); scsi_lock(host);
} }
/* /*
......
...@@ -331,8 +331,10 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, ...@@ -331,8 +331,10 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff,
* Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly * Like the SIIG unit above, this unit needs an INQUIRY to ask for exactly
* 36 bytes of data. No more, no less. That is the only reason this entry * 36 bytes of data. No more, no less. That is the only reason this entry
* is needed. * is needed.
*/ *
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, * ST818 slim drives (rev 0.02) don't need special care.
*/
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001,
"EagleTec", "EagleTec",
"External Hard Disk", "External Hard Disk",
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
...@@ -548,17 +550,22 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001, ...@@ -548,17 +550,22 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001,
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ),
/* Submitted by Brian Hall <brihall@bigfoot.com> /* Submitted by Brian Hall <brihall@pcisys.net>
* Needed for START_STOP flag */ * Needed for START_STOP flag */
UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100,
"JMTek", "JMTek",
"USBDrive", "USBDrive",
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
US_FL_START_STOP ), US_FL_START_STOP ),
UNUSUAL_DEV( 0x0c76, 0x0005, 0x0100, 0x0100,
"JMTek",
"USBDrive",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_START_STOP ),
/* Reported by Dan Pilone <pilone@slac.com> /* Reported by Dan Pilone <pilone@slac.com>
* The device needs the flags only. * The device needs the flags only.
* Also reported by Brian Hall <brihall@bigfoot.com>, again for flags. * Also reported by Brian Hall <brihall@pcisys.net>, again for flags.
* I also suspect this device may have a broken serial number. * I also suspect this device may have a broken serial number.
*/ */
UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999,
......
/* /*
* USB Skeleton driver - 0.7 * USB Skeleton driver - 0.8
* *
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of * published by the Free Software Foundation, version 2.
* the License, or (at your option) any later version.
* *
* *
* This driver is to be used as a skeleton driver to be able to create a * This driver is to be used as a skeleton driver to be able to create a
...@@ -22,6 +21,8 @@ ...@@ -22,6 +21,8 @@
* *
* History: * History:
* *
* 2002_09_26 - 0.8 - changes due to USB core conversion to struct device
* driver.
* 2002_02_12 - 0.7 - zero out dev in probe function for devices that do * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do
* not have both a bulk in and bulk out endpoint. * not have both a bulk in and bulk out endpoint.
* Thanks to Holger Waechtler for the fix. * Thanks to Holger Waechtler for the fix.
...@@ -133,8 +134,8 @@ static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd ...@@ -133,8 +134,8 @@ static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd
static int skel_open (struct inode *inode, struct file *file); static int skel_open (struct inode *inode, struct file *file);
static int skel_release (struct inode *inode, struct file *file); static int skel_release (struct inode *inode, struct file *file);
static void * skel_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id); static int skel_probe (struct usb_interface *intf, const struct usb_device_id *id);
static void skel_disconnect (struct usb_device *dev, void *ptr); static void skel_disconnect (struct usb_interface *intf);
static void skel_write_bulk_callback (struct urb *urb); static void skel_write_bulk_callback (struct urb *urb);
...@@ -509,10 +510,10 @@ static void skel_write_bulk_callback (struct urb *urb) ...@@ -509,10 +510,10 @@ static void skel_write_bulk_callback (struct urb *urb)
* Called by the usb core when a new device is connected that it thinks * Called by the usb core when a new device is connected that it thinks
* this driver might be interested in. * this driver might be interested in.
*/ */
static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{ {
struct usb_device *udev = interface_to_usbdev(interface);
struct usb_skel *dev = NULL; struct usb_skel *dev = NULL;
struct usb_interface *interface;
struct usb_interface_descriptor *iface_desc; struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
int minor; int minor;
...@@ -525,7 +526,7 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -525,7 +526,7 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
/* See if the device offered us matches what we can accept */ /* See if the device offered us matches what we can accept */
if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
(udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
return NULL; return -ENODEV;
} }
down (&minor_table_mutex); down (&minor_table_mutex);
...@@ -545,8 +546,6 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -545,8 +546,6 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
memset (dev, 0x00, sizeof (*dev)); memset (dev, 0x00, sizeof (*dev));
minor_table[minor] = dev; minor_table[minor] = dev;
interface = &udev->actconfig->interface[ifnum];
init_MUTEX (&dev->sem); init_MUTEX (&dev->sem);
dev->udev = udev; dev->udev = udev;
dev->interface = interface; dev->interface = interface;
...@@ -619,7 +618,11 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -619,7 +618,11 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
exit: exit:
up (&minor_table_mutex); up (&minor_table_mutex);
return dev; if (dev) {
dev_set_drvdata (&interface->dev, dev);
return 0;
}
return -ENODEV;
} }
...@@ -628,13 +631,17 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru ...@@ -628,13 +631,17 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
* *
* Called by the usb core when the device is removed from the system. * Called by the usb core when the device is removed from the system.
*/ */
static void skel_disconnect(struct usb_device *udev, void *ptr) static void skel_disconnect(struct usb_interface *interface)
{ {
struct usb_skel *dev; struct usb_skel *dev;
int minor; int minor;
dev = (struct usb_skel *)ptr; dev = dev_get_drvdata (&interface->dev);
dev_set_drvdata (&interface->dev, NULL);
if (!dev)
return;
down (&minor_table_mutex); down (&minor_table_mutex);
down (&dev->sem); down (&dev->sem);
......
...@@ -276,6 +276,7 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) { ...@@ -276,6 +276,7 @@ static void DAC1064_setmclk(WPMINFO int oscinfo, unsigned long fmem) {
hw->MXoptionReg = mx; hw->MXoptionReg = mx;
} }
#ifdef CONFIG_FB_MATROX_G450
static void g450_set_plls(WPMINFO2) { static void g450_set_plls(WPMINFO2) {
u_int32_t c2_ctl; u_int32_t c2_ctl;
unsigned int pxc; unsigned int pxc;
...@@ -365,6 +366,7 @@ static void g450_set_plls(WPMINFO2) { ...@@ -365,6 +366,7 @@ static void g450_set_plls(WPMINFO2) {
} }
} }
} }
#endif
void DAC1064_global_init(WPMINFO2) { void DAC1064_global_init(WPMINFO2) {
struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
...@@ -372,6 +374,7 @@ void DAC1064_global_init(WPMINFO2) { ...@@ -372,6 +374,7 @@ void DAC1064_global_init(WPMINFO2) {
hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
#ifdef CONFIG_FB_MATROX_G450
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */ hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */
hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */ hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */
...@@ -420,7 +423,9 @@ void DAC1064_global_init(WPMINFO2) { ...@@ -420,7 +423,9 @@ void DAC1064_global_init(WPMINFO2) {
} }
/* Now set timming related variables... */ /* Now set timming related variables... */
g450_set_plls(PMINFO2); g450_set_plls(PMINFO2);
} else { } else
#endif
{
if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) { if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
...@@ -621,6 +626,7 @@ static struct matrox_altout m1064 = { ...@@ -621,6 +626,7 @@ static struct matrox_altout m1064 = {
.compute = m1064_compute, .compute = m1064_compute,
}; };
#ifdef CONFIG_FB_MATROX_G450
static int g450_compute(void* out, struct my_timming* m) { static int g450_compute(void* out, struct my_timming* m) {
#define minfo ((struct matrox_fb_info*)out) #define minfo ((struct matrox_fb_info*)out)
if (m->mnp < 0) { if (m->mnp < 0) {
...@@ -637,6 +643,7 @@ static struct matrox_altout g450out = { ...@@ -637,6 +643,7 @@ static struct matrox_altout g450out = {
.name = "Primary output", .name = "Primary output",
.compute = g450_compute, .compute = g450_compute,
}; };
#endif
#endif /* NEED_DAC1064 */ #endif /* NEED_DAC1064 */
...@@ -819,6 +826,7 @@ static void MGA1064_reset(WPMINFO2) { ...@@ -819,6 +826,7 @@ static void MGA1064_reset(WPMINFO2) {
#endif #endif
#ifdef CONFIG_FB_MATROX_G100 #ifdef CONFIG_FB_MATROX_G100
#ifdef CONFIG_FB_MATROX_G450
static void g450_mclk_init(WPMINFO2) { static void g450_mclk_init(WPMINFO2) {
/* switch all clocks to PCI source */ /* switch all clocks to PCI source */
pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4); pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
...@@ -936,6 +944,10 @@ static void g450_preinit(WPMINFO2) { ...@@ -936,6 +944,10 @@ static void g450_preinit(WPMINFO2) {
return; return;
} }
#else
static inline void g450_preinit(WPMINFO2) {
}
#endif
static int MGAG100_preinit(WPMINFO2) { static int MGAG100_preinit(WPMINFO2) {
static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960, static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
...@@ -973,9 +985,12 @@ static int MGAG100_preinit(WPMINFO2) { ...@@ -973,9 +985,12 @@ static int MGAG100_preinit(WPMINFO2) {
ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
? ACCESS_FBINFO(devflags.sgram) : 1; ? ACCESS_FBINFO(devflags.sgram) : 1;
#ifdef CONFIG_FB_MATROX_G450
if (ACCESS_FBINFO(devflags.g450dac)) { if (ACCESS_FBINFO(devflags.g450dac)) {
ACCESS_FBINFO(outputs[0]).output = &g450out; ACCESS_FBINFO(outputs[0]).output = &g450out;
} else { } else
#endif
{
ACCESS_FBINFO(outputs[0]).output = &m1064; ACCESS_FBINFO(outputs[0]).output = &m1064;
} }
ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1; ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
......
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
#endif #endif
#endif #endif
#if defined(__alpha__) || defined(__m68k__) #if defined(__alpha__) || defined(__mc68000__)
#define READx_WORKS #define READx_WORKS
#define MEMCPYTOIO_WORKS #define MEMCPYTOIO_WORKS
#else #else
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
#endif #endif
#endif #endif
#if defined(__m68k__) #if defined(__mc68000__)
#define MAP_BUSTOVIRT #define MAP_BUSTOVIRT
#else #else
#define MAP_IOREMAP #define MAP_IOREMAP
......
...@@ -2830,6 +2830,86 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot) ...@@ -2830,6 +2830,86 @@ void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
return; return;
} }
/*
* add_missing_indices()
*
* function: Fix dtree page in which one or more entries has an invalid index.
* fsck.jfs should really fix this, but it currently does not.
* Called from jfs_readdir when bad index is detected.
*/
static void add_missing_indices(struct inode *inode, s64 bn)
{
struct ldtentry *d;
struct dt_lock *dtlck;
int i;
uint index;
struct lv *lv;
struct metapage *mp;
dtpage_t *p;
int rc;
s8 *stbl;
tid_t tid;
struct tlock *tlck;
tid = txBegin(inode->i_sb, 0);
DT_GETPAGE(inode, bn, mp, PSIZE, p, rc);
if (rc) {
printk(KERN_ERR "DT_GETPAGE failed!\n");
goto end;
}
BT_MARK_DIRTY(mp, inode);
ASSERT(p->header.flag & BT_LEAF);
tlck = txLock(tid, inode, mp, tlckDTREE | tlckENTRY);
dtlck = (struct dt_lock *) &tlck->lock;
stbl = DT_GETSTBL(p);
for (i = 0; i < p->header.nextindex; i++) {
d = (struct ldtentry *) &p->slot[stbl[i]];
index = le32_to_cpu(d->index);
if ((index < 2) || (index >= JFS_IP(inode)->next_index)) {
d->index = cpu_to_le32(add_index(tid, inode, bn, i));
if (dtlck->index >= dtlck->maxcnt)
dtlck = (struct dt_lock *) txLinelock(dtlck);
lv = dtlck->lv;
lv->offset = stbl[i];
lv->length = 1;
dtlck->index++;
}
}
DT_PUTPAGE(mp);
(void) txCommit(tid, 1, &inode, 0);
end:
txEnd(tid);
}
/*
* Buffer to hold directory entry info while traversing a dtree page
* before being fed to the filldir function
*/
struct jfs_dirent {
loff_t position;
int ino;
u16 name_len;
char name[0];
};
/*
* function to determine next variable-sized jfs_dirent in buffer
*/
inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
{
return (struct jfs_dirent *)
((char *)dirent +
((sizeof (struct jfs_dirent) + dirent->name_len + 1 +
sizeof (loff_t) - 1) &
~(sizeof (loff_t) - 1)));
}
/* /*
* jfs_readdir() * jfs_readdir()
* *
...@@ -2846,11 +2926,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2846,11 +2926,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct inode *ip = filp->f_dentry->d_inode; struct inode *ip = filp->f_dentry->d_inode;
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab; struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
int rc = 0; int rc = 0;
loff_t dtpos; /* legacy OS/2 style position */
struct dtoffset { struct dtoffset {
s16 pn; s16 pn;
s16 index; s16 index;
s32 unused; s32 unused;
} *dtoffset = (struct dtoffset *) &filp->f_pos; } *dtoffset = (struct dtoffset *) &dtpos;
s64 bn; s64 bn;
struct metapage *mp; struct metapage *mp;
dtpage_t *p; dtpage_t *p;
...@@ -2860,12 +2941,17 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2860,12 +2941,17 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
int i, next; int i, next;
struct ldtentry *d; struct ldtentry *d;
struct dtslot *t; struct dtslot *t;
int d_namleft, d_namlen, len, outlen; int d_namleft, len, outlen;
char *d_name, *name_ptr; unsigned long dirent_buf;
char *name_ptr;
int dtlhdrdatalen; int dtlhdrdatalen;
u32 dir_index; u32 dir_index;
int do_index = 0; int do_index = 0;
uint loop_count = 0; uint loop_count = 0;
struct jfs_dirent *jfs_dirent;
int jfs_dirents;
int overflow, fix_page, page_fixed = 0;
static int unique_pos = 2; /* If we can't fix broken index */
if (filp->f_pos == DIREND) if (filp->f_pos == DIREND)
return 0; return 0;
...@@ -2885,7 +2971,9 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2885,7 +2971,9 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (dir_index > 1) { if (dir_index > 1) {
struct dir_table_slot dirtab_slot; struct dir_table_slot dirtab_slot;
if (dtEmpty(ip)) { if (dtEmpty(ip) ||
(dir_index >= JFS_IP(ip)->next_index)) {
/* Stale position. Directory has shrunk */
filp->f_pos = DIREND; filp->f_pos = DIREND;
return 0; return 0;
} }
...@@ -2963,13 +3051,15 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2963,13 +3051,15 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
*/ */
dtlhdrdatalen = DTLHDRDATALEN_LEGACY; dtlhdrdatalen = DTLHDRDATALEN_LEGACY;
if (filp->f_pos == 0) { dtpos = filp->f_pos;
if (dtpos == 0) {
/* build "." entry */ /* build "." entry */
if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino, if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
DT_DIR)) DT_DIR))
return 0; return 0;
dtoffset->index = 1; dtoffset->index = 1;
filp->f_pos = dtpos;
} }
if (dtoffset->pn == 0) { if (dtoffset->pn == 0) {
...@@ -2985,6 +3075,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -2985,6 +3075,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
dtoffset->pn = 1; dtoffset->pn = 1;
dtoffset->index = 0; dtoffset->index = 0;
filp->f_pos = dtpos;
} }
if (dtEmpty(ip)) { if (dtEmpty(ip)) {
...@@ -3009,32 +3100,72 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -3009,32 +3100,72 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
} }
d_name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS); dirent_buf = __get_free_page(GFP_KERNEL);
if (d_name == NULL) { if (dirent_buf == 0) {
DT_PUTPAGE(mp); DT_PUTPAGE(mp);
jERROR(1, ("jfs_readdir: kmalloc failed!\n")); jERROR(1, ("jfs_readdir: __get_free_page failed!\n"));
filp->f_pos = DIREND; filp->f_pos = DIREND;
return 0; return -ENOMEM;
} }
while (1) { while (1) {
jfs_dirent = (struct jfs_dirent *) dirent_buf;
jfs_dirents = 0;
overflow = fix_page = 0;
stbl = DT_GETSTBL(p); stbl = DT_GETSTBL(p);
for (i = index; i < p->header.nextindex; i++) { for (i = index; i < p->header.nextindex; i++) {
d = (struct ldtentry *) & p->slot[stbl[i]]; d = (struct ldtentry *) & p->slot[stbl[i]];
if (((long) jfs_dirent + d->namlen + 1) >
(dirent_buf + PSIZE)) {
/* DBCS codepages could overrun dirent_buf */
index = i;
overflow = 1;
break;
}
d_namleft = d->namlen; d_namleft = d->namlen;
name_ptr = d_name; name_ptr = jfs_dirent->name;
jfs_dirent->ino = le32_to_cpu(d->inumber);
if (do_index) { if (do_index) {
filp->f_pos = le32_to_cpu(d->index);
len = min(d_namleft, DTLHDRDATALEN); len = min(d_namleft, DTLHDRDATALEN);
} else jfs_dirent->position = le32_to_cpu(d->index);
/*
* d->index should always be valid, but it
* isn't. fsck.jfs doesn't create the
* directory index for the lost+found
* directory. Rather than let it go,
* we can try to fix it.
*/
if ((jfs_dirent->position < 2) ||
(jfs_dirent->position >=
JFS_IP(ip)->next_index)) {
if (!page_fixed && !isReadOnly(ip)) {
fix_page = 1;
/*
* setting overflow and setting
* index to i will cause the
* same page to be processed
* again starting here
*/
overflow = 1;
index = i;
break;
}
jfs_dirent->position = unique_pos++;
}
} else {
jfs_dirent->position = dtpos;
len = min(d_namleft, DTLHDRDATALEN_LEGACY); len = min(d_namleft, DTLHDRDATALEN_LEGACY);
}
/* copy the name of head/only segment */ /* copy the name of head/only segment */
outlen = jfs_strfromUCS_le(name_ptr, d->name, len, outlen = jfs_strfromUCS_le(name_ptr, d->name, len,
codepage); codepage);
d_namlen = outlen; jfs_dirent->name_len = outlen;
/* copy name in the additional segment(s) */ /* copy name in the additional segment(s) */
next = d->next; next = d->next;
...@@ -3053,56 +3184,66 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -3053,56 +3184,66 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
len = min(d_namleft, DTSLOTDATALEN); len = min(d_namleft, DTSLOTDATALEN);
outlen = jfs_strfromUCS_le(name_ptr, t->name, outlen = jfs_strfromUCS_le(name_ptr, t->name,
len, codepage); len, codepage);
d_namlen+= outlen; jfs_dirent->name_len += outlen;
next = t->next; next = t->next;
} }
if (filldir(dirent, d_name, d_namlen, filp->f_pos, jfs_dirents++;
le32_to_cpu(d->inumber), DT_UNKNOWN)) jfs_dirent = next_jfs_dirent(jfs_dirent);
goto out;
skip_one: skip_one:
if (!do_index) if (!do_index)
dtoffset->index++; dtoffset->index++;
} }
/* if (!overflow) {
* get next leaf page /* Point to next leaf page */
*/ if (p->header.flag & BT_ROOT)
bn = 0;
else {
bn = le64_to_cpu(p->header.next);
index = 0;
/* update offset (pn:index) for new page */
if (!do_index) {
dtoffset->pn++;
dtoffset->index = 0;
}
}
page_fixed = 0;
}
if (p->header.flag & BT_ROOT) { /* unpin previous leaf page */
filp->f_pos = DIREND; DT_PUTPAGE(mp);
break;
jfs_dirent = (struct jfs_dirent *) dirent_buf;
while (jfs_dirents--) {
filp->f_pos = jfs_dirent->position;
if (filldir(dirent, jfs_dirent->name,
jfs_dirent->name_len, filp->f_pos,
jfs_dirent->ino, DT_UNKNOWN))
goto out;
jfs_dirent = next_jfs_dirent(jfs_dirent);
} }
bn = le64_to_cpu(p->header.next); if (fix_page) {
if (bn == 0) { add_missing_indices(ip, bn);
page_fixed = 1;
}
if (!overflow && (bn == 0)) {
filp->f_pos = DIREND; filp->f_pos = DIREND;
break; break;
} }
/* unpin previous leaf page */
DT_PUTPAGE(mp);
/* get next leaf page */
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
if (rc) { if (rc) {
kfree(d_name); free_page(dirent_buf);
return -rc; return -rc;
} }
/* update offset (pn:index) for new page */
index = 0;
if (!do_index) {
dtoffset->pn++;
dtoffset->index = 0;
}
} }
out: out:
kfree(d_name); free_page(dirent_buf);
DT_PUTPAGE(mp);
return rc; return rc;
} }
......
...@@ -365,11 +365,7 @@ int diRead(struct inode *ip) ...@@ -365,11 +365,7 @@ int diRead(struct inode *ip)
if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) || if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) ||
(addressPXD(&iagp->inoext[extno]) == 0)) { (addressPXD(&iagp->inoext[extno]) == 0)) {
jERROR(1, ("diRead: Bad inoext: 0x%lx, 0x%lx\n",
(ulong) addressPXD(&iagp->inoext[extno]),
(ulong) lengthPXD(&iagp->inoext[extno])));
release_metapage(mp); release_metapage(mp);
updateSuper(ip->i_sb, FM_DIRTY);
return ESTALE; return ESTALE;
} }
...@@ -416,12 +412,9 @@ int diRead(struct inode *ip) ...@@ -416,12 +412,9 @@ int diRead(struct inode *ip)
jERROR(1, ("diRead: i_ino != di_number\n")); jERROR(1, ("diRead: i_ino != di_number\n"));
updateSuper(ip->i_sb, FM_DIRTY); updateSuper(ip->i_sb, FM_DIRTY);
rc = EIO; rc = EIO;
} else if (le32_to_cpu(dp->di_nlink) == 0) { } else if (le32_to_cpu(dp->di_nlink) == 0)
jERROR(1,
("diRead: di_nlink is zero. ino=%ld\n", ip->i_ino));
updateSuper(ip->i_sb, FM_DIRTY);
rc = ESTALE; rc = ESTALE;
} else else
/* copy the disk inode to the in-memory inode */ /* copy the disk inode to the in-memory inode */
rc = copy_from_dinode(dp, ip); rc = copy_from_dinode(dp, ip);
......
...@@ -1552,7 +1552,12 @@ static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate) ...@@ -1552,7 +1552,12 @@ static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate)
memcpy(logsuper->active[i].uuid, NULL_UUID, 16); memcpy(logsuper->active[i].uuid, NULL_UUID, 16);
break; break;
} }
assert(i < MAX_ACTIVE); if (i == MAX_ACTIVE) {
jERROR(1,("Somebody stomped on the journal!\n"));
lbmFree(bpsuper);
return EIO;
}
} }
/* /*
......
...@@ -1459,10 +1459,8 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l) ...@@ -1459,10 +1459,8 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l)
break; break;
} }
out: out:
if (error) { locks_free_lock(file_lock);
locks_free_lock(file_lock);
}
return error; return error;
} }
...@@ -1601,11 +1599,8 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l) ...@@ -1601,11 +1599,8 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l)
break; break;
} }
out: out:
if (error) { locks_free_lock(file_lock);
locks_free_lock(file_lock);
}
return error; return error;
} }
#endif /* BITS_PER_LONG == 32 */ #endif /* BITS_PER_LONG == 32 */
......
...@@ -228,6 +228,26 @@ enum acpi_interrupt_id { ...@@ -228,6 +228,26 @@ enum acpi_interrupt_id {
ACPI_INTERRUPT_COUNT ACPI_INTERRUPT_COUNT
}; };
#define ACPI_SPACE_MEM 0
struct acpi_gen_regaddr {
u8 space_id;
u8 bit_width;
u8 bit_offset;
u8 resv;
u32 addrl;
u32 addrh;
} __attribute__ ((packed));
struct acpi_table_hpet {
struct acpi_table_header header;
u32 id;
struct acpi_gen_regaddr addr;
u8 number;
u16 min_tick;
u8 page_protect;
} __attribute__ ((packed));
/* /*
* System Resource Affinity Table (SRAT) * System Resource Affinity Table (SRAT)
* see http://www.microsoft.com/hwdev/design/srat.htm * see http://www.microsoft.com/hwdev/design/srat.htm
...@@ -333,6 +353,7 @@ enum acpi_table_id { ...@@ -333,6 +353,7 @@ enum acpi_table_id {
ACPI_SRAT, ACPI_SRAT,
ACPI_SSDT, ACPI_SSDT,
ACPI_SPMI, ACPI_SPMI,
ACPI_HPET,
ACPI_TABLE_COUNT ACPI_TABLE_COUNT
}; };
......
...@@ -66,6 +66,7 @@ enum chipset_type { ...@@ -66,6 +66,7 @@ enum chipset_type {
AMD_IRONGATE, AMD_IRONGATE,
AMD_761, AMD_761,
AMD_762, AMD_762,
AMD_8151,
ALI_M1541, ALI_M1541,
ALI_M1621, ALI_M1621,
ALI_M1631, ALI_M1631,
...@@ -161,7 +162,7 @@ extern agp_memory *agp_allocate_memory(size_t, u32); ...@@ -161,7 +162,7 @@ extern agp_memory *agp_allocate_memory(size_t, u32);
* *
*/ */
extern void agp_copy_info(agp_kern_info *); extern int agp_copy_info(agp_kern_info *);
/* /*
* agp_copy_info : * agp_copy_info :
...@@ -257,7 +258,7 @@ typedef struct { ...@@ -257,7 +258,7 @@ typedef struct {
void (*enable)(u32); void (*enable)(u32);
int (*acquire)(void); int (*acquire)(void);
void (*release)(void); void (*release)(void);
void (*copy_info)(agp_kern_info *); int (*copy_info)(agp_kern_info *);
} drm_agp_t; } drm_agp_t;
extern const drm_agp_t *drm_agp_p; extern const drm_agp_t *drm_agp_p;
......
...@@ -67,6 +67,8 @@ struct bus_type { ...@@ -67,6 +67,8 @@ struct bus_type {
int (*match)(struct device * dev, struct device_driver * drv); int (*match)(struct device * dev, struct device_driver * drv);
struct device * (*add) (struct device * parent, char * bus_id); struct device * (*add) (struct device * parent, char * bus_id);
int (*hotplug) (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
}; };
......
#ifndef _LINUX_ELEVATOR_H #ifndef _LINUX_ELEVATOR_H
#define _LINUX_ELEVATOR_H #define _LINUX_ELEVATOR_H
typedef int (elevator_merge_fn) (request_queue_t *, struct request **, typedef int (elevator_merge_fn) (request_queue_t *, struct list_head **,
struct bio *); struct bio *);
typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *); typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
...@@ -42,7 +42,7 @@ struct elevator_s ...@@ -42,7 +42,7 @@ struct elevator_s
*/ */
extern void __elv_add_request(request_queue_t *, struct request *, extern void __elv_add_request(request_queue_t *, struct request *,
struct list_head *); struct list_head *);
extern int elv_merge(request_queue_t *, struct request **, struct bio *); extern int elv_merge(request_queue_t *, struct list_head **, struct bio *);
extern void elv_merge_requests(request_queue_t *, struct request *, extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *); struct request *);
extern void elv_merged_request(request_queue_t *, struct request *); extern void elv_merged_request(request_queue_t *, struct request *);
...@@ -78,7 +78,7 @@ extern void elevator_exit(request_queue_t *, elevator_t *); ...@@ -78,7 +78,7 @@ extern void elevator_exit(request_queue_t *, elevator_t *);
extern inline int bio_rq_in_between(struct bio *, struct request *, struct list_head *); extern inline int bio_rq_in_between(struct bio *, struct request *, struct list_head *);
extern inline int elv_rq_merge_ok(struct request *, struct bio *); extern inline int elv_rq_merge_ok(struct request *, struct bio *);
extern inline int elv_try_merge(struct request *, struct bio *); extern inline int elv_try_merge(struct request *, struct bio *);
extern inline int elv_try_last_merge(request_queue_t *, struct request **, struct bio *); extern inline int elv_try_last_merge(request_queue_t *, struct bio *);
/* /*
* Return values from elevator merger * Return values from elevator merger
......
...@@ -75,7 +75,7 @@ typedef __s64 Elf64_Sxword; ...@@ -75,7 +75,7 @@ typedef __s64 Elf64_Sxword;
#define EM_IA_64 50 /* HP/Intel IA-64 */ #define EM_IA_64 50 /* HP/Intel IA-64 */
#define EM_X8664 62 /* AMD x86-64 */ #define EM_X86_64 62 /* AMD x86-64 */
#define EM_S390 22 /* IBM S/390 */ #define EM_S390 22 /* IBM S/390 */
......
...@@ -6,6 +6,6 @@ ...@@ -6,6 +6,6 @@
#define FUTEX_WAKE (1) #define FUTEX_WAKE (1)
#define FUTEX_FD (2) #define FUTEX_FD (2)
extern asmlinkage int sys_futex(void *uaddr, int op, int val, struct timespec *utime); extern asmlinkage int sys_futex(unsigned long uaddr, int op, int val, struct timespec *utime);
#endif #endif
...@@ -374,6 +374,7 @@ extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsi ...@@ -374,6 +374,7 @@ extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsi
extern int make_pages_present(unsigned long addr, unsigned long end); extern int make_pages_present(unsigned long addr, unsigned long end);
extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
extern struct page * follow_page(struct mm_struct *mm, unsigned long address, int write);
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
......
...@@ -398,6 +398,7 @@ ...@@ -398,6 +398,7 @@
#define PCI_DEVICE_ID_AMD_8111_LAN 0x7462 #define PCI_DEVICE_ID_AMD_8111_LAN 0x7462
#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469 #define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
#define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d #define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d
#define PCI_DEVICE_ID_AMD_8151_0 0x7454
#define PCI_VENDOR_ID_TRIDENT 0x1023 #define PCI_VENDOR_ID_TRIDENT 0x1023
#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
......
/*
* virtual => physical mapping cache support.
*/
#ifndef _LINUX_VCACHE_H
#define _LINUX_VCACHE_H
typedef struct vcache_s {
unsigned long address;
struct mm_struct *mm;
struct list_head hash_entry;
void (*callback)(struct vcache_s *data, struct page *new_page);
} vcache_t;
extern spinlock_t vcache_lock;
extern void __attach_vcache(vcache_t *vcache,
unsigned long address,
struct mm_struct *mm,
void (*callback)(struct vcache_s *data, struct page *new_page));
extern void detach_vcache(vcache_t *vcache);
extern void invalidate_vcache(unsigned long address, struct mm_struct *mm,
struct page *new_page);
#endif
...@@ -127,7 +127,7 @@ struct irda_class_desc { ...@@ -127,7 +127,7 @@ struct irda_class_desc {
struct irda_usb_cb { struct irda_usb_cb {
struct irda_class_desc *irda_desc; struct irda_class_desc *irda_desc;
struct usb_device *usbdev; /* init: probe_irda */ struct usb_device *usbdev; /* init: probe_irda */
unsigned int ifnum; /* Interface number of the USB dev. */ struct usb_interface *usbintf; /* init: probe_irda */
int netopen; /* Device is active for network */ int netopen; /* Device is active for network */
int present; /* Device is present on the bus */ int present; /* Device is present on the bus */
__u32 capability; /* Capability of the hardware */ __u32 capability; /* Capability of the hardware */
......
...@@ -381,7 +381,7 @@ void mm_release(void) ...@@ -381,7 +381,7 @@ void mm_release(void)
* not set up a proper pointer then tough luck. * not set up a proper pointer then tough luck.
*/ */
put_user(0, tsk->user_tid); put_user(0, tsk->user_tid);
sys_futex(tsk->user_tid, FUTEX_WAKE, 1, NULL); sys_futex((unsigned long)tsk->user_tid, FUTEX_WAKE, 1, NULL);
} }
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/futex.h> #include <linux/futex.h>
#include <linux/vcache.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
...@@ -38,7 +39,6 @@ ...@@ -38,7 +39,6 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/dcache.h> #include <linux/dcache.h>
#include <asm/uaccess.h>
/* Simple "sleep if unchanged" interface. */ /* Simple "sleep if unchanged" interface. */
...@@ -55,9 +55,14 @@ static struct vfsmount *futex_mnt; ...@@ -55,9 +55,14 @@ static struct vfsmount *futex_mnt;
struct futex_q { struct futex_q {
struct list_head list; struct list_head list;
wait_queue_head_t waiters; wait_queue_head_t waiters;
/* Page struct and offset within it. */ /* Page struct and offset within it. */
struct page *page; struct page *page;
unsigned int offset; unsigned int offset;
/* the virtual => physical cache */
vcache_t vcache;
/* For fd, sigio sent using these. */ /* For fd, sigio sent using these. */
int fd; int fd;
struct file *filp; struct file *filp;
...@@ -85,21 +90,43 @@ static inline void tell_waiter(struct futex_q *q) ...@@ -85,21 +90,43 @@ static inline void tell_waiter(struct futex_q *q)
send_sigio(&q->filp->f_owner, q->fd, POLL_IN); send_sigio(&q->filp->f_owner, q->fd, POLL_IN);
} }
/* Get kernel address of the user page and pin it. */
static struct page *pin_page(unsigned long page_start)
{
struct mm_struct *mm = current->mm;
struct page *page = NULL;
int err;
down_read(&mm->mmap_sem);
err = get_user_pages(current, mm, page_start,
1 /* one page */,
0 /* not writable */,
0 /* don't force */,
&page,
NULL /* don't return vmas */);
up_read(&mm->mmap_sem);
if (err < 0)
return ERR_PTR(err);
return page;
}
static inline void unpin_page(struct page *page) static inline void unpin_page(struct page *page)
{ {
/* Avoid releasing the page which is on the LRU list. I don't
know if this is correct, but it stops the BUG() in
__free_pages_ok(). */
page_cache_release(page); page_cache_release(page);
} }
static int futex_wake(struct list_head *head, static int futex_wake(unsigned long uaddr, unsigned int offset, int num)
struct page *page,
unsigned int offset,
int num)
{ {
struct list_head *i, *next; struct list_head *i, *next, *head;
int num_woken = 0; struct page *page;
int ret;
page = pin_page(uaddr - offset);
ret = IS_ERR(page);
if (ret)
goto out;
head = hash_futex(page, offset);
spin_lock(&futex_lock); spin_lock(&futex_lock);
list_for_each_safe(i, next, head) { list_for_each_safe(i, next, head) {
...@@ -108,36 +135,81 @@ static int futex_wake(struct list_head *head, ...@@ -108,36 +135,81 @@ static int futex_wake(struct list_head *head,
if (this->page == page && this->offset == offset) { if (this->page == page && this->offset == offset) {
list_del_init(i); list_del_init(i);
tell_waiter(this); tell_waiter(this);
num_woken++; ret++;
if (num_woken >= num) break; if (ret >= num)
break;
} }
} }
spin_unlock(&futex_lock); spin_unlock(&futex_lock);
return num_woken; unpin_page(page);
out:
return ret;
}
static void futex_vcache_callback(vcache_t *vcache, struct page *new_page)
{
struct futex_q *q = container_of(vcache, struct futex_q, vcache);
struct list_head *head = hash_futex(new_page, q->offset);
BUG_ON(list_empty(&q->list));
spin_lock(&futex_lock);
q->page = new_page;
list_del_init(&q->list);
list_add_tail(&q->list, head);
spin_unlock(&futex_lock);
} }
/* Add at end to avoid starvation */ /* Add at end to avoid starvation */
static inline void queue_me(struct list_head *head, static inline int queue_me(struct list_head *head,
struct futex_q *q, struct futex_q *q,
struct page *page, struct page *page,
unsigned int offset, unsigned int offset,
int fd, int fd,
struct file *filp) struct file *filp,
unsigned long uaddr)
{ {
q->page = page; struct page *tmp;
int ret = 0;
q->offset = offset; q->offset = offset;
q->fd = fd; q->fd = fd;
q->filp = filp; q->filp = filp;
spin_lock(&vcache_lock);
spin_lock(&futex_lock); spin_lock(&futex_lock);
list_add_tail(&q->list, head); spin_lock(&current->mm->page_table_lock);
/*
* Has the mapping changed meanwhile?
*/
tmp = follow_page(current->mm, uaddr, 0);
if (tmp == page) {
q->page = page;
list_add_tail(&q->list, head);
/*
* We register a futex callback to this virtual address,
* to make sure a COW properly rehashes the futex-queue.
*/
__attach_vcache(&q->vcache, uaddr, current->mm, futex_vcache_callback);
} else
ret = 1;
spin_unlock(&current->mm->page_table_lock);
spin_unlock(&futex_lock); spin_unlock(&futex_lock);
spin_unlock(&vcache_lock);
return ret;
} }
/* Return 1 if we were still queued (ie. 0 means we were woken) */ /* Return 1 if we were still queued (ie. 0 means we were woken) */
static inline int unqueue_me(struct futex_q *q) static inline int unqueue_me(struct futex_q *q)
{ {
int ret = 0; int ret = 0;
spin_lock(&futex_lock); spin_lock(&futex_lock);
if (!list_empty(&q->list)) { if (!list_empty(&q->list)) {
list_del(&q->list); list_del(&q->list);
...@@ -147,46 +219,34 @@ static inline int unqueue_me(struct futex_q *q) ...@@ -147,46 +219,34 @@ static inline int unqueue_me(struct futex_q *q)
return ret; return ret;
} }
/* Get kernel address of the user page and pin it. */ static int futex_wait(unsigned long uaddr,
static struct page *pin_page(unsigned long page_start)
{
struct mm_struct *mm = current->mm;
struct page *page;
int err;
down_read(&mm->mmap_sem);
err = get_user_pages(current, mm, page_start,
1 /* one page */,
0 /* writable not important */,
0 /* don't force */,
&page,
NULL /* don't return vmas */);
up_read(&mm->mmap_sem);
if (err < 0)
return ERR_PTR(err);
return page;
}
static int futex_wait(struct list_head *head,
struct page *page,
int offset, int offset,
int val, int val,
int *uaddr,
unsigned long time) unsigned long time)
{ {
int curval;
struct futex_q q;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int ret = 0; struct list_head *head;
int ret = 0, curval;
struct page *page;
struct futex_q q;
repeat_lookup:
page = pin_page(uaddr - offset);
ret = IS_ERR(page);
if (ret)
goto out;
head = hash_futex(page, offset);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
init_waitqueue_head(&q.waiters); init_waitqueue_head(&q.waiters);
add_wait_queue(&q.waiters, &wait); add_wait_queue(&q.waiters, &wait);
queue_me(head, &q, page, offset, -1, NULL); if (queue_me(head, &q, page, offset, -1, NULL, uaddr)) {
unpin_page(page);
goto repeat_lookup;
}
/* Page is pinned, but may no longer be in this address space. */ /* Page is pinned, but may no longer be in this address space. */
if (get_user(curval, uaddr) != 0) { if (get_user(curval, (int *)uaddr) != 0) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
} }
...@@ -204,11 +264,15 @@ static int futex_wait(struct list_head *head, ...@@ -204,11 +264,15 @@ static int futex_wait(struct list_head *head,
ret = -EINTR; ret = -EINTR;
goto out; goto out;
} }
out: out:
detach_vcache(&q.vcache);
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
/* Were we woken up anyway? */ /* Were we woken up anyway? */
if (!unqueue_me(&q)) if (!unqueue_me(&q))
return 0; ret = 0;
if (page)
unpin_page(page);
return ret; return ret;
} }
...@@ -251,25 +315,26 @@ static struct file_operations futex_fops = { ...@@ -251,25 +315,26 @@ static struct file_operations futex_fops = {
/* Signal allows caller to avoid the race which would occur if they /* Signal allows caller to avoid the race which would occur if they
set the sigio stuff up afterwards. */ set the sigio stuff up afterwards. */
static int futex_fd(struct list_head *head, static int futex_fd(unsigned long uaddr, int offset, int signal)
struct page *page,
int offset,
int signal)
{ {
int fd; struct page *page = NULL;
struct list_head *head;
struct futex_q *q; struct futex_q *q;
struct file *filp; struct file *filp;
int ret;
ret = -EINVAL;
if (signal < 0 || signal > _NSIG) if (signal < 0 || signal > _NSIG)
return -EINVAL; goto out;
fd = get_unused_fd(); ret = get_unused_fd();
if (fd < 0) if (ret < 0)
return fd; goto out;
filp = get_empty_filp(); filp = get_empty_filp();
if (!filp) { if (!filp) {
put_unused_fd(fd); put_unused_fd(ret);
return -ENFILE; ret = -ENFILE;
goto out;
} }
filp->f_op = &futex_fops; filp->f_op = &futex_fops;
filp->f_vfsmnt = mntget(futex_mnt); filp->f_vfsmnt = mntget(futex_mnt);
...@@ -280,37 +345,55 @@ static int futex_fd(struct list_head *head, ...@@ -280,37 +345,55 @@ static int futex_fd(struct list_head *head,
ret = f_setown(filp, current->tgid, 1); ret = f_setown(filp, current->tgid, 1);
if (ret) { if (ret) {
put_unused_fd(fd); put_unused_fd(ret);
put_filp(filp); put_filp(filp);
return ret; goto out;
} }
filp->f_owner.signum = signal; filp->f_owner.signum = signal;
} }
q = kmalloc(sizeof(*q), GFP_KERNEL); q = kmalloc(sizeof(*q), GFP_KERNEL);
if (!q) { if (!q) {
put_unused_fd(fd); put_unused_fd(ret);
put_filp(filp);
ret = -ENOMEM;
goto out;
}
repeat_lookup:
page = pin_page(uaddr - offset);
ret = IS_ERR(page);
if (ret) {
put_unused_fd(ret);
put_filp(filp); put_filp(filp);
return -ENOMEM; kfree(q);
page = NULL;
goto out;
} }
head = hash_futex(page, offset);
/* Initialize queue structure, and add to hash table. */ /* Initialize queue structure, and add to hash table. */
filp->private_data = q; filp->private_data = q;
init_waitqueue_head(&q->waiters); init_waitqueue_head(&q->waiters);
queue_me(head, q, page, offset, fd, filp); if (queue_me(head, q, page, offset, ret, filp, uaddr)) {
unpin_page(page);
goto repeat_lookup;
}
/* Now we map fd to filp, so userspace can access it */ /* Now we map fd to filp, so userspace can access it */
fd_install(fd, filp); fd_install(ret, filp);
return fd; page = NULL;
out:
if (page)
unpin_page(page);
return ret;
} }
asmlinkage int sys_futex(void *uaddr, int op, int val, struct timespec *utime) asmlinkage int sys_futex(unsigned long uaddr, int op, int val, struct timespec *utime)
{ {
int ret;
unsigned long pos_in_page;
struct list_head *head;
struct page *page;
unsigned long time = MAX_SCHEDULE_TIMEOUT; unsigned long time = MAX_SCHEDULE_TIMEOUT;
unsigned long pos_in_page;
int ret;
if (utime) { if (utime) {
struct timespec t; struct timespec t;
...@@ -319,38 +402,27 @@ asmlinkage int sys_futex(void *uaddr, int op, int val, struct timespec *utime) ...@@ -319,38 +402,27 @@ asmlinkage int sys_futex(void *uaddr, int op, int val, struct timespec *utime)
time = timespec_to_jiffies(&t) + 1; time = timespec_to_jiffies(&t) + 1;
} }
pos_in_page = ((unsigned long)uaddr) % PAGE_SIZE; pos_in_page = uaddr % PAGE_SIZE;
/* Must be "naturally" aligned, and not on page boundary. */ /* Must be "naturally" aligned, and not on page boundary. */
if ((pos_in_page % __alignof__(int)) != 0 if ((pos_in_page % __alignof__(int)) != 0
|| pos_in_page + sizeof(int) > PAGE_SIZE) || pos_in_page + sizeof(int) > PAGE_SIZE)
return -EINVAL; return -EINVAL;
/* Simpler if it doesn't vanish underneath us. */
page = pin_page((unsigned long)uaddr - pos_in_page);
if (IS_ERR(page))
return PTR_ERR(page);
head = hash_futex(page, pos_in_page);
switch (op) { switch (op) {
case FUTEX_WAIT: case FUTEX_WAIT:
ret = futex_wait(head, page, pos_in_page, val, uaddr, time); ret = futex_wait(uaddr, pos_in_page, val, time);
break; break;
case FUTEX_WAKE: case FUTEX_WAKE:
ret = futex_wake(head, page, pos_in_page, val); ret = futex_wake(uaddr, pos_in_page, val);
break; break;
case FUTEX_FD: case FUTEX_FD:
/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */ /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
ret = futex_fd(head, page, pos_in_page, val); ret = futex_fd(uaddr, pos_in_page, val);
if (ret >= 0)
/* Leave page pinned (attached to fd). */
return ret;
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
unpin_page(page);
return ret; return ret;
} }
......
...@@ -9,6 +9,6 @@ obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ ...@@ -9,6 +9,6 @@ obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \ page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \ shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \
pdflush.o page-writeback.o rmap.o madvise.o pdflush.o page-writeback.o rmap.o madvise.o vcache.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/iobuf.h> #include <linux/iobuf.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/vcache.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/rmap.h> #include <asm/rmap.h>
...@@ -463,7 +464,7 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned ...@@ -463,7 +464,7 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
* Do a quick page-table lookup for a single page. * Do a quick page-table lookup for a single page.
* mm->page_table_lock must be held. * mm->page_table_lock must be held.
*/ */
static inline struct page * struct page *
follow_page(struct mm_struct *mm, unsigned long address, int write) follow_page(struct mm_struct *mm, unsigned long address, int write)
{ {
pgd_t *pgd; pgd_t *pgd;
...@@ -494,7 +495,7 @@ follow_page(struct mm_struct *mm, unsigned long address, int write) ...@@ -494,7 +495,7 @@ follow_page(struct mm_struct *mm, unsigned long address, int write)
} }
out: out:
return 0; return NULL;
} }
/* /*
...@@ -973,6 +974,7 @@ static inline void establish_pte(struct vm_area_struct * vma, unsigned long addr ...@@ -973,6 +974,7 @@ static inline void establish_pte(struct vm_area_struct * vma, unsigned long addr
static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address, static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address,
pte_t *page_table) pte_t *page_table)
{ {
invalidate_vcache(address, vma->vm_mm, new_page);
flush_page_to_ram(new_page); flush_page_to_ram(new_page);
flush_cache_page(vma, address); flush_cache_page(vma, address);
establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
......
/*
* linux/mm/vcache.c
*
* virtual => physical page mapping cache. Users of this mechanism
* register callbacks for a given (virt,mm,phys) page mapping, and
* the kernel guarantees to call back when this mapping is invalidated.
* (ie. upon COW or unmap.)
*
* Started by Ingo Molnar, Copyright (C) 2002
*/
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/hash.h>
#include <linux/vcache.h>
#define VCACHE_HASHBITS 8
#define VCACHE_HASHSIZE (1 << VCACHE_HASHBITS)
spinlock_t vcache_lock = SPIN_LOCK_UNLOCKED;
static struct list_head hash[VCACHE_HASHSIZE];
static struct list_head *hash_vcache(unsigned long address,
struct mm_struct *mm)
{
return &hash[hash_long(address + (unsigned long)mm, VCACHE_HASHBITS)];
}
void __attach_vcache(vcache_t *vcache,
unsigned long address,
struct mm_struct *mm,
void (*callback)(struct vcache_s *data, struct page *new))
{
struct list_head *hash_head;
address &= PAGE_MASK;
vcache->address = address;
vcache->mm = mm;
vcache->callback = callback;
hash_head = hash_vcache(address, mm);
list_add(&vcache->hash_entry, hash_head);
}
void detach_vcache(vcache_t *vcache)
{
spin_lock(&vcache_lock);
list_del(&vcache->hash_entry);
spin_unlock(&vcache_lock);
}
void invalidate_vcache(unsigned long address, struct mm_struct *mm,
struct page *new_page)
{
struct list_head *l, *hash_head;
vcache_t *vcache;
address &= PAGE_MASK;
hash_head = hash_vcache(address, mm);
/*
* This is safe, because this path is called with the mm
* semaphore read-held, and the add/remove path calls with the
* mm semaphore write-held. So while other mm's might add new
* entries in parallel, and *this* mm is locked out, so if the
* list is empty now then we do not have to take the vcache
* lock to see it's really empty.
*/
if (likely(list_empty(hash_head)))
return;
spin_lock(&vcache_lock);
list_for_each(l, hash_head) {
vcache = list_entry(l, vcache_t, hash_entry);
if (vcache->address != address || vcache->mm != mm)
continue;
vcache->callback(vcache, new_page);
}
spin_unlock(&vcache_lock);
}
static int __init vcache_init(void)
{
unsigned int i;
for (i = 0; i < VCACHE_HASHSIZE; i++)
INIT_LIST_HEAD(hash + i);
return 0;
}
__initcall(vcache_init);
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