Commit 743eee7c authored by Linus Torvalds's avatar Linus Torvalds

Import 2.2.8pre6

parent 3eb6861c
......@@ -256,6 +256,10 @@ W: http://math-www.uni-paderborn.de/~axel/
D: Configuration help text support
D: Linux CD and Support Giveaway List
N: Zoltan Boszormenyi
E: zboszor@mol.hu
D: MTRR emulation with Cyrix style ARR registers
N: John Boyd
E: boyd@cis.ohio-state.edu
D: Co-author of wd7000 SCSI driver
......
......@@ -8666,17 +8666,24 @@ CONFIG_FT_FDC_MAX_RATE
MTRR control and configuration
CONFIG_MTRR
On Intel Pentium Pro and Pentium II systems the Memory Type Range
Registers (MTRRs) may be used to control processor access to memory
ranges. This is most useful when you have a video (VGA) card on a
PCI or AGP bus. Enabling write-combining allows bus write transfers
to be combined into a larger transfer before bursting over the
PCI/AGP bus. This can increase performance of image write operations
2.5 times or more. This option creates a /proc/mtrr file which may
be used to manipulate your MTRRs. Typically the X server should use
this. This should have a reasonably generic interface so that
similar control registers on other processors can be easily
supported.
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
processor access to memory ranges. This is most useful when you have
a video (VGA) card on a PCI or AGP bus. Enabling write-combining
allows bus write transfers to be combined into a larger transfer
before bursting over the PCI/AGP bus. This can increase performance
of image write operations 2.5 times or more. This option creates a
/proc/mtrr file which may be used to manipulate your
MTRRs. Typically the X server should use this. This should have a
reasonably generic interface so that similar control registers on
other processors can be easily supported.
The Cyrix 6x86, 6x86MX and M II processors have Address Range
Registers (ARRs) which provide a similar functionality to MTRRs. For
these, the ARRs are used to emulate the MTRRs.
The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
MTRRs. These are supported.
Saying Y here also fixes a problem with buggy SMP BIOSes which only
set the MTRRs for the boot CPU and not the secondary CPUs. This can
......
......@@ -62,6 +62,23 @@ in other words the X server will manipulate /proc/mtrr using the
ioctl() interface, so users won't have to do anything. If you use a
commercial X server, lobby your vendor to add support for MTRRs.
===============================================================================
Creating overlapping MTRRs:
%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
And the results: cat /proc/mtrr
reg00: base=0x00000000 ( 0MB), size= 64MB: write-back, count=1
reg01: base=0xfb000000 (4016MB), size= 16MB: write-combining, count=1
reg02: base=0xfb000000 (4016MB), size= 4kB: uncachable, count=1
Some cards (especially Voodoo Graphics boards) need this 4 kB area
excluded from the beginning of the region because it is used for
registers.
NOTE: You can only create type=uncachable region, if the first
region that you created is type=write-combining.
===============================================================================
Removing MTRRs from the shell:
% echo "disable=2" >! /proc/mtrr
===============================================================================
......
......@@ -211,4 +211,4 @@ kuznet@ms2.inr.ac.ru
Updated by:
Andi Kleen
ak@muc.de
$Id: ip-sysctl.txt,v 1.8 1999/01/02 16:37:06 davem Exp $
$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $
......@@ -54,12 +54,10 @@ unset CONFIG_PCI CONFIG_ALPHA_EISA
unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
then
define_bool CONFIG_PCI y
define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
fi
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
then
......@@ -108,7 +106,7 @@ then
then
define_bool CONFIG_ALPHA_EV5 y
else
define_bool CONFIG_ALPHA_EV4 y
define_bool CONFIG_ALPHA_EV4 y
fi
define_bool CONFIG_ALPHA_T2 y
fi
......@@ -141,11 +139,6 @@ if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
then
define_bool CONFIG_ALPHA_EV4 y
fi
if [ "$CONFIG_ALPHA_EV4" = "y" ]
then
# EV45 and older do not support all rounding modes in hw:
define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
fi
if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
......
This diff is collapsed.
......@@ -885,7 +885,21 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
case GSI_IEEE_FP_CONTROL:
/* Return current software fp control & status bits. */
/* Note that DU doesn't verify available space here. */
w = current->tss.flags & IEEE_SW_MASK;
/* EV6 implements most of the bits in hardware. If
UNDZ is not set, UNFD is maintained in software. */
if (implver() == IMPLVER_EV6) {
unsigned long fpcr = rdfpcr();
w = ieee_fpcr_to_swcr(fpcr);
if (!(fpcr & FPCR_UNDZ)) {
w &= ~IEEE_TRAP_ENABLE_UNF;
w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF;
}
} else {
/* Otherwise we are forced to do everything in sw. */
w = current->tss.flags & IEEE_SW_MASK;
}
if (put_user(w, (unsigned long *) buffer))
return -EFAULT;
return 0;
......@@ -935,7 +949,7 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
{
switch (op) {
case SSI_IEEE_FP_CONTROL: {
unsigned long swcr, fpcr;
unsigned long swcr, fpcr, undz;
/*
* Alpha Architecture Handbook 4.7.7.3:
......@@ -950,11 +964,12 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
current->tss.flags &= ~IEEE_SW_MASK;
current->tss.flags |= swcr & IEEE_SW_MASK;
/* Update the real fpcr. For exceptions that are disabled in
software but have not been seen, enable the exception in
hardware so that we can update our software status mask. */
fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
/* Update the real fpcr. Keep UNFD off if not UNDZ. */
fpcr = rdfpcr();
undz = (fpcr & FPCR_UNDZ);
fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ);
fpcr |= ieee_swcr_to_fpcr(swcr);
fpcr &= ~(undz << 1);
wrfpcr(fpcr);
return 0;
......
......@@ -237,10 +237,13 @@ void exit_thread(void)
void flush_thread(void)
{
/* Arrange for each exec'ed process to start off with a
clean slate with respect to the FPU. */
/* Arrange for each exec'ed process to start off with a clean slate
with respect to the FPU. This is all exceptions disabled. Note
that EV6 defines UNFD valid only with UNDZ, which we don't want
for IEEE conformance -- so that disabled bit remains in software. */
current->tss.flags &= ~IEEE_SW_MASK;
wrfpcr(FPCR_DYN_NORMAL);
wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
}
void release_thread(struct task_struct *dead_task)
......@@ -270,8 +273,6 @@ int alpha_vfork(struct switch_stack * swstack)
(struct pt_regs *) (swstack+1));
}
extern void ret_from_sys_call(void);
extern void ret_from_smpfork(void);
/*
* Copy an alpha thread..
*
......@@ -282,9 +283,13 @@ extern void ret_from_smpfork(void);
* Use the passed "regs" pointer to determine how much space we need
* for a kernel fork().
*/
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
extern void ret_from_sys_call(void);
extern void ret_from_smp_fork(void);
struct pt_regs * childregs;
struct switch_stack * childstack, *stack;
unsigned long stack_offset;
......@@ -292,18 +297,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
if (!(regs->ps & 8))
stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (long)p);
*childregs = *regs;
childregs->r0 = 0;
childregs->r19 = 0;
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics.. */
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
regs->r20 = 0;
stack = ((struct switch_stack *) regs) - 1;
childstack = ((struct switch_stack *) childregs) - 1;
*childstack = *stack;
#ifdef __SMP__
childstack->r26 = (unsigned long) ret_from_smpfork;
childstack->r26 = (unsigned long) ret_from_smp_fork;
#else
childstack->r26 = (unsigned long) ret_from_sys_call;
#endif
......@@ -328,10 +333,12 @@ void dump_thread(struct pt_regs * pt, struct user * dump)
dump->start_code = current->mm->start_code;
dump->start_data = current->mm->start_data;
dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT;
dump->u_ssize =
(current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
dump->u_tsize = ((current->mm->end_code - dump->start_code)
>> PAGE_SHIFT);
dump->u_dsize = ((current->mm->brk + PAGE_SIZE-1 - dump->start_data)
>> PAGE_SHIFT);
dump->u_ssize = (current->mm->start_stack - dump->start_stack
+ PAGE_SIZE-1) >> PAGE_SHIFT;
/*
* We store the registers in an order/format that is
......
......@@ -37,7 +37,18 @@
#define DBGS(args)
#endif
struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
struct ipi_msg_flush_tb_struct {
volatile unsigned int flush_tb_mask;
union {
struct mm_struct * flush_mm;
struct vm_area_struct * flush_vma;
} p;
unsigned long flush_addr;
unsigned long flush_end;
};
static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
struct cpuinfo_alpha cpu_data[NR_CPUS];
......@@ -786,7 +797,7 @@ flush_tlb_all(void)
unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
long timeout = 1000000;
spin_lock_own(&kernel_flag, "flush_tlb_all");
spin_lock(&flush_tb_lock);
ipi_msg_flush_tb.flush_tb_mask = to_whom;
send_ipi_message(to_whom, IPI_TLB_ALL);
......@@ -803,6 +814,8 @@ flush_tlb_all(void)
ipi_msg_flush_tb.flush_tb_mask);
ipi_msg_flush_tb.flush_tb_mask = 0;
}
spin_unlock(&flush_tb_lock);
}
void
......@@ -811,7 +824,7 @@ flush_tlb_mm(struct mm_struct *mm)
unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
long timeout = 1000000;
spin_lock_own(&kernel_flag, "flush_tlb_mm");
spin_lock(&flush_tb_lock);
ipi_msg_flush_tb.flush_tb_mask = to_whom;
ipi_msg_flush_tb.p.flush_mm = mm;
......@@ -833,6 +846,8 @@ flush_tlb_mm(struct mm_struct *mm)
ipi_msg_flush_tb.flush_tb_mask);
ipi_msg_flush_tb.flush_tb_mask = 0;
}
spin_unlock(&flush_tb_lock);
}
void
......@@ -843,7 +858,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
struct mm_struct * mm = vma->vm_mm;
int timeout = 1000000;
spin_lock_own(&kernel_flag, "flush_tlb_page");
spin_lock(&flush_tb_lock);
ipi_msg_flush_tb.flush_tb_mask = to_whom;
ipi_msg_flush_tb.p.flush_vma = vma;
......@@ -866,6 +881,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
ipi_msg_flush_tb.flush_tb_mask);
ipi_msg_flush_tb.flush_tb_mask = 0;
}
spin_unlock(&flush_tb_lock);
}
void
......
......@@ -125,13 +125,16 @@ do_entArith(unsigned long summary, unsigned long write_mask,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
if ((summary & 1)) {
/*
* Software-completion summary bit is set, so try to
* emulate the instruction.
*/
if (alpha_fp_emul_imprecise(&regs, write_mask)) {
return; /* emulation was successful */
if (summary & 1) {
/* Software-completion summary bit is set, so try to
emulate the instruction. */
if (implver() == IMPLVER_EV6) {
/* Whee! EV6 has precice exceptions. */
if (alpha_fp_emul(regs.pc - 4))
return;
} else {
if (alpha_fp_emul_imprecise(&regs, write_mask))
return;
}
}
......@@ -141,7 +144,7 @@ do_entArith(unsigned long summary, unsigned long write_mask,
current->comm, regs.pc, summary, write_mask);
#endif
die_if_kernel("Arithmetic fault", &regs, 0, 0);
force_sig(SIGFPE, current);
send_sig(SIGFPE, current, 1);
unlock_kernel();
}
......@@ -150,14 +153,17 @@ do_entIF(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
lock_kernel();
die_if_kernel("Instruction fault", &regs, type, 0);
switch (type) {
case 0: /* breakpoint */
if (ptrace_cancel_bpt(current)) {
regs.pc -= 4; /* make pc point to former bpt */
}
force_sig(SIGTRAP, current);
send_sig(SIGTRAP, current, 1);
break;
case 1: /* bugcheck */
send_sig(SIGTRAP, current, 1);
break;
case 2: /* gentrap */
......@@ -171,14 +177,13 @@ do_entIF(unsigned long type, unsigned long a1,
switch ((long) regs.r16) {
case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
case GEN_FLTINE:
force_sig(SIGFPE, current);
case GEN_FLTINE: case GEN_ROPRAND:
send_sig(SIGFPE, current, 1);
break;
case GEN_DECOVF:
case GEN_DECDIV:
case GEN_DECINV:
case GEN_ROPRAND:
case GEN_ASSERTERR:
case GEN_NULPTRERR:
case GEN_STKOVF:
......@@ -193,42 +198,29 @@ do_entIF(unsigned long type, unsigned long a1,
case GEN_SUBRNG5:
case GEN_SUBRNG6:
case GEN_SUBRNG7:
force_sig(SIGILL, current);
send_sig(SIGTRAP, current, 1);
break;
}
break;
case 1: /* bugcheck */
case 3: /* FEN fault */
force_sig(SIGILL, current);
send_sig(SIGILL, current, 1);
break;
case 4: /* opDEC */
#ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
{
unsigned int opcode;
/* get opcode of faulting instruction: */
get_user(opcode, (__u32*)(regs.pc - 4));
opcode >>= 26;
if (opcode == 0x16) {
/*
* It's a FLTI instruction, emulate it
* (we don't do no stinkin' VAX fp...)
*/
if (!alpha_fp_emul(regs.pc - 4))
force_sig(SIGFPE, current);
break;
}
if (implver() == IMPLVER_EV4) {
/* EV4 does not implement anything except normal
rounding. Everything else will come here as
an illegal instruction. Emulate them. */
if (alpha_fp_emul(regs.pc - 4))
return;
}
#endif
force_sig(SIGILL, current);
send_sig(SIGILL, current, 1);
break;
default:
panic("do_entIF: unexpected instruction-fault type");
}
unlock_kernel();
}
/* There is an ifdef in the PALcode in MILO that enables a
......@@ -877,14 +869,14 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv:
regs->pc -= 4; /* make pc point to faulting insn */
lock_kernel();
force_sig(SIGSEGV, current);
send_sig(SIGSEGV, current, 1);
unlock_kernel();
return;
give_sigbus:
regs->pc -= 4;
lock_kernel();
force_sig(SIGBUS, current);
send_sig(SIGBUS, current, 1);
unlock_kernel();
return;
}
......
......@@ -13,6 +13,7 @@
#define OPC_INTL 0x11
#define OPC_INTS 0x12
#define OPC_INTM 0x13
#define OPC_FLTC 0x14
#define OPC_FLTV 0x15
#define OPC_FLTI 0x16
#define OPC_FLTL 0x17
......@@ -21,33 +22,37 @@
#define OPC_JSR 0x1a
#define OP_FUN(OP,FUN) ((OP << 26) | (FUN << 5))
/*
* "Base" function codes for the FLTI-class instructions. These
* instructions all have opcode 0x16. Note that in most cases these
* actually correspond to the "chopped" form of the instruction. Not
* to worry---we extract the qualifier bits separately and deal with
* them separately. Notice that base function code 0x2c is used for
* both CVTTS and CVTST. The other bits in the function code are used
* to distinguish the two.
* "Base" function codes for the FLTI-class instructions.
* Note that in most cases these actually correspond to the "chopped"
* form of the instruction. Not to worry---we extract the qualifier
* bits separately and deal with them separately. Notice that base
* function code 0x2c is used for both CVTTS and CVTST. The other bits
* in the function code are used to distinguish the two.
*/
#define FLTI_FUNC_ADDS 0x000
#define FLTI_FUNC_ADDT 0x020
#define FLTI_FUNC_CMPTEQ 0x025
#define FLTI_FUNC_CMPTLT 0x026
#define FLTI_FUNC_CMPTLE 0x027
#define FLTI_FUNC_CMPTUN 0x024
#define FLTI_FUNC_CVTTS_or_CVTST 0x02c
#define FLTI_FUNC_CVTTQ 0x02f
#define FLTI_FUNC_CVTQS 0x03c
#define FLTI_FUNC_CVTQT 0x03e
#define FLTI_FUNC_DIVS 0x003
#define FLTI_FUNC_DIVT 0x023
#define FLTI_FUNC_MULS 0x002
#define FLTI_FUNC_MULT 0x022
#define FLTI_FUNC_SUBS 0x001
#define FLTI_FUNC_SUBT 0x021
#define FLTI_FUNC_CVTQL 0x030 /* opcode 0x17 */
#define FLTI_FUNC_ADDS OP_FUN(OPC_FLTI, 0x000)
#define FLTI_FUNC_ADDT OP_FUN(OPC_FLTI, 0x020)
#define FLTI_FUNC_CMPTEQ OP_FUN(OPC_FLTI, 0x025)
#define FLTI_FUNC_CMPTLT OP_FUN(OPC_FLTI, 0x026)
#define FLTI_FUNC_CMPTLE OP_FUN(OPC_FLTI, 0x027)
#define FLTI_FUNC_CMPTUN OP_FUN(OPC_FLTI, 0x024)
#define FLTI_FUNC_CVTTS_or_CVTST OP_FUN(OPC_FLTI, 0x02c)
#define FLTI_FUNC_CVTTQ OP_FUN(OPC_FLTI, 0x02f)
#define FLTI_FUNC_CVTQS OP_FUN(OPC_FLTI, 0x03c)
#define FLTI_FUNC_CVTQT OP_FUN(OPC_FLTI, 0x03e)
#define FLTI_FUNC_DIVS OP_FUN(OPC_FLTI, 0x003)
#define FLTI_FUNC_DIVT OP_FUN(OPC_FLTI, 0x023)
#define FLTI_FUNC_MULS OP_FUN(OPC_FLTI, 0x002)
#define FLTI_FUNC_MULT OP_FUN(OPC_FLTI, 0x022)
#define FLTI_FUNC_SUBS OP_FUN(OPC_FLTI, 0x001)
#define FLTI_FUNC_SUBT OP_FUN(OPC_FLTI, 0x021)
#define FLTC_FUNC_SQRTS OP_FUN(OPC_FLTC, 0x00B)
#define FLTC_FUNC_SQRTT OP_FUN(OPC_FLTC, 0x02B)
#define FLTL_FUNC_CVTQL OP_FUN(OPC_FLTL, 0x030)
#define MISC_TRAPB 0x0000
#define MISC_EXCB 0x0400
......@@ -101,7 +106,7 @@ void cleanup_module(void)
long
alpha_fp_emul (unsigned long pc)
{
unsigned long opcode, fa, fb, fc, func, mode;
unsigned long op_fun, fa, fb, fc, func, mode;
unsigned long fpcw = current->tss.flags;
unsigned long va, vb, vc, res, fpcr;
__u32 insn;
......@@ -110,10 +115,11 @@ alpha_fp_emul (unsigned long pc)
get_user(insn, (__u32*)pc);
fc = (insn >> 0) & 0x1f; /* destination register */
func = (insn >> 5) & 0x7ff;
fb = (insn >> 16) & 0x1f;
fa = (insn >> 21) & 0x1f;
opcode = insn >> 26;
func = (insn >> 5) & 0x7ff;
mode = (insn >> 5) & 0xc0;
op_fun = insn & OP_FUN(0x3f, 0x3f);
va = alpha_read_fp_reg(fa);
vb = alpha_read_fp_reg(fb);
......@@ -123,7 +129,6 @@ alpha_fp_emul (unsigned long pc)
* Try the operation in software. First, obtain the rounding
* mode...
*/
mode = func & 0xc0;
if (mode == 0xc0) {
/* dynamic---get rounding mode from fpcr: */
mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT;
......@@ -135,8 +140,7 @@ alpha_fp_emul (unsigned long pc)
something_is_wrong();
}
/* least 6 bits contain operation code: */
switch (func & 0x3f) {
switch (op_fun) {
case FLTI_FUNC_CMPTEQ:
res = ieee_CMPTEQ(va, vb, &vc);
break;
......@@ -153,7 +157,7 @@ alpha_fp_emul (unsigned long pc)
res = ieee_CMPTUN(va, vb, &vc);
break;
case FLTI_FUNC_CVTQL:
case FLTL_FUNC_CVTQL:
/*
* Notice: We can get here only due to an integer
* overflow. Such overflows are reported as invalid
......@@ -222,6 +226,14 @@ alpha_fp_emul (unsigned long pc)
res = ieee_CVTTQ(mode, vb, &vc);
break;
case FLTC_FUNC_SQRTS:
res = ieee_SQRTS(mode, vb, &vc);
break;
case FLTC_FUNC_SQRTT:
res = ieee_SQRTT(mode, vb, &vc);
break;
default:
printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
func & 0x3f, pc);
......@@ -247,7 +259,7 @@ alpha_fp_emul (unsigned long pc)
/* Update hardware control register */
fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16);
fpcr |= ieee_swcr_to_fpcr(fpcw);
wrfpcr(fpcr);
/* Do we generate a signal? */
......@@ -319,6 +331,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
write_mask &= ~(1UL << rc);
break;
case OPC_FLTC:
case OPC_FLTV:
case OPC_FLTI:
case OPC_FLTL:
......@@ -326,13 +339,11 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
break;
}
if (!write_mask) {
if ((opcode == OPC_FLTI || opcode == OPC_FLTL)
&& alpha_fp_emul(trigger_pc))
{
/* re-execute insns in trap-shadow: */
regs->pc = trigger_pc + 4;
MOD_DEC_USE_COUNT;
return 1;
if (alpha_fp_emul(trigger_pc)) {
/* re-execute insns in trap-shadow: */
regs->pc = trigger_pc + 4;
MOD_DEC_USE_COUNT;
return 1;
}
break;
}
......
......@@ -22,6 +22,7 @@
* functions are used on exceptional numbers only (well, assuming you
* don't turn on the "trap on inexact"...).
*/
#include <linux/sched.h>
#include "ieee-math.h"
#define STICKY_S 0x20000000 /* both in longword 0 of fraction */
......@@ -1340,3 +1341,41 @@ ieee_DIVT (int f, unsigned long a, unsigned long b, unsigned long *c)
op_c.e -= 9; /* remove excess exp from original shift */
return round_t_ieee(f, &op_c, c);
}
/*
* Sqrt a = b, where a and b are ieee s-floating numbers. "f"
* contains the rounding mode etc.
*/
unsigned long
ieee_SQRTS (int f, unsigned long a, unsigned long *b)
{
fpclass_t a_type;
EXTENDED op_a, op_b;
*b = IEEE_QNaN;
a_type = extend_ieee(a, &op_a, SINGLE);
if (op_a.s == 0) {
/* FIXME -- handle positive denormals. */
send_sig(SIGFPE, current, 1);
}
return FPCR_INV;
}
/*
* Sqrt a = b, where a and b are ieee t-floating numbers. "f"
* contains the rounding mode etc.
*/
unsigned long
ieee_SQRTT (int f, unsigned long a, unsigned long *b)
{
fpclass_t a_type;
EXTENDED op_a, op_b;
*b = IEEE_QNaN;
a_type = extend_ieee(a, &op_a, DOUBLE);
if (op_a.s == 0) {
/* FIXME -- handle positive denormals. */
send_sig(SIGFPE, current, 1);
}
return FPCR_INV;
}
......@@ -48,5 +48,7 @@ extern unsigned long ieee_DIVS (int rm, unsigned long a, unsigned long b,
unsigned long *c);
extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b,
unsigned long *c);
extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b);
extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b);
#endif /* __ieee_math_h__ */
......@@ -92,7 +92,7 @@ EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(mtrr_hook);
EXPORT_SYMBOL(smp_call_function);
#endif
#ifdef CONFIG_MCA
......
......@@ -322,7 +322,7 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_INTERRUPT(mtrr_interrupt)
BUILD_SMP_INTERRUPT(call_function_interrupt)
BUILD_SMP_INTERRUPT(spurious_interrupt)
/*
......@@ -1094,8 +1094,8 @@ __initfunc(void init_IRQ(void))
/* self generated IPI for local APIC timer */
set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
/* IPI for MTRR control */
set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
/* IPI for generic function call */
set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
/* IPI vector for APIC spurious interrupts */
set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
......
......@@ -65,7 +65,7 @@ typedef struct {
#define INVALIDATE_TLB_VECTOR 0x31
#define STOP_CPU_VECTOR 0x40
#define LOCAL_TIMER_VECTOR 0x41
#define MTRR_CHANGE_VECTOR 0x50
#define CALL_FUNCTION_VECTOR 0x50
/*
* First APIC vector available to drivers: (vectors 0x51-0xfe)
......@@ -99,7 +99,6 @@ extern void disable_8259A_irq(unsigned int irq);
extern int i8259A_irq_pending(unsigned int irq);
extern void ack_APIC_irq(void);
extern void FASTCALL(send_IPI_self(int vector));
extern void smp_send_mtrr(void);
extern void init_VISWS_APIC_irqs(void);
extern void setup_IO_APIC(void);
extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
......
This diff is collapsed.
......@@ -5,6 +5,10 @@
*
* Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
* and Martin Mares, November 1997.
*
* Force Cyrix 6x86(MX) and M II processors to report MTRR capability
* and fix against Cyrix "coma bug" by
* Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
*/
/*
......@@ -395,6 +399,14 @@ __initfunc(static int get_model_name(struct cpuinfo_x86 *c))
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
/* Set MTRR capability flag if appropriate */
if(boot_cpu_data.x86 !=5)
return 1;
if((boot_cpu_data.x86_model == 9) ||
((boot_cpu_data.x86_model == 8) &&
(boot_cpu_data.x86_mask >= 8)))
c->x86_capability |= X86_FEATURE_MTRR;
return 1;
}
......@@ -574,6 +586,10 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
(c->x86_model)++;
} else /* 686 */
p = Cx86_cb+1;
/* Emulate MTRRs using Cyrix's ARRs. */
c->x86_capability |= X86_FEATURE_MTRR;
/* 6x86's contain this bug */
c->coma_bug = 1;
break;
case 4: /* MediaGX/GXm */
......@@ -598,11 +614,14 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
case 5: /* 6x86MX/M II */
if (dir1 > 7) dir0_msn++; /* M II */
else c->coma_bug = 1; /* 6x86MX, it has the bug. */
tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
p = Cx86_cb+tmp;
if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
(c->x86_model)++;
/* Emulate MTRRs using Cyrix's ARRs. */
c->x86_capability |= X86_FEATURE_MTRR;
break;
case 0xf: /* Cyrix 486 without DEVID registers */
......@@ -856,7 +875,7 @@ int get_cpuinfo(char * buffer)
int sep_bug;
static char *x86_cap_flags[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
"cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
"cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov",
"16", "17", "psn", "19", "20", "21", "22", "mmx",
"24", "kni", "26", "27", "28", "29", "30", "31"
};
......@@ -904,7 +923,6 @@ int get_cpuinfo(char * buffer)
} else if (c->x86_vendor == X86_VENDOR_INTEL) {
x86_cap_flags[6] = "pae";
x86_cap_flags[9] = "apic";
x86_cap_flags[12] = "mtrr";
x86_cap_flags[14] = "mca";
x86_cap_flags[16] = "pat";
x86_cap_flags[17] = "pse36";
......@@ -923,6 +941,7 @@ int get_cpuinfo(char * buffer)
"hlt_bug\t\t: %s\n"
"sep_bug\t\t: %s\n"
"f00f_bug\t: %s\n"
"coma_bug\t: %s\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
"cpuid level\t: %d\n"
......@@ -932,6 +951,7 @@ int get_cpuinfo(char * buffer)
c->hlt_works_ok ? "no" : "yes",
sep_bug ? "yes" : "no",
c->f00f_bug ? "yes" : "no",
c->coma_bug ? "yes" : "no",
c->hard_math ? "yes" : "no",
(c->hard_math && ignore_irq13) ? "yes" : "no",
c->cpuid_level,
......
......@@ -44,6 +44,8 @@
#include "irq.h"
#define JIFFIE_TIMEOUT 100
extern void update_one_process( struct task_struct *p,
unsigned long ticks, unsigned long user,
unsigned long system, int cpu);
......@@ -1651,15 +1653,84 @@ void smp_send_stop(void)
send_IPI_allbutself(STOP_CPU_VECTOR);
}
/* Structure and data for smp_call_function(). This is designed to minimise
* static memory requirements. It also looks cleaner.
*/
struct smp_call_function_struct {
void (*func) (void *info);
void *info;
atomic_t unstarted_count;
atomic_t unfinished_count;
int wait;
};
static volatile struct smp_call_function_struct *smp_call_function_data = NULL;
/*
* this function sends an 'reload MTRR state' IPI to all other CPUs
* in the system. it goes straight through, completion processing
* is done on the mttr.c level.
* this function sends a 'generic call function' IPI to all other CPUs
* in the system.
*/
void smp_send_mtrr(void)
int smp_call_function (void (*func) (void *info), void *info, int retry,
int wait)
/* [SUMMARY] Run a function on all other CPUs.
<func> The function to run. This must be fast and non-blocking.
<info> An arbitrary pointer to pass to the function.
<retry> If true, keep retrying until ready.
<wait> If true, wait until function has completed on other CPUs.
[RETURNS] 0 on success, else a negative status code. Does not return until
remote CPUs are nearly ready to execute <<func>> or are or have executed.
*/
{
send_IPI_allbutself(MTRR_CHANGE_VECTOR);
unsigned long timeout;
struct smp_call_function_struct data;
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
if (retry) {
while (1) {
if (smp_call_function_data) {
schedule (); /* Give a mate a go */
continue;
}
spin_lock (&lock);
if (smp_call_function_data) {
spin_unlock (&lock); /* Bad luck */
continue;
}
/* Mine, all mine! */
break;
}
}
else {
if (smp_call_function_data) return -EBUSY;
spin_lock (&lock);
if (smp_call_function_data) {
spin_unlock (&lock);
return -EBUSY;
}
}
smp_call_function_data = &data;
spin_unlock (&lock);
data.func = func;
data.info = info;
atomic_set (&data.unstarted_count, smp_num_cpus - 1);
data.wait = wait;
if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1);
/* Send a message to all other CPUs and wait for them to respond */
send_IPI_allbutself (CALL_FUNCTION_VECTOR);
/* Wait for response */
timeout = jiffies + JIFFIE_TIMEOUT;
while ( (atomic_read (&data.unstarted_count) > 0) &&
time_before (jiffies, timeout) )
barrier ();
if (atomic_read (&data.unstarted_count) > 0) {
smp_call_function_data = NULL;
return -ETIMEDOUT;
}
if (wait)
while (atomic_read (&data.unfinished_count) > 0)
barrier ();
smp_call_function_data = NULL;
return 0;
}
/*
......@@ -1798,12 +1869,19 @@ asmlinkage void smp_stop_cpu_interrupt(void)
stop_this_cpu();
}
void (*mtrr_hook) (void) = NULL;
asmlinkage void smp_mtrr_interrupt(void)
asmlinkage void smp_call_function_interrupt(void)
{
ack_APIC_irq();
if (mtrr_hook) (*mtrr_hook)();
void (*func) (void *info) = smp_call_function_data->func;
void *info = smp_call_function_data->info;
int wait = smp_call_function_data->wait;
ack_APIC_irq ();
/* Notify initiating CPU that I've grabbed the data and am about to
execute the function */
atomic_dec (&smp_call_function_data->unstarted_count);
/* At this point the structure may be out of scope unless wait==1 */
(*func) (info);
if (wait) atomic_dec (&smp_call_function_data->unfinished_count);
}
/*
......
......@@ -47,7 +47,11 @@ endif
ifeq ($(CONFIG_USB),y)
SUB_DIRS += usb
MOD_SUB_DIRS += usb
endif
else
ifeq ($(CONFIG_USB),m)
MOD_SUB_DIRS += usb
endif
endif
# If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
# but some of the low-level things may also be modules.
......
......@@ -202,9 +202,7 @@ struct lp_struct lp_table[LP_NO] =
/* Test if the printer is not acking the strobe */
#define LP_NO_ACKING(status) ((status) & LP_PACK)
/* Test if the printer has error conditions */
#define LP_NO_ERROR(status) \
(((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
(LP_PSELECD|LP_PERRORP))
#define LP_NO_ERROR(status) ((status) & LP_PERRORP)
#undef LP_DEBUG
#undef LP_READ_DEBUG
......@@ -424,7 +422,10 @@ static int lp_check_status(int minor)
{
unsigned int last = lp_table[minor].last_error;
unsigned char status = r_str(minor);
if ((status & LP_POUTPA)) {
if (status & LP_PERRORP)
/* No error. */
last = 0;
else if ((status & LP_POUTPA)) {
if (last != LP_POUTPA) {
last = LP_POUTPA;
printk(KERN_INFO "lp%d out of paper\n", minor);
......@@ -434,13 +435,12 @@ static int lp_check_status(int minor)
last = LP_PSELECD;
printk(KERN_INFO "lp%d off-line\n", minor);
}
} else if (!(status & LP_PERRORP)) {
} else {
if (last != LP_PERRORP) {
last = LP_PERRORP;
printk(KERN_INFO "lp%d on fire!\n", minor);
printk(KERN_INFO "lp%d on fire\n", minor);
}
}
else last = 0;
lp_table[minor].last_error = last;
......
......@@ -57,7 +57,10 @@ int uhci_init(void);
#ifdef CONFIG_USB_OHCI
int ohci_init(void);
#endif
#ifdef CONFIG_USB_OHCI_HCD
int ohci_hcd_init(void);
#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
const char * buf, size_t count, loff_t *ppos)
{
......@@ -612,6 +615,9 @@ __initfunc(int chr_dev_init(void))
#ifdef CONFIG_USB_OHCI
ohci_init();
#endif
#ifdef CONFIG_USB_OHCI_HCD
ohci_hcd_init();
#endif
#endif
#if defined (CONFIG_FB)
fbmem_init();
......
......@@ -29,7 +29,6 @@
/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
#include <linux/config.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/errno.h>
......
......@@ -48,25 +48,22 @@ int parport_wait_peripheral(struct parport *port, unsigned char mask,
int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode)
{
/* make sure it's a valid state, set nStrobe & nAutoFeed high */
parport_write_control(port, (parport_read_control(port) \
& ~1 ) & ~2);
parport_frob_control (port, (1|2), 0);
udelay(1);
parport_write_data(port, mode);
udelay(400);
/* nSelectIn high, nAutoFd low */
parport_write_control(port, (parport_read_control(port) & ~8) | 2);
parport_frob_control(port, (2|8), 2);
if (parport_wait_peripheral(port, 0x78, 0x38)) {
parport_write_control(port,
(parport_read_control(port) & ~2) | 8);
parport_frob_control(port, (2|8), 8);
return 0;
}
/* nStrobe low */
parport_write_control(port, parport_read_control(port) | 1);
parport_frob_control (port, 1, 1);
udelay(1); /* Strobe wait */
/* nStrobe high, nAutoFeed low, last step before transferring
* reverse data */
parport_write_control(port, (parport_read_control(port) \
& ~1) & ~2);
parport_frob_control (port, (1|2), 0);
udelay(1);
/* Data available? */
parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
......
......@@ -53,6 +53,8 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
static int user_specified = 0;
static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
parport_generic_irq(irq, (struct parport *) dev_id, regs);
......@@ -103,19 +105,24 @@ unsigned char parport_pc_read_data(struct parport *p)
void parport_pc_write_control(struct parport *p, unsigned char d)
{
struct parport_pc_private *priv = p->private_data;
priv->ctr = d;/* update soft copy */
outb(d, p->base+CONTROL);
}
unsigned char parport_pc_read_control(struct parport *p)
{
return inb(p->base+CONTROL);
struct parport_pc_private *priv = p->private_data;
return priv->ctr;
}
unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
unsigned char old = inb(p->base+CONTROL);
outb(((old & ~mask) ^ val), p->base+CONTROL);
return old;
struct parport_pc_private *priv = p->private_data;
unsigned char ctr = priv->ctr;
ctr = (ctr & ~mask) ^ val;
outb (ctr, p->base+CONTROL);
return priv->ctr = ctr; /* update soft copy */
}
void parport_pc_write_status(struct parport *p, unsigned char d)
......@@ -345,6 +352,8 @@ int parport_pc_epp_clear_timeout(struct parport *pb)
*/
static int parport_SPP_supported(struct parport *pb)
{
unsigned char r, w;
/*
* first clear an eventually pending EPP timeout
* I (sailer@ife.ee.ethz.ch) have an SMSC chipset
......@@ -354,14 +363,54 @@ static int parport_SPP_supported(struct parport *pb)
parport_pc_epp_clear_timeout(pb);
/* Do a simple read-write test to make sure the port exists. */
parport_pc_write_control(pb, 0xc);
parport_pc_write_data(pb, 0xaa);
if (parport_pc_read_data(pb) != 0xaa) return 0;
parport_pc_write_data(pb, 0x55);
if (parport_pc_read_data(pb) != 0x55) return 0;
w = 0xc;
parport_pc_write_control(pb, w);
/* Can we read from the control register? Some ports don't
* allow reads, so read_control just returns a software
* copy. Some ports _do_ allow reads, so bypass the software
* copy here. In addition, some bits aren't writable. */
r = inb (pb->base+CONTROL);
if ((r & 0x3f) == w) {
w = 0xe;
parport_pc_write_control (pb, w);
r = inb (pb->base+CONTROL);
parport_pc_write_control (pb, 0xc);
if ((r & 0x3f) == w)
return PARPORT_MODE_PCSPP;
}
return PARPORT_MODE_PCSPP;
if (user_specified)
/* That didn't work, but the user thinks there's a
* port here. */
printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
pb->base, w, r);
/* Try the data register. The data lines aren't tri-stated at
* this stage, so we expect back what we wrote. */
w = 0xaa;
parport_pc_write_data (pb, w);
r = parport_pc_read_data (pb);
if (r == w) {
w = 0x55;
parport_pc_write_data (pb, w);
r = parport_pc_read_data (pb);
if (r == w)
return PARPORT_MODE_PCSPP;
}
if (user_specified)
/* Didn't work with 0xaa, but the user is convinced
* this is the place. */
printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
pb->base, w, r);
/* It's possible that we can't read the control register or
the data register. In that case just believe the user. */
if (user_specified)
return PARPORT_MODE_PCSPP;
return 0;
}
/* Check for ECP
......@@ -712,6 +761,15 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
if (check_region(base, 3)) return 0;
if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
return 0;
p->private_data = kmalloc (sizeof (struct parport_pc_private),
GFP_KERNEL);
if (!p->private_data) {
/* Not enough memory. */
printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
parport_unregister_port (p);
return 0;
}
((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
if (p->base != 0x3bc) {
if (!check_region(base+0x400,3)) {
p->modes |= parport_ECR_present(p);
......@@ -725,6 +783,7 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
}
if (!parport_SPP_supported(p)) {
/* No port. */
kfree (p->private_data);
parport_unregister_port (p);
return 0;
}
......@@ -787,6 +846,7 @@ int parport_pc_init(int *io, int *irq, int *dma)
int count = 0, i = 0;
if (io && *io) {
/* Only probe the ports we were given. */
user_specified = 1;
do {
count += probe_one_port(*(io++), *(irq++), *(dma++));
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
......@@ -829,6 +889,7 @@ void cleanup_module(void)
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
parport_proc_unregister(p);
kfree (p->private_data);
parport_unregister_port(p);
}
p = tmp;
......
......@@ -98,6 +98,7 @@ __initfunc(int ethertap_probe(struct device *dev))
ether_setup(dev);
dev->hard_header_len = 16;
dev->tx_queue_len = 0;
dev->flags|=IFF_NOARP;
tap_map[dev->base_addr]=dev;
......
......@@ -16,6 +16,10 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ ! "$CONFIG_USB" = "n" ]; then
bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
fi
bool 'USB mouse support' CONFIG_USB_MOUSE
bool 'USB keyboard support' CONFIG_USB_KBD
......
......@@ -59,7 +59,17 @@ ifeq ($(CONFIG_USB_OHCI),y)
endif
endif
ifeq ($(CONFIG_USB_OHCI_HCD),y)
ifeq ($(CONFIG_USB), y)
L_OBJS += ohci-hcd.o ohci-root-hub.o
else
ifeq ($(CONFIG_USB),m)
USBO_OBJS += ohci-hcd.o ohci-root-hub.o
M_OBJS += usb-ohci-hcd.o
MIX_OBJS += $(USBX_OBJS)
endif
endif
endif
include $(TOPDIR)/Rules.make
keymap.o: keymap.c
......@@ -73,3 +83,6 @@ usb-uhci.o: uhci.o uhci-debug.o $(USBX_OBJS)
usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS)
$(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS)
usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
The OHCI HCD layer is a simple but nearly complete implementation of what the
USB people would call a HCD for the OHCI.
(ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers.
- Roman Weissgaerber <weissg@vienna.at>
* v2.1 1999/05/09 ep_addr correction, code cleanup
* v0.2.0 1999/05/04
* everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
* virtual root hub is now an option,
* memory allocation based on kmalloc and kfree now, simple Bus error handling,
* INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
*
* from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
* from Greg Smith (ohci.c): better reset ohci-controller handling, hub
*
* v0.1.0 1999/04/27 initial release
to remove the module try:
killall root-hub
:
rmmod usb-ohci-hcd
Features:
- virtual root hub, all basic hub descriptors and commands (state: complete)
this is an option now (v0.2.0)
#define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
default is without.
(at the moment: the Virtual Root Hub option is not recommended)
files: ohci-root-hub.c, ohci-root-hub.h
- Endpoint Descriptor (ED) handling more static approach
(EDs should be allocated in parallel to the SET CONFIGURATION command and they live
as long as the function (device) is alive or another configuration is choosen.
In the HCD layer the EDs has to be allocated manually either by calling a subroutine
or by sending a USB root hub vendor specific command to the virtual root hub.
At the alternate linux usb stack EDs will be added (allocated) at their first use.
files: ohci-hcd.c ohci-hcd.h
routines: (do not use for drivers, use the top layer alternate usb commands instead)
int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1,
int interval, int load, f_handler handler, int ep_size, int speed)
adds an endpoint, (if the endpoint already exists some parameters will be updated)
int usb_ohci_rm_ep(struct usb_ohci_ed *ed, struct ohci * ohci)
removes an endpoint and all pending TDs of that EP
usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr)
removes all Endpoints of a function (device)
- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
to take care of buffer allocation.
files: ohci-hcd.c ohci-hcd.h
There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
CTRL: ctrl, ctrl_len ... cmd buffer
data, data_len ... data buffer (in or out)
INT, BULK: ctrl = NULL, ctrl_len=0,
data, data_len ... data buffer (in or out)
ISO: tbd
There is no buffer reinsertion done by the internal HCD function.
(The interface layer does this for a INT-pipe on request.)
If you want a transfer then you have to
provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
you can send as many as you like. They should come back by the callback f_handler in
the same order (for each endpoint, not globally) If an error occurs all
queued transfers of an endpoint will return unsent. They will be marked with an error status.
e.g double-buffering for int transfers:
ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
and when a data0 packet returns by the callback f_handler requeue it:
ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
and when a data1 packet returns by the callback f_handler requeue it:
ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
The alternate usb uses them for dev_id and usb_device_irq handler.
- Done list handling: returns the requests (callback f_handler in ED) and does
some error handling, root-hub request dequeuing
(files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
ep_addr union or int is for addressing devices&endpoints:
__u8 ep_addr.bep.ep ... bit 3..0 endpoint address
bit 4 0
bit 6,5 type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO
bit 7 direction 1 IN, 0 OUT
__u8 ep_addr.bep.fa ... bit 6..0 function address
bit 7 0
(__u8 ep_addr.bep.hc ... host controller nr) not used
(__u8 ep_addr.bep.host ... host nr) not used
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* HCD (OHCI) Virtual Root Hub Protocol for USB.
*
* (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
*
* The Root Hub is build into the HC (UHCI or OHCI) hardware.
* This piece of code lets it look like it resides on the bus
* like the other hubs.
* (for anyone who wants to do a control operation on the root hub)
*
* v1.0 1999/04/27
* ohci-root-hub.h
*
*/
/* destination of request */
#define RH_INTERFACE 0x01
#define RH_ENDPOINT 0x02
#define RH_OTHER 0x03
#define RH_CLASS 0x20
#define RH_VENDOR 0x40
/* Requests: bRequest << 8 | bmRequestType */
#define RH_GET_STATUS 0x0080
#define RH_CLEAR_FEATURE 0x0100
#define RH_SET_FEATURE 0x0300
#define RH_SET_ADDRESS 0x0500
#define RH_GET_DESCRIPTOR 0x0680
#define RH_SET_DESCRIPTOR 0x0700
#define RH_GET_CONFIGURATION 0x0880
#define RH_SET_CONFIGURATION 0x0900
#define RH_GET_STATE 0x0280
#define RH_GET_INTERFACE 0x0A80
#define RH_SET_INTERFACE 0x0B00
#define RH_SYNC_FRAME 0x0C80
/* Our Vendor Specific Request */
#define RH_SET_EP 0x2000
/* Hub port features */
#define RH_PORT_CONNECTION 0x00
#define RH_PORT_ENABLE 0x01
#define RH_PORT_SUSPEND 0x02
#define RH_PORT_OVER_CURRENT 0x03
#define RH_PORT_RESET 0x04
#define RH_PORT_POWER 0x08
#define RH_PORT_LOW_SPEED 0x09
#define RH_C_PORT_CONNECTION 0x10
#define RH_C_PORT_ENABLE 0x11
#define RH_C_PORT_SUSPEND 0x12
#define RH_C_PORT_OVER_CURRENT 0x13
#define RH_C_PORT_RESET 0x14
/* Hub features */
#define RH_C_HUB_LOCAL_POWER 0x00
#define RH_C_HUB_OVER_CURRENT 0x01
#define RH_DEVICE_REMOTE_WAKEUP 0x00
#define RH_ENDPOINT_STALL 0x01
/* Our Vendor Specific feature */
#define RH_REMOVE_EP 0x00
#define RH_ACK 0x01
#define RH_REQ_ERR -1
#define RH_NACK 0x00
#define min(a,b) (((a)<(b))?(a):(b))
......@@ -9,7 +9,7 @@
static __inline__ void wait_ms(unsigned int ms)
{
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(1 + ms / 10);
schedule_timeout(1 + ms * HZ / 1000);
}
......
......@@ -635,10 +635,8 @@ __initfunc(void vesafb_init(void))
video_cmap_len = 256;
}
request_region(0x3c0, 32, "vga+");
#ifdef CONFIG_MTRR
if (mtrr)
mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1);
#endif
strcpy(fb_info.modename, "VESA VGA");
fb_info.changevar = NULL;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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