Commit 78ff69d0 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.4.0-test9

    - USB: ohci controller update, round-robin device numbering
    - ksymoops moved: document
    - sparc updates
    - sg.c: get rid of more #ifdef MODULE code
parent 33aa1817
Quick Summary
-------------
Install ksymoops from ftp://ftp.ocs.com.au/pub/ksymoops
Install ksymoops from
ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops
Read the ksymoops man page.
ksymoops < the_oops.txt
......
......@@ -44,7 +44,7 @@ typedef struct urb
// status after each completion
int status; // returned status
unsigned int transfer_flags; // ASAP, SP_OK, EARLY_COMPLETE
unsigned int transfer_flags; // ASAP, SP_OK, etc.
// for data stage (CTRL), BULK, INT and ISO
void *transfer_buffer; // associated data buffer
......@@ -105,10 +105,9 @@ For ASAP set USB_ISO_ASAP in transfer_flags.
If short packets should NOT be tolerated, set USB_DISABLE_SPD in
transfer_flags.
Usually, (to reduce restart time) the completion handler is called
AFTER the URB re-submission. You can get the other way by setting
USB_URB_EARLY_COMPLETE in transfer_flags. This is implicit for
INT transfers.
Usually, to reduce restart time, the completion handler is called
AFTER the URB re-submission. However, it is called BEFORE URB
re-submission for INT transfers that are being continued.
1.5. How to submit an URB?
......@@ -172,10 +171,12 @@ In the completion handler, you should have a look at urb->status to
detect any USB errors. Since the context parameter is included in the URB,
you can pass information to the completion handler.
Avoid using the urb->dev field in your completion handler; it's cleared
NOTE: ***** WARNING *****
AVOID using the urb->dev field in your completion handler; it's cleared
as part of URB unlinking. Instead, use urb->context to hold all the
data your driver needs.
NOTE: ***** WARNING *****
Also, NEVER SLEEP IN A COMPLETION HANDLER. These are normally called
during hardware interrupt processing. If you can, defer substantial
work to a tasklet (bottom half) to keep system latencies low. You'll
......
......@@ -270,7 +270,8 @@ IF SOMETHING GOES WRONG:
on making sense of the dump is in Documentation/oops-tracing.txt
- You can use the "ksymoops" program to make sense of the dump. This
utility can be downloaded from ftp://ftp.ocs.com.au/pub/ksymoops .
utility can be downloaded from
ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops.
Alternately you can do the dump lookup by hand:
- In debugging dumps like the above, it helps enormously if you can
......
/* $Id: pcic.c,v 1.17 2000/09/05 06:49:44 anton Exp $
/* $Id: pcic.c,v 1.18 2000/09/25 06:09:12 anton Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
......@@ -35,11 +35,6 @@
#ifndef CONFIG_PCI
int pcibios_present(void)
{
return 0;
}
asmlinkage int sys_pciconfig_read(unsigned long bus,
unsigned long dfn,
unsigned long off,
......@@ -976,7 +971,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
if(!suser())
return -EPERM;
lock_kernel();
switch(len) {
case 1:
err = get_user(ubyte, (unsigned char *)buf);
......@@ -1004,7 +998,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
break;
};
unlock_kernel();
return err;
}
......
/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:26 jj Exp $
/* $Id: piggyback.c,v 1.2 2000/09/19 14:34:39 anton Exp $
Simple utility to make a single-image install kernel with initial ramdisk
for Sparc64 tftpbooting without need to set up nfs.
......@@ -50,9 +50,9 @@ int main(int argc,char **argv)
map = fopen (argv[2], "r");
if (!map) die(argv[2]);
while (fgets (buffer, 1024, map)) {
if (!strcmp (buffer + 19, "start\n"))
if (!strcmp (buffer + 19, "_start\n"))
start = strtoul (buffer + 8, NULL, 16);
else if (!strcmp (buffer + 19, "end\n"))
else if (!strcmp (buffer + 19, "_end\n"))
end = strtoul (buffer + 8, NULL, 16);
}
fclose (map);
......
......@@ -18,6 +18,7 @@
#include <asm/sbus.h>
#include <asm/ebus.h>
#include <asm/fhc.h>
#include <asm/starfire.h>
/* Probe and map in the Auxiliary I/O register */
unsigned long auxio_register = 0;
......@@ -55,7 +56,7 @@ void __init auxio_probe(void)
return;
}
#endif
if(central_bus) {
if(central_bus || this_is_starfire) {
auxio_register = 0UL;
return;
}
......
/* $Id: central.c,v 1.13 1999/12/01 10:44:43 davem Exp $
/* $Id: central.c,v 1.14 2000/09/21 06:25:14 anton Exp $
* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
* Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
......@@ -15,6 +15,7 @@
#include <asm/page.h>
#include <asm/fhc.h>
#include <asm/starfire.h>
struct linux_central *central_bus = NULL;
struct linux_fhc *fhc_list = NULL;
......@@ -254,9 +255,8 @@ void central_probe(void)
cnode = prom_finddevice("/central");
if(cnode == 0 || cnode == -1) {
extern void starfire_check(void);
starfire_check();
if (this_is_starfire)
starfire_cpu_setup();
return;
}
......
/* $Id: irq.c,v 1.93 2000/08/31 10:00:39 anton Exp $
/* $Id: irq.c,v 1.94 2000/09/21 06:27:10 anton Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
......@@ -31,6 +31,7 @@
#include <asm/smp.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
#include <asm/starfire.h>
/* Internal flag, should not be visible elsewhere at all. */
#define SA_IMAP_MASKED 0x100
......@@ -123,7 +124,6 @@ int get_irq_list(char *buf)
/* Now these are always passed a true fully specified sun4u INO. */
void enable_irq(unsigned int irq)
{
extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(irq);
unsigned long imap;
unsigned long tid;
......@@ -139,9 +139,6 @@ void enable_irq(unsigned int irq)
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
} else {
extern unsigned int starfire_translate(unsigned long imap,
unsigned int upaid);
tid = (starfire_translate(imap, current->processor) << 26);
}
......@@ -715,7 +712,6 @@ void handler_irq(int irq, struct pt_regs *regs)
struct ino_bucket *bp, *nbp;
int cpu = smp_processor_id();
#ifdef CONFIG_SMP
extern int this_is_starfire;
int should_forward = (this_is_starfire == 0 &&
irq < 10 &&
current->pid != 0);
......@@ -1029,7 +1025,6 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
#ifdef CONFIG_SMP
static int retarget_one_irq(struct irqaction *p, int goal_cpu)
{
extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(p->mask);
unsigned long imap = bucket->imap;
unsigned int tid;
......@@ -1041,9 +1036,6 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
if(this_is_starfire == 0) {
tid = __cpu_logical_map[goal_cpu] << 26;
} else {
extern unsigned int starfire_translate(unsigned long imap,
unsigned int upaid);
tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26);
}
upa_writel(IMAP_VALID | (tid & IMAP_TID), imap);
......
......@@ -24,7 +24,6 @@ unsigned long pci_memspace_mask = 0xffffffffUL;
#ifndef CONFIG_PCI
/* A "nop" PCI implementation. */
int pcibios_present(void) { return 0; }
asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
unsigned long off, unsigned long len,
unsigned char *buf)
......@@ -316,7 +315,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
goto out;
}
lock_kernel();
switch(len) {
case 1:
err = get_user(byte, (u8 *)buf);
......@@ -344,7 +342,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
break;
};
unlock_kernel();
out:
return err;
......
/* $Id: pci_psycho.c,v 1.16 2000/04/15 10:06:16 davem Exp $
/* $Id: pci_psycho.c,v 1.17 2000/09/21 06:25:14 anton Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
......@@ -15,6 +15,7 @@
#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
#include "pci_impl.h"
......@@ -1254,8 +1255,6 @@ static void __init psycho_scan_bus(struct pci_controller_info *p)
static void __init psycho_iommu_init(struct pci_controller_info *p)
{
extern int this_is_starfire;
extern void *starfire_hookup(int);
unsigned long tsbbase, i;
u64 control;
......
/* $Id: sbus.c,v 1.11 2000/04/14 09:13:04 davem Exp $
/* $Id: sbus.c,v 1.12 2000/09/21 06:25:14 anton Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
......@@ -18,6 +18,7 @@
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/starfire.h>
#include "iommu_common.h"
......@@ -1151,15 +1152,10 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
upa_writeq(control, iommu->sbus_control_reg);
/* Now some Xfire specific grot... */
{
extern void *starfire_hookup(int);
extern int this_is_starfire;
if (this_is_starfire)
sbus->starfire_cookie = starfire_hookup(sbus->portid);
else
sbus->starfire_cookie = NULL;
}
if (this_is_starfire)
sbus->starfire_cookie = starfire_hookup(sbus->portid);
else
sbus->starfire_cookie = NULL;
sysio_register_error_handlers(sbus);
}
/* $Id: setup.c,v 1.55 2000/07/24 14:13:13 anton Exp $
/* $Id: setup.c,v 1.56 2000/09/21 06:29:01 anton Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
......@@ -37,6 +37,7 @@
#include <asm/pgtable.h>
#include <asm/idprom.h>
#include <asm/head.h>
#include <asm/starfire.h>
#ifdef CONFIG_IP_PNP
#include <net/ipconfig.h>
......@@ -479,6 +480,9 @@ void __init setup_arch(char **cmdline_p)
conswitchp = &prom_con;
#endif
/* Work out if we are starfire early on */
check_if_starfire();
boot_flags_init(*cmdline_p);
idprom_init();
......
/* $Id: starfire.c,v 1.5 2000/01/31 04:59:12 davem Exp $
/* $Id: starfire.c,v 1.7 2000/09/22 23:02:13 davem Exp $
* starfire.c: Starfire/E10000 support.
*
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
* Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
*/
#include <linux/kernel.h>
......@@ -11,23 +12,31 @@
#include <asm/oplib.h>
#include <asm/smp.h>
#include <asm/upa.h>
#include <asm/starfire.h>
/* A few places around the kernel check this to see if
/*
* A few places around the kernel check this to see if
* they need to call us to do things in a Starfire specific
* way.
*/
int this_is_starfire = 0;
void starfire_check(void)
void check_if_starfire(void)
{
int ssnode = prom_finddevice("/ssp-serial");
if(ssnode != 0 && ssnode != -1)
this_is_starfire = 1;
}
if(ssnode != 0 && ssnode != -1) {
void starfire_cpu_setup(void)
{
if (this_is_starfire) {
/* We do this in starfire_translate - Anton */
#if 0
int i;
this_is_starfire = 1;
/* Now must fixup cpu MIDs. OBP gave us a logical
/*
* Now must fixup cpu MIDs. OBP gave us a logical
* linear cpuid number, not the real upaid.
*/
for(i = 0; i < linux_num_cpus; i++) {
......@@ -39,6 +48,7 @@ void starfire_check(void)
linux_cpus[i].mid = mid;
}
#endif
}
}
......@@ -47,7 +57,8 @@ int starfire_hard_smp_processor_id(void)
return upa_readl(0x1fff40000d0UL);
}
/* Each Starfire board has 32 registers which perform translation
/*
* Each Starfire board has 32 registers which perform translation
* and delivery of traditional interrupt packets into the extended
* Starfire hardware format. Essentially UPAID's now have 2 more
* bits than in all previous Sun5 systems.
......@@ -82,6 +93,9 @@ void *starfire_hookup(int upaid)
for(i = 0; i < 32; i++) {
p->imap_slots[i] = 0UL;
p->tregs[i] = treg_base + (i * 0x10UL);
/* Lets play it safe and not overwrite existing mappings */
if (upa_readl(p->tregs[i]) != 0)
p->imap_slots[i] = 0xdeadbeaf;
}
p->upaid = upaid;
p->next = sflist;
......@@ -116,6 +130,12 @@ unsigned int starfire_translate(unsigned long imap,
panic("Lucy in the sky....");
}
p->imap_slots[i] = imap;
/* map to real upaid */
upaid = (((upaid & 0x3c) << 1) |
((upaid & 0x40) >> 4) |
(upaid & 0x3));
upa_writel(upaid, p->tregs[i]);
return i;
......
/* $Id: time.c,v 1.29 2000/09/16 07:33:45 davem Exp $
/* $Id: time.c,v 1.32 2000/09/22 23:02:13 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
......@@ -30,6 +30,7 @@
#include <asm/fhc.h>
#include <asm/pbm.h>
#include <asm/ebus.h>
#include <asm/starfire.h>
extern rwlock_t xtime_lock;
......@@ -305,6 +306,20 @@ void __init clock_probe(void)
struct linux_ebus *ebus = NULL;
#endif
if (this_is_starfire) {
/* davem suggests we keep this within the 4M locked kernel image */
static char obp_gettod[256];
static u32 unix_tod;
sprintf(obp_gettod, "h# %08x unix-gettod",
(unsigned int) (long) &unix_tod);
prom_feval(obp_gettod);
xtime.tv_sec = unix_tod;
xtime.tv_usec = 0;
return;
}
__save_and_cli(flags);
if(central_bus != NULL) {
......@@ -473,6 +488,9 @@ static __inline__ unsigned long do_gettimeoffset(void)
void do_settimeofday(struct timeval *tv)
{
if (this_is_starfire)
return;
write_lock_irq(&xtime_lock);
tv->tv_usec -= do_gettimeoffset();
......@@ -496,7 +514,10 @@ static int set_rtc_mmss(unsigned long nowtime)
unsigned long regs = mstk48t02_regs;
u8 tmp;
/* Not having a register set can lead to trouble. */
/*
* Not having a register set can lead to trouble.
* Also starfire doesnt have a tod clock.
*/
if (!regs)
return -1;
......
/* $Id: init.c,v 1.155 2000/09/09 00:02:19 davem Exp $
/* $Id: init.c,v 1.156 2000/09/21 06:34:48 anton Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
......@@ -29,6 +29,7 @@
#include <asm/mmu_context.h>
#include <asm/vaddrs.h>
#include <asm/dma.h>
#include <asm/starfire.h>
extern void device_scan(void);
......@@ -200,7 +201,7 @@ static void inherit_prom_mappings(void)
for (i = 0; i < n; i++) {
unsigned long vaddr;
if (trans[i].virt >= 0xf0000000 && trans[i].virt < 0x100000000) {
for (vaddr = trans[i].virt;
vaddr < trans[i].virt + trans[i].size;
......@@ -808,7 +809,6 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
unsigned long bootmap_pfn, bytes_avail, size;
int i;
bytes_avail = 0UL;
for (i = 0; sp_banks[i].num_bytes != 0; i++) {
end_of_phys_memory = sp_banks[i].base_addr +
......@@ -999,12 +999,7 @@ void __init paging_init(void)
*/
{
extern void setup_tba(int);
int is_starfire = prom_finddevice("/ssp-serial");
if (is_starfire != 0 && is_starfire != -1)
is_starfire = 1;
else
is_starfire = 0;
setup_tba(is_starfire);
setup_tba(this_is_starfire);
}
inherit_locked_prom_mappings(1);
......
......@@ -19,7 +19,7 @@
*/
#include <linux/config.h>
#ifdef CONFIG_PROC_FS
static char * sg_version_str = "Version: 3.1.17 (20000921)";
static char * sg_version_str = "Version: 3.1.17 (20001002)";
#endif
static int sg_version_num = 30117; /* 2 digits for each component */
/*
......@@ -69,10 +69,8 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
static int sg_proc_init(void);
#ifdef MODULE
static void sg_proc_cleanup(void);
#endif
#endif
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
......@@ -271,7 +269,8 @@ static int sg_open(struct inode * inode, struct file * filp)
* else try and use this device. Also, if error recovery fails, it
* may try and take the device offline, in which case all further
* access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device))
if (! ((flags & O_NONBLOCK) ||
scsi_block_when_processing_errors(sdp->device)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
......@@ -279,7 +278,7 @@ static int sg_open(struct inode * inode, struct file * filp)
if (flags & O_EXCL) {
if (O_RDONLY == (flags & O_ACCMODE))
return -EACCES; /* Can't lock it with read only access */
if (sdp->headfp && (filp->f_flags & O_NONBLOCK))
if (sdp->headfp && (flags & O_NONBLOCK))
return -EBUSY;
res = 0; /* following is a macro that beats race condition */
__wait_event_interruptible(sdp->o_excl_wait,
......@@ -289,7 +288,7 @@ static int sg_open(struct inode * inode, struct file * filp)
return res; /* -ERESTARTSYS because signal hit process */
}
else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
if (filp->f_flags & O_NONBLOCK)
if (flags & O_NONBLOCK)
return -EBUSY;
res = 0; /* following is a macro that beats race condition */
__wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
......@@ -353,9 +352,6 @@ static ssize_t sg_read(struct file * filp, char * buf,
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
if(! scsi_block_when_processing_errors(sdp->device))
return -ENXIO;
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_WRITE, buf, count)))
......@@ -451,15 +447,11 @@ static ssize_t sg_read(struct file * filp, char * buf,
static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
Sg_request * srp)
{
Sg_device * sdp = sfp->parentdp;
sg_io_hdr_t * hp = &srp->header;
int k, len;
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
if (count < size_sg_io_hdr)
return -EINVAL;
hp->sb_len_wr = 0;
if ((hp->mx_sb_len > 0) && hp->sbp) {
if ((CHECK_CONDITION & hp->masked_status) ||
......@@ -503,7 +495,8 @@ static ssize_t sg_write(struct file * filp, const char * buf,
SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
if(! scsi_block_when_processing_errors(sdp->device) )
if (! ((filp->f_flags & O_NONBLOCK) ||
scsi_block_when_processing_errors(sdp->device)))
return -ENXIO;
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
......@@ -712,8 +705,6 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
MINOR(sdp->i_rdev), (int)cmd_in));
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
switch(cmd_in)
......@@ -885,7 +876,11 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
case SG_EMULATED_HOST:
return put_user(sdp->device->host->hostt->emulated, (int *)arg);
case SG_SCSI_RESET:
if (! scsi_block_when_processing_errors(sdp->device))
if (filp->f_flags & O_NONBLOCK) {
if (sdp->device->host->in_recovery)
return -EBUSY;
}
else if (! scsi_block_when_processing_errors(sdp->device))
return -EBUSY;
result = get_user(val, (int *)arg);
if (result) return result;
......@@ -1301,16 +1296,14 @@ static void sg_detach(Scsi_Device * scsidp)
return;
}
#ifdef MODULE
MODULE_AUTHOR("Douglas Gilbert");
MODULE_DESCRIPTION("SCSI generic (sg) driver");
MODULE_PARM(def_reserved_size, "i");
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
#endif /* MODULE */
static int __init init_sg(void) {
#ifdef MODULE
if (def_reserved_size >= 0)
sg_big_buff = def_reserved_size;
#endif /* MODULE */
sg_template.module = THIS_MODULE;
return scsi_register_module(MODULE_SCSI_DEV, &sg_template);
}
......@@ -2551,7 +2544,6 @@ static int sg_proc_init()
return 0;
}
#ifdef MODULE
static void sg_proc_cleanup()
{
int k;
......@@ -2563,7 +2555,6 @@ static void sg_proc_cleanup()
remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp);
remove_proc_entry(sg_proc_sg_dirname, proc_scsi);
}
#endif
static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset,
int size, int * eof, void * data)
......
......@@ -23,7 +23,7 @@ typedef struct
wait_queue_head_t wait;
wait_queue_head_t remove_ok;
spinlock_t lock;
volatile atomic_t pending_io;
atomic_t pending_io;
driver_state_t state;
int remove_pending;
int got_mem;
......
......@@ -12,6 +12,10 @@
*
* History:
*
* 2000/09/26 fixed races in removing the private portion of the urb
* 2000/09/07 disable bulk and control lists when unlinking the last
* endpoint descriptor in order to avoid unrecoverable errors on
* the Lucent chips.
* 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
* urb unlink probs, indentation fixes
* 2000/08/11 various oops fixes mostly affecting iso and cleanup from
......@@ -78,8 +82,9 @@
/* For initializing controller (mask in an HCFS mode too) */
#define OHCI_CONTROL_INIT \
(OHCI_CTRL_CBSR & 0x3) \
| OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
#define OHCI_UNLINK_TIMEOUT (HZ / 10)
static LIST_HEAD (ohci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
......@@ -89,36 +94,54 @@ static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
*-------------------------------------------------------------------------*/
/* free HCD-private data associated with this URB */
static void urb_rm_priv (urb_t * urb)
static void urb_free_priv (urb_priv_t * urb_priv)
{
urb_priv_t * urb_priv = urb->hcpriv;
int i;
/* Release int/iso bandwidth for Interrupt or Isoc. transfers */
if (urb->bandwidth) {
switch (usb_pipetype(urb->pipe)) {
case PIPE_INTERRUPT:
usb_release_bandwidth (urb->dev, urb, 0);
break;
case PIPE_ISOCHRONOUS:
usb_release_bandwidth (urb->dev, urb, 1);
break;
default:
break;
}
}
if (!urb_priv)
return;
for (i = 0; i < urb_priv->length; i++) {
if (urb_priv->td [i]) {
OHCI_FREE (urb_priv->td [i]);
}
}
kfree (urb->hcpriv);
urb->hcpriv = NULL;
kfree (urb_priv);
}
static void urb_rm_priv_locked (urb_t * urb)
{
urb_priv_t * urb_priv = urb->hcpriv;
if (urb_priv) {
urb->hcpriv = NULL;
/* Release int/iso bandwidth */
if (urb->bandwidth) {
switch (usb_pipetype(urb->pipe)) {
case PIPE_INTERRUPT:
usb_release_bandwidth (urb->dev, urb, 0);
break;
case PIPE_ISOCHRONOUS:
usb_release_bandwidth (urb->dev, urb, 1);
break;
default:
break;
}
}
urb_free_priv (urb_priv);
usb_dec_dev_use (urb->dev);
urb->dev = NULL;
}
}
static void urb_rm_priv (urb_t * urb)
{
unsigned long flags;
spin_lock_irqsave (&usb_ed_lock, flags);
urb_rm_priv_locked (urb);
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
/*-------------------------------------------------------------------------*/
......@@ -366,15 +389,15 @@ static int sohci_return_urb (urb_t * urb)
unsigned long flags;
int i;
if (!urb_priv)
return -1; /* urb already unlinked */
/* just to be sure */
if (!urb->complete) {
urb_rm_priv (urb);
usb_dec_dev_use (urb->dev);
return -1;
}
if (!urb_priv) return -1; /* urb already unlinked */
#ifdef DEBUG
urb_print (urb, "RET", usb_pipeout (urb->pipe));
#endif
......@@ -408,7 +431,6 @@ static int sohci_return_urb (urb_t * urb)
} else { /* unlink URB, call complete */
urb_rm_priv (urb);
usb_dec_dev_use (urb->dev);
urb->complete (urb);
}
break;
......@@ -416,7 +438,6 @@ static int sohci_return_urb (urb_t * urb)
case PIPE_BULK:
case PIPE_CONTROL: /* unlink URB, call complete */
urb_rm_priv (urb);
usb_dec_dev_use (urb->dev);
urb->complete (urb);
break;
}
......@@ -438,7 +459,7 @@ static int sohci_submit_urb (urb_t * urb)
int bustime = 0;
if (!urb->dev || !urb->dev->bus)
return -EINVAL;
return -ENODEV;
if (urb->hcpriv) /* urb already in use */
return -EINVAL;
......@@ -453,7 +474,7 @@ static int sohci_submit_urb (urb_t * urb)
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
/* a request to the virtual root hub */
/* handle a request to the virtual root hub */
if (usb_pipedevice (pipe) == ohci->rh.devnum)
return rh_submit_urb (urb);
......@@ -505,26 +526,22 @@ static int sohci_submit_urb (urb_t * urb)
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
/* fill the private part of the URB */
urb->hcpriv = urb_priv;
urb_priv->length = size;
urb_priv->td_cnt = 0;
urb_priv->state = 0;
urb_priv->ed = ed;
/* allocate the TDs */
for (i = 0; i < size; i++) {
OHCI_ALLOC (urb_priv->td[i], sizeof (td_t));
if (!urb_priv->td[i]) {
urb_rm_priv (urb);
urb_free_priv (urb_priv);
usb_dec_dev_use (urb->dev);
return -ENOMEM;
}
}
spin_lock_irqsave (&usb_ed_lock, flags);
if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
urb_rm_priv(urb);
urb_free_priv (urb_priv);
usb_dec_dev_use (urb->dev);
spin_unlock_irqrestore(&usb_ed_lock, flags);
return -EINVAL;
}
......@@ -544,23 +561,24 @@ static int sohci_submit_urb (urb_t * urb)
bustime = usb_check_bandwidth (urb->dev, urb);
}
if (bustime < 0) {
urb_rm_priv (urb);
urb_free_priv (urb_priv);
usb_dec_dev_use (urb->dev);
spin_unlock_irqrestore (&usb_ed_lock, flags);
return bustime;
}
usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
}
urb->status = USB_ST_URB_PENDING;
spin_lock_irqsave (&usb_ed_lock, flags);
urb->actual_length = 0;
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
urb->hcpriv = urb_priv;
urb->status = USB_ST_URB_PENDING;
/* link the ed into a chain if is not already */
if (ed->state != ED_OPER)
ep_link (ohci, ed);
urb->status = USB_ST_URB_PENDING;
td_submit_urb (urb); /* fill the TDs and link it to the ed */
/* fill the TDs and link it to the ed */
td_submit_urb (urb);
spin_unlock_irqrestore (&usb_ed_lock, flags);
return 0;
......@@ -570,7 +588,7 @@ static int sohci_submit_urb (urb_t * urb)
/* deactivate all TDs and remove the private part of the URB */
/* interrupt callers must use async unlink mode */
static int sohci_unlink_urb (urb_t * urb)
{
unsigned long flags;
......@@ -587,16 +605,14 @@ static int sohci_unlink_urb (urb_t * urb)
#ifdef DEBUG
urb_print (urb, "UNLINK", 1);
#endif
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) {
usb_dec_dev_use(urb->dev);
return rh_unlink_urb (urb); /* a request to the virtual root hub */
}
if (urb->hcpriv) {
/* URB active? */
if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) {
urb_priv_t * urb_priv = urb->hcpriv;
/* handle a request to the virtual root hub */
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb);
if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) {
if (!ohci->disabled) {
urb_priv_t * urb_priv;
/* interrupt code may not sleep; it must use
* async status return to unlink pending urbs.
......@@ -608,44 +624,50 @@ static int sohci_unlink_urb (urb_t * urb)
return -EWOULDBLOCK;
}
/* flag the urb and its TDs for deletion in some
* upcoming SF interrupt delete list processing
*/
urb_priv->state = URB_DEL;
spin_lock_irqsave (&usb_ed_lock, flags);
urb_priv = urb->hcpriv;
if (urb_priv->ed->state == ED_OPER)
ep_unlink(ohci, urb_priv->ed);
if (!urb_priv || (urb_priv->state == URB_DEL)) {
spin_unlock_irqrestore (&usb_ed_lock, flags);
return 0;
}
urb_priv->state = URB_DEL;
ep_rm_ed (urb->dev, urb_priv->ed);
urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
DECLARE_WAITQUEUE (wait, current);
int timeout = OHCI_UNLINK_TIMEOUT;
usb_dec_dev_use (urb->dev);
/* wait until all TDs are deleted */
add_wait_queue (&unlink_wakeup, &wait);
urb_priv->wait = &unlink_wakeup;
current->state = TASK_UNINTERRUPTIBLE;
schedule ();
spin_unlock_irqrestore (&usb_ed_lock, flags);
/* wait until all TDs are deleted */
set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && (urb->status == USB_ST_URB_PENDING))
timeout = schedule_timeout (timeout);
remove_wait_queue (&unlink_wakeup, &wait);
urb->status = -ENOENT;
urb_priv->wait = 0;
if (urb->status == USB_ST_URB_PENDING) {
err ("unlink URB timeout");
return -ETIMEDOUT;
}
} else {
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
} else {
urb_rm_priv (urb);
usb_dec_dev_use (urb->dev);
if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
urb->complete (urb);
urb->status = 0;
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
if (urb->complete)
urb->complete (urb);
} else
urb->status = -ENOENT;
}
......@@ -729,14 +751,19 @@ static int sohci_free_dev (struct usb_device * usb_dev)
} else if (!in_interrupt ()) {
DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup);
DECLARE_WAITQUEUE (wait, current);
int timeout = OHCI_UNLINK_TIMEOUT;
/* SF interrupt handler calls dl_del_list */
add_wait_queue (&freedev_wakeup, &wait);
dev->wait = &freedev_wakeup;
current->state = TASK_UNINTERRUPTIBLE;
schedule ();
set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && dev->ed_cnt)
timeout = schedule_timeout (timeout);
remove_wait_queue (&freedev_wakeup, &wait);
if (dev->ed_cnt) {
err ("free device %d timeout", usb_dev->devnum);
return -ETIMEDOUT;
}
} else {
/* likely some interface's driver has a refcount bug */
err ("bus %s devnum %d deletion in interrupt",
......@@ -836,7 +863,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
ed->state = ED_OPER;
switch (ed->type) {
case CTRL:
case PIPE_CONTROL:
ed->hwNextED = 0;
if (ohci->ed_controltail == NULL) {
writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
......@@ -844,10 +871,15 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
}
ed->ed_prev = ohci->ed_controltail;
if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
!ohci->ed_rm_list[1]) {
ohci->hc_control |= OHCI_CTRL_CLE;
writel (ohci->hc_control, &ohci->regs->control);
}
ohci->ed_controltail = edi;
break;
case BULK:
case PIPE_BULK:
ed->hwNextED = 0;
if (ohci->ed_bulktail == NULL) {
writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
......@@ -855,10 +887,15 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
}
ed->ed_prev = ohci->ed_bulktail;
if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
!ohci->ed_rm_list[1]) {
ohci->hc_control |= OHCI_CTRL_BLE;
writel (ohci->hc_control, &ohci->regs->control);
}
ohci->ed_bulktail = edi;
break;
case INT:
case PIPE_INTERRUPT:
load = ed->int_load;
interval = ep_2_n_interval (ed->int_period);
ed->int_interval = interval;
......@@ -879,7 +916,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
#endif
break;
case ISO:
case PIPE_ISOCHRONOUS:
ed->hwNextED = 0;
ed->int_interval = 1;
if (ohci->ed_isotail != NULL) {
......@@ -923,21 +960,29 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
switch (ed->type) {
case CTRL:
case PIPE_CONTROL:
if (ed->ed_prev == NULL) {
if (!ed->hwNextED) {
ohci->hc_control &= ~OHCI_CTRL_CLE;
writel (ohci->hc_control, &ohci->regs->control);
}
writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
} else {
ed->ed_prev->hwNextED = ed->hwNextED;
}
if(ohci->ed_controltail == ed) {
if (ohci->ed_controltail == ed) {
ohci->ed_controltail = ed->ed_prev;
} else {
((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
}
break;
case BULK:
case PIPE_BULK:
if (ed->ed_prev == NULL) {
if (!ed->hwNextED) {
ohci->hc_control &= ~OHCI_CTRL_BLE;
writel (ohci->hc_control, &ohci->regs->control);
}
writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
} else {
ed->ed_prev->hwNextED = ed->hwNextED;
......@@ -949,7 +994,7 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
}
break;
case INT:
case PIPE_INTERRUPT:
int_branch = ed->int_branch;
interval = ed->int_interval;
......@@ -971,7 +1016,7 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
#endif
break;
case ISO:
case PIPE_ISOCHRONOUS:
if (ohci->ed_isotail == ed)
ohci->ed_isotail = ed->ed_prev;
if (ed->hwNextED != 0)
......@@ -1054,7 +1099,7 @@ static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int int
| usb_pipeslow (pipe) << 13
| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
if (ed->type == INT && ed->state == ED_UNLINK) {
if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
ed->int_period = interval;
ed->int_load = load;
}
......@@ -1081,13 +1126,13 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
if (!ohci->disabled) {
switch (ed->type) {
case CTRL: /* stop CTRL list */
writel (ohci->hc_control &= ~OHCI_CTRL_CLE,
&ohci->regs->control);
case PIPE_CONTROL: /* stop control list */
ohci->hc_control &= ~OHCI_CTRL_CLE;
writel (ohci->hc_control, &ohci->regs->control);
break;
case BULK: /* stop BULK list */
writel (ohci->hc_control &= ~OHCI_CTRL_BLE,
&ohci->regs->control);
case PIPE_BULK: /* stop bulk list */
ohci->hc_control &= ~OHCI_CTRL_BLE;
writel (ohci->hc_control, &ohci->regs->control);
break;
}
}
......@@ -1128,7 +1173,7 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int i
td->index = index;
td->urb = urb;
td->hwINFO = cpu_to_le32 (info);
if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
if ((td->ed->type) == PIPE_ISOCHRONOUS) {
td->hwCBP = cpu_to_le32 (((!data || !len)
? 0
: virt_to_bus (data)) & 0xFFFFF000);
......@@ -1269,6 +1314,27 @@ static void dl_transfer_length(td_t * td)
}
}
/* handle an urb that is being unlinked */
static void dl_del_urb (urb_t * urb)
{
wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
urb_rm_priv_locked (urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
if (urb->complete)
urb->complete (urb);
} else {
urb->status = -ENOENT;
/* unblock sohci_unlink_urb */
if (wait_head)
wake_up (wait_head);
}
}
/*-------------------------------------------------------------------------*/
/* replies to the request have to be on a FIFO basis so
......@@ -1330,6 +1396,7 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
int ctrl = 0, bulk = 0;
spin_lock_irqsave (&usb_ed_lock, flags);
for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
......@@ -1344,22 +1411,13 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
tdINFO = le32_to_cpup (&td->hwINFO);
if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
if (TD_CC_GET (tdINFO) < 0xE)
dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
/* URB is done; clean up */
if (++(urb_priv->td_cnt) == urb_priv->length) {
void *condition = urb_priv->wait;
urb_rm_priv (urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
usb_dec_dev_use (urb->dev);
urb->status = -ECONNRESET;
urb->complete (urb);
} else if (condition) {
/* unblock sohci_unlink_urb */
wake_up (condition);
}
}
if (++(urb_priv->td_cnt) == urb_priv->length)
dl_del_urb (urb);
} else {
td_p = &td->hwNextTD;
}
......@@ -1371,31 +1429,54 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
ed->state = ED_NEW;
/* if all eds are removed wake up sohci_free_dev */
if (!--dev->ed_cnt && dev->wait)
wake_up (dev->wait);
}
else {
if (!--dev->ed_cnt) {
wait_queue_head_t *wait_head = dev->wait;
dev->wait = 0;
if (wait_head)
wake_up (wait_head);
}
} else {
ed->state &= ~ED_URB_DEL;
ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
if (tdHeadP == tdTailP) {
if (ed->state == ED_OPER)
ep_unlink(ohci, ed);
OHCI_FREE (tdTailP);
ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
ed->state = ED_NEW;
--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;
} else
ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
}
if ((ed->type & 3) == CTRL) ctrl |= 1;
if ((ed->type & 3) == BULK) bulk |= 1;
switch (ed->type) {
case PIPE_CONTROL:
ctrl = 1;
break;
case PIPE_BULK:
bulk = 1;
break;
}
}
/* maybe reenable CTRL and BULK lists */
/* maybe reenable control and bulk lists */
if (!ohci->disabled) {
if (ctrl) /* reset CTRL list */
if (ctrl) /* reset control list */
writel (0, &ohci->regs->ed_controlcurrent);
if (bulk) /* reset BULK list */
if (bulk) /* reset bulk list */
writel (0, &ohci->regs->ed_bulkcurrent);
if (!ohci->ed_rm_list[!frame]) {
ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE;
if (ohci->ed_controltail)
ohci->hc_control |= OHCI_CTRL_CLE;
if (ohci->ed_bulktail)
ohci->hc_control |= OHCI_CTRL_BLE;
writel (ohci->hc_control, &ohci->regs->control);
}
}
ohci->ed_rm_list[frame] = NULL;
ohci->ed_rm_list[frame] = NULL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
......@@ -1439,14 +1520,15 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
cc = TD_CC_NOERROR;
if (++(urb_priv->td_cnt) == urb_priv->length) {
if (urb_priv->state != URB_DEL
&& !(ed->state & ED_DEL)
&& ed->state != ED_NEW) {
if ((ed->state & (ED_OPER | ED_UNLINK))
&& (urb_priv->state != URB_DEL)) {
urb->status = cc_to_error[cc];
sohci_return_urb (urb);
} else {
urb_rm_priv (urb);
}
spin_lock_irqsave (&usb_ed_lock, flags);
dl_del_urb (urb);
spin_unlock_irqrestore (&usb_ed_lock, flags);
}
}
spin_lock_irqsave (&usb_ed_lock, flags);
......@@ -1600,7 +1682,8 @@ static void rh_int_timer_do (unsigned long ptr)
#ifdef DEBUG
urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
#endif
if (urb->complete) urb->complete (urb);
if (urb->complete)
urb->complete (urb);
}
}
out:
......@@ -1656,7 +1739,6 @@ static int rh_submit_urb (urb_t * urb)
__u16 wLength;
if (usb_pipeint(pipe)) {
ohci->rh.urb = urb;
ohci->rh.send = 1;
ohci->rh.interval = urb->interval;
......@@ -1827,9 +1909,11 @@ static int rh_submit_urb (urb_t * urb)
urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
#endif
urb->hcpriv = NULL;
usb_dec_dev_use (usb_dev);
urb->dev = NULL;
if (urb->complete)
urb->complete (urb);
usb_dec_dev_use (urb->dev);
return 0;
}
......@@ -1842,6 +1926,17 @@ static int rh_unlink_urb (urb_t * urb)
if (ohci->rh.urb == urb) {
ohci->rh.send = 0;
del_timer (&ohci->rh.rh_int_timer);
ohci->rh.urb = NULL;
urb->hcpriv = NULL;
usb_dec_dev_use(urb->dev);
urb->dev = NULL;
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
if (urb->complete)
urb->complete (urb);
} else
urb->status = -ENOENT;
}
return 0;
}
......@@ -2352,6 +2447,12 @@ ohci_pci_resume (struct pci_dev *dev)
ohci->disabled = 0;
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
if (!ohci->ed_rm_list[0] & !ohci->ed_rm_list[1]) {
if (ohci->ed_controltail)
ohci->hc_control |= OHCI_CTRL_CLE;
if (ohci->ed_bulktail)
ohci->hc_control |= OHCI_CTRL_BLE;
}
writel (ohci->hc_control, &ohci->regs->control);
#ifdef CONFIG_PMAC_PBOOK
enable_irq (ohci->irq);
......@@ -2448,7 +2549,6 @@ static int __init ohci_hcd_init (void)
return ret;
}
/*-------------------------------------------------------------------------*/
static void __exit ohci_hcd_cleanup (void)
......@@ -2463,6 +2563,5 @@ module_init (ohci_hcd_init);
module_exit (ohci_hcd_cleanup);
MODULE_AUTHOR ("Roman Weissgaerber <weissg@vienna.at>, David Brownell");
MODULE_DESCRIPTION ("USB OHCI Host Controller Driver");
......@@ -107,7 +107,7 @@ typedef struct td {
__u32 hwBE; /* Memory Buffer End Pointer */
__u16 hwPSW[MAXPSW];
__u8 type;
__u8 unused;
__u8 index;
struct ed * ed;
struct td * next_dl_td;
......@@ -115,18 +115,6 @@ typedef struct td {
} td_t;
/* TD types */
#define BULK 0x03
#define INT 0x01
#define CTRL 0x02
#define ISO 0x00
#define SEND 0x01
#define ST_ADDR 0x02
#define ADD_LEN 0x04
#define DEL 0x08
#define OHCI_ED_SKIP (1 << 14)
/*
......@@ -347,7 +335,7 @@ typedef struct
__u16 length; // number of tds associated with this request
__u16 td_cnt; // number of tds already serviced
int state;
void * wait;
wait_queue_head_t * wait;
td_t * td[0]; // list pointer to all corresponding TDs associated with this request
} urb_priv_t;
......@@ -398,7 +386,7 @@ typedef struct ohci {
struct ohci_device {
ed_t ed[NUM_EDS];
int ed_cnt;
void * wait;
wait_queue_head_t * wait;
};
// #define ohci_to_usb(ohci) ((ohci)->usb)
......
......@@ -1057,6 +1057,7 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
uhci_desc_t *qh;
urb_priv_t *urb_priv;
unsigned long flags=0;
struct usb_device *usb_dev;
spin_lock_irqsave (&s->urb_list_lock, flags);
......@@ -1103,11 +1104,13 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
#else
kfree (urb->hcpriv);
#endif
usb_dev = urb->dev;
if (urb->complete) {
dbg("unlink_urb: calling completion");
urb->dev = NULL;
urb->complete ((struct urb *) urb);
}
usb_dec_dev_use (urb->dev);
usb_dec_dev_use (usb_dev);
}
else {
if (!in_interrupt())
......@@ -1171,6 +1174,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force)
if (urb->complete) {
spin_unlock(&s->urb_list_lock);
urb->dev = NULL;
urb->complete ((struct urb *) urb);
spin_lock(&s->urb_list_lock);
}
......@@ -2082,6 +2086,7 @@ _static int rh_submit_urb (urb_t *urb)
urb->actual_length = len;
urb->status = stat;
urb->dev=NULL;
if (urb->complete)
urb->complete (urb);
return 0;
......@@ -2484,7 +2489,6 @@ _static int process_urb (uhci_t *s, struct list_head *p)
int ret = 0;
urb_t *urb;
urb=list_entry (p, urb_t, urb_list);
//dbg("process_urb: found queued urb: %p", urb);
......@@ -2508,6 +2512,9 @@ _static int process_urb (uhci_t *s, struct list_head *p)
if (urb->status != -EINPROGRESS) {
int proceed = 0;
struct usb_device *usb_dev;
usb_dev=urb->dev;
/* Release bandwidth for Interrupt or Iso transfers */
if (urb->bandwidth) {
......@@ -2549,9 +2556,12 @@ _static int process_urb (uhci_t *s, struct list_head *p)
// In case you need the current URB status for your completion handler (before resubmit)
if (urb->complete && (!proceed )) {
dbg("process_transfer: calling early completion");
urb->dev = NULL;
urb->complete ((struct urb *) urb);
if (!proceed && is_ring && (urb->status != -ENOENT))
if (!proceed && is_ring && (urb->status != -ENOENT)) {
urb->dev=usb_dev;
uhci_submit_urb (urb);
}
}
if (proceed && urb->next) {
......@@ -2567,11 +2577,13 @@ _static int process_urb (uhci_t *s, struct list_head *p)
if (urb->complete) {
dbg("process_transfer: calling completion");
urb->dev=NULL;
urb->complete ((struct urb *) urb);
}
}
usb_dec_dev_use (urb->dev);
urb->dev=NULL; // Just in case no completion was called
usb_dec_dev_use (usb_dev);
spin_unlock(&urb->lock);
spin_lock(&s->urb_list_lock);
}
......
......@@ -35,6 +35,11 @@
#endif
#include <linux/usb.h>
#define DEVNUM_ROUND_ROBIN /***** OPTION *****/
#ifdef DEVNUM_ROUND_ROBIN
static int devnum_next = 1;
#endif
static const int usb_bandwidth_option =
#ifdef CONFIG_USB_BANDWIDTH
1;
......@@ -1470,7 +1475,19 @@ void usb_connect(struct usb_device *dev)
* which hopefully doesn't run on multiple CPU's simultaneously 8-)
*/
dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */
#ifndef DEVNUM_ROUND_ROBIN
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
#else /* round_robin alloc of devnums */
/* Try to allocate the next devnum beginning at devnum_next. */
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
devnum_next = devnum + 1;
if (devnum_next >= 128)
devnum_next = 1;
#endif /* round_robin alloc of devnums */
if (devnum < 128) {
set_bit(devnum, dev->bus->devmap.devicemap);
dev->devnum = devnum;
......
......@@ -2,6 +2,7 @@
#define _ALPHA_BITOPS_H
#include <linux/config.h>
#include <linux/kernel.h>
/*
* Copyright 1994, Linus Torvalds.
......
......@@ -7,8 +7,6 @@
*
*/
#include <linux/config.h>
typedef struct { volatile int counter; } atomic_t;
#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
......
......@@ -8,19 +8,12 @@
#include <linux/config.h>
#ifdef CONFIG_SMP
/* This is a temporary measure. -DaveM */
typedef struct { volatile int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i << 8) }
#else
typedef struct { int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i) }
#endif
#ifdef __KERNEL__
#ifndef CONFIG_SMP
#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) ((v)->counter)
#define atomic_set(v, i) (((v)->counter) = i)
......@@ -39,6 +32,8 @@ typedef struct { int counter; } atomic_t;
* 31 8 7 0
*/
#define ATOMIC_INIT(i) { (i << 8) }
static __inline__ int atomic_read(atomic_t *v)
{
int ret = v->counter;
......
/* $Id: bitops.h,v 1.60 2000/08/10 23:49:16 davem Exp $
/* $Id: bitops.h,v 1.61 2000/09/23 02:11:22 davem Exp $
* bitops.h: Bit string operations on the Sparc.
*
* Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
......@@ -156,6 +156,9 @@ extern __inline__ void change_bit(unsigned long nr, volatile void *addr)
#endif /* __KERNEL__ */
#define smp_mb__before_clear_bit() do { } while(0)
#define smp_mb__after_clear_bit() do { } while(0)
/* The following routine need not be atomic. */
extern __inline__ int test_bit(int nr, __const__ void *addr)
{
......
/* $Id: system.h,v 1.83 2000/08/04 05:35:55 davem Exp $ */
/* $Id: system.h,v 1.84 2000/09/23 02:11:22 davem Exp $ */
#include <linux/config.h>
#ifndef __SPARC_SYSTEM_H
......@@ -280,6 +280,9 @@ extern void __global_restore_flags(unsigned long flags);
#define wmb() mb()
#define set_mb(__var, __value) do { __var = __value; mb(); } while(0)
#define set_wmb(__var, __value) set_mb(__var, __value)
#define smp_mb() __asm__ __volatile__("":::"memory");
#define smp_rmb() __asm__ __volatile__("":::"memory");
#define smp_wmb() __asm__ __volatile__("":::"memory");
#define nop() __asm__ __volatile__ ("nop");
......
......@@ -8,7 +8,7 @@
#ifndef __ARCH_SPARC64_ATOMIC__
#define __ARCH_SPARC64_ATOMIC__
typedef struct { int counter; } atomic_t;
typedef struct { volatile int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) ((v)->counter)
......
/* $Id: bitops.h,v 1.30 2000/08/10 23:49:16 davem Exp $
/* $Id: bitops.h,v 1.31 2000/09/23 02:09:21 davem Exp $
* bitops.h: Bit string operations on the V9.
*
* Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
......@@ -20,6 +20,9 @@ extern long __test_and_change_bit(unsigned long nr, volatile void *addr);
#define clear_bit(nr,addr) ((void)__test_and_clear_bit(nr,addr))
#define change_bit(nr,addr) ((void)__test_and_change_bit(nr,addr))
#define smp_mb__before_clear_bit() do { } while(0)
#define smp_mb__after_clear_bit() do { } while(0)
extern __inline__ int test_bit(int nr, __const__ void *addr)
{
return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63))) != 0UL;
......
......@@ -9,6 +9,7 @@
#include <linux/config.h>
#include <linux/threads.h>
#include <asm/asi.h>
#include <asm/starfire.h>
#ifndef __ASSEMBLY__
/* PROM provided per-processor information we need
......@@ -82,11 +83,7 @@ extern __inline__ int cpu_number_map(int cpu)
extern __inline__ int hard_smp_processor_id(void)
{
extern int this_is_starfire;
if(this_is_starfire != 0) {
extern int starfire_hard_smp_processor_id(void);
return starfire_hard_smp_processor_id();
} else {
unsigned long upaconfig;
......
/* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $
* starfire.h: Group all starfire specific code together.
*
* Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
*/
#ifndef _SPARC64_STARFIRE_H
#define _SPARC64_STARFIRE_H
#ifndef __ASSEMBLY__
extern int this_is_starfire;
extern void check_if_starfire(void);
extern void starfire_cpu_setup(void);
extern int starfire_hard_smp_processor_id(void);
extern void *starfire_hookup(int);
extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
#endif
#endif
/* $Id: system.h,v 1.61 2000/08/04 05:35:55 davem Exp $ */
/* $Id: system.h,v 1.62 2000/09/23 02:09:21 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
......@@ -95,11 +95,11 @@ extern void __global_restore_flags(unsigned long flags);
#endif
#define mb() __asm__ __volatile__ ("stbar" : : : "memory")
#define nop() __asm__ __volatile__ ("nop")
#define membar(type) __asm__ __volatile__ ("membar " type : : : "memory");
#define mb() \
membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad");
#define rmb() membar("#LoadLoad")
#define wmb() membar("#StoreStore")
#define set_mb(__var, __value) \
......@@ -107,6 +107,16 @@ extern void __global_restore_flags(unsigned long flags);
#define set_wmb(__var, __value) \
do { __var = __value; membar("#StoreStore"); } while(0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#else
#define smp_mb() __asm__ __volatile__("":::"memory");
#define smp_rmb() __asm__ __volatile__("":::"memory");
#define smp_wmb() __asm__ __volatile__("":::"memory");
#endif
#define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
#define flushw_all() __asm__ __volatile__("flushw")
......
......@@ -147,6 +147,10 @@
#define UNIX98_PTY_MAJOR_COUNT 8
#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */
#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */
#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */
#define MSR_MAJOR 202
#define CPUID_MAJOR 203
......
......@@ -1066,16 +1066,13 @@ static int arp_get_info(char *buffer, char **start, off_t offset, int length)
{
char tbuf[16];
sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key));
size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s",
size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s"
" * %s\n",
tbuf,
hatype,
arp_state_to_flags(n),
hbuffer);
size += sprintf(buffer+len+size,
" %-8s %s\n",
"*", dev->name);
hbuffer,
dev->name);
}
read_unlock(&n->lock);
......@@ -1102,15 +1099,14 @@ static int arp_get_info(char *buffer, char **start, off_t offset, int length)
{
char tbuf[16];
sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s",
size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s"
" * %s\n",
tbuf,
hatype,
ATF_PUBL|ATF_PERM,
"00:00:00:00:00:00");
"00:00:00:00:00:00",
dev ? dev->name : "*");
}
size += sprintf(buffer+len+size,
" * %-16s\n",
dev ? dev->name : "*");
len += size;
pos += size;
......
ksymoops has been removed from the kernel. It was always meant to be a
free standing utility, not linked to any particular kernel version.
The latest version can be found in ftp://ftp.ocs.com.au/pub/ksymoops,
together with patches to other utilities in order to give more accurate
Oops debugging.
The latest version can be found in
ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops together
with patches to other utilities in order to give more accurate Oops
debugging.
Keith Owens <kaos@ocs.com.au> Sat Jun 19 10:30:34 EST 1999
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