diff -u --recursive --new-file v2.3.44/linux/CREDITS linux/CREDITS --- v2.3.44/linux/CREDITS Thu Feb 10 17:11:01 2000 +++ linux/CREDITS Sun Feb 13 18:21:45 2000 @@ -637,13 +637,6 @@ S: S-114 53 Stockholm S: Sweden -N: Stephane Eranian -E: eranian@hpl.hp.com -D: Linux/ia64 -S: 1501 Page Mill Rd, MS 1U17 -S: Palo Alto, CA 94304 -S: USA - N: Paal-Kristian Engstad E: engstad@intermetrics.com D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) @@ -651,6 +644,13 @@ S: Huntington Beach, California 92649 S: USA +N: Stephane Eranian +E: eranian@hpl.hp.com +D: Linux/ia64 +S: 1501 Page Mill Rd, MS 1U17 +S: Palo Alto, CA 94304 +S: USA + N: Johannes Erdfelt E: jerdfelt@valinux.com D: Linux/IA-64 bootloader and kernel goop, USB @@ -1832,17 +1832,17 @@ S: 13349 Berlin S: Germany -N: Nicolas Pitre -E: nico@cam.org -D: StrongARM SA1100 support integrator & hacker -S: Montreal, Quebec, Canada - N: Emanuel Pirker E: epirker@edu.uni-klu.ac.at D: AIC5800 IEEE 1394, RAW I/O on 1394 D: Starter of Linux1394 effort S: ask per mail for current address +N: Nicolas Pitre +E: nico@cam.org +D: StrongARM SA1100 support integrator & hacker +S: Montreal, Quebec, Canada + N: Ken Pizzini E: ken@halcyon.com D: CDROM driver "sonycd535" (Sony CDU-535/531) @@ -2613,13 +2613,6 @@ S: 3078 Sulphur Spring Court S: San Jose, California 95148 S: USA - -N: Alessandro Zummo -E: azummo@ita.flashnet.it -W: http://freepage.logicom.it/azummo/ -D: CMI8330 support is sb_card.c -D: ISAPnP fixes in sb_card.c -S: Italy N: Alessandro Zummo E: azummo@ita.flashnet.it diff -u --recursive --new-file v2.3.44/linux/Makefile linux/Makefile --- v2.3.44/linux/Makefile Sat Feb 12 11:22:10 2000 +++ linux/Makefile Sat Feb 12 11:22:20 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 44 +SUBLEVEL = 45 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.3.44/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.3.44/linux/arch/alpha/kernel/pci_iommu.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/pci_iommu.c Sun Feb 13 10:15:21 2000 @@ -16,7 +16,6 @@ #define DEBUG_ALLOC 0 - #if DEBUG_ALLOC > 0 # define DBGA(args...) printk(KERN_DEBUG ##args) #else @@ -40,6 +39,20 @@ { return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; } + +static inline long +calc_order(long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} struct pci_iommu_arena * iommu_arena_new(dma_addr_t base, unsigned long window_size, @@ -173,10 +186,6 @@ ret = arena->dma_base + dma_ofs * PAGE_SIZE; ret += (unsigned long)cpu_addr & ~PAGE_MASK; - /* ??? This shouldn't have been needed, since the entries - we've just modified were not in the iommu tlb. */ - alpha_mv.mv_pci_tbi(hose, ret, ret + size - 1); - DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n", cpu_addr, size, npages, ret, __builtin_return_address(0)); @@ -239,11 +248,12 @@ pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp) { void *cpu_addr; + long order = calc_order(size); - cpu_addr = kmalloc(size, GFP_ATOMIC); + cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order); if (! cpu_addr) { - printk(KERN_INFO "dma_alloc_consistent: " - "kmalloc failed from %p\n", + printk(KERN_INFO "pci_alloc_consistent: " + "get_free_pages failed from %p\n", __builtin_return_address(0)); /* ??? Really atomic allocation? Otherwise we could play with vmalloc and sg if we can't find contiguous memory. */ @@ -253,11 +263,11 @@ *dma_addrp = pci_map_single(pdev, cpu_addr, size); if (*dma_addrp == 0) { - kfree_s(cpu_addr, size); + free_pages((unsigned long)cpu_addr, order); return NULL; } - DBGA2("dma_alloc_consistent: %lx -> [%p,%x] from %p\n", + DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n", size, cpu_addr, *dma_addrp, __builtin_return_address(0)); return cpu_addr; @@ -275,32 +285,33 @@ dma_addr_t dma_addr) { pci_unmap_single(pdev, dma_addr, size); - kfree_s(cpu_addr, size); + free_pages((unsigned long)cpu_addr, calc_order(size)); - DBGA2("dma_free_consistent: [%x,%lx] from %p\n", + DBGA2("pci_free_consistent: [%x,%lx] from %p\n", dma_addr, size, __builtin_return_address(0)); } /* Classify the elements of the scatterlist. Write dma_address of each element with: - 0 : Not mergable. - 1 : Followers all physically adjacent. - [23]: Followers all virtually adjacent. - -1 : Not leader. + 0 : Followers all physically adjacent. + 1 : Followers all virtually adjacent. + -1 : Not leader, physically adjacent to previous. + -2 : Not leader, virtually adjacent to previous. Write dma_length of each leader with the combined lengths of the mergable followers. */ static inline void -sg_classify(struct scatterlist *sg, struct scatterlist *end) +sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok) { unsigned long next_vaddr; struct scatterlist *leader; + long leader_flag, leader_length; leader = sg; - leader->dma_address = 0; - leader->dma_length = leader->length; - next_vaddr = (unsigned long)leader->address + leader->length; + leader_flag = 0; + leader_length = leader->length; + next_vaddr = (unsigned long)leader->address + leader_length; for (++sg; sg < end; ++sg) { unsigned long addr, len; @@ -309,20 +320,24 @@ if (next_vaddr == addr) { sg->dma_address = -1; - leader->dma_address |= 1; - leader->dma_length += len; - } else if (((next_vaddr | addr) & ~PAGE_MASK) == 0) { - sg->dma_address = -1; - leader->dma_address |= 2; - leader->dma_length += len; + leader_length += len; + } else if (((next_vaddr | addr) & ~PAGE_MASK) == 0 && virt_ok) { + sg->dma_address = -2; + leader_flag = 1; + leader_length += len; } else { + leader->dma_address = leader_flag; + leader->dma_length = leader_length; leader = sg; - leader->dma_address = 0; - leader->dma_length = len; + leader_flag = 0; + leader_length = len; } next_vaddr = addr + len; } + + leader->dma_address = leader_flag; + leader->dma_length = leader_length; } /* Given a scatterlist leader, choose an allocation method and fill @@ -334,21 +349,21 @@ dma_addr_t max_dma) { unsigned long paddr = virt_to_phys(leader->address); - unsigned long size = leader->dma_length; + long size = leader->dma_length; struct scatterlist *sg; unsigned long *ptes; long npages, dma_ofs, i; /* If everything is physically contiguous, and the addresses fall into the direct-map window, use it. */ - if (leader->dma_address < 2 + if (leader->dma_address == 0 && paddr + size + __direct_map_base - 1 <= max_dma && paddr + size <= __direct_map_size) { out->dma_address = paddr + __direct_map_base; out->dma_length = size; - DBGA2("sg_fill: [%p,%lx] -> direct %x\n", - leader->address, size, out->dma_address); + DBGA(" sg_fill: [%p,%lx] -> direct %x\n", + leader->address, size, out->dma_address); return 0; } @@ -365,48 +380,70 @@ out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr; out->dma_length = size; - DBGA("sg_fill: [%p,%lx] -> sg %x\n", - leader->address, size, out->dma_address); + DBGA(" sg_fill: [%p,%lx] -> sg %x np %ld\n", + leader->address, size, out->dma_address, npages); ptes = &arena->ptes[dma_ofs]; sg = leader; - do { - paddr = virt_to_phys(sg->address); - npages = calc_npages((paddr & ~PAGE_MASK) + sg->length); - - DBGA(" (%ld) [%p,%x]\n", - sg - leader, sg->address, sg->length); + if (0 && leader->dma_address == 0) { + /* All physically contiguous. We already have the + length, all we need is to fill in the ptes. */ - paddr &= PAGE_MASK; + paddr = virt_to_phys(sg->address) & PAGE_MASK; for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) *ptes++ = mk_iommu_pte(paddr); - ++sg; - } while (sg < end && sg->dma_address == -1); +#if DEBUG_ALLOC > 0 + DBGA(" (0) [%p,%x] np %ld\n", + sg->address, sg->length, npages); + for (++sg; sg < end && (int) sg->dma_address < 0; ++sg) + DBGA(" (%ld) [%p,%x] cont\n", + sg - leader, sg->address, sg->length); +#endif + } else { + /* All virtually contiguous. We need to find the + length of each physically contiguous subsegment + to fill in the ptes. */ + do { + struct scatterlist *last_sg = sg; + + size = sg->length; + paddr = virt_to_phys(sg->address); + + while (sg+1 < end && (int) sg[1].dma_address == -1) { + size += sg[1].length; + sg++; + } + + npages = calc_npages((paddr & ~PAGE_MASK) + size); + + paddr &= PAGE_MASK; + for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) + *ptes++ = mk_iommu_pte(paddr); + +#if DEBUG_ALLOC > 0 + DBGA(" (%ld) [%p,%x] np %ld\n", + last_sg - leader, last_sg->address, + last_sg->length, npages); + while (++last_sg <= sg) { + DBGA(" (%ld) [%p,%x] cont\n", + last_sg - leader, last_sg->address, + last_sg->length); + } +#endif + } while (++sg < end && (int) sg->dma_address < 0); + } return 1; } -/* TODO: Only use the iommu when it helps. Non-mergable scatterlist - entries might as well use direct mappings. */ - int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents) { struct scatterlist *start, *end, *out; struct pci_controler *hose; struct pci_iommu_arena *arena; - dma_addr_t max_dma, fstart, fend; - - /* If pci_tbi is not available, we must not be able to control - an iommu. Direct map everything, no merging. */ - if (! alpha_mv.mv_pci_tbi) { - for (end = sg + nents; sg < end; ++sg) { - sg->dma_address = virt_to_bus(sg->address); - sg->dma_length = sg->length; - } - return nents; - } + dma_addr_t max_dma; /* Fast path single entry scatterlists. */ if (nents == 1) { @@ -416,50 +453,42 @@ return sg->dma_address != 0; } - hose = pdev ? pdev->sysdata : pci_isa_hose; - max_dma = pdev ? pdev->dma_mask : 0x00ffffff; - arena = hose->sg_pci; - if (!arena || arena->dma_base + arena->size > max_dma) - arena = hose->sg_isa; start = sg; end = sg + nents; - fstart = -1; - fend = 0; - + /* First, prepare information about the entries. */ - sg_classify(sg, end); + sg_classify(sg, end, alpha_mv.mv_pci_tbi != 0); - /* Second, iterate over the scatterlist leaders and allocate + /* Second, figure out where we're going to map things. */ + if (alpha_mv.mv_pci_tbi) { + hose = pdev ? pdev->sysdata : pci_isa_hose; + max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + arena = hose->sg_pci; + if (!arena || arena->dma_base + arena->size > max_dma) + arena = hose->sg_isa; + } else { + max_dma = -1; + arena = NULL; + hose = NULL; + } + + /* Third, iterate over the scatterlist leaders and allocate dma space as needed. */ for (out = sg; sg < end; ++sg) { int ret; - if (sg->dma_address == -1) + if ((int) sg->dma_address < 0) continue; ret = sg_fill(sg, end, out, arena, max_dma); if (ret < 0) goto error; - else if (ret > 0) { - dma_addr_t ts, te; - - ts = out->dma_address; - te = ts + out->dma_length - 1; - if (fstart > ts) - fstart = ts; - if (fend < te) - fend = te; - } out++; } - /* ??? This shouldn't have been needed, since the entries - we've just modified were not in the iommu tlb. */ - if (fend) - alpha_mv.mv_pci_tbi(hose, fstart, fend); - if (out - start == 0) printk(KERN_INFO "pci_map_sg failed: no entries?\n"); + DBGA("pci_map_sg: %ld entries\n", out - start); return out - start; @@ -496,9 +525,11 @@ arena = hose->sg_pci; if (!arena || arena->dma_base + arena->size > max_dma) arena = hose->sg_isa; + + DBGA("pci_unmap_sg: %d entries\n", nents); + fstart = -1; fend = 0; - for (end = sg + nents; sg < end; ++sg) { unsigned long addr, size; @@ -508,7 +539,8 @@ if (addr >= __direct_map_base && addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ - DBGA2("pci_unmap_sg: direct [%lx,%lx]\n", addr, size); + DBGA(" (%ld) direct [%lx,%lx]\n", + sg - end + nents, addr, size); } else { long npages, ofs; dma_addr_t tend; @@ -523,7 +555,8 @@ if (fend < tend) fend = tend; - DBGA2("pci_unmap_sg: sg [%lx,%lx]\n", addr, size); + DBGA(" (%ld) sg [%lx,%lx]\n", + sg - end + nents, addr, size); } } if (fend) diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.3.44/linux/arch/arm/kernel/armksyms.c Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/kernel/armksyms.c Sun Feb 13 10:47:01 2000 @@ -188,6 +188,10 @@ EXPORT_SYMBOL(uaccess_user); #endif +EXPORT_SYMBOL(consistent_alloc); +EXPORT_SYMBOL(consistent_free); +EXPORT_SYMBOL(consistent_sync); + /* gcc lib functions */ EXPORT_SYMBOL_NOVERS(__gcc_bcmp); EXPORT_SYMBOL_NOVERS(__ashldi3); @@ -234,5 +238,8 @@ EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); EXPORT_SYMBOL_NOVERS(__down_trylock_failed); EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); EXPORT_SYMBOL(get_wchan); diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.3.44/linux/arch/arm/kernel/entry-common.S Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/kernel/entry-common.S Sun Feb 13 10:47:01 2000 @@ -15,26 +15,28 @@ #define HARVARD_CACHE #endif + .macro get_softirq, rd +#ifdef __SMP__ +#error SMP not supported +#else + ldr \rd, __softirq_state +#endif + .endm + .globl ret_from_sys_call .align 5 fast_syscall_return: - str r0, [sp, #S_R0 + S_OFF] @ returned r0 + str r0, [sp, #S_R0 + S_OFF] @ returned r0 slow_syscall_return: add sp, sp, #S_OFF -ret_from_sys_call: -#ifdef HARVARD_CACHE - ldr r0, bh_data - ldr r4, bh_data+4 -#else - adr r0, bh_data - ldmia r0, {r0, r4} -#endif - ldr r0, [r0] - ldr r1, [r4] +ret_from_sys_call: @ external entry + get_softirq r0 + ldmia r0, {r0, r1} + mov r4, #1 @ flag this as being syscall return tst r0, r1 - blne SYMBOL_NAME(do_bottom_half) -ret_with_reschedule: + blne SYMBOL_NAME(do_softirq) +ret_with_reschedule: @ external entry (__irq_usr) get_current_task r5 ldr r0, [r5, #TSK_NEED_RESCHED] ldr r1, [r5, #TSK_SIGPENDING] @@ -43,30 +45,23 @@ teq r1, #0 @ check for signals bne ret_signal -ret_from_all: restore_user_regs +ret_from_all: restore_user_regs @ internal -ret_signal: mov r1, sp +ret_signal: mov r1, sp @ internal adrsvc al, lr, ret_from_all mov r2, r4 b SYMBOL_NAME(do_signal) -ret_reschedule: adrsvc al, lr, ret_with_reschedule +ret_reschedule: adrsvc al, lr, ret_with_reschedule @ internal b SYMBOL_NAME(schedule) .globl ret_from_exception -ret_from_exception: -#ifdef HARVARD_CACHE - ldr r0, bh_data - ldr r1, bh_data + 4 -#else - adr r0, bh_data +ret_from_exception: @ external entry + get_softirq r0 ldmia r0, {r0, r1} -#endif - ldr r0, [r0] - ldr r1, [r1] mov r4, #0 tst r0, r1 - blne SYMBOL_NAME(do_bottom_half) + blne SYMBOL_NAME(do_softirq) ldr r0, [sp, #S_PSR] tst r0, #3 @ returning to user mode? beq ret_with_reschedule @@ -147,8 +142,8 @@ .align 5 -bh_data: .word SYMBOL_NAME(bh_mask) - .word SYMBOL_NAME(bh_active) +__softirq_state: + .word SYMBOL_NAME(softirq_state) ENTRY(sys_call_table) #include "calls.S" diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.3.44/linux/arch/arm/kernel/irq.c Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/kernel/irq.c Sun Feb 13 10:47:01 2000 @@ -237,16 +237,8 @@ irq_exit(cpu, irq); - /* - * This should be conditional: we should really get - * a return code from the irq handler to tell us - * whether the handler wants us to do software bottom - * half handling or not.. - */ - if (1) { - if (bh_active & bh_mask) - do_bottom_half(); - } + if (softirq_state[cpu].active & softirq_state[cpu].mask) + do_softirq(); } #if defined(CONFIG_ARCH_ACORN) diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.3.44/linux/arch/arm/kernel/semaphore.c Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/kernel/semaphore.c Sun Feb 13 10:47:01 2000 @@ -164,6 +164,126 @@ return 1; } +struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!sem->read_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */ + + for (;;) { + if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!sem->write_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* if the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); + + return sem; +} + +/* Wait for the lock to become unbiased. Readers + * are non-exclusive. =) + */ +struct rw_semaphore *down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + /* this takes care of granting the lock */ + __up_op_read(sem, __rwsem_wake); + + add_wait_queue(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +/* Wait for the lock to become unbiased. Since we're + * a writer, we'll make ourselves exclusive. + */ +struct rw_semaphore *down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + /* this takes care of granting the lock */ + __up_op_write(sem, __rwsem_wake); + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (atomic_read(&sem->count) >= 0) + break; /* we must attempt to aquire or bias the lock */ schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + return sem; +} + +/* Called when someone has done an up that transitioned from + * negative to non-negative, meaning that the lock has been + * granted to whomever owned the bias. + */ +struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem) +{ + if (xchg(&sem->read_bias_granted, 1)) + BUG(); + wake_up(&sem->wait); + return sem; +} + +struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem) +{ + if (xchg(&sem->write_bias_granted, 1)) + BUG(); + wake_up(&sem->write_bias_wait); + return sem; +} + /* * The semaphore operations have a special calling sequence that * allow us to do a simpler in-line version of them. These routines @@ -174,30 +294,65 @@ * registers (r0 to r3, ip and lr) except r0 in the cases where it * is used as a return value.. */ -asm(".align 5 +asm(" .section .text.lock, \"ax\" + .align 5 .globl __down_failed __down_failed: stmfd sp!, {r0 - r3, ip, lr} bl __down - ldmfd sp!, {r0 - r3, ip, pc}"); + ldmfd sp!, {r0 - r3, ip, pc} -asm(".align 5 + .align 5 .globl __down_interruptible_failed __down_interruptible_failed: stmfd sp!, {r1 - r3, ip, lr} bl __down_interruptible - ldmfd sp!, {r1 - r3, ip, pc}"); + ldmfd sp!, {r1 - r3, ip, pc} -asm(".align 5 + .align 5 .globl __down_trylock_failed __down_trylock_failed: stmfd sp!, {r1 - r3, ip, lr} bl __down_trylock - ldmfd sp!, {r1 - r3, ip, pc}"); + ldmfd sp!, {r1 - r3, ip, pc} -asm(".align 5 + .align 5 .globl __up_wakeup __up_wakeup: stmfd sp!, {r0 - r3, ip, lr} bl __up - ldmfd sp!, {r0 - r3, ip, pc}"); + ldmfd sp!, {r0 - r3, ip, pc} + + .align 5 + .globl __down_read_failed +__down_read_failed: + stmfd sp!, {r0 - r3, ip, lr} + bcc 1f + bl down_read_failed_biased + ldmfd sp!, {r0 - r3, ip, pc} +1: bl down_read_failed + /***/ + + .align 5 + .globl __down_write_failed +__down_write_failed: + stmfd sp!, {r0 - r3, ip, lr} + bcc 1f + bl down_write_failed_biased + ldmfd sp!, {r0 - r3, ip, pc} +1: bl down_write_failed + /***/ + + .align 5 + .globl __rwsem_wake +__rwsem_wake: + stmfd sp!, {r0 - r3, ip, lr} + beq 1f + bl rwsem_wake_readers + ldmfd sp!, {r0 - r3, ip, pc} +1: bl rwsem_wake_writer + ldmfd sp!, {r0 - r3, ip, pc} + + .previous + "); + diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.3.44/linux/arch/arm/mm/Makefile Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/mm/Makefile Sun Feb 13 10:47:01 2000 @@ -8,8 +8,8 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(PROCESSOR).o \ - small_page.o +O_OBJS := consistent.o extable.o fault-$(PROCESSOR).o init.o \ + mm-$(PROCESSOR).o small_page.o ifeq ($(CONFIG_CPU_26),y) O_OBJS += proc-arm2,3.o diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c --- v2.3.44/linux/arch/arm/mm/consistent.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/consistent.c Sun Feb 13 10:47:01 2000 @@ -0,0 +1,102 @@ +/* + * Dynamic DMA mapping support. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Pure 2^n version of get_order */ +extern __inline__ int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +/* + * This allocates one page of cache-coherent memory space and returns + * both the virtual and a "dma" address to that space. It is not clear + * whether this could be called from an interrupt context or not. For + * now, we expressly forbid it, especially as some of the stuff we do + * here is not interrupt context safe. + */ +void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) +{ + int order; + unsigned long page; + struct vm_struct *area; + void *ret; + + if (in_interrupt()) + BUG(); + + order = __get_order(size); + + page = __get_free_pages(gfp, order); + if (!page) + goto no_page; + + memset((void *)page, 0, PAGE_SIZE << order); + clean_cache_area(page, PAGE_SIZE << order); + + *dma_handle = virt_to_bus((void *)page); + + area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */ + if (!area) + goto no_area; + + ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0); + if (ret) + return ret; + +no_area: + free_pages(page, order); +no_page: + BUG(); + return NULL; +} + +/* + * free a page as defined by the above mapping. We expressly forbid + * calling this from interrupt context. + */ +void consistent_free(void *vaddr) +{ + if (in_interrupt()) + BUG(); + + __iounmap(vaddr); +} + +/* + * make an area consistent. + */ +void consistent_sync(void *vaddr, size_t size, int rw) +{ + switch (rw) { + case 0: + BUG(); + case 1: /* invalidate only */ + dma_cache_inv(vaddr, size); + break; + case 2: /* writeback only */ + dma_cache_wback(vaddr, size); + break; + case 3: /* writeback and invalidate */ + dma_cache_wback_inv(vaddr, size); + break; + } +} diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.3.44/linux/arch/arm/mm/proc-arm6,7.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/mm/proc-arm6,7.S Sun Feb 13 10:47:01 2000 @@ -103,9 +103,9 @@ .align ENTRY(cpu_arm6_data_abort) -Ldata_simple: ldr r4, [r0] @ read instruction causing problem mov r2, r4, lsr #19 @ r2 b1 = L +Ldata_simple: and r2, r2, #2 @ check read/write bit mrc p15, 0, r0, c6, c0, 0 @ get FAR mrc p15, 0, r1, c5, c0, 0 @ get FSR diff -u --recursive --new-file v2.3.44/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c --- v2.3.44/linux/arch/arm/nwfpe/fpmodule.c Fri Oct 22 13:21:44 1999 +++ linux/arch/arm/nwfpe/fpmodule.c Sun Feb 13 10:47:01 2000 @@ -128,23 +128,41 @@ void float_raise(signed char flags) { + register unsigned int fpsr, cumulativeTraps; + #ifdef CONFIG_DEBUG_USER printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", current->comm, current->pid, flags, __builtin_return_address(0), userRegisters[15]); #endif + /* Keep SoftFloat exception flags up to date. */ float_exception_flags |= flags; - if (readFPSR() & (flags << 16)) - { - /* raise exception */ + + /* Read fpsr and initialize the cumulativeTraps. */ + fpsr = readFPSR(); + cumulativeTraps = 0; + + /* For each type of exception, the cumulative trap exception bit is only + set if the corresponding trap enable bit is not set. */ + if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) + cumulativeTraps |= BIT_IXC; + if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) + cumulativeTraps |= BIT_UFC; + if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) + cumulativeTraps |= BIT_OFC; + if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) + cumulativeTraps |= BIT_DZC; + if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) + cumulativeTraps |= BIT_IOC; + + /* Set the cumulative exceptions flags. */ + if (cumulativeTraps) + writeFPSR(fpsr | cumulativeTraps); + + /* Raise an exception if necessary. */ + if (fpsr & (flags << 16)) fp_send_sig(SIGFPE, current, 1); - } - else - { - /* set the cumulative exceptions flags */ - writeFPSR(flags); - } } module_init(fpe_init); diff -u --recursive --new-file v2.3.44/linux/arch/arm/nwfpe/fpsr.h linux/arch/arm/nwfpe/fpsr.h --- v2.3.44/linux/arch/arm/nwfpe/fpsr.h Tue Aug 31 17:29:12 1999 +++ linux/arch/arm/nwfpe/fpsr.h Sun Feb 13 10:47:01 2000 @@ -63,12 +63,12 @@ #define MASK_SYSTEM_CONTROL 0x0000ff00 #define MASK_TRAP_STRICT 0x00001f00 -#define BIT_AC 0x00100000 /* use alternative C-flag definition +#define BIT_AC 0x00001000 /* use alternative C-flag definition for compares */ -#define BIT_EP 0x00080000 /* use expanded packed decimal format */ -#define BIT_SO 0x00040000 /* select synchronous operation of FPA */ -#define BIT_NE 0x00020000 /* NaN exception bit */ -#define BIT_ND 0x00010000 /* no denormalized numbers bit */ +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ +#define BIT_NE 0x00000200 /* NaN exception bit */ +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ /* CUMULATIVE EXCEPTION FLAGS BYTE ---------------------------------- */ diff -u --recursive --new-file v2.3.44/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- v2.3.44/linux/arch/i386/boot/bootsect.S Tue Nov 23 22:42:20 1999 +++ linux/arch/i386/boot/bootsect.S Sun Feb 13 10:16:36 2000 @@ -106,9 +106,8 @@ pushw %ds ldsw %fs:(%bx), %si # ds:si is source movb $6, %cl # copy 12 bytes - cld pushw %di # di = 0x4000-12. - rep + rep # don't need cld -> done on line 66 movsw popw %di popw %ds @@ -140,20 +139,7 @@ jmp load_setup ok_load_setup: -# Get disk drive parameters, specifically nr of sectors/track. - -#if 0 - -# bde - the Phoenix BIOS manual says function 0x08 only works for fixed -# disks. It doesn't work for one of my BIOS's (1987 Award). It was -# fatal not to check the error code. - - xorb %dl, %dl - movb $0x08, %ah # AH=8 is get drive parameters - int $0x13 - xorb %ch, %ch - -#else +# Get disk drive parameters, specifically number of sectors/track. # It seems that there is no BIOS call to get the number of sectors. # Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18 @@ -176,7 +162,6 @@ movw $0x0201, %ax # service 2, 1 sector int $0x13 jc probe_loop # try next value -#endif got_sectors: movw $INITSEG, %ax @@ -200,11 +185,11 @@ # Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8) # depending on the number of sectors we pretend to know we have. - movw %cs:root_dev, %ax + movw root_dev, %ax orw %ax, %ax jne root_defined - movw %cs:sectors, %bx + movw sectors, %bx movw $0x0208, %ax # /dev/ps0 - 1.2Mb cmpw $15, %bx je root_defined @@ -219,7 +204,7 @@ movb $0, %al # /dev/fd0 - autodetect root_defined: - movw %ax, %cs:root_dev + movw %ax, root_dev # After that (everything loaded), we jump to the setup-routine # loaded directly after the bootblock: diff -u --recursive --new-file v2.3.44/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.44/linux/arch/i386/defconfig Thu Feb 10 17:11:03 2000 +++ linux/arch/i386/defconfig Sun Feb 13 18:48:07 2000 @@ -270,15 +270,15 @@ # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set # CONFIG_TULIP is not set # CONFIG_DGRS is not set CONFIG_EEXPRESS_PRO100=y # CONFIG_NE2K_PCI is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set @@ -453,7 +453,6 @@ # CONFIG_SYSV_FS is not set # CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set diff -u --recursive --new-file v2.3.44/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.3.44/linux/arch/i386/kernel/pci-pc.c Sat Feb 12 11:22:10 2000 +++ linux/arch/i386/kernel/pci-pc.c Sun Feb 13 10:37:41 2000 @@ -1057,8 +1057,8 @@ static unsigned int pcibios_irq_mask = 0xfff8; static unsigned pcibios_irq_penalty[16] = { - 1000, 1000, 1000, 10, 10, 0, 0, 10, - 0, 0, 0, 0, 10, 100, 100, 100 + 10000, 10000, 10000, 100, 100, 0, 0, 100, + 0, 0, 0, 0, 100, 1000, 1000, 1000 }; static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign) diff -u --recursive --new-file v2.3.44/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.3.44/linux/arch/ia64/config.in Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/config.in Sun Feb 13 10:30:38 2000 @@ -3,6 +3,8 @@ mainmenu_option next_comment comment 'General setup' +define_bool CONFIG_IA64 y + choice 'IA-64 system type' \ "Generic CONFIG_IA64_GENERIC \ HP-simulator CONFIG_IA64_HP_SIM \ diff -u --recursive --new-file v2.3.44/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.3.44/linux/arch/ia64/ia32/ia32_entry.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/ia32/ia32_entry.S Sun Feb 13 10:30:38 2000 @@ -144,7 +144,7 @@ data8 sys32_settimeofday data8 sys_getgroups /* 80 */ data8 sys_setgroups - data8 sys_ni_syscall + data8 old_select data8 sys_symlink data8 sys_ni_syscall data8 sys_readlink /* 85 */ diff -u --recursive --new-file v2.3.44/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c --- v2.3.44/linux/arch/ia64/ia32/ia32_signal.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/ia32/ia32_signal.c Sun Feb 13 10:30:38 2000 @@ -342,7 +342,16 @@ } asmlinkage int -sys32_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack) +sys32_sigreturn( +int arg0, +int arg1, +int arg2, +int arg3, +int arg4, +int arg5, +int arg6, +int arg7, +unsigned long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8); @@ -375,7 +384,16 @@ } asmlinkage int -sys32_rt_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack) +sys32_rt_sigreturn( +int arg0, +int arg1, +int arg2, +int arg3, +int arg4, +int arg5, +int arg6, +int arg7, +unsigned long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4); diff -u --recursive --new-file v2.3.44/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.3.44/linux/arch/ia64/ia32/sys_ia32.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/ia32/sys_ia32.c Sun Feb 13 10:30:38 2000 @@ -240,18 +240,29 @@ return -EINVAL; if (prot & PROT_WRITE) prot |= PROT_EXEC; +#ifdef DDD +#else // DDD + prot |= PROT_WRITE; +#endif // DDD front = NULL; back = NULL; if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { front = kmalloc(addr - baddr, GFP_KERNEL); memcpy(front, (void *)baddr, addr - baddr); } - if ((addr + len) & ~PAGE_MASK && get_user(c, (char *)(addr + len)) == 0) { +#ifndef DDD + if (addr) +#endif + if (((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); memcpy(back, addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } if ((r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0)) < 0) return(r); +#ifndef DDD + if (addr == 0) + addr = r; +#endif // DDD if (back) { memcpy(addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); kfree(back); @@ -315,7 +326,11 @@ } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +#ifdef DDD if ((a.flags & MAP_FIXED) && ((a.addr & ~PAGE_MASK) || (a.offset & ~PAGE_MASK))) { +#else // DDD + if (1) { +#endif // DDD unlock_kernel(); up(¤t->mm->mmap_sem); error = do_mmap_fake(file, a.addr, a.len, a.prot, a.flags, a.offset); @@ -665,7 +680,7 @@ }; static void -xlate_dirent(void *dirent, long n) +xlate_dirent(void *dirent64, void *dirent32, long n) { long off; struct dirent *dirp; @@ -673,9 +688,9 @@ off = 0; while (off < n) { - dirp = (struct dirent *)(dirent + off); + dirp = (struct dirent *)(dirent64 + off); + dirp32 = (struct dirent32 *)(dirent32 + off); off += dirp->d_reclen; - dirp32 = (struct dirent32 *)dirp; dirp32->d_ino = dirp->d_ino; dirp32->d_off = (unsigned int)dirp->d_off; dirp32->d_reclen = dirp->d_reclen; @@ -685,26 +700,27 @@ } asmlinkage long -sys32_getdents(unsigned int fd, void * dirent, unsigned int count) +sys32_getdents(unsigned int fd, void * dirent32, unsigned int count) { long n; + void *dirent64; - if ((n = sys_getdents(fd, dirent, count)) < 0) + dirent64 = (unsigned long)(dirent32 + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + if ((n = sys_getdents(fd, dirent64, count - (dirent64 - dirent32))) < 0) return(n); - xlate_dirent(dirent, n); + xlate_dirent(dirent64, dirent32, n); return(n); } asmlinkage int -sys32_readdir(unsigned int fd, void * dirent, unsigned int count) +sys32_readdir(unsigned int fd, void * dirent32, unsigned int count) { int n; - struct dirent *dirp; + struct dirent dirent64; - if ((n = old_readdir(fd, dirent, count)) < 0) + if ((n = old_readdir(fd, &dirent64, count)) < 0) return(n); - dirp = (struct dirent *)dirent; - xlate_dirent(dirent, dirp->d_reclen); + xlate_dirent(&dirent64, dirent32, dirent64.d_reclen); return(n); } @@ -807,6 +823,23 @@ kfree(bits); out_nofds: return ret; +} + +struct sel_arg_struct { + unsigned int n; + unsigned int inp; + unsigned int outp; + unsigned int exp; + unsigned int tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + return sys32_select(a.n, a.inp, a.outp, a.exp, a.tvp); } struct rusage32 { diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.3.44/linux/arch/ia64/kernel/efi.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/efi.c Sun Feb 13 10:30:38 2000 @@ -15,7 +15,6 @@ * * Implemented EFI runtime services and virtual mode calls. --davidm */ -#include #include #include #include @@ -166,14 +165,12 @@ case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: -#ifndef CONFIG_IA64_VIRTUAL_MEM_MAP if (md->phys_addr > 1024*1024*1024UL) { printk("Warning: ignoring %luMB of memory above 1GB!\n", md->num_pages >> 8); md->type = EFI_UNUSABLE_MEMORY; continue; } -#endif curr.start = PAGE_OFFSET + md->phys_addr; curr.end = curr.start + (md->num_pages << 12); diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.3.44/linux/arch/ia64/kernel/entry.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/entry.S Sun Feb 13 10:30:38 2000 @@ -496,18 +496,27 @@ (p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure ia64_leave_kernel: - // check & deliver software interrupts (bottom half handlers): + // check & deliver software interrupts: - movl r2=bh_active // sheesh, why aren't these two in - movl r3=bh_mask // a struct?? +#ifdef CONFIG_SMP + adds r2=IA64_TASK_PROCESSOR_OFFSET,r13 + movl r3=softirq_state ;; - ld8 r2=[r2] - ld8 r3=[r3] + ld4 r2=[r2] + ;; + shladd r3=r2,3,r3 +#else + movl r3=softirq_state +#endif + ;; + ld8 r2=[r3] // r3 is guaranteed to be 8-byte aligned! + ;; + shr r3=r2,32 ;; and r2=r2,r3 ;; - cmp.ne p6,p7=r2,r0 // any soft interrupts ready for delivery? -(p6) br.call.dpnt.few rp=invoke_do_bottom_half + cmp4.ne p6,p7=r2,r0 +(p6) br.call.spnt.many rp=invoke_do_softirq 1: (pKern) br.cond.dpnt.many restore_all // yup -> skip check for rescheduling & signal delivery @@ -751,20 +760,20 @@ #endif /* CONFIG_SMP */ /* - * Invoke do_bottom_half() while preserving in0-in7, which may be needed + * Invoke do_softirq() while preserving in0-in7, which may be needed * in case a system call gets restarted. */ - .proc invoke_do_bottom_half -invoke_do_bottom_half: + .proc invoke_do_softirq +invoke_do_softirq: alloc loc0=ar.pfs,8,2,0,0 mov loc1=rp ;; - br.call.sptk.few rp=do_bottom_half + br.call.sptk.few rp=do_softirq .ret9: mov ar.pfs=loc0 mov rp=loc1 br.ret.sptk.many rp - .endp invoke_do_bottom_half + .endp invoke_do_softirq /* * Invoke schedule() while preserving in0-in7, which may be needed diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.3.44/linux/arch/ia64/kernel/gate.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/gate.S Sun Feb 13 10:30:38 2000 @@ -132,6 +132,7 @@ ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0 cmp.ne p8,p0=r14,r15 // do we need to restore the rbs? (p8) br.cond.spnt.few restore_rbs // yup -> (clobbers r14 and r16) + ;; back_from_restore_rbs: { and r9=0x7f,r8 // r9 <- CFM0.sof diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.3.44/linux/arch/ia64/kernel/head.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/head.S Sun Feb 13 10:30:38 2000 @@ -133,6 +133,7 @@ #endif /* CONFIG_IA64_EARLY_PRINTK */ alloc r2=ar.pfs,8,0,2,0 + ;; #ifdef CONFIG_SMP (isAP) br.call.sptk.few rp=smp_callin .ret1: @@ -174,7 +175,7 @@ st8.nta [in0]=r16,8 st8.nta [r19]=r17,8 br.cloop.sptk.few 1b - + ;; mov ar.lc=r20 // restore ar.lc br.ret.sptk.few b0 .endp ia64_save_debug_regs @@ -197,7 +198,7 @@ mov dbr[r18]=r16 mov ibr[r18]=r17 br.cloop.sptk.few 1b - + ;; mov ar.lc=r20 // restore ar.lc br.ret.sptk.few b0 .endp ia64_load_debug_regs diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.3.44/linux/arch/ia64/kernel/irq.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/irq.c Sun Feb 13 10:30:38 2000 @@ -128,6 +128,18 @@ return p - buf; } +int usbfix; + +static int __init +usbfix_option (char *str) +{ + printk("irq: enabling USB workaround\n"); + usbfix = 1; + return 1; +} + +__setup("usbfix", usbfix_option); + /* * That's where the IVT branches when we get an external * interrupt. This branches to the correct hardware IRQ handler via @@ -146,7 +158,8 @@ unsigned long eoi_ptr; # ifdef CONFIG_USB - disable_usb(); + if (usbfix) + disable_usb(); # endif /* * Stop IPIs by getting the ivr_read_lock @@ -170,7 +183,8 @@ spin_unlock(&ivr_read_lock); # ifdef CONFIG_USB - reenable_usb(); + if (usbfix) + reenable_usb(); # endif # ifndef CONFIG_SMP diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/irq_lock.c linux/arch/ia64/kernel/irq_lock.c --- v2.3.44/linux/arch/ia64/kernel/irq_lock.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/irq_lock.c Sun Feb 13 10:30:38 2000 @@ -26,7 +26,7 @@ spinlock_t global_irq_lock; atomic_t global_irq_count; atomic_t global_bh_count; -atomic_t global_bh_lock; +spinlock_t global_bh_lock; #define INIT_STUCK (1<<26) diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/pci-dma.c linux/arch/ia64/kernel/pci-dma.c --- v2.3.44/linux/arch/ia64/kernel/pci-dma.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/pci-dma.c Sun Feb 13 10:30:38 2000 @@ -21,7 +21,7 @@ extern __inline__ unsigned long get_order (unsigned long size) { - unsigned long order = ia64_fls(size); + unsigned long order = ia64_fls(size - 1) + 1; printk ("get_order: size=%lu, order=%lu\n", size, order); diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c --- v2.3.44/linux/arch/ia64/kernel/pci.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/pci.c Sun Feb 13 10:30:38 2000 @@ -226,14 +226,3 @@ pcibios_align_resource (void *data, struct resource *res, unsigned long size) { } - -#if 0 /*def CONFIG_PROC_FS*/ -/* - * This is an ugly hack to get a (weak) unresolved reference to something that is - * in drivers/pci/proc.c. Without this, the file does not get linked in at all - * (I suspect the reason this isn't needed on Linux/x86 is that most people compile - * with module support, in which case the EXPORT_SYMBOL() stuff will ensure the - * code gets linked in. Sigh... --davidm 99/12/20. - */ -asm ("data8 proc_bus_pci_add"); -#endif diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.3.44/linux/arch/ia64/kernel/smp.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/smp.c Sun Feb 13 10:30:38 2000 @@ -57,7 +57,7 @@ unsigned long cpu_online_map = 1; #endif -volatile int cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ +volatile int __cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> SAPIC ID */ int smp_num_cpus = 1; int bootstrap_processor = -1; /* SAPIC ID of BSP */ @@ -586,7 +586,7 @@ alive: /* Remember the AP data */ - cpu_number_map[cpuid] = cpunum; + __cpu_number_map[cpuid] = cpunum; #ifdef CONFIG_KDB cpu_online_map |= (1<processor = bootstrap_processor; diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.3.44/linux/arch/ia64/kernel/sys_ia64.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/sys_ia64.c Sun Feb 13 10:30:38 2000 @@ -2,8 +2,8 @@ * This file contains various system calls that have different calling * conventions on different platforms. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang */ #include #include diff -u --recursive --new-file v2.3.44/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile --- v2.3.44/linux/arch/ia64/lib/Makefile Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/Makefile Sun Feb 13 10:30:38 2000 @@ -3,7 +3,7 @@ # .S.o: - $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@ + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@ OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o \ diff -u --recursive --new-file v2.3.44/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.3.44/linux/arch/ia64/tools/print_offsets.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/tools/print_offsets.c Sun Feb 13 10:30:38 2000 @@ -47,6 +47,7 @@ { "IA64_TASK_FLAGS_OFFSET", offsetof (struct task_struct, flags) }, { "IA64_TASK_SIGPENDING_OFFSET", offsetof (struct task_struct, sigpending) }, { "IA64_TASK_NEED_RESCHED_OFFSET", offsetof (struct task_struct, need_resched) }, + { "IA64_TASK_PROCESSOR_OFFSET", offsetof (struct task_struct, processor) }, { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, diff -u --recursive --new-file v2.3.44/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.3.44/linux/arch/m68k/config.in Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/config.in Sun Feb 13 11:21:42 2000 @@ -161,10 +161,17 @@ comment 'SCSI support type (disk, tape, CD-ROM)' dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + fi dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 + fi dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 fi dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI @@ -273,9 +280,13 @@ tristate ' Apollo 3c505 support' CONFIG_APOLLO_ELPLUS fi if [ "$CONFIG_MAC" = "y" ]; then - bool ' Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT -# bool ' Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE - bool ' Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC + bool ' Macintosh NS 8390 based ethernet cards' CONFIG_MAC8390 + tristate ' Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)' CONFIG_MACSONIC + tristate ' Macintosh SMC 9194 based ethernet cards' CONFIG_SMC9194 + tristate ' Macintosh CS89x0 based ethernet cards' CONFIG_MAC89x0 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)' CONFIG_MACMACE + fi fi if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then tristate ' MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET @@ -352,12 +363,6 @@ define_bool CONFIG_BUSMOUSE y fi fi -if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac ADB mouse support' CONFIG_ADBMOUSE - if [ "$CONFIG_ADBMOUSE" != "n" ]; then - define_bool CONFIG_BUSMOUSE y - fi -fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER tristate 'Atari SCC serial support' CONFIG_ATARI_SCC @@ -384,7 +389,20 @@ fi fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac SCC serial support' CONFIG_MAC_SCC + tristate 'Macintosh serial support' CONFIG_MAC_SCC + bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB + if [ "$CONFIG_ADB" = "y" ]; then + bool ' Support for ADB keyboard' CONFIG_ADB_KEYBOARD + bool ' Support for ADB mouse' CONFIG_ADBMOUSE + bool ' Include Mac II ADB driver' CONFIG_ADB_MACII + bool ' Include Mac IIsi ADB driver' CONFIG_ADB_MACIISI + bool ' Include CUDA ADB driver' CONFIG_ADB_CUDA + bool ' Include IOP (IIfx/Quadra 9x0) ADB driver' CONFIG_ADB_IOP + bool ' Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU68K + fi + if [ "$CONFIG_ADBMOUSE" = "y" ]; then + define_bool CONFIG_BUSMOUSE y + fi fi if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then tristate 'HP DCA serial support' CONFIG_HPDCA diff -u --recursive --new-file v2.3.44/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile --- v2.3.44/linux/arch/m68k/kernel/Makefile Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/kernel/Makefile Sun Feb 13 11:21:42 2000 @@ -27,6 +27,8 @@ head.o: head.S m68k_defs.h +entry.o: entry.S m68k_defs.h + sun3-head.o: sun3-head.S m68k_defs.h m68k_defs.h: m68k_defs.c m68k_defs.head diff -u --recursive --new-file v2.3.44/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.3.44/linux/arch/m68k/kernel/entry.S Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/kernel/entry.S Sun Feb 13 11:21:42 2000 @@ -236,12 +236,12 @@ #endif /* check if we need to do software interrupts */ - movel SYMBOL_NAME(bh_active),%d0 - andl SYMBOL_NAME(bh_mask),%d0 + movel SYMBOL_NAME(softirq_state),%d0 + andl SYMBOL_NAME(softirq_state)+4,%d0 jeq SYMBOL_NAME(ret_from_exception) pea SYMBOL_NAME(ret_from_exception) - jra SYMBOL_NAME(do_bottom_half) + jra SYMBOL_NAME(do_softirq) /* Handler for uninitialized and spurious interrupts */ diff -u --recursive --new-file v2.3.44/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.3.44/linux/arch/m68k/kernel/m68k_ksyms.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/kernel/m68k_ksyms.c Sun Feb 13 11:21:42 2000 @@ -18,7 +18,6 @@ #include #include #include -#include asmlinkage long long __ashrdi3 (long long, int); asmlinkage long long __lshrdi3 (long long, int); diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile --- v2.3.44/linux/arch/m68k/mac/Makefile Tue Sep 7 12:14:06 1999 +++ linux/arch/m68k/mac/Makefile Sun Feb 13 11:21:42 2000 @@ -10,6 +10,6 @@ O_TARGET := mac.o OX_OBJS := mac_ksyms.o O_OBJS := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ - macboing.o debug.o misc.o + baboon.o macboing.o debug.o misc.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c --- v2.3.44/linux/arch/m68k/mac/adb-bus.c Thu Feb 10 17:11:04 2000 +++ linux/arch/m68k/mac/adb-bus.c Wed Dec 31 16:00:00 1969 @@ -1,2699 +0,0 @@ -/* - * MACII ADB keyboard handler. - * Copyright (c) 1997 Alan Cox - * - * Derived from code - * Copyright (C) 1996 Paul Mackerras. - * - * MSch (9/97) Partial rewrite of interrupt handler to MacII style - * ADB handshake, based on: - * - Guide to Mac Hardware - * - Guido Koerber's session with a logic analyzer - * - * MSch (1/98) Integrated start of IIsi driver by Robert Thompson - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "via6522.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -#define MACII /* For now - will be a switch */ - -/* Bits in B data register: all active low */ -#define TREQ 0x08 /* Transfer request (input) */ -#define TACK 0x10 /* Transfer acknowledge (output) */ -#define TIP 0x20 /* Transfer in progress (output) */ - -/* Bits in B data register: ADB transaction states MacII */ -#define ST_MASK 0x30 /* mask for selecting ADB state bits */ -/* ADB transaction states according to GMHW */ -#define ST_CMD 0x00 /* ADB state: command byte */ -#define ST_EVEN 0x10 /* ADB state: even data byte */ -#define ST_ODD 0x20 /* ADB state: odd data byte */ -#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ - -/* Bits in ACR */ -#define SR_CTRL 0x1c /* Shift register control bits */ -#ifdef USE_ORIG -#define SR_EXT 0x1c /* Shift on external clock */ -#else -#define SR_EXT 0x0c /* Shift on external clock */ -#endif -#define SR_OUT 0x10 /* Shift out if 1 */ - -/* Bits in IFR and IER */ -#define IER_SET 0x80 /* set bits in IER */ -#define IER_CLR 0 /* clear bits in IER */ -#define SR_INT 0x04 /* Shift register full/empty */ -#define SR_DATA 0x08 /* Shift register data */ -#define SR_CLOCK 0x10 /* Shift register clock */ - -/* JRT */ -#define ADB_DELAY 150 - -static struct adb_handler { - void (*handler)(unsigned char *, int, struct pt_regs *); -} adb_handler[16]; - -static enum adb_state { - idle, - sent_first_byte, - sending, - reading, - read_done, - awaiting_reply -} adb_state; - -static struct adb_request *current_req; -static struct adb_request *last_req; -static unsigned char cuda_rbuf[16]; -static unsigned char *reply_ptr; -static int reply_len; -static int reading_reply; -static int data_index; -static int first_byte; -static int prefix_len; - -static int status = ST_IDLE|TREQ; -static int last_status; - -static int driver_running = 0; - -/*static int adb_delay;*/ -int in_keybinit = 1; - -static void adb_start(void); -extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs); -extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); -static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); - -static void adb_hw_setup_IIsi(void); -static void adb_hw_setup_cuda(void); - -/* - * debug level 10 required for ADB logging (should be && debug_adb, ideally) - */ - -extern int console_loglevel; - -/* - * Misc. defines for testing - should go to header :-( - */ - -#define ADBDEBUG_STATUS (1) -#define ADBDEBUG_STATE (2) -#define ADBDEBUG_READ (4) -#define ADBDEBUG_WRITE (8) -#define ADBDEBUG_START (16) -#define ADBDEBUG_RETRY (32) -#define ADBDEBUG_POLL (64) -#define ADBDEBUG_INT (128) -#define ADBDEBUG_PROT (256) -#define ADBDEBUG_SRQ (512) -#define ADBDEBUG_REQUEST (1024) -#define ADBDEBUG_INPUT (2048) -#define ADBDEBUG_DEVICE (4096) - -#define ADBDEBUG_IISI (8192) - - -/*#define DEBUG_ADB*/ - -#ifdef DEBUG_ADB -#define ADBDEBUG (ADBDEBUG_INPUT | ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST) -#else -#define ADBDEBUG (0) -#endif - -#define TRY_CUDA - -void adb_bus_init(void) -{ - unsigned long flags; - unsigned char c, i; - - save_flags(flags); - cli(); - - /* - * Setup ADB - */ - - switch(macintosh_config->adb_type) - { - - case MAC_ADB_II: - printk("adb: MacII style keyboard/mouse driver.\n"); - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); - /* - * Docs suggest TREQ should be output - that seems nuts - * BSD agrees here :-) - * Setup vPCR ?? - */ - -#ifdef USE_ORIG - /* Lower the bus signals (MacII is active low it seems ???) */ - via_write(via1, vBufB, via_read(via1, vBufB)&~TACK); -#else - /* Corresponding state: idle (clear state bits) */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - last_status = (via_read(via1, vBufB)&~ST_MASK); -#endif - /* Shift register on input */ - c=via_read(via1, vACR); - c&=~SR_CTRL; /* Clear shift register bits */ - c|=SR_EXT; /* Shift on external clock; out or in? */ - via_write(via1, vACR, c); - /* Wipe any pending data and int */ - via_read(via1, vSR); - - /* This is interrupts on enable SR for keyboard */ - via_write(via1, vIER, IER_SET|SR_INT); - /* This clears the interrupt bit */ - via_write(via1, vIFR, SR_INT); - - /* - * Ok we probably ;) have a ready to use adb bus. Its also - * hopefully idle (Im assuming the mac didnt leave a half - * complete transaction on booting us). - */ - - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_interrupt); - adb_state = idle; - break; - /* - * Unsupported; but later code doesn't notice !! - */ - case MAC_ADB_CUDA: - printk("adb: CUDA interface.\n"); -#if 0 - /* don't know what to set up here ... */ - adb_state = idle; - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); -#endif - adb_hw_setup_cuda(); - adb_state = idle; - request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, - "adb CUDA interrupt", adb_cuda_interrupt); - break; - case MAC_ADB_IISI: - printk("adb: Using IIsi hardware.\n"); - printk("\tDEBUG_JRT\n"); - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); - - /* - * MSch: I'm pretty sure the setup is mildly wrong - * for the IIsi. - */ - /* Initial state: idle (clear state bits) */ - via_write(via1, vBufB, (via_read(via1, vBufB) & ~(TIP|TACK)) ); - last_status = (via_read(via1, vBufB)&~ST_MASK); - /* Shift register on input */ - c=via_read(via1, vACR); - c&=~SR_CTRL; /* Clear shift register bits */ - c|=SR_EXT; /* Shift on external clock; out or in? */ - via_write(via1, vACR, c); - /* Wipe any pending data and int */ - via_read(via1, vSR); - - /* This is interrupts on enable SR for keyboard */ - via_write(via1, vIER, IER_SET|SR_INT); - /* This clears the interrupt bit */ - via_write(via1, vIFR, SR_INT); - - /* get those pesky clock ticks we missed while booting */ - for ( i = 0; i < 60; i++) { - udelay(ADB_DELAY); - adb_hw_setup_IIsi(); - udelay(ADB_DELAY); - if (via_read(via1, vBufB) & TREQ) - break; - } - if (i == 60) - printk("adb_IIsi: maybe bus jammed ??\n"); - - /* - * Ok we probably ;) have a ready to use adb bus. Its also - */ - request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_cuda_interrupt); - adb_state = idle; - break; - default: - printk("adb: Unknown hardware interface.\n"); - nosupp: - printk("adb: Interface unsupported.\n"); - restore_flags(flags); - return; - } - - /* - * XXX: interrupt only registered if supported HW !! - * -> unsupported HW will just time out on keyb_init! - */ -#if 0 - request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, - "adb interrupt", adb_interrupt); -#endif -#ifdef DEBUG_ADB_INTS - request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, - "adb clock interrupt", adb_clock_interrupt); - request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK, - "adb data interrupt", adb_data_interrupt); -#endif - - printk("adb: init done.\n"); - restore_flags(flags); -} - -void adb_hw_setup_cuda(void) -{ - int x; - unsigned long flags; - - printk("CUDA: HW Setup:"); - - save_flags(flags); - cli(); - - if (console_loglevel == 10) - printk(" 1,"); - - /* Set the direction of the cuda signals, TIP+TACK are output TREQ is an input */ - via_write( via1, vDirB, via_read( via1, vDirB ) | TIP | TACK ); - via_write( via1, vDirB, via_read( via1, vDirB ) & ~TREQ ); - - if (console_loglevel == 10) - printk("2,"); - - /* Set the clock control. Set to shift data in by external clock CB1 */ - via_write( via1, vACR, ( via_read(via1, vACR ) | SR_EXT ) & ~SR_OUT ); - - if (console_loglevel == 10) - printk("3,"); - - /* Clear any possible Cuda interrupt */ - x = via_read( via1, vSR ); - - if (console_loglevel == 10) - printk("4,"); - - /* Terminate transaction and set idle state */ - via_write( via1, vBufB, via_read( via1, vBufB ) | TIP | TACK ); - - if (console_loglevel == 10) - printk("5,"); - - /* Delay 4 mS for ADB reset to complete */ - udelay(4000); - - if (console_loglevel == 10) - printk("6,"); - - /* Clear pending interrupts... */ - x = via_read( via1, vSR ); - - if (console_loglevel == 10) - printk("7,"); - /* Issue a sync transaction, TACK asserted while TIP negated */ - via_write( via1, vBufB, via_read( via1, vBufB ) & ~TACK ); - - if (console_loglevel == 10) - printk("8,"); - - /* Wait for the sync acknowledgement, Cuda to assert TREQ */ - while( ( via_read( via1, vBufB ) & TREQ ) != 0 ) - barrier(); - - if (console_loglevel == 10) - printk("9,"); - - /* Wait for the sync acknowledment interrupt */ - while( ( via_read( via1, vIFR ) & SR_INT ) == 0 ) - barrier(); - - if (console_loglevel == 10) - printk("10,"); - - /* Clear pending interrupts... */ - x = via_read( via1, vSR ); - - if (console_loglevel == 10) - printk("11,"); - - /* Terminate the sync cycle by negating TACK */ - via_write( via1, vBufB, via_read( via1, vBufB ) | TACK ); - - if (console_loglevel == 10) - printk("12,"); - - /* Wait for the sync termination acknowledgement, Cuda to negate TREQ */ - while( ( via_read( via1, vBufB ) & TREQ ) == 0 ) - barrier(); - - if (console_loglevel == 10) - printk("13,"); - - /* Wait for the sync termination acknowledment interrupt */ - while( ( via_read( via1, vIFR ) & SR_INT ) == 0 ) - barrier(); - - if (console_loglevel == 10) - printk("14,"); - - /* Terminate transaction and set idle state, TIP+TACK negate */ - via_write( via1, vBufB, via_read( via1, vBufB ) | TIP ); - - if (console_loglevel == 10) - printk("15 !"); - - /* Clear pending interrupts... */ - x = via_read( via1, vSR ); - - restore_flags(flags); - - printk("\nCUDA: HW Setup done!\n"); -} - -void adb_hw_setup_IIsi(void) -{ - int dummy; - long poll_timeout; - - printk("adb_IIsi: cleanup!\n"); - - /* ??? */ - udelay(ADB_DELAY); - - /* disable SR int. */ - via_write(via1, vIER, IER_CLR|SR_INT); - /* set SR to shift in */ - via_write(via1, vACR, via_read(via1, vACR ) & ~SR_OUT); - - /* this is required, especially on faster machines */ - udelay(ADB_DELAY); - - if (!(via_read(via1, vBufB) & TREQ)) { /* IRQ on */ - /* start frame */ - via_write(via1, vBufB,via_read(via1,vBufB) | TIP); - - while (1) { - /* poll for ADB interrupt and watch for timeout */ - /* if time out, keep going in hopes of not hanging the - * ADB chip - I think */ - poll_timeout = ADB_DELAY * 5; - while ( !(via_read(via1, vIFR) & SR_INT) - && (poll_timeout-- > 0) ) - dummy = via_read(via1, vBufB); - - dummy = via_read(via1, vSR); /* reset interrupt flag */ - - /* perhaps put in a check here that ignores all data - * after the first ADB_MAX_MSG_LENGTH bytes ??? */ - - /* end of frame reached ?? */ - if (via_read(via1, vBufB) & TREQ) - break; - - /* set ACK */ - via_write(via1,vBufB,via_read(via1, vBufB) | TACK); - /* delay */ - udelay(ADB_DELAY); - /* clear ACK */ - via_write(via1,vBufB,via_read(via1, vBufB) & ~TACK); - } - /* end frame */ - via_write(via1, vBufB,via_read(via1,vBufB) & ~TIP); - /* probably don't need to delay this long */ - udelay(ADB_DELAY); - } - /* re-enable SR int. */ - via_write(via1, vIER, IER_SET|SR_INT); -} - -#define WAIT_FOR(cond, what) \ - do { \ - for (x = 1000; !(cond); --x) { \ - if (x == 0) { \ - printk("Timeout waiting for " what); \ - return 0; \ - } \ - __delay(100*160); \ - } \ - } while (0) - -/* - * Construct and send an adb request - * This function is the main entry point into the ADB driver from - * kernel code; it takes the request data supplied and populates the - * adb_request structure. - * In order to keep this interface independent from any assumption about - * the underlying ADB hardware, we take requests in CUDA format here, - * the ADB packet 'prefixed' with a packet type code. - * Non-CUDA hardware is confused by this, so we strip the packet type - * here depending on hardware type ... - */ -int adb_request(struct adb_request *req, void (*done)(struct adb_request *), - int nbytes, ...) -{ - va_list list; - int i, start; - - va_start(list, nbytes); - - /* - * skip first byte if not CUDA - */ - if (macintosh_config->adb_type == MAC_ADB_II) { - start = va_arg(list, int); - nbytes--; - } - req->nbytes = nbytes; - req->done = done; -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("adb_request, data bytes: "); -#endif - for (i = 0; i < nbytes; ++i) { - req->data[i] = va_arg(list, int); -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("%x ", req->data[i]); -#endif - } -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk(" !\n"); -#endif - va_end(list); - /* - * XXX: This might be fatal if no reply is generated (i.e. Listen) ! - * Currently, the interrupt handler 'fakes' a reply on non-TALK - * commands for this reason. - * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA - * Macs, and some mechanism to remember the last issued TALK - * request for resending it repeatedly on timeout! - */ - req->reply_expected = 1; - return adb_send_request(req); -} - -/* - * Construct an adb request for later sending - * This function only populates the adb_request structure, without - * actually queueing it. - * Reason: Poll requests and Talk requests need to be handled in a way - * different from 'user' requests; no reply_expected is set and - * Poll requests need to be placed at the head of the request queue. - * Using adb_request results in implicit queueing at the tail of the - * request queue (duplicating the Poll) with reply_expected set. - * No adjustment of packet data is necessary, as this mechanisnm is not - * used by CUDA hardware (Autopoll used instead). - */ -int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *), - int nbytes, ...) -{ - va_list list; - int i; - - req->nbytes = nbytes; - req->done = done; - va_start(list, nbytes); -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("adb__build_request, data bytes: "); -#endif - /* - * skip first byte if not CUDA ? - */ - for (i = 0; i < nbytes; ++i) { - req->data[i] = va_arg(list, int); -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk("%x ", req->data[i]); -#endif - } -#if (ADBDEBUG & ADBDEBUG_REQUEST) - if (console_loglevel == 10) - printk(" !\n"); -#endif - va_end(list); - - req->reply_expected = 0; - return 0; -} - -/* - * Send an ADB poll (Talk, tagged on the front of the request queue) - */ -void adb_queue_poll(void) -{ - static int pod=0; - static int in_poll=0; - static struct adb_request r; - unsigned long flags; - - if(in_poll) - printk("Double poll!\n"); - - in_poll++; - pod++; - if(pod>7) /* 15 */ - pod=0; - -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("adb: Polling %d\n",pod); -#endif - - if (macintosh_config->adb_type == MAC_ADB_II) - /* XXX: that's a TALK, register 0, MacII version */ - adb_build_request(&r,NULL, 1, (pod<<4|0xC)); - else - /* CUDA etc. version */ - adb_build_request(&r,NULL, 2, 0, (pod<<4|0xC)); - - r.reply_expected=0; - r.done=NULL; - r.sent=0; - r.got_reply=0; - r.reply_len=0; - save_flags(flags); - cli(); - /* Poll inserted at head of queue ... */ - r.next=current_req; - current_req=&r; - restore_flags(flags); - adb_start(); - in_poll--; -} - -/* - * Send an ADB retransmit (Talk, appended to the request queue) - */ -void adb_retransmit(int device) -{ - static int in_retransmit=0; - static struct adb_request rt; - unsigned long flags; - - if(in_retransmit) - printk("Double retransmit!\n"); - - in_retransmit++; - -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("adb: Sending retransmit: %d\n", device); -#endif - - /* MacII version */ - adb_build_request(&rt,NULL, 1, (device<<4|0xC)); - - rt.reply_expected = 0; - rt.done = NULL; - rt.sent = 0; - rt.got_reply = 0; - rt.reply_len = 0; - rt.next = NULL; - - save_flags(flags); - cli(); - - /* Retransmit inserted at tail of queue ... */ - - if (current_req != NULL) - { - last_req->next = &rt; - last_req = &rt; - } - else - { - current_req = &rt; - last_req = &rt; - } - - /* always restart driver (send_retransmit used in place of adb_start!)*/ - - if (adb_state == idle) - adb_start(); - - restore_flags(flags); - in_retransmit--; -} - -/* - * Queue an ADB request; start ADB transfer if necessary - */ -int adb_send_request(struct adb_request *req) -{ - unsigned long flags; - - req->next = 0; - req->sent = 0; - req->got_reply = 0; - req->reply_len = 0; - save_flags(flags); - cli(); - - if (current_req != NULL) - { - last_req->next = req; - last_req = req; - } - else - { - current_req = req; - last_req = req; - if (adb_state == idle) - adb_start(); - } - - restore_flags(flags); - return 0; -} - -static int nclock, ndata; - -static int need_poll = 0; -static int command_byte = 0; -static int last_reply = 0; -static int last_active = 0; - -static struct adb_request *retry_req; - -/* - * Start sending ADB packet - */ -static void adb_start(void) -{ - unsigned long flags; - struct adb_request *req; - - /* - * We get here on three 'sane' conditions: - * 1) called from send_adb_request, if adb_state == idle - * 2) called from within adb_interrupt, if adb_state == idle - * (after receiving, or after sending a LISTEN) - * 3) called from within adb_interrupt, if adb_state == sending - * and no reply is expected (immediate next command). - * Maybe we get here on SRQ as well ?? - */ - - /* get the packet to send */ - req = current_req; - /* assert adb_state == idle */ - if (adb_state != idle) { - printk("ADB: adb_start called while driver busy (%p %x %x)!\n", - req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); - return; - } - if (req == 0) - return; - save_flags(flags); - cli(); - -#if (ADBDEBUG & ADBDEBUG_START) - if (console_loglevel == 10) - printk("adb_start: request %p ", req); -#endif - - nclock = 0; - ndata = 0; - - /* - * IRQ signaled ?? (means ADB controller wants to send, or might - * be end of packet if we were reading) - */ - if ((via_read(via1, vBufB) & TREQ) == 0) - { - switch(macintosh_config->adb_type) - { - /* - * FIXME - we need to restart this on a timer - * or a collision at boot hangs us. - * Never set adb_state to idle here, or adb_start - * won't be called again from send_request! - * (need to re-check other cases ...) - */ - case MAC_ADB_CUDA: - /* printk("device busy - fail\n"); */ - restore_flags(flags); - /* a byte is coming in from the CUDA */ - return; - case MAC_ADB_IISI: - printk("adb_start: device busy - fail\n"); - retry_req = req; - restore_flags(flags); - return; - case MAC_ADB_II: - /* - * if the interrupt handler set the need_poll - * flag, it's hopefully a SRQ poll or re-Talk - * so we try to send here anyway - */ - if (!need_poll) { - printk("device busy - retry %p state %d status %x!\n", - req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); - retry_req = req; - /* set ADB status here ? */ - restore_flags(flags); - return; - } else { -#if (ADBDEBUG & ADBDEBUG_START) - if (console_loglevel == 10) - printk("device busy - polling; state %d status %x!\n", - adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); -#endif - need_poll = 0; - break; - } - } - } - -#if 0 - /* - * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here! - * OTOH: setting ST_CMD in the interrupt routine would make the - * ADB contoller shift in before this routine starts shifting out ... - */ - if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE) - { -#if (ADBDEBUG & ADBDEBUG_STATE) - if (console_loglevel == 10) - printk("ADB bus not idle (%x), retry later!\n", - via_read(via1, vBufB)&(ST_MASK|TREQ)); -#endif - retry_req = req; - restore_flags(flags); - return; - } -#endif - - /* - * Another retry pending? (sanity check) - */ - if (retry_req) { -#if (ADBDEBUG & ADBDEBUG_RETRY) - if (console_loglevel == 10) - if (retry_req == req) - /* new requests are appended at tail of request queue */ - printk("adb_start: retry %p pending ! \n", req); - else - /* poll requests are added to the head of queue */ - printk("adb_start: retry %p pending, req %p (poll?) current! \n", - retry_req, req); -#endif - retry_req = NULL; - } - - /* - * Seems OK, go for it! - */ - switch(macintosh_config->adb_type) - { - case MAC_ADB_CUDA: - /* store command byte (first byte is 'type' byte) */ - command_byte = req->data[1]; - /* set the shift register to shift out and send a byte */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - via_write(via1, vSR, req->data[0]); - via_write(via1, vBufB, via_read(via1, vBufB)&~TIP); - break; - case MAC_ADB_IISI: - /* store command byte (first byte is 'type' byte) */ - command_byte = req->data[1]; - /* set ADB state to 'active' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* switch ACK off (in case it was left on) */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* set the shift register to shift out and send a byte */ - via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); - via_write(via1, vSR, req->data[0]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - break; - case MAC_ADB_II: - /* store command byte */ - command_byte = req->data[0]; - /* Output mode */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - /* Load data */ - via_write(via1, vSR, req->data[0]); -#ifdef USE_ORIG - /* Turn off TIP/TACK - this should tell the external logic to - start the external shift clock */ -/* via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/ - via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK)); -#else - /* set ADB state to 'command' */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD); -#endif - break; - } - adb_state = sent_first_byte; - data_index = 1; -#if (ADBDEBUG & ADBDEBUG_START) - if (console_loglevel == 10) - printk("sent first byte of %d: %x, (%x %x) ... ", - req->nbytes, req->data[0], adb_state, - (via_read(via1, vBufB) & (ST_MASK|TREQ)) ); -#endif - restore_flags(flags); -} - -/* - * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs) - */ -void adb_poll(void) -{ - unsigned char c; - unsigned long flags; - save_flags(flags); - cli(); - c=via_read(via1, vIFR); -#if (ADBDEBUG & ADBDEBUG_POLL) -#ifdef DEBUG_ADB_INTS - if (console_loglevel == 10) { - printk("adb_poll: IFR %x state %x cl %d dat %d ", - c, adb_state, nclock, ndata); - if (c & (SR_CLOCK|SR_DATA)) { - if (c & SR_CLOCK) - printk("adb clock event "); - if (c & SR_DATA) - printk("adb data event "); - } - } -#else - if (console_loglevel == 10) - printk("adb_poll: IFR %x state %x ", - c, adb_state); -#endif - if (console_loglevel == 10) - printk("\r"); -#endif - if (c & SR_INT) - { -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("adb_poll: adb interrupt event\n"); -#endif - adb_interrupt(0, 0, 0); - } - restore_flags(flags); -} - -/* - * Debugging gimmicks - */ -void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - nclock++; -} - -void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - ndata++; -} - -/* - * The notorious ADB interrupt handler - does all of the protocol handling, - * except for starting new send operations. Relies heavily on the ADB - * controller sending and receiving data, thereby generating SR interrupts - * for us. This means there has to be always activity on the ADB bus, otherwise - * the whole process dies and has to be re-kicked by sending TALK requests ... - * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type - * ADB the problem isn't solved yet (retransmit of the latest active TALK seems - * a good choice; either on timeout or on a timer interrupt). - * - * The basic ADB state machine was left unchanged from the original MacII code - * by Alan Cox, which was based on the CUDA driver for PowerMac. - * The syntax of the ADB status lines seems to be totally different on MacII, - * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for - * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start - * and end of a receive packet are signaled by asserting /IRQ on the interrupt - * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on - * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the - * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB - * protocol with a logic analyzer!!) - * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK - * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for - * receiving. No clue how timeouts are handled; SRQ seems to be sent as a - * separate packet. Quite a few changes have been made outside the handshake - * code, so I don't know if the CUDA code still behaves as before. - * - * Note: As of 21/10/97, the MacII ADB part works including timeout detection - * and retransmit (Talk to the last active device). Cleanup of code and - * testing of the CUDA functionality is required, though. - * Note2: As of 13/12/97, CUDA support is definitely broken ... - * Note3: As of 21/12/97, CUDA works on a P475. What was broken? The assumption - * that Q700 and Q800 use CUDA :-( - * - * 27/01/98: IIsi driver implemented (thanks to Robert Thompson for the - * initial bits). See adb_cuda_interrupts ... - * - * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG - * conditionals can be a start?) - */ -void adb_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - int x, adbdir; - unsigned long flags; - struct adb_request *req; - - last_status = status; - - /* prevent races due to SCSI enabling ints */ - save_flags(flags); - cli(); - - if (driver_running) { - restore_flags(flags); - return; - } - - driver_running = 1; - -#ifdef USE_ORIG - status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); -#else - if (macintosh_config->adb_type==MAC_ADB_CUDA) - status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); - else - /* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */ - status = (via_read(via1, vBufB) & (ST_MASK|TREQ)); -#endif - adbdir = (via_read(via1, vACR) & SR_OUT); -#if (ADBDEBUG & ADBDEBUG_INT) - if (console_loglevel == 10) - printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n", - adb_state, status, last_status, adbdir); -#endif - - switch (adb_state) - { - case idle: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - /* CUDA has sent us the first byte of data - unsolicited */ - if (status != TREQ) - printk("cuda: state=idle, status=%x\n", status); - x = via_read(via1, vSR); - via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - udelay(150); - /* set SR to IN (??? no byte received else) */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macIIsi : receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status == TREQ && !adbdir) - /* that's: not IRQ, idle, input -> weird */ - printk("adb_macII: idle, status=%x dir=%x\n", - status, adbdir); -#endif - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macII: receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - /* set ADB state = even for first data byte */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - } - adb_state = reading; - reply_ptr = cuda_rbuf; - reply_len = 0; - reading_reply = 0; - prefix_len = 0; - if (macintosh_config->adb_type==MAC_ADB_II) { - *reply_ptr++ = ADB_PACKET; - *reply_ptr++ = first_byte; - *reply_ptr++ = command_byte; /*first_byte;*/ - reply_len = 3; - prefix_len = 3; - } - break; - - case awaiting_reply: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - /* CUDA has sent us the first byte of data of a reply */ - if (status != TREQ) - printk("cuda: state=awaiting_reply, status=%x\n", status); - x = via_read(via1, vSR); - via_write(via1,vBufB, - via_read(via1, vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* set SR to IN */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macIIsi: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif -#if 0 - if( via_read(via1,vBufB) & TREQ) - ending = 1; - else - ending = 0; -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - /* handshake etc. for II ?? */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_macII: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif - /* set ADB state = even for first data byte */ - via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - } - adb_state = reading; - reply_ptr = current_req->reply; - reading_reply = 1; - reply_len = 0; - prefix_len = 0; - if (macintosh_config->adb_type==MAC_ADB_II) { - *reply_ptr++ = ADB_PACKET; - *reply_ptr++ = first_byte; - *reply_ptr++ = first_byte; /* should be command byte */ - reply_len = 3; - prefix_len = 3; - } - break; - - case sent_first_byte: -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" sending: %x (%x %x) ", - current_req->data[1], adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - if (status == TREQ + TIP + SR_OUT) - { - /* collision */ - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TIP|TACK); - adb_state = idle; - } - else - { - /* assert status == TIP + SR_OUT */ - if (status != TIP + SR_OUT) - printk("cuda: state=sent_first_byte status=%x\n", status); - via_write(via1,vSR,current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index = 2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - if ( !(via_read(via1, vBufB) & TREQ) ) - { - /* collision */ -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("adb_macIIsi: send collison, aborting!\n"); -#endif - /* set shift in */ - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state to 'idle' */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TIP|TACK)); - adb_state = idle; - } - else - { - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); -#endif - via_write(via1, vSR, current_req->data[1]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - data_index=2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - /* how to detect a collision here ?? */ - /* maybe we're already done (Talk, or Poll)? */ - if (data_index >= current_req->nbytes) - { - /* assert it's a Talk ?? */ - if ( (command_byte&0xc) != 0xc - && console_loglevel == 10 ) - printk("ADB: single byte command, no Talk: %x!\n", - command_byte); -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" -> end (%d of %d) (%x %x)!\n", - data_index, current_req->nbytes, adb_state, status); -#endif - current_req->sent = 1; - if (current_req->reply_expected) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("ADB: reply expected on poll!\n"); -#endif - adb_state = awaiting_reply; - reading_reply = 0; - } else { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("ADB: no reply for poll, not calling done()!\n"); -#endif - req = current_req; - current_req = req->next; -#if 0 /* XXX Not sure about that one ... probably better enabled */ - if (req->done) - (*req->done)(req); -#endif - adb_state = idle; - reading_reply = 0; - } - /* set to shift in */ - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - /* set ADB state idle - might get SRQ */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - break; - } -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT)) - printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n", - status, adbdir); -#endif - /* SR already set to shift out; send byte */ - via_write(via1, vSR, current_req->data[1]); - /* set state to ST_EVEN (first byte was: ST_CMD) */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - data_index=2; - adb_state = sending; - } - break; - - case sending: - req = current_req; - if (data_index >= req->nbytes) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" -> end (%d of %d) (%x %x)!\n", - data_index-1, req->nbytes, adb_state, status); -#endif - /* end of packet */ - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TACK|TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* XXX maybe clear ACK here ??? */ - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift in */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state 'idle' (end of frame) */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TACK|TIP)); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - /* - * XXX Not sure: maybe only switch to - * input mode on Talk ?? - */ - /* set to shift in */ - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - /* set ADB state idle - might get SRQ */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - } - req->sent = 1; - if (req->reply_expected) - { - /* - * maybe fake a reply here on Listen ?? - * Otherwise, a Listen hangs on success - */ - if ( macintosh_config->adb_type==MAC_ADB_II - && ((req->data[0]&0xc) == 0xc) ) - adb_state = awaiting_reply; - else if ( macintosh_config->adb_type != MAC_ADB_II - && ( req->data[0] == 0x0) - && ((req->data[1]&0xc) == 0xc) ) - adb_state = awaiting_reply; - else { - /* - * Reply expected, but none - * possible -> fake reply. - * Problem: sending next command - * should probably be done - * without setting bus to 'idle'! - * (except if no more commands) - */ -#if (ADBDEBUG & ADBDEBUG_PROT) - printk("ADB: reply expected on Listen, faking reply\n"); -#endif - /* make it look weird */ - /* XXX: return reply_len -1? */ - /* XXX: fake ADB header? */ - req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; - req->reply_len = 3; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - /* - * ready with this one, run - * next command or repeat last - * Talk (=idle on II) - */ - /* set state to idle !! */ - adb_state = idle; - if (current_req || retry_req) - adb_start(); - } - } - else - { - current_req = req->next; - if (req->done) - (*req->done)(req); - /* not sure about this */ - /* - * MS: Must set idle, no new request - * started else ! - */ - adb_state = idle; - /* - * requires setting ADB state to idle, - * maybe read a byte ! (done above) - */ - if (current_req || retry_req) - adb_start(); - } - } - else - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - req->data[data_index], adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* XXX: need to check for collision?? */ - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); -#endif - via_write(via1, vSR, req->data[data_index++]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vSR, req->data[data_index++]); - /* invert state bits, toggle ODD/EVEN */ - x = via_read(via1, vBufB); - via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); - } - } - break; - - case reading: - - /* timeout / SRQ handling for II hw */ -#ifdef POLL_ON_TIMEOUT - if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) -#else - if( (first_byte == 0xFF && (reply_len-prefix_len)==2 - && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || - ((reply_len-prefix_len)==3 - && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) -#endif - { - /* - * possible timeout (in fact, most probably a - * timeout, since SRQ can't be signaled without - * transfer on the bus). - * The last three bytes seen were FF, together - * with the starting byte (in case we started - * on 'idle' or 'awaiting_reply') this probably - * makes four. So this is mostl likely #5! - * The timeout signal is a pattern 1 0 1 0 0.. - * on /INT, meaning we missed it :-( - */ - x = via_read(via1, vSR); - if (x != 0xFF) - printk("ADB: mistaken timeout/SRQ!\n"); - - /* - * ADB status bits: either even or odd. - * adb_state: need to set 'idle' here. - * Maybe saner: set 'need_poll' or - * 'need_resend' here, fall through to - * read_done ?? - */ -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" -> read aborted: %x (%x %x)!\n", - x, adb_state, status); -#endif - -#if 0 /* XXX leave status unchanged!! - need to check this again! */ - /* XXX Only touch status on II !!! */ - /* set ADB state to idle (required by adb_start()) */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); -#endif - - /* - * What if the timeout happens on reading a - * reply ?? Assemble error reply and call - * current_request->done()? Keep request - * on queue? - */ - - /* prevent 'busy' in adb_start() */ - need_poll = 1; - - /* - * Timeout: /IRQ alternates high/low during - * 4 'FF' bytes (1 0 1 0 0...) - * We're on byte 5, so we need one - * more backlog here (TBI) .... - */ - if ((status&TREQ) != (last_status&TREQ)) { -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("ADB: reply timeout, resending!\n"); -#endif - /* - * first byte received should be the - * command byte timing out !! - */ - if (first_byte != 0xff) - command_byte = first_byte; - - /* - * compute target for retransmit: if - * last_active is set, use that one, - * else use command_byte - */ - if (last_active == -1) - last_active = (command_byte&0xf0)>>4; - adb_state = idle; - /* resend if TALK, don't poll! */ - if (current_req) - adb_start(); - else - /* - * XXX: need to count the timeouts ?? - * restart last active TALK ?? - * If no current_req, reuse old one! - */ - adb_retransmit(last_active); - - } else { - /* - * SRQ: NetBSD suggests /IRQ is asserted!? - */ - if (status&TREQ) - printk("ADB: SRQ signature w/o /INT!\n"); -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("ADB: empty SRQ packet!\n"); -#endif - /* Terminate the SRQ packet and poll */ - adb_state = idle; - adb_queue_poll(); - } - /* - * Leave ADB status lines unchanged (means /IRQ - * will still be low when entering adb_start!) - */ - break; - } - /* end timeout / SRQ handling for II hw. */ - if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) - { - /* SRQ tacked on data packet */ - /* Check /IRQ here ?? */ -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("\nADB: Packet with SRQ!\n"); -#endif - /* Terminate the packet (SRQ never ends) */ - x = via_read(via1, vSR); - adb_state = read_done; - reply_len -= 3; - reply_ptr -= 3; - need_poll = 1; - /* need to continue; next byte not seen else */ - /* - * XXX: not at all sure here; maybe need to - * send away the reply and poll immediately? - */ - } else { - /* Sanity check */ - if(reply_len>15) - reply_len=0; - /* read byte */ - *reply_ptr = via_read(via1, vSR); - x = *reply_ptr; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - *reply_ptr, adb_state, status); -#endif - reply_ptr++; - reply_len++; - } - /* The usual handshake ... */ - if (macintosh_config->adb_type==MAC_ADB_CUDA) - { - if (status == TIP) - { - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { - /* assert status == TIP | TREQ */ - if (status != TIP + TREQ) - printk("cuda: state=reading status=%x\n", status); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - else if (macintosh_config->adb_type==MAC_ADB_IISI) - { - /* ACK adb chip (maybe check for end first?) */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* end of frame?? */ - if (status & TREQ) - { -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi: end of frame!\n"); -#endif - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB) & ~(TACK|TIP)); - adb_state = read_done; - /* maybe process read_done here?? Handshake anyway?? */ - } - } - else if (macintosh_config->adb_type==MAC_ADB_II) - { - /* - * NetBSD hints that the next to last byte - * is sent with IRQ !! - * Guido found out it's the last one (0x0), - * but IRQ should be asserted already. - * Problem with timeout detection: First - * transition to /IRQ might be second - * byte of timeout packet! - * Timeouts are signaled by 4x FF. - */ - if(!(status&TREQ) && x == 0x00) /* != 0xFF */ - { -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" -> read done!\n"); -#endif -#if 0 /* XXX: we take one more byte (why?), so handshake! */ - /* set ADB state to idle */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); -#else - /* invert state bits, toggle ODD/EVEN */ - x = via_read(via1, vBufB); - via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); -#endif - /* adjust packet length */ - reply_len--; - reply_ptr--; - adb_state = read_done; - } - else - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(status!=TIP+TREQ) - printk("macII_adb: state=reading status=%x\n", status); -#endif - /* not caught: ST_CMD */ - /* required for re-entry 'reading'! */ - if ((status&ST_MASK) == ST_IDLE) { - /* (in)sanity check - set even */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); - } else { - /* invert state bits, toggle ODD/EVEN */ - x = via_read(via1, vBufB); - via_write(via1, vBufB, - (x&~ST_MASK)|~(x&ST_MASK)); - } - } - } - break; - - case read_done: - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("ADB: read done: %x (%x %x)!\n", - x, adb_state, status); -#endif - if (reading_reply) - { - req = current_req; - req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - } - else - { - adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); - } - - /* - * remember this device ID; it's the latest we got a - * reply from! - */ - last_reply = command_byte; - last_active = (command_byte&0xf0)>>4; - - /* - * Assert status = ST_IDLE ?? - */ - /* - * SRQ seen before, initiate poll now - */ - if (need_poll) { -#if (ADBDEBUG & ADBDEBUG_POLL) - if (console_loglevel == 10) - printk("ADB: initiate poll!\n"); -#endif - adb_state = idle; - /* - * set ADB status bits?? (unchanged above!) - */ - adb_queue_poll(); - need_poll = 0; - /* hope this is ok; queue_poll runs adb_start */ - break; - } - - /* - * /IRQ seen, so the ADB controller has data for us - */ - if (!(status&TREQ)) - { - /* set ADB state to idle */ - via_write(via1, vBufB, - (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); - - adb_state = reading; - reply_ptr = cuda_rbuf; - reply_len = 0; - prefix_len = 0; - if (macintosh_config->adb_type==MAC_ADB_II) { - *reply_ptr++ = ADB_PACKET; - *reply_ptr++ = command_byte; - reply_len = 2; - prefix_len = 2; - } - reading_reply = 0; - } - else - { - /* - * no IRQ, send next packet or wait - */ - adb_state = idle; - if (current_req) - adb_start(); - else - adb_retransmit(last_active); - } - break; - - default: -#if (ADBDEBUG & ADBDEBUG_STATE) - printk("adb_interrupt: unknown adb_state %d?\n", adb_state); -#endif - } - /* reset mutex and interrupts */ - driver_running = 0; - restore_flags(flags); -} - -/* - * Restart of CUDA support: please modify this interrupt handler while - * working at the Quadra etc. ADB driver. We can try to merge them later, or - * remove the CUDA stuff from the MacII handler - * - * MSch 27/01/98: Implemented IIsi driver based on initial code by Robert - * Thompson and hints from the NetBSD driver. CUDA and IIsi seem more closely - * related than to the MacII code, so merging all three might be a bad - * idea. - */ - -void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs) -{ - int x, status; - struct adb_request *req; - unsigned long flags; - - save_flags(flags); - cli(); - - if(macintosh_config->adb_type==MAC_ADB_CUDA) - status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); - else - status = via_read(via1, vBufB) & (TIP|TREQ); - -#if (ADBDEBUG & ADBDEBUG_INT) - if (console_loglevel == 10) - printk("adb_interrupt: state=%d status=%x\n", adb_state, status); -#endif - - switch (adb_state) - { - case idle: - first_byte = 0; - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - /* CUDA has sent us the first byte of data - unsolicited */ - if (status != TREQ) - printk("cuda: state=idle, status=%x want=%x\n", - status, TREQ); -#endif - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_cuda: receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - udelay(150); - /* set SR to IN */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi : receiving unsol. packet: %x (%x %x) ", - x, adb_state, status); -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - if (status != TREQ) - printk("adb_macII: state=idle status=%x want=%x\n", - status, TREQ); - x = via_read(via1, vSR); - via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); - } - adb_state = reading; - reply_ptr = cuda_rbuf; - reply_len = 0; - reading_reply = 0; - break; - - case awaiting_reply: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - /* CUDA has sent us the first byte of data of a reply */ -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status != TREQ) - printk("cuda: state=awaiting_reply, status=%x want=%x\n", - status, TREQ); -#endif - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_cuda: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif - via_write(via1,vBufB, - via_read(via1, vBufB)&~TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* udelay(150);*/ - /* set SR to IN */ - via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); - /* signal start of frame */ - via_write(via1, vBufB, via_read(via1, vBufB) | TIP); - /* read first byte */ - x = via_read(via1, vSR); - first_byte = x; -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi: reading reply: %x (%x %x) ", - x, adb_state, status); -#endif -#if 0 - if( via_read(via1,vBufB) & TREQ) - ending = 1; - else - ending = 0; -#endif - /* ACK adb chip */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - } - adb_state = reading; - reply_ptr = current_req->reply; - reading_reply = 1; - reply_len = 0; - break; - - case sent_first_byte: - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" sending: %x (%x %x) ", - current_req->data[1], adb_state, status); -#endif - if (status == TREQ + TIP + SR_OUT) - { - /* collision */ - if (console_loglevel == 10) - printk("adb_cuda: send collision!\n"); - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TIP|TACK); - adb_state = idle; - } - else - { - /* assert status == TIP + SR_OUT */ -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status != TIP + SR_OUT) - printk("adb_cuda: state=sent_first_byte status=%x want=%x\n", - status, TIP + SR_OUT); -#endif - via_write(via1,vSR,current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index = 2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - if ( !(via_read(via1, vBufB) & TREQ) ) - { - /* collision */ -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk("adb_macIIsi: send collison, aborting!\n"); -#endif - /* set shift in */ - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state to 'idle' */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TIP|TACK)); - adb_state = idle; - } - else - { - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); -#endif - via_write(via1, vSR, current_req->data[1]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - data_index=2; - adb_state = sending; - } - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - if(status!=TIP+SR_OUT) - printk("adb_macII: state=send_first_byte status=%x want=%x\n", - status, TIP+SR_OUT); - via_write(via1, vSR, current_req->data[1]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - data_index=2; - adb_state = sending; - } - break; - - case sending: - req = current_req; - if (data_index >= req->nbytes) - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" -> end (%d of %d) (%x %x)!\n", - data_index-1, req->nbytes, adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vACR, - via_read(via1, vACR)&~SR_OUT); - x = via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1,vBufB)|TACK|TIP); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* XXX maybe clear ACK here ??? */ - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* set the shift register to shift in */ - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); - /* clear SR int. */ - x = via_read(via1, vSR); - /* set ADB state 'idle' (end of frame) */ - via_write(via1, vBufB, - via_read(via1,vBufB) & ~(TACK|TIP)); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vACR, - via_read(via1, vACR) & ~SR_OUT); - x=via_read(via1, vSR); - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - } - req->sent = 1; - if (req->reply_expected) - { - /* - * maybe fake a reply here on Listen ?? - * Otherwise, a Listen hangs on success - * CUDA+IIsi: only ADB Talk considered - * RTC/PRAM read (0x1 0x3) to follow. - */ - if ( (req->data[0] == 0x0) && ((req->data[1]&0xc) == 0xc) ) - adb_state = awaiting_reply; - else { - /* - * Reply expected, but none - * possible -> fake reply. - */ -#if (ADBDEBUG & ADBDEBUG_PROT) - printk("ADB: reply expected on Listen, faking reply\n"); -#endif - /* make it look weird */ - /* XXX: return reply_len -1? */ - /* XXX: fake ADB header? */ - req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; - req->reply_len = 3; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - /* - * ready with this one, run - * next command ! - */ - /* set state to idle !! */ - adb_state = idle; - if (current_req || retry_req) - adb_start(); - } - } - else - { - current_req = req->next; - if (req->done) - (*req->done)(req); - /* not sure about this */ - adb_state = idle; - adb_start(); - } - } - else - { -#if (ADBDEBUG & ADBDEBUG_WRITE) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - req->data[data_index], adb_state, status); -#endif - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_IISI) - { - /* switch ACK off */ - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* delay */ - udelay(ADB_DELAY); - /* XXX: need to check for collision?? */ - /* set the shift register to shift out and send a byte */ -#if 0 - via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); -#endif - via_write(via1, vSR, req->data[data_index++]); - /* signal 'byte ready' */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - } - else if(macintosh_config->adb_type==MAC_ADB_II) - { - via_write(via1, vSR, req->data[data_index++]); - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - break; - - case reading: - if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) - { - /* Terminate the SRQ packet */ -#if (ADBDEBUG & ADBDEBUG_SRQ) - if (console_loglevel == 10) - printk("adb: Got an SRQ\n"); -#endif - adb_state = idle; - adb_queue_poll(); - break; - } - /* Sanity check - botched in orig. code! */ - if(reply_len>15) { - printk("adb_cuda: reply buffer overrun!\n"); - /* wrap buffer */ - reply_len=0; - if (reading_reply) - reply_ptr = current_req->reply; - else - reply_ptr = cuda_rbuf; - } - *reply_ptr = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk(" %x (%x %x) ", - *reply_ptr, adb_state, status); -#endif - reply_ptr++; - reply_len++; - if(macintosh_config->adb_type==MAC_ADB_CUDA) - { - if (status == TIP) - { - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { - /* assert status == TIP | TREQ */ -#if (ADBDEBUG & ADBDEBUG_STATUS) - if (status != TIP + TREQ) - printk("cuda: state=reading status=%x want=%x\n", - status, TIP + TREQ); -#endif - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - else if (macintosh_config->adb_type==MAC_ADB_IISI) - { - /* ACK adb chip (maybe check for end first?) */ - via_write(via1, vBufB, via_read(via1, vBufB) | TACK); - udelay(150); - via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK); - /* end of frame?? */ - if (status & TREQ) - { -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb_IIsi: end of frame!\n"); -#endif - /* that's all folks */ - via_write(via1, vBufB, - via_read(via1, vBufB) & ~(TACK|TIP)); - adb_state = read_done; - /* XXX maybe process read_done here?? - Handshake anyway?? */ - } - } - if(macintosh_config->adb_type==MAC_ADB_II) - { - if( status == TIP) - { - via_write(via1, vBufB, - via_read(via1, vBufB)|TACK|TIP); - adb_state = read_done; - } - else - { -#if (ADBDEBUG & ADBDEBUG_STATUS) - if(status!=TIP+TREQ) - printk("macII_adb: state=reading status=%x\n", status); -#endif - via_write(via1, vBufB, - via_read(via1, vBufB)^TACK); - } - } - /* fall through for IIsi on end of frame */ - if (macintosh_config->adb_type != MAC_ADB_IISI - || adb_state != read_done) - break; - - case read_done: - x = via_read(via1, vSR); -#if (ADBDEBUG & ADBDEBUG_READ) - if (console_loglevel == 10) - printk("adb: read done: %x (%x %x)!\n", - x, adb_state, status); -#endif - if (reading_reply) - { - req = current_req; - req->reply_len = reply_ptr - req->reply; - req->got_reply = 1; - current_req = req->next; - if (req->done) - (*req->done)(req); - } - else - { - adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); - } - - if (macintosh_config->adb_type==MAC_ADB_CUDA - && status & TREQ) - { - via_write(via1, vBufB, - via_read(via1, vBufB)&~TIP); - adb_state = reading; - reply_ptr = cuda_rbuf; - reading_reply = 0; - } - else if (macintosh_config->adb_type==MAC_ADB_IISI - && !(status & TREQ)) - { - udelay(150); - via_write(via1, vBufB, - via_read(via1, vBufB) | TIP); - adb_state = reading; - reply_ptr = cuda_rbuf; - reading_reply = 0; - } - else - { - adb_state = idle; - adb_start(); - } - break; - - default: - printk("adb_cuda_interrupt: unknown adb_state %d?\n", adb_state); - } - - restore_flags(flags); - -} - -/* - * The 'reply delivery' routine; determines which device sent the - * request and calls the appropriate handler. - * Reply data are expected in CUDA format (again, argh...) so we need - * to fake this in the interrupt handler for MacII. - * Only one handler per device ID is currently possible. - * XXX: is the ID field here representing the default or real ID? - */ -static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs) -{ - int i, id; - - switch (buf[0]) - { - case ADB_PACKET: - /* what's in buf[1] ?? */ - id = buf[2] >> 4; -#if 0 - xmon_printf("adb packet: "); - for (i = 0; i < nb; ++i) - xmon_printf(" %x", buf[i]); - xmon_printf(", id = %d\n", id); -#endif -#if (ADBDEBUG & ADBDEBUG_INPUT) - if (console_loglevel == 10) { - printk("adb_input: adb packet "); - for (i = 0; i < nb; ++i) - printk(" %x", buf[i]); - printk(", id = %d\n", id); - } -#endif - if (adb_handler[id].handler != 0) - { - (*adb_handler[id].handler)(buf, nb, regs); - } - break; - - default: -#if (ADBDEBUG & ADBDEBUG_INPUT) - if (console_loglevel == 10) { - printk("adb_input: data from via (%d bytes):", nb); - for (i = 0; i < nb; ++i) - printk(" %.2x", buf[i]); - printk("\n"); - } -#endif - } -} - -/* Ultimately this should return the number of devices with - the given default id. */ - -int adb_register(int default_id, - void (*handler)(unsigned char *, int, struct pt_regs *)) -{ - if (adb_handler[default_id].handler != 0) - panic("Two handlers for ADB device %d\n", default_id); - adb_handler[default_id].handler = handler; - return 1; -} - -/* - * /dev/adb device driver. - */ - -#define ADB_MAJOR 56 /* major number for /dev/adb */ - -#define ADB_MAX_MINOR 64 /* range of ADB minors */ -#define ADB_TYPE_SHIFT 4 /* # bits for device ID/type in subdevices */ - -#define ADB_TYPE_RAW 0 /* raw device; unbuffered */ -#define ADB_TYPE_BUFF 1 /* raw device; buffered */ -#define ADB_TYPE_COOKED 2 /* 'cooked' device */ - - -extern void adbdev_init(void); - -struct adbdev_state { - struct adb_request req; -}; - -static DECLARE_WAIT_QUEUE_HEAD(adb_wait); - -static int adb_wait_reply(struct adbdev_state *state, struct file *file) -{ - int ret = 0; - DECLARE_WAITQUEUE(wait,current); - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&adb_wait, &wait); - - while (!state->req.got_reply) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&adb_wait, &wait); - - return ret; -} - -static void adb_write_done(struct adb_request *req) -{ - if (!req->got_reply) { - req->reply_len = 0; - req->got_reply = 1; - } - wake_up_interruptible(&adb_wait); -} - -struct file_operations *adb_raw[16]; -struct file_operations *adb_buffered[16]; -struct file_operations *adb_cooked[16]; - -static int adb_open(struct inode *inode, struct file *file) -{ - int adb_type, adb_subtype; - struct adbdev_state *state; - - if (MINOR(inode->i_rdev) > ADB_MAX_MINOR) - return -ENXIO; - - switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) { - case ADB_TYPE_RAW: - /* see code below */ - break; - case ADB_TYPE_BUFF: - /* TBI */ - return -ENXIO; - case ADB_TYPE_COOKED: - /* subtypes such as kbd, mouse, ... */ - adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT; - if ((file->f_op = adb_cooked[adb_subtype])) - return file->f_op->open(inode,file); - else - return -ENODEV; - } - - state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); - if (state == 0) - return -ENOMEM; - file->private_data = state; - state->req.reply_expected = 0; - return 0; -} - -static void adb_release(struct inode *inode, struct file *file) -{ - struct adbdev_state *state = file->private_data; - - if (state) { - file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) - if (adb_wait_reply(state, file)) - return; - kfree(state); - } - return; -} - -static int adb_lseek(struct inode *inode, struct file *file, - off_t offset, int origin) -{ - return -ESPIPE; -} - -static int adb_read(struct inode *inode, struct file *file, - char *buf, int count) -{ - int ret; - struct adbdev_state *state = file->private_data; - - if (count < 2) - return -EINVAL; - if (count > sizeof(state->req.reply)) - count = sizeof(state->req.reply); - ret = verify_area(VERIFY_WRITE, buf, count); - if (ret) - return ret; - - if (!state->req.reply_expected) - return 0; - - ret = adb_wait_reply(state, file); - if (ret) - return ret; - - state->req.reply_expected = 0; - ret = state->req.reply_len; - copy_to_user(buf, state->req.reply, ret); - - return ret; -} - -static int adb_write(struct inode *inode, struct file *file, - const char *buf, int count) -{ - int ret, i; - struct adbdev_state *state = file->private_data; - - if (count < 2 || count > sizeof(state->req.data)) - return -EINVAL; - ret = verify_area(VERIFY_READ, buf, count); - if (ret) - return ret; - - if (state->req.reply_expected && !state->req.got_reply) { - /* A previous request is still being processed. - Wait for it to finish. */ - ret = adb_wait_reply(state, file); - if (ret) - return ret; - } - - state->req.nbytes = count; - state->req.done = adb_write_done; - state->req.got_reply = 0; - copy_from_user(state->req.data, buf, count); -#if 0 - switch (adb_hardware) { - case ADB_NONE: - return -ENXIO; - case ADB_VIACUDA: - state->req.reply_expected = 1; - cuda_send_request(&state->req); - break; - default: -#endif - if (state->req.data[0] != ADB_PACKET) - return -EINVAL; - for (i = 1; i < state->req.nbytes; ++i) - state->req.data[i] = state->req.data[i+1]; - state->req.reply_expected = - ((state->req.data[0] & 0xc) == 0xc); - adb_send_request(&state->req); -#if 0 - break; - } -#endif - - return count; -} - -static struct file_operations adb_fops = { - llseek: adb_lseek, - read: adb_read, - write: adb_write, - open: adb_open, - release: adb_release, -}; - -int adbdev_register(int subtype, struct file_operations *fops) -{ - if (subtype < 0 || subtype > 15) - return -EINVAL; - if (adb_cooked[subtype]) - return -EBUSY; - adb_cooked[subtype] = fops; - return 0; -} - -int adbdev_unregister(int subtype) -{ - if (subtype < 0 || subtype > 15) - return -EINVAL; - if (!adb_cooked[subtype]) - return -ENODEV; - adb_cooked[subtype] = NULL; - return 0; -} - -void adbdev_init() -{ - if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) - printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); -} - - -#if 0 /* old ADB device */ - -/* - * Here are the file operations we export for /dev/adb. - */ - -#define ADB_MINOR 140 /* /dev/adb is c 10 140 */ - -extern void adbdev_inits(void); - -struct adbdev_state { - struct adb_request req; -}; - -static DECLARE_WAIT_QUEUE_HEAD(adb_wait); - -static int adb_wait_reply(struct adbdev_state *state, struct file *file) -{ - int ret = 0; - DECLARE_WAITQUEUE(wait, current); - -#if (ADBDEBUG & ADBDEBUG_DEVICE) - printk("ADB request: wait_reply (blocking ... \n"); -#endif - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&adb_wait, &wait); - - while (!state->req.got_reply) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&adb_wait, &wait); - - return ret; -} - -static void adb_write_done(struct adb_request *req) -{ - if (!req->got_reply) { - req->reply_len = 0; - req->got_reply = 1; - } - wake_up_interruptible(&adb_wait); -} - -static int adb_open(struct inode *inode, struct file *file) -{ - struct adbdev_state *state; - - state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); - if (state == 0) - return -ENOMEM; - file->private_data = state; - state->req.reply_expected = 0; - return 0; -} - -static void adb_release(struct inode *inode, struct file *file) -{ - struct adbdev_state *state = file->private_data; - - if (state) { - file->private_data = NULL; - if (state->req.reply_expected && !state->req.got_reply) - if (adb_wait_reply(state, file)) - return; - kfree(state); - } - return; -} - -static int adb_lseek(struct inode *inode, struct file *file, - off_t offset, int origin) -{ - return -ESPIPE; -} - -static int adb_read(struct inode *inode, struct file *file, - char *buf, int count) -{ - int ret; - struct adbdev_state *state = file->private_data; - - if (count < 2) - return -EINVAL; - if (count > sizeof(state->req.reply)) - count = sizeof(state->req.reply); - ret = verify_area(VERIFY_WRITE, buf, count); - if (ret) - return ret; - - if (!state->req.reply_expected) - return 0; - - ret = adb_wait_reply(state, file); - if (ret) - return ret; - - ret = state->req.reply_len; - memcpy_tofs(buf, state->req.reply, ret); - state->req.reply_expected = 0; - - return ret; -} - -static int adb_write(struct inode *inode, struct file *file, - const char *buf, int count) -{ - int ret; - struct adbdev_state *state = file->private_data; - - if (count < 2 || count > sizeof(state->req.data)) - return -EINVAL; - ret = verify_area(VERIFY_READ, buf, count); - if (ret) - return ret; - - if (state->req.reply_expected && !state->req.got_reply) { - /* A previous request is still being processed. - Wait for it to finish. */ - ret = adb_wait_reply(state, file); - if (ret) - return ret; - } - - state->req.nbytes = count; - state->req.done = adb_write_done; - memcpy_fromfs(state->req.data, buf, count); - state->req.reply_expected = 1; - state->req.got_reply = 0; - adb_send_request(&state->req); - - return count; -} - -static struct file_operations adb_fops = { - llseek: adb_lseek, - read: adb_read, - write: adb_write, - open: adb_open, - release: adb_release, -}; - -static struct miscdevice adb_dev = { - ADB_MINOR, - "adb", - &adb_fops -}; - -void adbdev_init(void) -{ - misc_register(&adb_dev); -} - -#endif /* old ADB device */ diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/baboon.c linux/arch/m68k/mac/baboon.c --- v2.3.44/linux/arch/m68k/mac/baboon.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/baboon.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,125 @@ +/* + * Baboon Custom IC Managment + * + * The Baboon custom IC controls the IDE, PCMCIA and media bay on the + * PowerBook 190. It multiplexes multiple interrupt sources onto the + * Nubus slot $C interrupt. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* #define DEBUG_BABOON /**/ +/* #define DEBUG_IRQS /**/ + +int baboon_present,baboon_active; +volatile struct baboon *baboon; + +void baboon_irq(int, void *, struct pt_regs *); + +extern int console_loglevel; + +extern int macide_ack_intr(ide_hwif_t *); + +/* + * Baboon initialization. + */ + +void __init baboon_init(void) +{ + if (macintosh_config->ident != MAC_MODEL_PB190) { + baboon = NULL; + baboon_present = 0; + return; + } + + baboon = (struct baboon *) BABOON_BASE; + baboon_present = 1; + baboon_active = 0; + + printk("Baboon detected at %p\n", baboon); +} + +/* + * Register the Baboon interrupt dispatcher on nubus slot $C. + */ + +void __init baboon_register_interrupts(void) +{ + request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "baboon", (void *) baboon); +} + +/* + * Baboon interrupt handler. This works a lot like a VIA. + */ + +void baboon_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int irq_bit,i; + unsigned char events; + +#ifdef DEBUG_IRQS + printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n", + (uint) baboon->mb_control, (uint) baboon->mb_ifr, + (uint) baboon->mb_status, baboon_active); +#endif + + if (!(events = baboon->mb_ifr & 0x07)) return; + + for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { + if (events & irq_bit/* & baboon_active*/) { + baboon_active &= ~irq_bit; + mac_do_irq_list(IRQ_BABOON_0 + i, regs); + baboon_active |= irq_bit; + baboon->mb_ifr &= ~irq_bit; + } + } +#if 0 + if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL); + /* for now we need to smash all interrupts */ + baboon->mb_ifr &= ~events; +#endif +} + +void baboon_irq_enable(int irq) { + int irq_idx = IRQ_IDX(irq); + +#ifdef DEBUG_IRQUSE + printk("baboon_irq_enable(%d)\n", irq); +#endif + baboon_active |= (1 << irq_idx); +} + +void baboon_irq_disable(int irq) { + int irq_idx = IRQ_IDX(irq); + +#ifdef DEBUG_IRQUSE + printk("baboon_irq_disable(%d)\n", irq); +#endif + baboon_active &= ~(1 << irq_idx); +} + +void baboon_irq_clear(int irq) { + int irq_idx = IRQ_IDX(irq); + + baboon->mb_ifr &= ~(1 << irq_idx); +} + +int baboon_irq_pending(int irq) +{ + int irq_idx = IRQ_IDX(irq); + + return baboon->mb_ifr & (1 << irq_idx); +} diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c --- v2.3.44/linux/arch/m68k/mac/config.c Tue Sep 7 12:14:06 1999 +++ linux/arch/m68k/mac/config.c Sun Feb 13 11:21:42 2000 @@ -42,16 +42,6 @@ #include #include -/* Offset between Unix time (1970-based) and Mac time (1904-based) */ - -#define MAC_TIME_OFFSET 2082844800 - -/* - * hardware reset vector - */ - -static void (*rom_reset)(void); - /* Mac bootinfo struct */ struct mac_booter_data mac_bi_data = {0,}; @@ -76,10 +66,11 @@ extern void mackbd_leds(unsigned int leds); /* Mac specific timer functions */ +extern void mac_gettod (int *, int *, int *, int *, int *, int *); extern unsigned long mac_gettimeoffset (void); -static void mac_gettod (int *, int *, int *, int *, int *, int *); -static int mac_hwclk (int, struct hwclk_time *); -static int mac_set_clock_mmss (unsigned long); +extern int mac_hwclk (int, struct hwclk_time *); +extern int mac_set_clock_mmss (unsigned long); +extern int mac_get_irq_list(char *); extern void iop_preinit(void); extern void iop_init(void); extern void via_init(void); @@ -87,6 +78,7 @@ extern void via_flush_cache(void); extern void oss_init(void); extern void psc_init(void); +extern void baboon_init(void); extern void (*kd_mksound)(unsigned int, unsigned int); extern void mac_mksound(unsigned int, unsigned int); @@ -99,18 +91,6 @@ extern void mac_debug_init(void); extern void mac_debugging_long(int, long); -/* poweroff functions */ -extern void via_poweroff(void); -extern void oss_poweroff(void); -extern void adb_poweroff(void); -extern void adb_hwreset(void); - -/* pram functions */ -extern __u32 via_read_time(void); -extern void via_write_time(__u32); -extern __u32 adb_read_time(void); -extern void adb_write_time(__u32); - #ifdef CONFIG_MAGIC_SYSRQ static char mac_sysrq_xlate[128] = "\000sdfghzxcv\000bqwer" /* 0x00 - 0x0f */ @@ -140,186 +120,6 @@ extern int console_loglevel; -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - -/* - * This function translates seconds since 1970 into a proper date. - * - * Algorithm cribbed from glibc2.1, __offtime(). - */ -#define SECS_PER_MINUTE (60) -#define SECS_PER_HOUR (SECS_PER_MINUTE * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) - -static void unmktime(unsigned long time, long offset, - int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - /* How many days come before each month (0-12). */ - static const unsigned short int __mon_yday[2][13] = - { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - long int days, rem, y, wday, yday; - const unsigned short int *ip; - - days = time / SECS_PER_DAY; - rem = time % SECS_PER_DAY; - rem += offset; - while (rem < 0) { - rem += SECS_PER_DAY; - --days; - } - while (rem >= SECS_PER_DAY) { - rem -= SECS_PER_DAY; - ++days; - } - *hourp = rem / SECS_PER_HOUR; - rem %= SECS_PER_HOUR; - *minp = rem / SECS_PER_MINUTE; - *secp = rem % SECS_PER_MINUTE; - /* January 1, 1970 was a Thursday. */ - wday = (4 + days) % 7; /* Day in the week. Not currently used */ - if (wday < 0) wday += 7; - y = 1970; - -#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) -#define __isleap(year) \ - ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) - - while (days < 0 || days >= (__isleap (y) ? 366 : 365)) - { - /* Guess a corrected year, assuming 365 days per year. */ - long int yg = y + days / 365 - (days % 365 < 0); - - /* Adjust DAYS and Y to match the guessed year. */ - days -= ((yg - y) * 365 - + LEAPS_THRU_END_OF (yg - 1) - - LEAPS_THRU_END_OF (y - 1)); - y = yg; - } - *yearp = y - 1900; - yday = days; /* day in the year. Not currently used. */ - ip = __mon_yday[__isleap(y)]; - for (y = 11; days < (long int) ip[y]; --y) - continue; - days -= ip[y]; - *monp = y; - *dayp = days + 1; /* day in the month */ - return; -} - -/* - * Return the boot time for use in initializing the kernel clock. - * - * I'd like to read the hardware clock here but many machines read - * the PRAM through ADB, and interrupts aren't initialized when this - * is called so ADB obviously won't work. - */ - -static void mac_gettod(int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - /* Yes the GMT bias is backwards. It looks like Penguin is - screwing up the boottime it gives us... This works for me - in Canada/Eastern but it might be wrong everywhere else. */ - unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60, - yearp, monp, dayp, hourp, minp, secp); - /* For some reason this is off by one */ - *monp = *monp + 1; -} - -/* - * Read/write the hardware clock. - */ - -static int mac_hwclk(int op, struct hwclk_time *t) -{ - unsigned long now; - - if (!op) { /* read */ - if (macintosh_config->adb_type == MAC_ADB_II) { - now = via_read_time(); - } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || - (macintosh_config->adb_type == MAC_ADB_CUDA)) { - now = adb_read_time(); - } else if (macintosh_config->adb_type == MAC_ADB_IOP) { - now = via_read_time(); - } else { - now = MAC_TIME_OFFSET; - } - - now -= MAC_TIME_OFFSET; - - t->wday = 0; - unmktime(now, 0, - &t->year, &t->mon, &t->day, - &t->hour, &t->min, &t->sec); - } else { /* write */ - now = mktime(t->year + 1900, t->mon + 1, t->day, - t->hour, t->min, t->sec) + MAC_TIME_OFFSET; - - if (macintosh_config->adb_type == MAC_ADB_II) { - via_write_time(now); - } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || - (macintosh_config->adb_type == MAC_ADB_CUDA)) { - adb_write_time(now); - } else if (macintosh_config->adb_type == MAC_ADB_IOP) { - via_write_time(now); - } - } - return 0; -} - -/* - * Set minutes/seconds in the hardware clock - */ - -static int mac_set_clock_mmss (unsigned long nowtime) -{ - struct hwclk_time now; - - mac_hwclk(0, &now); - now.sec = nowtime % 60; - now.min = (nowtime / 60) % 60; - mac_hwclk(1, &now); - - return 0; -} - #if 0 void mac_waitbut (void) { @@ -330,9 +130,23 @@ extern struct consw fb_con; extern struct fb_info *mac_fb_init(long *); - /* - * Parse a Macintosh-specific record in the bootinfo - */ +extern void mac_default_handler(int, void *, struct pt_regs *); + +void (*mac_handlers[8])(int, void *, struct pt_regs *)= +{ + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler +}; + +/* + * Parse a Macintosh-specific record in the bootinfo + */ int __init mac_parse_bootinfo(const struct bi_record *record) { @@ -384,9 +198,9 @@ } /* - * Flip into 24bit mode for an instant - flushes the L2 cache card. We - * have to disable interrupts for this. Our IRQ handlers will crap - * themselves if they take an IRQ in 24bit mode! + * Flip into 24bit mode for an instant - flushes the L2 cache card. We + * have to disable interrupts for this. Our IRQ handlers will crap + * themselves if they take an IRQ in 24bit mode! */ static void mac_cache_card_flush(int writeback) @@ -414,6 +228,8 @@ enable_irq = mac_enable_irq; disable_irq = mac_disable_irq; mach_get_model = mac_get_model; + mach_default_handler = &mac_handlers; + mach_get_irq_list = mac_get_irq_list; mach_gettimeoffset = mac_gettimeoffset; mach_gettod = mac_gettod; mach_hwclk = mac_hwclk; @@ -489,7 +305,6 @@ static struct mac_model mac_data_table[]= { /* - * The default machine, in case we get an unsupported one * We'll pretend to be a Macintosh II, that's pretty safe. */ @@ -509,10 +324,6 @@ * Weirdified MacII hardware - all subtley different. Gee thanks * Apple. All these boxes seem to have VIA2 in a different place to * the MacII (+1A000 rather than +4000) - * - * The IIfx apparently has different ADB hardware, and stuff - * so zany nobody knows how to drive it. - * Even so, with Marten's help we'll try to deal with it :-) * CSA: see http://developer.apple.com/technotes/hw/hw_09.html */ @@ -584,28 +395,33 @@ { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_MACE, MAC_NUBUS}, /* - * Power books - seem similar to early Quadras ? (most have 030 though) - */ - - { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - /* The PB150 has IDE, and IIci style VIA */ - { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_PB190, "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - /* These have onboard SONIC */ - { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - - /* - * Power book Duos - similar to Power books, I hope + * The PowerBooks all the same "Combo" custom IC for SCSI and SCC + * and a PMU (in two variations?) for ADB. Most of them use the + * Quadra-style VIAs. A few models also have IDE from hell. + */ + + { MAC_MODEL_PB140, "PowerBook 140", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB145, "PowerBook 145", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB150, "PowerBook 150", MAC_ADB_PB1, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_PB, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB160, "PowerBook 160", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165, "PowerBook 165", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB165C, "PowerBook 165c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB170, "PowerBook 170", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180, "PowerBook 180", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB180C, "PowerBook 180c", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB190, "PowerBook 190", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_BABOON, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_PB520, "PowerBook 520", MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, + + /* + * PowerBook Duos are pretty much like normal PowerBooks + * All of these probably have onboard SONIC in the Dock which + * means we'll have to probe for it eventually. + * + * Are these reallly MAC_VIA_IIci? The developer notes for the + * Duos show pretty much the same custom parts as in most of + * the other PowerBooks which would imply MAC_VIA_QUADRA. */ - /* All of these might have onboard SONIC in the Dock but I'm not quite sure */ { MAC_MODEL_PB210, "PowerBook Duo 210", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB230, "PowerBook Duo 230", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_PB250, "PowerBook Duo 250", MAC_ADB_PB2, MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, @@ -694,6 +510,7 @@ via_init(); oss_init(); psc_init(); + baboon_init(); } void mac_report_hardware(void) @@ -706,137 +523,3 @@ strcpy(str,"Macintosh "); strcat(str, macintosh_config->name); } - -/* - * The power switch - yes it's software! - */ - -void mac_poweroff(void) -{ - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (oss_present) { - oss_poweroff(); - } else if (macintosh_config->adb_type == MAC_ADB_II) { - via_poweroff(); - } else { - adb_poweroff(); - } -} - -/* - * Not all Macs support software power down; for the rest, just - * try the ROM reset vector ... - */ -void mac_reset(void) -{ - /* - * MAC_ADB_IISI may need to be moved up here if it doesn't actually - * work using the ADB packet method. --David Kilzer - */ - - if (macintosh_config->adb_type == MAC_ADB_II) { - unsigned long cpu_flags; - - /* need ROMBASE in booter */ - /* indeed, plus need to MAP THE ROM !! */ - - if (mac_bi_data.rombase == 0) - mac_bi_data.rombase = 0x40800000; - - /* works on some */ - rom_reset = (void *) (mac_bi_data.rombase + 0xa); - - if (macintosh_config->ident == MAC_MODEL_SE30) { - /* - * MSch: Machines known to crash on ROM reset ... - */ - printk("System halted.\n"); - while(1); - } else { - save_flags(cpu_flags); - cli(); - - rom_reset(); - - restore_flags(cpu_flags); - } - - /* We never make it this far... it usually panics above. */ - printk ("Restart failed. Please restart manually.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } else if (macintosh_config->adb_type == MAC_ADB_IISI - || macintosh_config->adb_type == MAC_ADB_CUDA) { - adb_hwreset(); - } else if (CPU_IS_030) { - - /* 030-specific reset routine. The idea is general, but the - * specific registers to reset are '030-specific. Until I - * have a non-030 machine, I can't test anything else. - * -- C. Scott Ananian - */ - - unsigned long rombase = 0x40000000; - - /* make a 1-to-1 mapping, using the transparent tran. reg. */ - unsigned long virt = (unsigned long) mac_reset; - unsigned long phys = virt_to_phys(mac_reset); - unsigned long offset = phys-virt; - cli(); /* lets not screw this up, ok? */ - __asm__ __volatile__(".chip 68030\n\t" - "pmove %0,%/tt0\n\t" - ".chip 68k" - : : "m" ((phys&0xFF000000)|0x8777)); - /* Now jump to physical address so we can disable MMU */ - __asm__ __volatile__( - ".chip 68030\n\t" - "lea %/pc@(1f),%/a0\n\t" - "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ - "addl %0,%/sp\n\t" - "pflusha\n\t" - "jmp %/a0@\n\t" /* jump into physical memory */ - "0:.long 0\n\t" /* a constant zero. */ - /* OK. Now reset everything and jump to reset vector. */ - "1:\n\t" - "lea %/pc@(0b),%/a0\n\t" - "pmove %/a0@, %/tc\n\t" /* disable mmu */ - "pmove %/a0@, %/tt0\n\t" /* disable tt0 */ - "pmove %/a0@, %/tt1\n\t" /* disable tt1 */ - "movel #0, %/a0\n\t" - "movec %/a0, %/vbr\n\t" /* clear vector base register */ - "movec %/a0, %/cacr\n\t" /* disable caches */ - "movel #0x0808,%/a0\n\t" - "movec %/a0, %/cacr\n\t" /* flush i&d caches */ - "movew #0x2700,%/sr\n\t" /* set up status register */ - "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ - "movec %/a0, %/isp\n\t" - "movel %1@(0x4),%/a0\n\t" /* load reset vector */ - "reset\n\t" /* reset external devices */ - "jmp %/a0@\n\t" /* jump to the reset vector */ - ".chip 68k" - : : "r" (offset), "a" (rombase) : "a0"); - - /* should never get here */ - sti(); /* sure, why not */ - printk ("030 Restart failed. Please restart manually.\n"); - while(1); - } else { - /* We never make it here... The above shoule handle all cases. */ - printk ("Restart failed. Please restart manually.\n"); - - /* XXX - delay do we need to spin here ? */ - while(1); /* Just in case .. */ - } -} - -/* - * Local variables: - * c-indent-level: 4 - * tab-width: 8 - * End: - */ diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/iop.c linux/arch/m68k/mac/iop.c --- v2.3.44/linux/arch/m68k/mac/iop.c Tue Nov 23 22:42:20 1999 +++ linux/arch/m68k/mac/iop.c Sun Feb 13 11:21:42 2000 @@ -319,7 +319,7 @@ { if (iop_ism_present) { if (oss_present) { - request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, + sys_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, IRQ_FLG_LOCK, "ISM IOP", (void *) IOP_NUM_ISM); oss_irq_enable(IRQ_MAC_ADB); diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c --- v2.3.44/linux/arch/m68k/mac/macints.c Thu Nov 18 20:25:37 1999 +++ linux/arch/m68k/mac/macints.c Sun Feb 13 11:21:42 2000 @@ -35,8 +35,8 @@ * 3 - unused (?) * * 4 - SCC (slot number determined by reading RR3 on the SSC itself) - * - slot 0: SCC channel A - * - slot 1: SCC channel B + * - slot 1: SCC channel A + * - slot 2: SCC channel B * * 5 - unused (?) * [serial errors or special conditions seem to raise level 6 @@ -55,8 +55,8 @@ * - slot 5: Slot $E * * 4 - SCC IOP - * - slot 0: SCC channel A - * - slot 1: SCC channel B + * - slot 1: SCC channel A + * - slot 2: SCC channel B * * 5 - ISM IOP (ADB?) * @@ -100,19 +100,18 @@ * bits. The handlers for this new machspec interrupt number are then * called. This puts Nubus interrupts into the range 56-62. * + * - The Baboon interrupts (used on some PowerBooks) are an even more special + * case. They're hidden behind the Nubus slot $C interrupt thus adding a + * third layer of indirection. Why oh why did the Apple engineers do that? + * * - We support "fast" and "slow" handlers, just like the Amiga port. The * fast handlers are called first and with all interrupts disabled. They * are expected to execute quickly (hence the name). The slow handlers are * called last with interrupts enabled and the interrupt level restored. * They must therefore be reentrant. * - * - Drivers should never try to request autovector interrupt numbers. It - * won't work. - * * TODO: * - * o Perhaps build some intelligence into mac_SCC_handler(); we could check - * the SCC ourselves and only call the handler for the appopriate channel. */ #include @@ -125,6 +124,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +133,18 @@ #include /* + * The mac_irq_list array is an array of linked lists of irq_node_t nodes. + * Each node contains one handler to be called whenever the interrupt + * occurs, with fast handlers listed before slow handlers. + */ + +irq_node_t *mac_irq_list[NUM_MAC_SOURCES]; + +/* SCC interrupt mask */ + +static int scc_mask; + +/* * VIA/RBV hooks */ @@ -176,6 +188,26 @@ extern void iop_register_interrupts(void); /* + * Baboon hooks + */ + +extern int baboon_present; + +extern void baboon_init(void); +extern void baboon_register_interrupts(void); +extern void baboon_irq_enable(int); +extern void baboon_irq_disable(int); +extern void baboon_irq_clear(int); +extern int baboon_irq_pending(int); + +/* + * SCC interrupt routines + */ + +static void scc_irq_enable(int); +static void scc_irq_disable(int); + +/* * console_loglevel determines NMI handler function */ @@ -184,17 +216,27 @@ extern void mac_bang(int, void *, struct pt_regs *); void mac_nmi_handler(int, void *, struct pt_regs *); -void mac_SCC_handler(int, void *, struct pt_regs *); +void mac_debug_handler(int, void *, struct pt_regs *); /* #define DEBUG_MACINTS */ void mac_init_IRQ(void) { + int i; + #ifdef DEBUG_MACINTS printk("mac_init_IRQ(): Setting things up...\n"); #endif + /* Initialize the IRQ handler lists. Initially each list is empty, */ + + for (i = 0; i < NUM_MAC_SOURCES; i++) { + mac_irq_list[i] = NULL; + } + + scc_mask = 0; + /* - * Register the handlers for the the master IRQ handlers + * Now register the handlers for the the master IRQ handlers * at levels 1-7. Most of the work is done elsewhere. */ @@ -204,8 +246,9 @@ via_register_interrupts(); } if (psc_present) psc_register_interrupts(); + if (baboon_present) baboon_register_interrupts(); iop_register_interrupts(); - request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); + sys_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); #ifdef DEBUG_MACINTS printk("mac_init_IRQ(): Done!\n"); #endif @@ -284,27 +327,20 @@ void mac_do_irq_list(int irq, struct pt_regs *fp) { - irq_node_t *node, *slow_nodes, **list = NULL; + irq_node_t *node, *slow_nodes; unsigned long cpu_flags; kstat.irqs[0][irq]++; - if (irq < VIA1_SOURCE_BASE) { - list = &autoirq_list[irq]; - } else if (irq < NUM_MAC_SOURCES) { - list = &userirq_list[irq - VIA1_SOURCE_BASE]; - } - if (!list) return; - #ifdef DEBUG_SPURIOUS - if (!*list && (console_loglevel > 7)) { + if (!mac_irq_list[irq] && (console_loglevel > 7)) { printk("mac_do_irq_list: spurious interrupt %d!\n", irq); return; } #endif /* serve first fast and normal handlers */ - for (node = *list; + for (node = mac_irq_list[irq]; node && (!(node->flags & IRQ_FLG_SLOW)); node = node->next) node->handler(irq, node->dev_id, fp); @@ -329,7 +365,9 @@ void mac_enable_irq (unsigned int irq) { - switch(IRQ_SRC(irq)) { + int irq_src = IRQ_SRC(irq); + + switch(irq_src) { case 1: via_irq_enable(irq); break; case 2: @@ -346,6 +384,12 @@ psc_irq_enable(irq); } else if (oss_present) { oss_irq_enable(irq); + } else if (irq_src == 4) { + scc_irq_enable(irq); + } + break; + case 8: if (baboon_present) { + baboon_irq_enable(irq); } break; } @@ -353,12 +397,13 @@ void mac_disable_irq (unsigned int irq) { - switch(IRQ_SRC(irq)) { + int irq_src = IRQ_SRC(irq); + + switch(irq_src) { case 1: via_irq_disable(irq); break; case 2: - case 7: - if (oss_present) { + case 7: if (oss_present) { oss_irq_disable(irq); } else { via_irq_disable(irq); @@ -371,6 +416,12 @@ psc_irq_disable(irq); } else if (oss_present) { oss_irq_disable(irq); + } else if (irq_src == 4) { + scc_irq_disable(irq); + } + break; + case 8: if (baboon_present) { + baboon_irq_disable(irq); } break; } @@ -397,6 +448,10 @@ oss_irq_clear(irq); } break; + case 8: if (baboon_present) { + baboon_irq_clear(irq); + } + break; } } @@ -434,29 +489,37 @@ void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { - int vec, ret; + irq_node_t *node; #ifdef DEBUG_MACINTS printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname); #endif if (irq < VIA1_SOURCE_BASE) { - vec = VEC_SPUR + irq; - } else if (irq < NUM_MAC_SOURCES) { - vec = VEC_USER + irq - VIA1_SOURCE_BASE; - } else { + return sys_request_irq(irq, handler, flags, devname, dev_id); + } + + if (irq >= NUM_MAC_SOURCES) { printk ("%s: unknown irq %d requested by %s\n", __FUNCTION__, irq, devname); - return -EAGAIN; } - ret = sys_request_listirq(vec, handler, flags, devname, dev_id); - if (!ret) { - vectors[vec] = autoirq_listhandler; - mac_enable_irq(irq); - } + /* Get a node and stick it onto the right list */ + + if (!(node = new_irq_node())) return -ENOMEM; - return ret; + node->handler = handler; + node->flags = flags; + node->dev_id = dev_id; + node->devname = devname; + node->next = NULL; + mac_insert_irq(&mac_irq_list[irq], node); + + /* Now enable the IRQ source */ + + mac_enable_irq(irq); + + return 0; } /* @@ -465,30 +528,120 @@ void mac_free_irq(unsigned int irq, void *dev_id) { - irq_node_t **list = NULL; - int vec = 0; - #ifdef DEBUG_MACINTS printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id); #endif if (irq < VIA1_SOURCE_BASE) { - vec = VEC_SPUR + irq; - list = &autoirq_list[irq]; - } else if (irq < NUM_MAC_SOURCES) { - vec = VEC_USER + irq - VIA1_SOURCE_BASE; - list = &userirq_list[irq - VIA1_SOURCE_BASE]; + return sys_free_irq(irq, dev_id); + } + + if (irq >= NUM_MAC_SOURCES) { + printk ("%s: unknown irq %d freed\n", + __FUNCTION__, irq); + return; } - if (!list) return; - sys_free_irq(vec, dev_id); + mac_delete_irq(&mac_irq_list[irq], dev_id); /* If the list for this interrupt is */ /* empty then disable the source. */ - if (!*list) { + if (!mac_irq_list[irq]) { mac_disable_irq(irq); - vectors[vec] = bad_interrupt; + } +} + +/* + * Generate a pretty listing for /proc/interrupts + * + * By the time we're called the autovector interrupt list has already been + * generated, so we just need to do the machspec interrupts. + * + * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers. + * Also removed display of num_spurious it is already + * displayed for us as autovector irq 0. + */ + +int mac_get_irq_list (char *buf) +{ + int i, len = 0; + irq_node_t *node; + char *base; + + /* Don't do Nubus interrupts in this loop; we do them separately */ + /* below so that we can print slot numbers instead of IRQ numbers */ + + for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) { + + /* Nonexistant interrupt or nothing registered; skip it. */ + + if ((node = mac_irq_list[i]) == NULL) continue; + if (node->flags & IRQ_FLG_STD) continue; + + base = ""; + switch(IRQ_SRC(i)) { + case 1: base = "via1"; + break; + case 2: if (oss_present) { + base = "oss"; + } else { + base = "via2"; + } + break; + case 3: + case 4: + case 5: + case 6: if (psc_present) { + base = "psc"; + } else if (oss_present) { + base = "oss"; + } else { + if (IRQ_SRC(i) == 4) base = "scc"; + } + break; + case 7: base = "nbus"; + break; + case 8: base = "bbn"; + break; + } + len += sprintf(buf+len, "%4s %2d: %10u ", + base, i, kstat.irqs[0][i]); + + do { + if (node->flags & IRQ_FLG_FAST) { + len += sprintf(buf+len, "F "); + } else if (node->flags & IRQ_FLG_SLOW) { + len += sprintf(buf+len, "S "); + } else { + len += sprintf(buf+len, " "); + } + len += sprintf(buf+len, "%s\n", node->devname); + if ((node = node->next)) { + len += sprintf(buf+len, " "); + } + } while(node); + + } + return len; +} + +void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +#ifdef DEBUG_SPURIOUS + if (console_loglevel > 6) { + printk("Unexpected IRQ %d on device %p\n", irq, dev_id); + } +#endif +} + +static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if (num_debug[irq] < 10) { + printk("DEBUG: Unexpected IRQ %d\n", irq); + num_debug[irq]++; } } @@ -543,12 +696,53 @@ } /* - * SCC master interrupt handler; sole purpose: pass the registered - * async struct to the SCC handler proper. + * Simple routines for masking and unmasking + * SCC interrupts in cases where this can't be + * done in hardware (only the PSC can do that.) + */ + +static void scc_irq_enable(int irq) { + int irq_idx = IRQ_IDX(irq); + + scc_mask |= (1 << irq_idx); +} + +static void scc_irq_disable(int irq) { + int irq_idx = IRQ_IDX(irq); + + scc_mask &= ~(1 << irq_idx); +} + +/* + * SCC master interrupt handler. We have to do a bit of magic here + * to figure out what channel gave us the interrupt; putting this + * here is cleaner than hacking it into drivers/char/macserial.c. */ -void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs) +void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs) { - mac_do_irq_list(IRQ_SCCA, regs); - mac_do_irq_list(IRQ_SCCB, regs); + volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2; + unsigned char reg; + unsigned long cpu_flags; + + /* Read RR3 from the chip. Always do this on channel A */ + /* This must be an atomic operation so disable irqs. */ + + save_flags(cpu_flags); cli(); + *scc = 3; + reg = *scc; + restore_flags(cpu_flags); + + /* Now dispatch. Bits 0-2 are for channel B and */ + /* bits 3-5 are for channel A. We can safely */ + /* ignore the remaining bits here. */ + /* */ + /* Note that we're ignoring scc_mask for now. */ + /* If we actually mask the ints then we tend to */ + /* get hammered by very persistant SCC irqs, */ + /* and since they're autovector interrupts they */ + /* pretty much kill the system. */ + + if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs); + if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs); } diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c --- v2.3.44/linux/arch/m68k/mac/mackeyb.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/mac/mackeyb.c Wed Dec 31 16:00:00 1969 @@ -1,762 +0,0 @@ -/* - * linux/arch/m68k/mac/mackeyb.c - * - * Keyboard driver for Macintosh computers. - * - * Adapted from drivers/macintosh/key_mac.c and arch/m68k/atari/akakeyb.c - * (see that file for its authors and contributors). - * - * Copyright (C) 1997 Michael Schmitz. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -/* - * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -/* keyb */ -#include -#include -#include -/* keyb */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -/* for keyboard_input stuff */ -#include -#define KEYB_KEYREG 0 /* register # for key up/down data */ -#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ -#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ -/* end keyboard_input stuff */ - -#include -#include - -static void kbd_repeat(unsigned long); -static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; -static int last_keycode; - -static void input_keycode(int, int); - -extern struct kbd_struct kbd_table[]; - -extern void adb_bus_init(void); -extern void handle_scancode(unsigned char, int); -extern void put_queue(int); - -/* keyb */ -static void mac_leds_done(struct adb_request *); -static void keyboard_input(unsigned char *, int, struct pt_regs *); -static void mouse_input(unsigned char *, int, struct pt_regs *); - -#ifdef CONFIG_ADBMOUSE -/* XXX: Hook for mouse driver */ -void (*adb_mouse_interrupt_hook)(unsigned char *, int); -int adb_emulate_buttons = 0; -int adb_button2_keycode = 0x7d; /* right control key */ -int adb_button3_keycode = 0x7c; /* right option key */ -#endif - -/* The mouse driver - for debugging */ -extern void adb_mouse_interrupt(char *, int); -/* end keyb */ - -/* this map indicates which keys shouldn't autorepeat. */ -static unsigned char dont_repeat[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -/* - * Mac private key maps - */ -u_short mac_plain_map[NR_KEYS] __initdata = { - 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, - 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, - 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, - 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, - 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, - 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, - 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, - 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, - 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_shift_map[NR_KEYS] __initdata = { - 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, - 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, - 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, - 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, - 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, - 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, - 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, - 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, - 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_altgr_map[NR_KEYS] __initdata = { - 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, - 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, - 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, - 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, - 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, - 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, - 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, - 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, - 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, - 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_ctrl_map[NR_KEYS] __initdata = { - 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, - 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, - 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, - 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, - 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, - 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, - 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, - 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_shift_ctrl_map[NR_KEYS] __initdata = { - 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, - 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, - 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, - 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, - 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, -}; - -u_short mac_alt_map[NR_KEYS] __initdata = { - 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, - 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, - 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, - 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, - 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, - 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, - 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, - 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, - 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, - 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, - 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short mac_ctrl_alt_map[NR_KEYS] __initdata = { - 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, - 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, - 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, - 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, - 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, - 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, - 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, - 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, - 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, - 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, - 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, - 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, - 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, - 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -extern unsigned int keymap_count; - -/* - * Misc. defines for testing - */ - -extern int console_loglevel; - -static struct adb_request led_request; -extern int in_keybinit; - -/* - * machdep keyboard routines, interface and key repeat method modeled after - * drivers/macintosh/keyb_mac.c - */ - -int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep, - char raw_mode) -{ - if (!raw_mode) { - /* - * Convert R-shift/control/option to L version. - * Remap keycode 0 (A) to the unused keycode 0x5a. - * Other parts of the system assume 0 is not a valid keycode. - */ - switch (keycode) { - case 0x7b: keycode = 0x38; break; /* R-shift */ - case 0x7c: keycode = 0x3a; break; /* R-option */ - case 0x7d: keycode = 0x36; break; /* R-control */ - case 0: keycode = 0x5a; break; /* A */ - } - } - *keycodep = keycode; - return 1; -} - -int mac_kbd_unexpected_up(unsigned char keycode) -{ - return 0x80; -} - -static void -keyboard_input(unsigned char *data, int nb, struct pt_regs *regs) -{ - /* first check this is from register 0 */ - if (nb != 5 || (data[2] & 3) != KEYB_KEYREG) - return; /* ignore it */ - kbd_pt_regs = regs; - input_keycode(data[3], 0); - if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f))) - input_keycode(data[4], 0); -} - -static void -input_keycode(int keycode, int repeat) -{ - struct kbd_struct *kbd; - int up_flag; - - kbd = kbd_table + fg_console; - up_flag = (keycode & 0x80); - keycode &= 0x7f; - - if (!repeat) - del_timer(&repeat_timer); - -#ifdef CONFIG_ADBMOUSE - /* - * XXX: Add mouse button 2+3 fake codes here if mouse open. - * As we only report up/down events, keep track of faked buttons. - * Really messy; might need to check if keyboard is in - * VC_RAW mode for X?. - * Might also want to know how many buttons need to be emulated. - * -> hide this as function in arch/m68k/mac ? - * Current emulation buttons: right alt/option and control - * (wanted: command and alt/option, or KP= and KP( ...) - * Debug version; might be rewritten to be faster on normal keys. - */ - if (adb_emulate_buttons - && (adb_mouse_interrupt_hook || console_loglevel >= 8)) { - unsigned char button, button2, button3, fake_event; - static unsigned char button2state=0, button3state=0; /* up */ - /* faked ADB packet */ - static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 }; - - button = 0; - fake_event = 0; - if (keycode == adb_button2_keycode) { /* which 'button' ? */ - /* R-option */ - button2 = (!up_flag); /* new state */ - if (button2 != button2state) /* change ? */ - button = 2; - button2state = button2; /* save state */ - fake_event = 2; - } else if (keycode == adb_button3_keycode) { - /* R-control */ - button3 = (!up_flag); /* new state */ - if (button3 != button3state) /* change ? */ - button = 3; - button3state = button3; /* save state */ - fake_event = 3; - } -#ifdef DEBUG_ADBMOUSE - if (fake_event && console_loglevel >= 8) - printk("fake event: button2 %d button3 %d button %d\n", - button2state, button3state, button); -#endif - if (button) { /* there's been a button state change */ - /* fake a mouse packet : send all bytes, change one! */ - data[button] = (up_flag ? 0x80 : 0); - if (adb_mouse_interrupt_hook) - adb_mouse_interrupt_hook(data, 4); -#ifdef DEBUG_ADBMOUSE - else - printk("mouse_fake: data %2x %2x %2x buttons %2x \n", - data[1], data[2], data[3], - ~( (data[1] & 0x80 ? 0 : 4) - | (data[2] & 0x80 ? 0 : 1) - | (data[3] & 0x80 ? 0 : 2) )&7 ); -#endif - } - /* - * for mouse 3-button emulation: don't process 'fake' keys! - * Keys might autorepeat, and console state gets generally messed - * up enough so that selection stops working. - */ - if (fake_event) - return; - } -#endif /* CONFIG_ADBMOUSE */ - - /* - * Convert R-shift/control/option to L version. - */ - switch (keycode) { - case 0x7b: keycode = 0x38; break; /* R-shift */ - case 0x7c: keycode = 0x3a; break; /* R-option */ - case 0x7d: keycode = 0x36; break; /* R-control */ - case 0x0: if (kbd->kbdmode != VC_RAW) - keycode = 0x5a; /* A; keycode 0 deprecated */ - break; - } - - if (kbd->kbdmode != VC_RAW) { - if (!up_flag && !dont_repeat[keycode]) { - last_keycode = keycode; - repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2); - add_timer(&repeat_timer); - } - - /* - * XXX fix caps-lock behaviour by turning the key-up - * transition into a key-down transition. - * MSch: need to turn each caps-lock event into a down-up - * double event (keyboard code assumes caps-lock is a toggle) - * 981127: fix LED behavior (kudos atong!) - */ - switch (keycode) { - case 0x39: - handle_scancode(keycode, 1); /* down */ - up_flag = 0x80; /* see below ... */ - mark_bh(KEYBOARD_BH); - break; - case 0x47: - mark_bh(KEYBOARD_BH); - break; - } - } - - handle_scancode(keycode, !up_flag); -} - -static void -kbd_repeat(unsigned long xxx) -{ - unsigned long flags; - - save_flags(flags); - cli(); - input_keycode(last_keycode, 1); - restore_flags(flags); -} - - /* [ACA:23-Mar-97] Three button mouse support. This is designed to - function with MkLinux DR-2.1 style X servers. It only works with - three-button mice that conform to Apple's multi-button mouse - protocol. */ - - /* - The X server for MkLinux DR2.1 uses the following unused keycodes to - read the mouse: - - 0x7e This indicates that the next two keycodes should be interpreted - as mouse information. The first following byte's high bit - represents the state of the left button. The lower seven bits - represent the x-axis acceleration. The lower seven bits of the - second byte represent y-axis acceleration. - - 0x3f The x server interprets this keycode as a middle button - release. - - 0xbf The x server interprets this keycode as a middle button - depress. - - 0x40 The x server interprets this keycode as a right button - release. - - 0xc0 The x server interprets this keycode as a right button - depress. - - NOTES: There should be a better way of handling mice in the X server. - The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead - of two. The three mouse buttons should then, in the X server, be read - as the high-bits of all three bytes. The x and y motions can still be - in the first two bytes. Maybe I'll do this... - */ - - /* - Handler 4 -- Apple Extended mouse protocol. - - For Apple's 3-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = 0100 0000 Extended protocol register. - Bits 6-7 are the device id, which should be 1. - Bits 4-5 are resolution which is in "units/inch". - The Logitech MouseMan returns these bits clear but it has - 200/300cpi resolution. - Bits 0-3 are unique vendor id. - data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. - Bits 2-3 should be 8 + 4. - Bits 4-7 should be 3 for a mouse device. - data[3] = bxxx xxxx Left button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - data[5] = byyy bxxx Third button and fourth button. Y is additional - high bits of y-axis motion. XY is additional - high bits of x-axis motion. - - NOTE: data[0] and data[2] are confirmed by the parent function and - need not be checked here. - */ - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = ???? ???? (?) - data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. - data[3] = bxxx xxxx First button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - - NOTE: data[0] is confirmed by the parent function and need not be - checked here. - */ - -static void -mouse_input(unsigned char *data, int nb, struct pt_regs *regs) -{ - struct kbd_struct *kbd; - int i; - - if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) { - printk("data from mouse:"); - for (i = 0; i < nb; ++i) - printk(" %x", data[i]); - printk("\n"); - return; - } - - if (adb_mouse_interrupt_hook) { - adb_mouse_interrupt_hook(data+2, nb-2); - /* - * passing the mouse data to i.e. the X server as done for - * Xpmac will confuse applications on a sane X server :-) - */ - return; - } -#ifdef DEBUG_ADBMOUSE - else - if (console_loglevel >= 8) - printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", - data[3], data[4], data[5], - ~((data[3] & 0x80 ? 0 : 4) - | (data[4] & 0x80 ? 0 : 1) - | (data[5] & 0x80 ? 0 : 2))&7, - ((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ), - ((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) ); -#endif - - - kbd = kbd_table + fg_console; - -#if 0 /* The entirely insane way of MkLinux handling mouse input */ - /* Requires put_queue which is static in keyboard.c :-( */ - /* Only send mouse codes when keyboard is in raw mode. */ - if (kbd->kbdmode == VC_RAW) { - static unsigned char uch_ButtonStateSecond = 0; - unsigned char uchButtonSecond; - - /* Send first button, second button and movement. */ - put_queue( 0x7e ); - put_queue( data[3] ); - put_queue( data[4] ); - - /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ - - /* Store the button state. */ - uchButtonSecond = (data[4] & 0x80); - - /* Send second button. */ - if (uchButtonSecond != uch_ButtonStateSecond) { - put_queue( 0x3f | uchButtonSecond ); - uch_ButtonStateSecond = uchButtonSecond; - } - - /* Macintosh 3-button mouse (handler 4). */ - if ((nb == 6) && (data[1] & 0x40)) { - static unsigned char uch_ButtonStateThird = 0; - unsigned char uchButtonThird; - - /* Store the button state for speed. */ - uchButtonThird = (data[5] & 0x80); - - /* Send third button. */ - if (uchButtonThird != uch_ButtonStateThird) { - put_queue( 0x40 | uchButtonThird ); - uch_ButtonStateThird = uchButtonThird; - } - } - } -#endif /* insane MkLinux mouse hack */ -} - -/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ -static unsigned char mac_ledmap[8] = { - 0, /* none */ - 4, /* scroll lock */ - 1, /* num lock */ - 5, /* scroll + num lock */ - 2, /* caps lock */ - 6, /* caps + scroll lock */ - 3, /* caps + num lock */ - 7, /* caps + num + scroll lock */ -}; - -static int leds_pending; - -void mac_kbd_leds(unsigned int leds) -{ - if (led_request.got_reply) { -#ifdef DEBUG_ADB - if (console_loglevel == 10) - printk("mac_kbd_leds: got reply, sending request!\n"); -#endif - adb_request(&led_request, mac_leds_done, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), - 0xff, ~mac_ledmap[leds]); - } else - leds_pending = leds | 0x100; -} - -static void mac_leds_done(struct adb_request *req) -{ - int leds; - - if (leds_pending) { - leds = leds_pending & 0xff; - leds_pending = 0; - mac_kbd_leds(leds); - } - mark_bh(KEYBOARD_BH); -} - -int mac_kbdrate(struct kbd_repeat *k) -{ - return 0; -} - -int __init mac_keyb_init(void) -{ - static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req; - volatile int ct; - - /* setup key map */ - memcpy(key_maps[0], mac_plain_map, sizeof(plain_map)); - memcpy(key_maps[1], mac_shift_map, sizeof(plain_map)); - memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map)); - memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map)); - memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map)); - memcpy(key_maps[8], mac_alt_map, sizeof(plain_map)); - memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map)); - - /* initialize mouse interrupt hook */ - adb_mouse_interrupt_hook = NULL; - - /* - * Might put that someplace else, possibly .... - */ - adb_bus_init(); - - /* the input functions ... */ - adb_register(ADB_KEYBOARD, keyboard_input); - adb_register(ADB_MOUSE, mouse_input); - - /* turn on ADB auto-polling in the CUDA */ - - /* - * Older boxes don't support CUDA_* targets and CUDA commands - * instead we emulate them in the adb_request hook to make - * the code interfaces saner. - * - * Note XXX: the Linux PMac and this code both assume the - * devices are at their primary ids and do not do device - * assignment. This isn't ideal. We should fix it to follow - * the reassignment specs. - */ - - if (macintosh_config->adb_type == MAC_ADB_CUDA) { - printk("CUDA autopoll on ...\n"); - adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); - ct=0; - while (!autopoll_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("Keyboard timed out.\n"); - autopoll_req.got_reply = 1; - } - } - - /* - * XXX: all ADB requests now in CUDA format; adb_request takes - * care of that for other Macs. - */ - - printk("Configuring keyboard:\n"); - - udelay(3000); - - /* - * turn on all leds - the keyboard driver will turn them back off - * via mac_kbd_leds if everything works ok! - */ - printk("leds on ...\n"); - adb_request(&led_request, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7); - - /* - * The polling stuff should go away as soon as the ADB driver is stable - */ - ct = 0; - while (!led_request.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("keyboard timed out.\n"); - led_request.got_reply = 1; - } - -#if 1 - printk("configuring coding mode ...\n"); - - udelay(3000); - - /* - * get the keyboard to send separate codes for - * left and right shift, control, option keys. - */ - adb_request(&confcod_req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); - - ct=0; - while (!confcod_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) { - printk("keyboard timed out.\n"); - confcod_req.got_reply = 1; - } -#endif - -#if 0 /* seems to hurt, at least Geert's Mac */ - printk("Configuring mouse (3-button mode) ...\n"); - - udelay(3000); - - /* - * XXX: taken from the PPC driver again ... - * Try to switch the mouse (id 3) to handler 4, for three-button - * mode. (0x20 is Service Request Enable, 0x03 is Device ID). - */ - adb_request(&mouse_req, NULL, 4, ADB_PACKET, - ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); - - ct=0; - while (!mouse_req.got_reply && ++ct<1000) - { - udelay(10); - } - if(ct==1000) - printk("Mouse timed out.\n"); -#endif - -#if 0 - printk("Start polling keyboard ...\n"); - - /* - * get the keyboard to send data back, via the adb_input hook - * XXX: was never used properly, and the driver takes care - * of polling and timeout retransmits now. - * Might be of use if we want to start talking to a specific - * device here... - */ - adb_request(&readkey_req, NULL, 2, ADB_PACKET, - ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG)); -#endif - - in_keybinit = 0; - printk("keyboard init done\n"); - - return 0; -} diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/misc.c linux/arch/m68k/mac/misc.c --- v2.3.44/linux/arch/m68k/mac/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/m68k/mac/misc.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,689 @@ +/* + * Miscellaneous Mac68K-specific stuff + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOTINFO_COMPAT_1_0 +#include +#include +#include + +/* Offset between Unix time (1970-based) and Mac time (1904-based) */ + +#define RTC_OFFSET 2082844800 + +extern struct mac_booter_data mac_bi_data; +static void (*rom_reset)(void); + +/* + * Return the current time as the number of seconds since January 1, 1904. + */ + +static long adb_read_time(void) +{ + volatile struct adb_request req; + long time; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 2, CUDA_PACKET, CUDA_GET_TIME); + + time = (req.reply[3] << 24) | (req.reply[4] << 16) + | (req.reply[5] << 8) | req.reply[6]; + return time - RTC_OFFSET; +} + +/* + * Set the current system time + */ + +static void adb_write_time(long data) +{ + volatile struct adb_request req; + + data += RTC_OFFSET; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 6, CUDA_PACKET, CUDA_SET_TIME, + (data >> 24) & 0xFF, (data >> 16) & 0xFF, + (data >> 8) & 0xFF, data & 0xFF); +} + +/* + * Get a byte from the NVRAM + */ + +static __u8 adb_read_pram(int offset) +{ + volatile struct adb_request req; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 4, CUDA_PACKET, CUDA_GET_PRAM, + (offset >> 8) & 0xFF, offset & 0xFF); + return req.reply[3]; +} + +/* + * Write a byte to the NVRAM + */ + +static void adb_write_pram(int offset, __u8 data) +{ + volatile struct adb_request req; + + adb_request((struct adb_request *) &req, NULL, + ADBREQ_RAW|ADBREQ_SYNC, + 5, CUDA_PACKET, CUDA_SET_PRAM, + (offset >> 8) & 0xFF, offset & 0xFF, + data); +} + +/* + * VIA PRAM/RTC access routines + * + * Must be called with interrupts disabled and + * the RTC should be enabled. + */ + +static __u8 via_pram_readbyte(void) +{ + int i,reg; + __u8 data; + + reg = via1[vBufB] & ~VIA1B_vRTCClk; + + /* Set the RTC data line to be an input. */ + + via1[vDirB] &= ~VIA1B_vRTCData; + + /* The bits of the byte come out in MSB order */ + + data = 0; + for (i = 0 ; i < 8 ; i++) { + via1[vBufB] = reg; + via1[vBufB] = reg | VIA1B_vRTCClk; + data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData); + } + + /* Return RTC data line to output state */ + + via1[vDirB] |= VIA1B_vRTCData; + + return data; +} + +static void via_pram_writebyte(__u8 data) +{ + int i,reg,bit; + + reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData); + + /* The bits of the byte go in in MSB order */ + + for (i = 0 ; i < 8 ; i++) { + bit = data & 0x80? 1 : 0; + data <<= 1; + via1[vBufB] = reg | bit; + via1[vBufB] = reg | bit | VIA1B_vRTCClk; + } +} + +/* + * Execute a VIA PRAM/RTC command. For read commands + * data should point to a one-byte buffer for the + * resulting data. For write commands it should point + * to the data byte to for the command. + * + * This function disables all interrupts while running. + */ + +static void via_pram_command(int command, __u8 *data) +{ + unsigned long cpu_flags; + int is_read; + + save_flags(cpu_flags); + cli(); + + /* Enable the RTC and make sure the strobe line is high */ + + via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb; + + if (command & 0xFF00) { /* extended (two-byte) command */ + via_pram_writebyte((command & 0xFF00) >> 8); + via_pram_writebyte(command & 0xFF); + is_read = command & 0x8000; + } else { /* one-byte command */ + via_pram_writebyte(command); + is_read = command & 0x80; + } + if (is_read) { + *data = via_pram_readbyte(); + } else { + via_pram_writebyte(*data); + } + + /* All done, disable the RTC */ + + via1[vBufB] |= VIA1B_vRTCEnb; + + restore_flags(cpu_flags); +} + +static __u8 via_read_pram(int offset) +{ + return 0; +} + +static void via_write_pram(int offset, __u8 data) +{ +} + +/* + * Return the current time in seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +static long via_read_time(void) +{ + union { + __u8 cdata[4]; + long idata; + } result, last_result; + int ct; + + /* + * The NetBSD guys say to loop until you get the same reading + * twice in a row. + */ + + ct = 0; + do { + if (++ct > 10) { + printk("via_read_time: couldn't get valid time, " + "last read = 0x%08X and 0x%08X\n", last_result.idata, + result.idata); + break; + } + + last_result.idata = result.idata; + result.idata = 0; + + via_pram_command(0x81, &result.cdata[3]); + via_pram_command(0x85, &result.cdata[2]); + via_pram_command(0x89, &result.cdata[1]); + via_pram_command(0x8D, &result.cdata[0]); + } while (result.idata != last_result.idata); + + return result.idata - RTC_OFFSET; +} + +/* + * Set the current time to a number of seconds since January 1, 1904. + * + * This only works on machines with the VIA-based PRAM/RTC, which + * is basically any machine with Mac II-style ADB. + */ + +static void via_write_time(long time) +{ + union { + __u8 cdata[4]; + long idata; + } data; + __u8 temp; + + /* Clear the write protect bit */ + + temp = 0x55; + via_pram_command(0x35, &temp); + + data.idata = time + RTC_OFFSET; + via_pram_command(0x01, &data.cdata[3]); + via_pram_command(0x05, &data.cdata[2]); + via_pram_command(0x09, &data.cdata[1]); + via_pram_command(0x0D, &data.cdata[0]); + + /* Set the write protect bit */ + + temp = 0xD5; + via_pram_command(0x35, &temp); +} + +static void via_shutdown(void) +{ + if (rbv_present) { + via2[rBufB] &= ~0x04; + } else { + /* Direction of vDirB is output */ + via2[vDirB] |= 0x04; + /* Send a value of 0 on that line */ + via2[vBufB] &= ~0x04; + mdelay(1000); + } +} + +/* + * FIXME: not sure how this is supposed to work exactly... + */ + +static void oss_shutdown(void) +{ + oss->rom_ctrl = OSS_POWEROFF; +} + +#ifdef CONFIG_ADB_CUDA + +static void cuda_restart(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 2, CUDA_PACKET, CUDA_RESET_SYSTEM); +} + +static void cuda_shutdown(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 2, CUDA_PACKET, CUDA_POWERDOWN); +} + +#endif /* CONFIG_ADB_CUDA */ + +#ifdef CONFIG_ADB_PMU + +void pmu_restart(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 3, PMU_PACKET, PMU_SET_INTR_MASK, + PMU_INT_ADB|PMU_INT_TICK); + + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 2, PMU_PACKET, PMU_RESET); +} + +void pmu_shutdown(void) +{ + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 3, PMU_PACKET, PMU_SET_INTR_MASK, + PMU_INT_ADB|PMU_INT_TICK); + + adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC, + 6, PMU_PACKET, PMU_SHUTDOWN, + 'M', 'A', 'T', 'T'); +} + +#endif /* CONFIG_ADB_PMU */ + +/* + *------------------------------------------------------------------- + * Below this point are the generic routines; they'll dispatch to the + * correct routine for the hardware on which we're running. + *------------------------------------------------------------------- + */ + +void mac_pram_read(int offset, __u8 *buffer, int len) +{ + __u8 (*func)(int) = NULL; + int i; + + if (macintosh_config->adb_type == MAC_ADB_IISI || + macintosh_config->adb_type == MAC_ADB_PB1 || + macintosh_config->adb_type == MAC_ADB_PB2 || + macintosh_config->adb_type == MAC_ADB_CUDA) { + func = adb_read_pram; + } else { + func = via_read_pram; + } + for (i = 0 ; i < len ; i++) { + buffer[i] = (*func)(offset++); + } +} + +void mac_pram_write(int offset, __u8 *buffer, int len) +{ + void (*func)(int, __u8) = NULL; + int i; + + if (macintosh_config->adb_type == MAC_ADB_IISI || + macintosh_config->adb_type == MAC_ADB_PB1 || + macintosh_config->adb_type == MAC_ADB_PB2 || + macintosh_config->adb_type == MAC_ADB_CUDA) { + func = adb_write_pram; + } else { + func = via_write_pram; + } + for (i = 0 ; i < len ; i++) { + (*func)(offset++, buffer[i]); + } +} + +void mac_poweroff(void) +{ + /* + * MAC_ADB_IISI may need to be moved up here if it doesn't actually + * work using the ADB packet method. --David Kilzer + */ + + if (oss_present) { + oss_shutdown(); + } else if (macintosh_config->adb_type == MAC_ADB_II) { + via_shutdown(); +#ifdef CONFIG_ADB_CUDA + } else if (macintosh_config->adb_type == MAC_ADB_CUDA) { + cuda_shutdown(); +#endif +#ifdef CONFIG_ADB_PMU + } else if (macintosh_config->adb_type == MAC_ADB_PB1 + || macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_shutdown(); +#endif + } + sti(); + printk("It is now safe to turn off your Macintosh.\n"); + while(1); +} + +void mac_reset(void) +{ + if (macintosh_config->adb_type == MAC_ADB_II) { + unsigned long cpu_flags; + + /* need ROMBASE in booter */ + /* indeed, plus need to MAP THE ROM !! */ + + if (mac_bi_data.rombase == 0) + mac_bi_data.rombase = 0x40800000; + + /* works on some */ + rom_reset = (void *) (mac_bi_data.rombase + 0xa); + + if (macintosh_config->ident == MAC_MODEL_SE30) { + /* + * MSch: Machines known to crash on ROM reset ... + */ + } else { + save_flags(cpu_flags); + cli(); + + rom_reset(); + + restore_flags(cpu_flags); + } +#ifdef CONFIG_ADB_CUDA + } else if (macintosh_config->adb_type == MAC_ADB_CUDA) { + cuda_restart(); +#endif +#ifdef CONFIG_ADB_PMU + } else if (macintosh_config->adb_type == MAC_ADB_PB1 + || macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_restart(); +#endif + } else if (CPU_IS_030) { + + /* 030-specific reset routine. The idea is general, but the + * specific registers to reset are '030-specific. Until I + * have a non-030 machine, I can't test anything else. + * -- C. Scott Ananian + */ + + unsigned long rombase = 0x40000000; + + /* make a 1-to-1 mapping, using the transparent tran. reg. */ + unsigned long virt = (unsigned long) mac_reset; + unsigned long phys = virt_to_phys(mac_reset); + unsigned long offset = phys-virt; + cli(); /* lets not screw this up, ok? */ + __asm__ __volatile__(".chip 68030\n\t" + "pmove %0,%/tt0\n\t" + ".chip 68k" + : : "m" ((phys&0xFF000000)|0x8777)); + /* Now jump to physical address so we can disable MMU */ + __asm__ __volatile__( + ".chip 68030\n\t" + "lea %/pc@(1f),%/a0\n\t" + "addl %0,%/a0\n\t"/* fixup target address and stack ptr */ + "addl %0,%/sp\n\t" + "pflusha\n\t" + "jmp %/a0@\n\t" /* jump into physical memory */ + "0:.long 0\n\t" /* a constant zero. */ + /* OK. Now reset everything and jump to reset vector. */ + "1:\n\t" + "lea %/pc@(0b),%/a0\n\t" + "pmove %/a0@, %/tc\n\t" /* disable mmu */ + "pmove %/a0@, %/tt0\n\t" /* disable tt0 */ + "pmove %/a0@, %/tt1\n\t" /* disable tt1 */ + "movel #0, %/a0\n\t" + "movec %/a0, %/vbr\n\t" /* clear vector base register */ + "movec %/a0, %/cacr\n\t" /* disable caches */ + "movel #0x0808,%/a0\n\t" + "movec %/a0, %/cacr\n\t" /* flush i&d caches */ + "movew #0x2700,%/sr\n\t" /* set up status register */ + "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */ + "movec %/a0, %/isp\n\t" + "movel %1@(0x4),%/a0\n\t" /* load reset vector */ + "reset\n\t" /* reset external devices */ + "jmp %/a0@\n\t" /* jump to the reset vector */ + ".chip 68k" + : : "r" (offset), "a" (rombase) : "a0"); + } + + /* should never get here */ + sti(); + printk ("Restart failed. Please restart manually.\n"); + while(1); +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +/* + * This function translates seconds since 1970 into a proper date. + * + * Algorithm cribbed from glibc2.1, __offtime(). + */ +#define SECS_PER_MINUTE (60) +#define SECS_PER_HOUR (SECS_PER_MINUTE * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +static void unmktime(unsigned long time, long offset, + int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + /* How many days come before each month (0-12). */ + static const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + long int days, rem, y, wday, yday; + const unsigned short int *ip; + + days = time / SECS_PER_DAY; + rem = time % SECS_PER_DAY; + rem += offset; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + *hourp = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + *minp = rem / SECS_PER_MINUTE; + *secp = rem % SECS_PER_MINUTE; + /* January 1, 1970 was a Thursday. */ + wday = (4 + days) % 7; /* Day in the week. Not currently used */ + if (wday < 0) wday += 7; + y = 1970; + +#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) +#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + + while (days < 0 || days >= (__isleap (y) ? 366 : 365)) + { + /* Guess a corrected year, assuming 365 days per year. */ + long int yg = y + days / 365 - (days % 365 < 0); + + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + *yearp = y - 1900; + yday = days; /* day in the year. Not currently used. */ + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + *monp = y; + *dayp = days + 1; /* day in the month */ + return; +} + +/* + * Return the boot time for use in initializing the kernel clock. + * + * I'd like to read the hardware clock here but many machines read + * the PRAM through ADB, and interrupts aren't initialized when this + * is called so ADB obviously won't work. + */ + +void mac_gettod(int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + /* Yes the GMT bias is backwards. It looks like Penguin is + screwing up the boottime it gives us... This works for me + in Canada/Eastern but it might be wrong everywhere else. */ + unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60, + yearp, monp, dayp, hourp, minp, secp); + /* For some reason this is off by one */ + *monp = *monp + 1; +} + +/* + * Read/write the hardware clock. + */ + +int mac_hwclk(int op, struct hwclk_time *t) +{ + unsigned long now; + + if (!op) { /* read */ + if (macintosh_config->adb_type == MAC_ADB_II) { + now = via_read_time(); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_PB1) || + (macintosh_config->adb_type == MAC_ADB_PB2) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + now = adb_read_time(); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + now = via_read_time(); + } else { + now = 0; + } + + t->wday = 0; + unmktime(now, 0, + &t->year, &t->mon, &t->day, + &t->hour, &t->min, &t->sec); + printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n", + t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec); + } else { /* write */ + printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n", + t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec); + +#if 0 /* it trashes my rtc */ + now = mktime(t->year + 1900, t->mon + 1, t->day, + t->hour, t->min, t->sec); + + if (macintosh_config->adb_type == MAC_ADB_II) { + via_write_time(now); + } else if ((macintosh_config->adb_type == MAC_ADB_IISI) || + (macintosh_config->adb_type == MAC_ADB_PB1) || + (macintosh_config->adb_type == MAC_ADB_PB2) || + (macintosh_config->adb_type == MAC_ADB_CUDA)) { + adb_write_time(now); + } else if (macintosh_config->adb_type == MAC_ADB_IOP) { + via_write_time(now); + } +#endif + } + return 0; +} + +/* + * Set minutes/seconds in the hardware clock + */ + +int mac_set_clock_mmss (unsigned long nowtime) +{ + struct hwclk_time now; + + mac_hwclk(0, &now); + now.sec = nowtime % 60; + now.min = (nowtime / 60) % 60; + mac_hwclk(1, &now); + + return 0; +} diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/oss.c linux/arch/m68k/mac/oss.c --- v2.3.44/linux/arch/m68k/mac/oss.c Tue Sep 7 12:14:06 1999 +++ linux/arch/m68k/mac/oss.c Sun Feb 13 11:21:42 2000 @@ -34,7 +34,7 @@ void oss_nubus_irq(int, void *, struct pt_regs *); extern void via1_irq(int, void *, struct pt_regs *); -extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern void mac_scc_dispatch(int, void *, struct pt_regs *); extern int console_loglevel; /* @@ -68,16 +68,16 @@ void __init oss_register_interrupts(void) { - request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, - "OSS SCSI Dispatch", (void *) oss); - request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK, - "SCC Dispatch", mac_SCC_handler); - request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, - "Nubus Dispatch", (void *) oss); - request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, - "OSS Sound Dispatch", (void *) oss); - request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, - "VIA1 Dispatch", (void *) via1); + sys_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, + "scsi", (void *) oss); + sys_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK, + "scc", mac_scc_dispatch); + sys_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, + "nubus", (void *) oss); + sys_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, + "sound", (void *) oss); + sys_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, + "via1", (void *) via1); } /* @@ -86,22 +86,6 @@ void __init oss_nubus_init(void) { -} - -/* - * Turn off the power via the ROM control register - * - * FIXME: not sure how this is supposed to work exactly... - */ - -void oss_poweroff(void) -{ - oss->rom_ctrl = OSS_POWEROFF; - - /* We should never make it this far... */ - - printk ("It is now safe to switch off your machine.\n"); - while(1); } /* diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c --- v2.3.44/linux/arch/m68k/mac/psc.c Thu Nov 18 20:25:37 1999 +++ linux/arch/m68k/mac/psc.c Sun Feb 13 11:21:42 2000 @@ -119,14 +119,14 @@ void __init psc_register_interrupts(void) { - request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x30); - request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x40); - request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x50); - request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch", - (void *) 0x60); + sys_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", + (void *) 0x30); + sys_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", + (void *) 0x40); + sys_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", + (void *) 0x50); + sys_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", + (void *) 0x60); } /* diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/via.c linux/arch/m68k/mac/via.c --- v2.3.44/linux/arch/m68k/mac/via.c Tue Sep 7 12:14:06 1999 +++ linux/arch/m68k/mac/via.c Sun Feb 13 11:21:42 2000 @@ -24,6 +24,8 @@ #include #include +#include + #include #include #include @@ -60,7 +62,7 @@ #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -static int nubus_active; +static int nubus_active = 0; void via_debug_dump(void); void via1_irq(int, void *, struct pt_regs *); @@ -71,7 +73,7 @@ void via_irq_clear(int irq); extern void mac_bang(int, void *, struct pt_regs *); -extern void mac_SCC_handler(int, void *, struct pt_regs *); +extern void mac_scc_dispatch(int, void *, struct pt_regs *); extern int console_loglevel; extern int oss_present; @@ -260,28 +262,28 @@ void __init via_register_interrupts(void) { if (via_alt_mapping) { - request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "Software IRQ", (void *) via1); - request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "VIA1 Dispatch", (void *) via1); + sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "software", (void *) via1); + sys_request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "via1", (void *) via1); } else { - request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "VIA1 Dispatch", (void *) via1); + sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "via1", (void *) via1); #if 0 /* interferes with serial on some machines */ if (!psc_present) { - request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, + sys_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, "Off Switch", mac_bang); } #endif } - request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "VIA2 Dispatch", (void *) via2); + sys_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + "via2", (void *) via2); if (!psc_present) { - request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK, - "SCC Dispatch", mac_SCC_handler); + sys_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK, + "scc", mac_scc_dispatch); } request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "Nubus Dispatch", (void *) via2); + "nubus", (void *) via2); } /* @@ -361,34 +363,13 @@ } /* - * VIA-based power switch, for machines that support it. - */ - -void via_poweroff(void) -{ - if (rbv_present) { - via2[rBufB] &= ~0x04; - } else { - /* Direction of vDirB is output */ - via2[vDirB] |= 0x04; - /* Send a value of 0 on that line */ - via2[vBufB] &= ~0x04; - /* Otherwise it prints "It is now.." then shuts off */ - mdelay(1000); - } - - /* We should never make it this far... */ - printk ("It is now safe to switch off your machine.\n"); - while(1); -} - -/* * Initialize VIA2 for Nubus access */ void __init via_nubus_init(void) { - nubus_active = 0; + /* don't set nubus_active = 0 here, it kills the Baboon */ + /* interrupt that we've already registered. */ /* unlock nubus transactions */ @@ -396,14 +377,22 @@ /* set the line to be an output on non-RBV machines */ via2[vDirB] |= 0x02; } - via2[gBufB] |= 0x02; + + /* this seems to be an ADB bit on PMU machines */ + /* according to MkLinux. -- jmt */ + + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { + via2[gBufB] |= 0x02; + } /* disable nubus slot interrupts. */ if (rbv_present) { - via2[rSIER] = 0x7F; /* like VIA; bit 7=clr,set */ + via2[rSIER] = 0x7F; + via2[rSIER] = nubus_active | 0x80; } else { - via2[vBufA] = 0xFF; /* active low irqs, force high */ - via2[vDirA] = 0xFF; /* ddr to output. */ + via2[vBufA] = 0xFF; + via2[vDirA] = ~nubus_active; } } @@ -478,7 +467,7 @@ int irq_bit, i; unsigned char events; - if (!(events = ~via2[gBufA] & nubus_active)) return; + if (!(events = ~via2[gBufA] & nubus_active)) return; for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { if (events & irq_bit) { @@ -586,189 +575,4 @@ return ~via2[gBufA] & irq_bit; } return 0; -} - -void via_scsi_clear(void) -{ - volatile unsigned char deep_magic; - -#ifdef DEBUG_IRQUSE - printk("via_scsi_clear()\n"); -#endif - - /* We handle this in oss.c , but this gets called in mac_scsinew.c */ - if(oss_present) return; - - if (rbv_present) { - via2[rIFR] = (1<<3) | (1<<0) | rbv_clear; - deep_magic = via2[rBufB]; - } else { - deep_magic = via2[vBufB]; - } - mac_enable_irq(IRQ_MAC_SCSI); -} - -/* - * PRAM/RTC access routines - * - * Must be called with interrupts disabled and - * the RTC should be enabled. - */ - -static __u8 via_pram_readbyte(void) -{ - int i,reg; - __u8 data; - - reg = via1[vBufB] & ~VIA1B_vRTCClk; - - /* Set the RTC data line to be an input. */ - - via1[vDirB] &= ~VIA1B_vRTCData; - - /* The bits of the byte come out in MSB order */ - - data = 0; - for (i = 0 ; i < 8 ; i++) { - via1[vBufB] = reg; - via1[vBufB] = reg | VIA1B_vRTCClk; - data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData); - } - - /* Return RTC data line to output state */ - - via1[vDirB] |= VIA1B_vRTCData; - - return data; -} - -static void via_pram_writebyte(__u8 data) -{ - int i,reg,bit; - - reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData); - - /* The bits of the byte go in in MSB order */ - - for (i = 0 ; i < 8 ; i++) { - bit = data & 0x80? 1 : 0; - data <<= 1; - via1[vBufB] = reg | bit; - via1[vBufB] = reg | bit | VIA1B_vRTCClk; - } -} - -/* - * Execute a PRAM/RTC command. For read commands - * data should point to a one-byte buffer for the - * resulting data. For write commands it should point - * to the data byte to for the command. - * - * This function disables all interrupts while running. - */ - -void via_pram_command(int command, __u8 *data) -{ - unsigned long cpu_flags; - int is_read; - - save_flags(cpu_flags); - cli(); - - /* Enable the RTC and make sure the strobe line is high */ - - via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb; - - if (command & 0xFF00) { /* extended (two-byte) command */ - via_pram_writebyte((command & 0xFF00) >> 8); - via_pram_writebyte(command & 0xFF); - is_read = command & 0x8000; - } else { /* one-byte command */ - via_pram_writebyte(command); - is_read = command & 0x80; - } - if (is_read) { - *data = via_pram_readbyte(); - } else { - via_pram_writebyte(*data); - } - - /* All done, disable the RTC */ - - via1[vBufB] |= VIA1B_vRTCEnb; - - restore_flags(cpu_flags); -} - -/* - * Return the current time in seconds since January 1, 1904. - * - * This only works on machines with the VIA-based PRAM/RTC, which - * is basically any machine with Mac II-style ADB. - */ - -__u32 via_read_time(void) -{ - union { - __u8 cdata[4]; - __u32 idata; - } result, last_result; - int ct; - - /* - * The NetBSD guys say to loop until you get the same reading - * twice in a row. - */ - - ct = 0; - do { - if (++ct > 10) { - printk("via_read_time: couldn't get valid time, " - "last read = 0x%08X and 0x%08X\n", last_result.idata, - result.idata); - break; - } - - last_result.idata = result.idata; - result.idata = 0; - - via_pram_command(0x81, &result.cdata[3]); - via_pram_command(0x85, &result.cdata[2]); - via_pram_command(0x89, &result.cdata[1]); - via_pram_command(0x8D, &result.cdata[0]); - } while (result.idata != last_result.idata); - - return result.idata; -} - -/* - * Set the current time to a number of seconds since January 1, 1904. - * - * This only works on machines with the VIA-based PRAM/RTC, which - * is basically any machine with Mac II-style ADB. - */ - -void via_write_time(__u32 time) -{ - union { - __u8 cdata[4]; - __u32 idata; - } data; - __u8 temp; - - /* Clear the write protect bit */ - - temp = 0x55; - via_pram_command(0x35, &temp); - - data.idata = time; - via_pram_command(0x01, &data.cdata[3]); - via_pram_command(0x05, &data.cdata[2]); - via_pram_command(0x09, &data.cdata[1]); - via_pram_command(0x0D, &data.cdata[0]); - - /* Set the write protect bit */ - - temp = 0xD5; - via_pram_command(0x35, &temp); } diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mm/motorola.c linux/arch/m68k/mm/motorola.c --- v2.3.44/linux/arch/m68k/mm/motorola.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/mm/motorola.c Sun Feb 13 11:21:42 2000 @@ -207,7 +207,7 @@ { int chunk; unsigned long mem_avail = 0; - unsigned int zones_size[3] = { 0, }; + unsigned long zones_size[3] = { 0, }; #ifdef DEBUG { diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mm/sun3mmu.c linux/arch/m68k/mm/sun3mmu.c --- v2.3.44/linux/arch/m68k/mm/sun3mmu.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/mm/sun3mmu.c Sun Feb 13 11:21:42 2000 @@ -30,7 +30,7 @@ extern void mmu_emu_init (void); -extern unsigned long free_area_init(unsigned long, unsigned long); +extern unsigned long free_area_init(unsigned long *zones_size); const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; diff -u --recursive --new-file v2.3.44/linux/arch/ppc/coffboot/misc.S linux/arch/ppc/coffboot/misc.S --- v2.3.44/linux/arch/ppc/coffboot/misc.S Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/coffboot/misc.S Sun Feb 13 10:47:01 2000 @@ -9,7 +9,7 @@ .text /* - * Use the BAT0 registers to map the 1st 8MB of RAM to + * Use the BAT3 registers to map the 1st 8MB of RAM to * the address given as the 1st argument. */ .globl setup_bats diff -u --recursive --new-file v2.3.44/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.3.44/linux/arch/ppc/configs/common_defconfig Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/configs/common_defconfig Sun Feb 13 10:47:01 2000 @@ -24,7 +24,7 @@ # CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_SMP is not set -# CONFIG_ALTIVEC is not set +CONFIG_ALTIVEC=y # # Loadable module support @@ -76,7 +76,7 @@ # # Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # @@ -178,9 +178,12 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y # @@ -239,6 +242,7 @@ # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -275,6 +279,7 @@ CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y +CONFIG_GMAC=y # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set @@ -472,6 +477,7 @@ # USB Controllers # # CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y # @@ -491,8 +497,7 @@ # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set -CONFIG_USB_SCSI=m -CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # @@ -513,11 +518,15 @@ # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set +CONFIG_HFS_FS=y # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y @@ -549,10 +558,51 @@ # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set # # Sound diff -u --recursive --new-file v2.3.44/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig --- v2.3.44/linux/arch/ppc/configs/gemini_defconfig Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/configs/gemini_defconfig Sun Feb 13 10:47:01 2000 @@ -24,7 +24,7 @@ CONFIG_GEMINI=y # CONFIG_APUS is not set # CONFIG_SMP is not set -# CONFIG_ALTIVEC is not set +CONFIG_ALTIVEC=y CONFIG_MACH_SPECIFIC=y # @@ -87,7 +87,6 @@ # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set # CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set @@ -151,9 +150,12 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 # CONFIG_CHR_DEV_SG is not set # @@ -208,6 +210,7 @@ # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -216,6 +219,7 @@ # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_MESH is not set # CONFIG_SCSI_MAC53C94 is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set # # IEEE 1394 (FireWire) support @@ -242,6 +246,7 @@ CONFIG_NET_ETHERNET=y # CONFIG_MACE is not set # CONFIG_BMAC is not set +# CONFIG_GMAC is not set CONFIG_NCR885E=y # CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set @@ -369,6 +374,7 @@ # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set @@ -405,10 +411,7 @@ # Partition Types # # CONFIG_PARTITION_ADVANCED is not set -CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.3.44/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.44/linux/arch/ppc/defconfig Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/defconfig Sun Feb 13 10:47:01 2000 @@ -24,7 +24,7 @@ # CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_SMP is not set -# CONFIG_ALTIVEC is not set +CONFIG_ALTIVEC=y # # Loadable module support @@ -76,7 +76,7 @@ # # Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # @@ -178,9 +178,12 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y # @@ -239,6 +242,7 @@ # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -275,6 +279,7 @@ CONFIG_NET_ETHERNET=y CONFIG_MACE=y CONFIG_BMAC=y +CONFIG_GMAC=y # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set @@ -472,6 +477,7 @@ # USB Controllers # # CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y # @@ -491,8 +497,7 @@ # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set -CONFIG_USB_SCSI=m -CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set # @@ -513,11 +518,15 @@ # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set +CONFIG_HFS_FS=y # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y @@ -549,10 +558,51 @@ # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set # # Sound diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.3.44/linux/arch/ppc/kernel/entry.S Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/entry.S Sun Feb 13 10:47:01 2000 @@ -176,7 +176,7 @@ 7: .string "syscall %d(%x, %x, %x, %x, %x, " 77: .string "%x, %x), current=%p\n" 79: .string " -> %x\n" - .align 2 + .align 2,0 #endif /* @@ -209,6 +209,9 @@ mflr r20 /* Return to switch caller */ mfmsr r22 li r0,MSR_FP /* Disable floating-point */ +#ifdef CONFIG_ALTIVEC + oris r0,r0,MSR_VEC@h +#endif /* CONFIG_ALTIVEC */ andc r22,r22,r0 stw r20,_NIP(r1) stw r22,_MSR(r1) @@ -274,7 +277,7 @@ SYNC rfi -#ifdef __SMP__ +#ifdef CONFIG_SMP .globl ret_from_smpfork ret_from_smpfork: bl schedule_tail @@ -310,22 +313,32 @@ lwz r5,_MSR(r1) andi. r5,r5,MSR_EE beq 2f + .globl lost_irq_ret +lost_irq_ret: 3: lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) cmpi 0,r4,0 beq+ 1f addi r3,r1,STACK_FRAME_OVERHEAD bl do_IRQ - .globl lost_irq_ret -lost_irq_ret: b 3b -1: lis r4,bh_mask@ha - lwz r4,bh_mask@l(r4) - lis r5,bh_active@ha - lwz r5,bh_active@l(r5) - and. r4,r4,r5 +1: lis r4,softirq_state@ha + addi r4,r4,softirq_state@l +#ifdef CONFIG_SMP + /* get processor # */ + lwz r3,PROCESSOR(r2) +#ifndef CONFIG_PPC64 + slwi r3,r3,5 +#else +#error not 64-bit ready +#endif + add r4,r4,r3 +#endif /* CONFIG_SMP */ + lwz r5,0(r4) + lwz r4,4(r4) + and. r5,r5,r4 beq+ 2f - bl do_bottom_half + bl do_softirq .globl do_bottom_half_ret do_bottom_half_ret: 2: /* disable interrupts */ diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.3.44/linux/arch/ppc/kernel/head.S Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/head.S Sun Feb 13 10:47:01 2000 @@ -460,8 +460,24 @@ STD_EXCEPTION(0xd00, SingleStep, SingleStepException) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) -#ifdef CONFIG_ALTIVEC - STD_EXCEPTION(0xf20, AltiVec, AltiVecUnavailable) +#ifndef CONFIG_ALTIVEC + STD_EXCEPTION(0xf00, Trap_0f, UnknownException) +#else +/* + * The Altivec unavailable trap is at 0x0f20. Foo. + * We effectively remap it to 0x3000. + */ + . = 0xf00 + b Trap_0f +trap_0f_cont: + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + bl transfer_to_handler + .long UnknownException + .long ret_from_except + + . = 0xf20 + b AltiVecUnavailable #endif /* CONFIG_ALTIVEC */ /* @@ -674,6 +690,21 @@ . = 0x3000 +#ifdef CONFIG_ALTIVEC +AltiVecUnavailable: + EXCEPTION_PROLOG + bne load_up_altivec /* if from user, just load it up */ + li r20,MSR_KERNEL + bl transfer_to_handler /* if from kernel, take a trap */ + .long KernelAltiVec + .long ret_from_except + +/* here are the bits of trap 0xf00 which got displaced */ +Trap_0f: + EXCEPTION_PROLOG + b trap_0f_cont +#endif /* CONFIG_ALTIVEC */ + /* * This code finishes saving the registers to the exception frame * and jumps to the appropriate handler for the exception, turning @@ -813,72 +844,134 @@ 86: .string "floating point used in kernel (task=%p, pc=%x)\n" .align 4 +#ifdef CONFIG_ALTIVEC +/* Note that the AltiVec support is closely modeled after the FP + * support. Changes to one are likely to be applicable to the + * other! */ +load_up_altivec: /* - * Take away the altivec regs. - * - * For now, ignore the vrsave regs and save them all - * -- Cort + * Disable AltiVec for the task which had AltiVec previously, + * and save its AltiVec registers in its thread_struct. + * Enables AltiVec for use in the kernel on return. + * On SMP we know the AltiVec units are free, since we give it up every + * switch. -- Kumar */ - .globl giveup_altivec -giveup_altivec: -#ifdef CONFIG_ALTIVEC - /* check for altivec */ - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,12 - bnelr - - /* enable altivec so we can save */ - mfmsr r4 - oris r4,r4,MSR_VEC@h - mtmsr r4 + mfmsr r5 + oris r5,r5,MSR_VEC@h + SYNC + mtmsr r5 /* enable use of AltiVec now */ + SYNC +/* + * For SMP, we don't do lazy AltiVec switching because it just gets too + * horrendously complex, especially when a task switches from one CPU + * to another. Instead we call giveup_altivec in switch_to. + */ +#ifndef __SMP__ +#ifndef CONFIG_APUS + lis r6,-KERNELBASE@h +#else + lis r6,CYBERBASEp@h + lwz r6,0(r6) +#endif + addis r3,r6,last_task_used_altivec@ha + lwz r4,last_task_used_altivec@l(r3) + cmpi 0,r4,0 + beq 1f + add r4,r4,r6 + addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ + SAVE_32VR(0,r20,r4) + MFVSCR(vr0) + li r20,THREAD_VSCR + STVX(vr0,r20,r4) + lwz r5,PT_REGS(r4) + add r5,r5,r6 + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r20,MSR_VEC@h + andc r4,r4,r20 /* disable altivec for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#endif /* __SMP__ */ + /* enable use of AltiVec after return */ + oris r23,r23,MSR_VEC@h + mfspr r5,SPRG3 /* current task's THREAD (phys) */ + li r20,THREAD_VSCR + LVX(vr0,r20,r5) + MTVSCR(vr0) + REST_32VR(0,r20,r5) +#ifndef __SMP__ + subi r4,r5,THREAD + sub r4,r4,r6 + stw r4,last_task_used_altivec@l(r3) +#endif /* __SMP__ */ + /* restore registers and return */ + lwz r3,_CCR(r21) + lwz r4,_LINK(r21) + mtcrf 0xff,r3 + mtlr r4 + REST_GPR(1, r21) + REST_4GPRS(3, r21) + /* we haven't used ctr or xer */ + mtspr SRR1,r23 + mtspr SRR0,r22 + REST_GPR(20, r21) + REST_2GPRS(22, r21) + lwz r21,GPR21(r21) + SYNC + rfi - /* make sure our tsk pointer is valid */ - cmpi 0,r3,0 - beqlr +/* + * AltiVec unavailable trap from kernel - print a message, but let + * the task use AltiVec in the kernel until it returns to user mode. + */ +KernelAltiVec: + lwz r3,_MSR(r1) + oris r3,r3,MSR_VEC@h + stw r3,_MSR(r1) /* enable use of AltiVec after return */ + lis r3,87f@h + ori r3,r3,87f@l + mr r4,r2 /* current */ + lwz r5,_NIP(r1) + bl printk + b ret_from_except +87: .string "AltiVec used in kernel (task=%p, pc=%x) \n" + .align 4 - /* save altivec regs */ - addi r4,r3,THREAD+THREAD_VRSAVE - mfspr r5,256 /* vrsave */ - stw r5,0(r4) - - /* get regs for the task */ - addi r4,r3,THREAD+PT_REGS - /* turn off the altivec bit in the tasks regs */ - lwz r5,_MSR(r4) - lis r6,MSR_VEC@h - andi. r5,r5,r6 - stw r5,_MSR(r4) +/* + * giveup_altivec(tsk) + * Disable AltiVec for the task given as the argument, + * and save the AltiVec registers in its thread_struct. + * Enables AltiVec for use in the kernel on return. + */ - /* we've given up the altivec - clear the pointer */ - li r3,0 - lis r4,last_task_used_altivec@h - stw r3,last_task_used_altivec@l(r4) -#endif /* CONFIG_ALTIVEC */ - blr - - .globl load_up_altivec -load_up_altivec: -#ifdef CONFIG_ALTIVEC - /* check for altivec */ - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,12 - bnelr - - /* restore altivec regs */ - addi r4,r3,THREAD+THREAD_VRSAVE - lwz r5,0(r4) - mtspr 256,r5 /* vrsave */ - - /* get regs for the task */ - addi r4,r3,THREAD+PT_REGS - /* turn on the altivec bit in the tasks regs */ - lwz r5,_MSR(r4) + .globl giveup_altivec +giveup_altivec: + mfmsr r5 oris r5,r5,MSR_VEC@h - stw r5,_MSR(r4) -#endif /* CONFIG_ALTIVEC */ + SYNC + mtmsr r5 /* enable use of AltiVec now */ + SYNC + cmpi 0,r3,0 + beqlr- /* if no previous owner, done */ + addi r3,r3,THREAD /* want THREAD of task */ + lwz r5,PT_REGS(r3) + cmpi 0,r5,0 + SAVE_32VR(0, r4, r3) + MFVSCR(vr0) + li r4,THREAD_VSCR + STVX(vr0, r4, r3) + beq 1f + lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) + lis r3,MSR_VEC@h + andc r4,r4,r3 /* disable AltiVec for previous task */ + stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) +1: +#ifndef __SMP__ + li r5,0 + lis r4,last_task_used_altivec@ha + stw r5,last_task_used_altivec@l(r4) +#endif /* __SMP__ */ blr +#endif /* CONFIG_ALTIVEC */ /* * giveup_fpu(tsk) @@ -1437,17 +1530,16 @@ #if 0 /* That's useful debug stuff */ setup_screen_bat: + li r3,0 + mtspr DBAT1U,r3 + mtspr IBAT1U,r3 lis r3, 0x9100 -#ifdef __SMP__ - ori r3,r3,0x12 -#else - ori r3,r3,0x2 -#endif - mtspr DBAT1L, r3 - mtspr IBAT1L, r3 + ori r4,r3,0x2a + mtspr DBAT1L,r4 + mtspr IBAT1L,r4 ori r3,r3,(BL_8M<<2)|0x2 /* set up BAT registers for 604 */ - mtspr DBAT1U, r3 - mtspr IBAT1U, r3 + mtspr DBAT1U,r3 + mtspr IBAT1U,r3 blr #endif diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.44/linux/arch/ppc/kernel/irq.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/irq.c Sun Feb 13 10:47:01 2000 @@ -74,8 +74,8 @@ irq_desc_t irq_desc[NR_IRQS]; int ppc_spurious_interrupts = 0; -unsigned int ppc_local_bh_count[NR_CPUS]; -unsigned int ppc_local_irq_count[NR_CPUS]; +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; struct irqaction *ppc_irq_action[NR_IRQS]; unsigned int ppc_cached_irq_mask[NR_MASK_WORDS]; unsigned int ppc_lost_interrupts[NR_MASK_WORDS]; @@ -350,7 +350,6 @@ atomic_t global_irq_count; atomic_t global_bh_count; -atomic_t global_bh_lock; static void show(char * str) { @@ -361,12 +360,12 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [%d %d]\n", atomic_read(&global_irq_count), - ppc_local_irq_count[0], - ppc_local_irq_count[1]); + local_irq_count[0], + local_irq_count[1]); printk("bh: %d [%d %d]\n", atomic_read(&global_bh_count), - ppc_local_bh_count[0], - ppc_local_bh_count[1]); + local_bh_count[0], + local_bh_count[1]); stack = (unsigned long *) &str; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -401,7 +400,7 @@ * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (ppc_local_bh_count[cpu] + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) break; } @@ -423,7 +422,7 @@ continue; if (global_irq_lock) continue; - if (!ppc_local_bh_count[cpu] + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) continue; if (!test_and_set_bit(0,&global_irq_lock)) @@ -514,7 +513,7 @@ if (flags & (1 << 15)) { int cpu = smp_processor_id(); __cli(); - if (!ppc_local_irq_count[cpu]) + if (!local_irq_count[cpu]) get_irqlock(cpu); } } @@ -523,7 +522,7 @@ { int cpu = smp_processor_id(); - if (!ppc_local_irq_count[cpu]) + if (!local_irq_count[cpu]) release_irqlock(cpu); __sti(); } @@ -547,7 +546,7 @@ retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!ppc_local_irq_count[smp_processor_id()]) { + if (!local_irq_count[smp_processor_id()]) { if (local_enabled) retval = 1; if (global_irq_holder == (unsigned char) smp_processor_id()) diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.3.44/linux/arch/ppc/kernel/misc.S Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/misc.S Sun Feb 13 10:47:01 2000 @@ -272,6 +272,38 @@ blr /* + * Copy a whole page. We use the dcbz instruction on the destination + * to reduce memory traffic (it eliminates the unnecessary reads of + * the destination into cache). This requires that the destination + * is cacheable. + */ +_GLOBAL(copy_page) + li r0,4096/CACHE_LINE_SIZE + mtctr r0 + addi r3,r3,-4 + addi r4,r4,-4 + li r5,4 +1: dcbz r5,r3 + lwz r6,4(r4) + lwz r7,8(r4) + lwz r8,12(r4) + lwzu r9,16(r4) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + stwu r9,16(r3) + lwz r6,4(r4) + lwz r7,8(r4) + lwz r8,12(r4) + lwzu r9,16(r4) + stw r6,4(r3) + stw r7,8(r3) + stw r8,12(r3) + stwu r9,16(r3) + bdnz 1b + blr + +/* * Atomic [test&set] exchange * * unsigned long xchg_u32(void *ptr, unsigned long val) diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.3.44/linux/arch/ppc/kernel/mk_defs.c Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/kernel/mk_defs.c Sun Feb 13 10:47:01 2000 @@ -48,9 +48,11 @@ DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched)); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); - DEFINE(THREAD_VRF, offsetof(struct thread_struct, vrf)); - DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); +#ifdef CONFIG_ALTIVEC + DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); + DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); +#endif /* CONFIG_ALTIVEC */ /* Interrupt register frame */ DEFINE(TASK_UNION_SIZE, sizeof(union task_union)); DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.3.44/linux/arch/ppc/kernel/open_pic.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/open_pic.c Sun Feb 13 10:47:01 2000 @@ -279,7 +279,7 @@ /* Initialize the spurious interrupt */ if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd); openpic_set_spurious(OPENPIC_VEC_SPURIOUS); - if ( !(_machine && (_MACH_gemini|_MACH_Pmac)) ) + if ( !(_machine & (_MACH_gemini|_MACH_Pmac)) ) { if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, "82c59 cascade", NULL)) @@ -490,7 +490,7 @@ /* make sure mask gets to controller before we return to user */ do { mb(); /* sync is probably useless here */ - } while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + } while(openpic_readfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK)); } @@ -501,7 +501,7 @@ /* make sure mask gets to controller before we return to user */ do { mb(); /* sync is probably useless here */ - } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + } while(!openpic_readfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK)); } diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.44/linux/arch/ppc/kernel/pmac_pic.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/pmac_pic.c Sun Feb 13 10:47:01 2000 @@ -31,8 +31,6 @@ static int max_real_irqs; static int has_openpic = 0; -#define MAXCOUNT 10000000 - #define GATWICK_IRQ_POOL_SIZE 10 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; @@ -186,25 +184,6 @@ #endif smp_message_recv(); return -2; /* ignore, already handled */ - } - - { - unsigned int loops = MAXCOUNT; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } } #endif /* __SMP__ */ diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.3.44/linux/arch/ppc/kernel/pmac_setup.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/pmac_setup.c Sun Feb 13 10:47:01 2000 @@ -60,6 +60,7 @@ #include #include #include +#include #include "time.h" #include "local_irq.h" @@ -440,6 +441,7 @@ { char *p; int n; + kdev_t __init pmac_find_ide_boot(char *bootdevice, int n); if (bootdevice == NULL) return 0; @@ -695,9 +697,12 @@ #ifdef CONFIG_BOOTX_TEXT extern void drawchar(char c); extern void drawstring(const char *c); +extern boot_infos_t *disp_bi; void pmac_progress(char *s, unsigned short hex) { + if (disp_bi == 0) + return; drawstring(s); drawchar('\n'); } diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.3.44/linux/arch/ppc/kernel/pmac_time.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/pmac_time.c Sun Feb 13 10:47:01 2000 @@ -71,8 +71,8 @@ if (req.reply_len != 7) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (unsigned long)(req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + (unsigned long)req.reply[4] - RTC_OFFSET; + return (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h --- v2.3.44/linux/arch/ppc/kernel/ppc_asm.h Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/kernel/ppc_asm.h Sun Feb 13 10:47:01 2000 @@ -44,6 +44,28 @@ #define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base) #define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base) +/* + * Once a version of gas that understands the AltiVec instructions + * is freely available, we can do this the normal way... - paulus + */ +#define LVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1) +#define STVX(r,a,b) .long (31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1) +#define MFVSCR(r) .long (4<<26)+((r)<<21)+(1540<<1) +#define MTVSCR(r) .long (4<<26)+((r)<<11)+(802<<1) + +#define SAVE_VR(n,b,base) li b,THREAD_VR0+(16*(n)); STVX(n,b,base) +#define SAVE_2VR(n,b,base) SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) +#define SAVE_4VR(n,b,base) SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) +#define SAVE_8VR(n,b,base) SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) +#define SAVE_16VR(n,b,base) SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base) +#define SAVE_32VR(n,b,base) SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base) +#define REST_VR(n,b,base) li b,THREAD_VR0+(16*(n)); LVX(n,b,base) +#define REST_2VR(n,b,base) REST_VR(n,b,base); REST_VR(n+1,b,base) +#define REST_4VR(n,b,base) REST_2VR(n,b,base); REST_2VR(n+2,b,base) +#define REST_8VR(n,b,base) REST_4VR(n,b,base); REST_4VR(n+4,b,base) +#define REST_16VR(n,b,base) REST_8VR(n,b,base); REST_8VR(n+8,b,base) +#define REST_32VR(n,b,base) REST_16VR(n,b,base); REST_16VR(n+16,b,base) + #define SYNC \ sync; \ isync diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl --- v2.3.44/linux/arch/ppc/kernel/ppc_asm.tmpl Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/kernel/ppc_asm.tmpl Sun Feb 13 10:47:01 2000 @@ -80,3 +80,36 @@ #define fr29 29 #define fr30 30 #define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.3.44/linux/arch/ppc/kernel/ppc_ksyms.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Sun Feb 13 10:47:01 2000 @@ -72,8 +72,8 @@ EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); -EXPORT_SYMBOL(ppc_local_irq_count); -EXPORT_SYMBOL(ppc_local_bh_count); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); #ifdef __SMP__ EXPORT_SYMBOL(kernel_flag); #endif /* __SMP__ */ @@ -272,4 +272,3 @@ EXPORT_SYMBOL(decrementer_count); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); -EXPORT_SYMBOL(do_bottom_half); diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.44/linux/arch/ppc/kernel/process.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/process.c Sun Feb 13 10:47:01 2000 @@ -140,15 +140,31 @@ } #endif /* defined(CHECK_STACK) */ +#ifdef CONFIG_ALTIVEC int -dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) { - if (regs->msr & MSR_FP) - giveup_fpu(current); - memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); + if (regs->msr & MSR_VEC) + giveup_altivec(current); + memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); return 1; } +void +enable_kernel_altivec(void) +{ +#ifdef __SMP__ + if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) + giveup_altivec(current); + else + giveup_altivec(NULL): /* just enable AltiVec for kernel - force */ +#else + giveup_altivec(last_task_used_altivec); +#endif /* __SMP __ */ + printk("MSR_VEC in enable_altivec_kernel\n"); +} +#endif /* CONFIG_ALTIVEC */ + void enable_kernel_fp(void) { @@ -162,6 +178,15 @@ #endif /* __SMP__ */ } +int +dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +{ + if (regs->msr & MSR_FP) + giveup_fpu(current); + memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); + return 1; +} + void _switch_to(struct task_struct *prev, struct task_struct *new, struct task_struct **last) @@ -194,6 +219,7 @@ */ if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) ) giveup_fpu(prev); +#ifdef CONFIG_ALTIVEC /* * If the previous thread 1) has some altivec regs it wants saved * (has bits in vrsave set) and 2) used altivec in the last quantum @@ -206,6 +232,7 @@ if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) && prev->thread.vrsave ) giveup_altivec(prev); +#endif /* CONFIG_ALTIVEC */ prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* __SMP__ */ @@ -337,13 +364,18 @@ p->thread.fpscr = current->thread.fpscr; childregs->msr &= ~MSR_FP; +#ifdef CONFIG_ALTIVEC + /* + * copy altiVec info - assume lazy altiVec switch + * - kumar + */ if (regs->msr & MSR_VEC) giveup_altivec(current); - if ( p->thread.vrsave ) - memcpy(&p->thread.vrf, ¤t->thread.vrf, sizeof(p->thread.vrf)); + + memcpy(&p->thread.vr, ¤t->thread.vr, sizeof(p->thread.vr)); p->thread.vscr = current->thread.vscr; - p->thread.vrsave = current->thread.vrsave; childregs->msr &= ~MSR_VEC; +#endif /* CONFIG_ALTIVEC */ #ifdef __SMP__ p->last_processor = NO_PROC_ID; @@ -463,6 +495,10 @@ goto out; if (regs->msr & MSR_FP) giveup_fpu(current); +#ifdef CONFIG_ALTIVEC + if (regs->msr & MSR_VEC) + giveup_altivec(current); +#endif /* CONFIG_ALTIVEC */ error = do_execve(filename, (char **) a1, (char **) a2, regs); putname(filename); out: diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.3.44/linux/arch/ppc/kernel/prom.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/prom.c Sun Feb 13 10:47:01 2000 @@ -802,42 +802,19 @@ { unsigned int len; int width = 640, height = 480, depth = 8, pitch; - unsigned address; + unsigned address; boot_infos_t* bi; unsigned long offset = reloc_offset(); - prom_print(RELOC("Initing fake screen\n")); + prom_print(RELOC("Initializing fake screen\n")); - len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width)); + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height)); call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len)); - if (len == 0) - prom_print(RELOC("Warning: assuming display depth = 8\n")); - else - depth = len; - width = len = 0; - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len)); - width = len; - if (width == 0) { - prom_print(RELOC("Failed to get width\n")); - return; - } - height = len = 0; - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len)); - height = len; - if (height == 0) { - prom_print(RELOC("Failed to get height\n")); - return; - } - pitch = len = 0; + pitch = width * ((depth + 7) / 8); call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len)); - pitch = len; - if (pitch == 0) { - prom_print(RELOC("Failed to get pitch\n")); - return; - } - address = len = 0; + address = 0; call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len)); - address = len; if (address == 0) { prom_print(RELOC("Failed to get address\n")); return; @@ -846,22 +823,22 @@ /* kludge for valkyrie */ if (strcmp(dp->name, "valkyrie") == 0) address += 0x1000; - } #endif - RELOC(disp_bi) = &fake_bi; - bi = PTRRELOC((&fake_bi)); - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; - bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = (unsigned char *)address; - bi->dispDeviceRowBytes = pitch; - bi->dispDeviceDepth = depth; - bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; + RELOC(disp_bi) = &fake_bi; + bi = PTRRELOC((&fake_bi)); + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = width / 8; + RELOC(g_max_loc_Y) = height / 16; + bi->logicalDisplayBase = (unsigned char *)address; + bi->dispDeviceBase = (unsigned char *)address; + bi->dispDeviceRowBytes = pitch; + bi->dispDeviceDepth = depth; + bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; + bi->dispDeviceRect[2] = width; + bi->dispDeviceRect[3] = height; + RELOC(disp_bi) = 0; } #endif diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.44/linux/arch/ppc/kernel/setup.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/setup.c Sun Feb 13 10:47:01 2000 @@ -221,7 +221,7 @@ if ( i ) len += sprintf(len+buffer,"\n"); len += sprintf(len+buffer,"processor\t: %lu\n",i); - len += sprintf(len+buffer,"cpu\t\t: "); + len += sprintf(len+buffer,"cpu\t\t: "); pvr = GET_PVR; @@ -656,7 +656,6 @@ #ifdef CONFIG_BOOTX_TEXT map_bootx_text(); - prom_print("identify machine\n"); #endif #ifdef CONFIG_XMON diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.3.44/linux/arch/ppc/kernel/smp.c Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/kernel/smp.c Sun Feb 13 10:47:01 2000 @@ -53,7 +53,6 @@ cycles_t cacheflush_time; /* all cpu mappings are 1-1 -- Cort */ -int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,}; volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; int start_secondary(void *); diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.3.44/linux/arch/ppc/kernel/syscalls.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/syscalls.c Sun Feb 13 10:47:01 2000 @@ -252,14 +252,13 @@ asmlinkage int sys_uname(struct old_utsname * name) { - int err; - - if (!name) - return -EFAULT; + int err = -EFAULT; + down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); - up(&uts_sem); - return err ? -EFAULT : 0; + if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + err = 0; + up_read(&uts_sem); + return err; } asmlinkage int sys_olduname(struct oldold_utsname * name) @@ -282,8 +281,8 @@ error -= __put_user(0,name->version+__OLD_UTS_LEN); error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); - error = error ? -EFAULT : 0; - up(&uts_sem); + up_read(&uts_sem); + error = error ? -EFAULT : 0; return error; } diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.3.44/linux/arch/ppc/kernel/traps.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/traps.c Sun Feb 13 10:47:01 2000 @@ -118,11 +118,11 @@ default: printk("Unknown values in msr\n"); } + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); #endif - show_regs(regs); - print_backtrace((unsigned long *)regs->gpr[1]); panic("machine check"); } _exception(SIGSEGV, regs); @@ -141,44 +141,6 @@ print_backtrace((unsigned long *)regs->gpr[1]); panic("System Management Interrupt"); } - -#if defined(CONFIG_ALTIVEC) -void -AltiVecUnavailable(struct pt_regs *regs) -{ - /* - * This should be changed so we don't take a trap if coming - * back when last_task_used_altivec == current. We should also - * allow the kernel to use the altivec regs on UP to store tasks - * regs during switch - * -- Cort - */ - if ( regs->msr & MSR_VEC ) - { - show_regs(regs); - panic("AltiVec trap with Altivec enabled!\n"); - } - - if ( !user_mode(regs) ) - { - show_regs(regs); - panic("Kernel Used Altivec with MSR_VEC off!\n"); - } - - if ( last_task_used_altivec != current ) - { - if ( last_task_used_altivec ) - giveup_altivec(current); - load_up_altivec(current); - /* on SMP we always save/restore on switch */ -#ifndef __SMP__ - last_task_used_altivec = current; -#endif - } - /* enable altivec for the task on return */ - regs->msr |= MSR_VEC; -} -#endif /* CONFIG_ALTIVEC */ void UnknownException(struct pt_regs *regs) diff -u --recursive --new-file v2.3.44/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S --- v2.3.44/linux/arch/ppc/lib/string.S Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/lib/string.S Sun Feb 13 10:47:01 2000 @@ -12,6 +12,11 @@ #include #include +CACHELINE_BYTES = 32 +LG_CACHELINE_BYTES = 5 +CACHELINE_MASK = 0x1f +CACHELINE_WORDS = 8 + .globl strcpy strcpy: addi r5,r3,-1 @@ -70,6 +75,55 @@ subf r3,r3,r4 blr +/* + * Use dcbz on the complete cache lines in the destination + * to set them to zero. This requires that the destination + * area is cacheable. -- paulus + */ + .globl cacheable_memzero +cacheable_memzero: + mr r5,r4 + li r4,0 + addi r6,r3,-4 + cmplwi 0,r5,4 + blt 7f + stwu r4,4(r6) + beqlr + andi. r0,r6,3 + add r5,r0,r5 + subf r6,r0,r6 + clrlwi r7,r6,32-LG_CACHELINE_BYTES + add r8,r7,r5 + srwi r9,r8,LG_CACHELINE_BYTES + addic. r9,r9,-1 /* total number of complete cachelines */ + ble 2f + xori r0,r7,CACHELINE_MASK & ~3 + srwi. r0,r0,2 + beq 3f + mtctr r0 +4: stwu r4,4(r6) + bdnz 4b +3: mtctr r9 + li r7,4 +10: dcbz r7,r6 + addi r6,r6,CACHELINE_BYTES + bdnz 10b + clrlwi r5,r8,32-LG_CACHELINE_BYTES + addi r5,r5,4 +2: srwi r0,r5,2 + mtctr r0 + bdz 6f +1: stwu r4,4(r6) + bdnz 1b +6: andi. r5,r5,3 +7: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r6,r6,3 +8: stbu r4,1(r6) + bdnz 8b + blr + .globl memset memset: rlwimi r4,r4,8,16,23 @@ -82,7 +136,7 @@ andi. r0,r6,3 add r5,r0,r5 subf r6,r0,r6 - rlwinm r0,r5,32-2,2,31 + srwi r0,r5,2 mtctr r0 bdz 6f 1: stwu r4,4(r6) @@ -103,6 +157,87 @@ mr r4,r6 b memcpy +/* + * This version uses dcbz on the complete cache lines in the + * destination area to reduce memory traffic. This requires that + * the destination area is cacheable. + * We only use this version if the source and dest don't overlap. + * -- paulus. + */ + .global cacheable_memcpy +cacheable_memcpy: + add r7,r3,r5 /* test if the src & dst overlap */ + add r8,r4,r5 + cmplw 0,r4,r7 + cmplw 1,r3,r8 + crand 0,0,4 /* cr0.lt &= cr1.lt */ + blt memcpy /* if regions overlap */ + + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + subf r5,r0,r5 + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ + stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ + stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + mtctr r0 + beq 63f +53: dcbz r11,r6 + lwz r7,4(r4) + lwz r8,8(r4) + lwz r9,12(r4) + lwzu r10,16(r4) + stw r7,4(r6) + stw r8,8(r6) + stw r9,12(r6) + stwu r10,16(r6) + lwz r7,4(r4) + lwz r8,8(r4) + lwz r9,12(r4) + lwzu r10,16(r4) + stw r7,4(r6) + stw r8,8(r6) + stw r9,12(r6) + stwu r10,16(r6) + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) + stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) + stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: blr + .globl memmove memmove: cmplw 0,r3,r4 @@ -111,7 +246,7 @@ .globl memcpy memcpy: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + srwi. r7,r5,3 addi r6,r3,-4 addi r4,r4,-4 beq 2f /* if less than 8 bytes to do */ @@ -218,106 +353,167 @@ .globl __copy_tofrom_user __copy_tofrom_user: - srwi. r7,r5,3 - addi r6,r3,-4 addi r4,r4,-4 - li r3,0 /* success return value */ - beq 2f /* if less than 8 bytes to do */ - andi. r0,r6,3 /* get dest word aligned */ - mtctr r7 - bne 5f -1: lwz r7,4(r4) -11: lwzu r8,8(r4) -12: stw r7,4(r6) -13: stwu r8,8(r6) - bdnz 1b - andi. r5,r5,7 -2: cmplwi 0,r5,4 - blt 3f -14: lwzu r0,4(r4) - addi r5,r5,-4 -15: stwu r0,4(r6) -3: cmpwi 0,r5,0 /* do 1 byte at a time for the remainder */ - beqlr - mtctr r5 - addi r4,r4,3 - addi r6,r6,3 -4: lbzu r0,1(r4) -16: stbu r0,1(r6) - bdnz 4b - blr -5: subfic r0,r0,4 /* copy bytes until we have the */ - mtctr r0 /* destination 4-byte aligned */ - subf r5,r0,r5 -6: lbz r7,4(r4) + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ +71: stb r9,4(r6) addi r4,r4,1 -17: stb r7,4(r6) addi r6,r6,1 - bdnz 6b - srwi. r7,r5,3 - beq 2b - mtctr r7 - b 1b -/* we come here on a fault in the 8-byte-at-a-time loop */ -88: subi r4,r4,8 /* compensate for the lwzu */ -98: mfctr r0 - rlwimi r5,r0,3,0,28 /* use the byte-at-a-time loop to */ - b 3b /* copy up to the byte at fault */ -/* here on a write fault in the single-word copy */ -96: subi r4,r4,4 - b 3b -/* here on a read fault in the initial single-byte copy */ -90: mfctr r3 - add r3,r3,r5 - b 70f -/* here on a read fault in the final single-byte copy */ -99: mfctr r3 - subi r6,r6,3 -/* clear out the rest of the destination: r3 bytes starting at 4(r6) */ -70: li r0,0 - mr. r5,r3 - beq 76f -71: andi. r4,r6,3 - beq 72f -77: stb r0,4(r6) + bdnz 70b +61: subf r5,r0,r5 + srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ +73: stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ + clrlwi r5,r5,32-LG_CACHELINE_BYTES + li r11,4 + mtctr r0 + beq 63f +53: dcbz r11,r6 +10: lwz r7,4(r4) +11: lwz r8,8(r4) +12: lwz r9,12(r4) +13: lwzu r10,16(r4) +14: stw r7,4(r6) +15: stw r8,8(r6) +16: stw r9,12(r6) +17: stwu r10,16(r6) +20: lwz r7,4(r4) +21: lwz r8,8(r4) +22: lwz r9,12(r4) +23: lwzu r10,16(r4) +24: stw r7,4(r6) +25: stw r8,8(r6) +26: stw r9,12(r6) +27: stwu r10,16(r6) + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) +31: stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) +41: stb r0,4(r6) + addi r4,r4,1 addi r6,r6,1 - addic. r5,r5,-1 - bne 71b -72: srwi. r7,r5,2 - beq 73f - mtctr r7 -74: stwu r0,4(r6) - bdnz 74b -73: andi. r5,r5,3 - beq 76f - mtctr r5 - addi r6,r6,3 -75: stbu r0,1(r6) - bdnz 75b -76: blr -/* here on a write fault in the initial single-byte copy */ -80: mfctr r3 - add r3,r3,r5 - blr -/* here on a write fault in the final single-byte copy */ -81: mfctr r3 + bdnz 40b +65: li r3,0 blr +/* read fault, initial single-byte copy */ +100: li r4,0 + b 90f +/* write fault, initial single-byte copy */ +101: li r4,1 +90: subf r5,r8,r5 + li r3,0 + b 99f +/* read fault, initial word copy */ +102: li r4,0 + b 91f +/* write fault, initial word copy */ +103: li r4,1 +91: li r3,2 + b 99f +/* read fault in 2nd half of cacheline loop */ +106: addi r5,r5,-16 +/* read fault in 1st half of cacheline loop */ +104: li r4,0 + b 92f +/* write fault in 2nd half of cacheline loop */ +107: addi r5,r5,-16 +/* fault on dcbz (effectively a write fault) */ +/* or write fault in 1st half of cacheline loop */ +105: li r4,1 +92: li r3,LG_CACHELINE_BYTES + b 99f +/* read fault in final word loop */ +108: li r4,0 + b 93f +/* write fault in final word loop */ +109: li r4,1 +93: andi. r5,r5,3 + li r3,2 + b 99f +/* read fault in final byte loop */ +110: li r4,0 + b 94f +/* write fault in final byte loop */ +111: li r4,1 +94: li r5,0 + li r3,0 +/* + * At this stage the number of bytes not copied is + * r5 + (ctr << r3), and r4 is 0 for read or 1 for write. + */ +99: mfctr r0 + slw r3,r0,r3 + add r3,r3,r5 + cmpwi 0,r4,0 + bne 120f +/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */ + srwi. r0,r3,2 + li r9,0 + mtctr r0 + beq 113f +112: stwu r9,4(r6) + bdnz 112b +113: andi. r0,r3,3 + mtctr r0 + beq 120f +114: stb r9,4(r6) + addi r6,r6,1 + bdnz 114b +120: blr + .section __ex_table,"a" .align 2 - .long 1b,98b - .long 11b,98b - .long 12b,88b - .long 13b,88b - .long 14b,3b - .long 15b,96b - .long 4b,99b - .long 16b,81b - .long 6b,90b - .long 17b,80b - .long 77b,76b - .long 74b,76b - .long 75b,76b + .long 70b,100b + .long 71b,101b + .long 72b,102b + .long 73b,103b + .long 53b,105b + .long 10b,104b + .long 11b,104b + .long 12b,104b + .long 13b,104b + .long 14b,105b + .long 15b,105b + .long 16b,105b + .long 17b,105b + .long 20b,106b + .long 21b,106b + .long 22b,106b + .long 23b,106b + .long 24b,107b + .long 25b,107b + .long 26b,107b + .long 27b,107b + .long 30b,108b + .long 31b,109b + .long 40b,110b + .long 41b,111b + .long 112b,120b + .long 114b,120b .text .globl __clear_user @@ -334,7 +530,6 @@ andi. r0,r6,3 add r4,r0,r4 subf r6,r0,r6 - /*rlwinm r0,r4,32-2,2,31*/ srwi r0,r4,2 mtctr r0 bdz 6f diff -u --recursive --new-file v2.3.44/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.44/linux/arch/ppc/mm/init.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/mm/init.c Sun Feb 13 10:47:01 2000 @@ -1107,7 +1107,7 @@ */ void __init paging_init(void) { - unsigned int zones_size[MAX_NR_ZONES], i; + unsigned long zones_size[MAX_NR_ZONES], i; /* * Grab some memory for bad_page and bad_pagetable to use. @@ -1197,7 +1197,7 @@ unsigned long a, total; /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (64<<20) +#define RAM_LIMIT (768<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { diff -u --recursive --new-file v2.3.44/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.3.44/linux/arch/ppc/xmon/start.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/xmon/start.c Sun Feb 13 10:47:01 2000 @@ -115,42 +115,41 @@ int xmon_write(void *handle, void *ptr, int nb) { - char *p = ptr; - int i, c, ct; + char *p = ptr; + int i, c, ct; #ifdef CONFIG_BOOTX_TEXT - if (use_screen) { - /* write it on the screen */ - for (i = 0; i < nb; ++i) - drawchar(*p++); - return nb; - } + if (use_screen) { + /* write it on the screen */ + for (i = 0; i < nb; ++i) + drawchar(*p++); + return nb; + } #endif - if (!scc_initialized) - xmon_init_scc(); - for (i = 0; i < nb; ++i) { - ct = 0; - while ((*sccc & TXRDY) == 0) + if (!scc_initialized) + xmon_init_scc(); + ct = 0; + for (i = 0; i < nb; ++i) { + while ((*sccc & TXRDY) == 0) { #ifdef CONFIG_ADB - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#else - ; + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll(); #endif /* CONFIG_ADB */ - c = p[i]; - if (c == '\n' && !ct) { - c = '\r'; - ct = 1; - --i; - } else { - if (console) - printk("%c", c); - ct = 0; + } + c = p[i]; + if (c == '\n' && !ct) { + c = '\r'; + ct = 1; + --i; + } else { + if (console) + printk("%c", c); + ct = 0; + } + buf_access(); + *sccd = c; } - buf_access(); - *sccd = c; - } - return i; + return i; } int xmon_wants_key; @@ -285,7 +284,7 @@ { int i, x; - if (macio_node != 0) { + if (via_modem && macio_node != 0) { unsigned int t0; feature_set(macio_node, FEATURE_Modem_power); diff -u --recursive --new-file v2.3.44/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.3.44/linux/arch/sparc/kernel/ioport.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/kernel/ioport.c Sun Feb 13 10:18:03 2000 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.31 2000/02/06 22:55:32 zaitcev Exp $ +/* $Id: ioport.c,v 1.32 2000/02/12 03:04:48 zaitcev Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -562,7 +562,7 @@ { int x; for (x = 0; x < n; x += PAGE_SIZE) { - (*_sparc_unmapioaddr)(p + n); + (*_sparc_unmapioaddr)((unsigned long)p + n); } } diff -u --recursive --new-file v2.3.44/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.3.44/linux/arch/sparc/kernel/pcic.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc/kernel/pcic.c Sun Feb 13 10:18:03 2000 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.12 2000/01/22 07:35:25 zaitcev Exp $ +/* $Id: pcic.c,v 1.13 2000/02/12 03:05:37 zaitcev Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -784,6 +784,7 @@ static __inline__ unsigned long do_gettimeoffset(void) { + struct tasklet_struct *t; unsigned long offset = 0; /* @@ -794,7 +795,8 @@ readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); - if(test_bit(TIMER_BH, &bh_active)) + t = &bh_task_vec[TIMER_BH]; + if (test_bit(TASKLET_STATE_SCHED, &t->state)) offset = 1000000; return offset + count; } diff -u --recursive --new-file v2.3.44/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.3.44/linux/arch/sparc/mm/srmmu.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/mm/srmmu.c Sun Feb 13 18:20:21 2000 @@ -1366,7 +1366,7 @@ if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) { struct vm_area_struct *vmaring; struct file *file; - struct inode *inode; + struct address_space *mapping; unsigned long flags, offset, vaddr, start; int alias_found = 0; pgd_t *pgdp; @@ -1378,10 +1378,10 @@ file = vma->vm_file; if (!file) goto done; - inode = file->f_dentry->d_inode; + mapping = file->f_dentry->d_inode->i_mapping; offset = (address & PAGE_MASK) - vma->vm_start; - spin_lock(&inode->i_shared_lock); - vmaring = inode->i_mmap; + spin_lock(&mapping->i_shared_lock); + vmaring = mapping->i_mmap; do { /* Do not mistake ourselves as another mapping. */ if(vmaring == vma) @@ -1414,7 +1414,7 @@ } } } while ((vmaring = vmaring->vm_next_share) != NULL); - spin_unlock(&inode->i_shared_lock); + spin_unlock(&mapping->i_shared_lock); if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) { pgdp = srmmu_pgd_offset(vma->vm_mm, address); diff -u --recursive --new-file v2.3.44/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.44/linux/arch/sparc/mm/sun4c.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/mm/sun4c.c Sun Feb 13 18:20:21 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.187 2000/02/08 07:46:01 davem Exp $ +/* $Id: sun4c.c,v 1.188 2000/02/12 03:07:35 zaitcev Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -591,7 +591,7 @@ return (pte << PAGE_SHIFT) + PAGE_OFFSET; } -static unsigned long sun4c_unmap_dma_area(unsigned long busa, int len) +static void sun4c_unmap_dma_area(unsigned long busa, int len) { /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ /* XXX Implement this */ @@ -2418,11 +2418,12 @@ if(dentry) inode = dentry->d_inode; if(inode) { + struct address_space *mapping = inode->i_mapping; unsigned long offset = (address & PAGE_MASK) - vma->vm_start; struct vm_area_struct *vmaring; int alias_found = 0; - spin_lock(&inode->i_shared_lock); - vmaring = inode->i_mmap; + spin_lock(&mapping->i_shared_lock); + vmaring = mapping->i_mmap; do { unsigned long vaddr = vmaring->vm_start + offset; unsigned long start; @@ -2453,7 +2454,7 @@ } } } while ((vmaring = vmaring->vm_next_share) != NULL); - spin_unlock(&inode->i_shared_lock); + spin_unlock(&mapping->i_shared_lock); if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) { pgdp = sun4c_pgd_offset(vma->vm_mm, address); diff -u --recursive --new-file v2.3.44/linux/arch/sparc/mm/swift.S linux/arch/sparc/mm/swift.S --- v2.3.44/linux/arch/sparc/mm/swift.S Wed Dec 29 13:13:13 1999 +++ linux/arch/sparc/mm/swift.S Sun Feb 13 10:18:03 2000 @@ -1,4 +1,4 @@ -/* $Id: swift.S,v 1.3 1999/11/14 06:13:56 zaitcev Exp $ +/* $Id: swift.S,v 1.4 2000/02/12 03:08:47 zaitcev Exp $ * swift.S: MicroSparc-II mmu/cache operations. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -41,10 +41,10 @@ swift_flush_page_to_ram: sethi %hi(0x2000), %o0 1: subcc %o0, 0x10, %o0 - sta %g0, [%o0] ASI_M_TXTC_TAG + add %o0, %o0, %o1 sta %g0, [%o0] ASI_M_DATAC_TAG bne 1b - nop + sta %g0, [%o1] ASI_M_TXTC_TAG retl nop #else diff -u --recursive --new-file v2.3.44/linux/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c --- v2.3.44/linux/drivers/acorn/char/keyb_ps2.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/acorn/char/keyb_ps2.c Sun Feb 13 10:45:13 2000 @@ -28,6 +28,7 @@ #include #include +extern struct tasklet_struct keyboard_tasklet; extern void kbd_reset_kdown(void); int kbd_read_mask; @@ -318,7 +319,7 @@ while (inb(IOMD_KCTRL) & (1 << 5)) handle_rawcode(inb(IOMD_KARTRX)); - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); } static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs) diff -u --recursive --new-file v2.3.44/linux/drivers/block/cs5530.c linux/drivers/block/cs5530.c --- v2.3.44/linux/drivers/block/cs5530.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/block/cs5530.c Sun Feb 13 18:21:45 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cs5530.c Version 0.2 Jan 30, 2000 + * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 * * Copyright (C) 2000 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -285,8 +285,6 @@ } outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ - if (!strcmp(drive->name, "hdc")) /* FIXME */ - return 0; /* * Finally, turn DMA on in software, and exit. */ diff -u --recursive --new-file v2.3.44/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.3.44/linux/drivers/block/loop.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/block/loop.c Sun Feb 13 10:33:23 2000 @@ -40,10 +40,10 @@ * it passes the underlying device's block number instead of the * offset. This makes it change for a given block when the file is * moved/restored/copied and also doesn't work over NFS. - * AV, Feb 11, 2000: for files we pass the page index now. It should fix the - * problem above. Since the granularity is PAGE_CACHE_SIZE now it seems to - * be correct way. OTOH, taking the thing from x86 to Alpha may become - * interesting, so we might want to rethink it. + * AV, Feb 12, 2000: we pass the logical block number now. It fixes the + * problem above. Encryption modules that used to rely on the old scheme + * should just call ->i_mapping->bmap() to calculate the physical block + * number. */ #include @@ -164,7 +164,8 @@ loop_sizes[lo->lo_number] = size; } -static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos) +static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos, + int blksize) { struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping; @@ -177,6 +178,7 @@ index = pos >> PAGE_CACHE_SHIFT; offset = pos & (PAGE_CACHE_SIZE - 1); while (len > 0) { + int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize; size = PAGE_CACHE_SIZE - offset; if (size > len) size = len; @@ -187,7 +189,7 @@ if (aops->prepare_write(page, offset, offset+size)) goto unlock; kaddr = (char*)page_address(page); - if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, index)) + if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV)) goto write_fail; if (aops->commit_write(file, page, offset, offset+size)) goto unlock; @@ -217,6 +219,7 @@ struct lo_read_data { struct loop_device *lo; char *data; + int blksize; }; static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) @@ -225,12 +228,13 @@ unsigned long count = desc->count; struct lo_read_data *p = (struct lo_read_data*)desc->buf; struct loop_device *lo = p->lo; + int IV = page->index * (PAGE_CACHE_SIZE/p->blksize) + offset/p->blksize; if (size > count) size = count; kaddr = (char*)kmap(page); - if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,page->index)) { + if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) { size = 0; printk(KERN_ERR "loop: transfer error block %ld\n",page->index); desc->error = -EINVAL; @@ -243,7 +247,8 @@ return size; } -static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos) +static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos, + int blksize) { struct file *file = lo->lo_backing_file; struct lo_read_data cookie; @@ -251,6 +256,7 @@ cookie.lo = lo; cookie.data = data; + cookie.blksize = blksize; desc.written = 0; desc.count = len; desc.buf = (char*)&cookie; @@ -287,8 +293,6 @@ dest_addr = current_request->buffer; len = current_request->current_nr_sectors << 9; - if (lo->lo_flags & LO_FLAGS_DO_BMAP) - goto file_backed; blksize = BLOCK_SIZE; if (blksize_size[MAJOR(lo->lo_device)]) { @@ -296,6 +300,10 @@ if (!blksize) blksize = BLOCK_SIZE; } + + if (lo->lo_flags & LO_FLAGS_DO_BMAP) + goto file_backed; + if (blksize < 512) { block = current_request->sector * (512/blksize); offset = 0; @@ -357,10 +365,10 @@ pos = ((loff_t)current_request->sector << 9) + lo->lo_offset; spin_unlock_irq(&io_request_lock); if (current_request->cmd == WRITE) { - if (lo_send(lo, dest_addr, len, pos)) + if (lo_send(lo, dest_addr, len, pos, blksize)) goto error_out_lock; } else { - if (lo_receive(lo, dest_addr, len, pos)) + if (lo_receive(lo, dest_addr, len, pos, blksize)) goto error_out_lock; } done: @@ -416,6 +424,7 @@ a file structure */ lo->lo_backing_file = NULL; } else if (S_ISREG(inode->i_mode)) { + struct address_space_operations *aops; /* Backed by a regular file - we need to hold onto a file structure for this file. Friggin' NFS can't live without it on write and for reading we use do_generic_file_read(), @@ -444,16 +453,23 @@ lo->lo_backing_file = NULL; } } + aops = lo->lo_dentry->d_inode->i_mapping->a_ops; + /* + * If we can't read - sorry. If we only can't write - well, + * it's going to be read-only. + */ + if (!aops->readpage) + error = -EINVAL; + else if (!aops->prepare_write || !aops->commit_write) + lo->lo_flags |= LO_FLAGS_READ_ONLY; } if (error) goto out_putf; - if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) { + if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) lo->lo_flags |= LO_FLAGS_READ_ONLY; - set_device_ro(dev, 1); - } else { - set_device_ro(dev, 0); - } + + set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0); lo->lo_dentry = dget(file->f_dentry); lo->transfer = NULL; diff -u --recursive --new-file v2.3.44/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.44/linux/drivers/char/Makefile Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/Makefile Sun Feb 13 11:21:42 2000 @@ -45,8 +45,12 @@ SERIAL =serial.o ifeq ($(ARCH),m68k) - KEYBD = - SERIAL = + ifdef CONFIG_AMIGA + KEYBD = amikeyb.o + else + KEYBD = + endif + SERIAL = endif ifeq ($(ARCH),arm) @@ -60,6 +64,7 @@ SERIAL = endif + obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) obj-$(CONFIG_SERIAL_21285) += serial_21285.o @@ -96,6 +101,7 @@ obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o +obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o ifeq ($(CONFIG_SX),y) obj-y += sx.o generic_serial.o diff -u --recursive --new-file v2.3.44/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c --- v2.3.44/linux/drivers/char/amikeyb.c Mon Aug 9 12:32:28 1999 +++ linux/drivers/char/amikeyb.c Sun Feb 13 11:21:42 2000 @@ -17,13 +17,14 @@ #include #include #include +#include +#include #include #include -#include #include #include #include -#include +#include #include #include @@ -230,7 +231,7 @@ /* switch CIA serial port to input mode */ ciaa.cra &= ~0x40; - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); /* rotate scan code to get up/down bit in proper position */ scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80); diff -u --recursive --new-file v2.3.44/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c --- v2.3.44/linux/drivers/char/amiserial.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/amiserial.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,2264 @@ +/* + * linux/drivers/char/amiserial.c + * + * Serial driver for the amiga builtin port. + * + * This code was created by taking serial.c version 4.30 from kernel + * release 2.3.22, replacing all hardware related stuff with the + * corresponding amiga hardware actions, and removing all irrelevant + * code. As a consequence, it uses many of the constants and names + * associated with the registers and bits of 16550 compatible UARTS - + * but only to keep track of status, etc in the state variables. It + * was done this was to make it easier to keep the code in line with + * (non hardware specific) changes to serial.c. + * + * The port is registered with the tty driver as minor device 64, and + * therefore other ports should should only use 65 upwards. + * + * Richard Lucock 28/12/99 + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, + * 1998, 1999 Theodore Ts'o + * + */ + +/* + * Serial driver configuration section. Here are the various options: + * + * SERIAL_PARANOIA_CHECK + * Check the magic number for the async_structure where + * ever possible. + */ + +#include +#include + +#undef SERIAL_PARANOIA_CHECK +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + +/* Sanity checks */ + +#define SERIAL_INLINE + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +/* + * End of serial driver configuration section. + */ + +#ifdef MODVERSIONS +#include +#endif +#include + +#include +#include +#include +#include +static char *serial_version = "4.30"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_AMIGA +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#endif + +static char *serial_name = "Amiga-builtin serial driver"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +static struct async_struct *IRQ_ports; + +static unsigned char current_ctl_bits; + +static void change_speed(struct async_struct *info, struct termios *old); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + + +static struct serial_state rs_table[1]; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +#include + +#define serial_isroot() (capable(CAP_SYS_ADMIN)) + + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* some serial hardware definitions */ +#define SDR_OVRUN (1<<15) +#define SDR_RBF (1<<14) +#define SDR_TBE (1<<13) +#define SDR_TSRE (1<<12) + +#define SERPER_PARENB (1<<15) + +#define AC_SETCLR (1<<15) +#define AC_UARTBRK (1<<11) + +#define SER_DTR (1<<7) +#define SER_RTS (1<<6) +#define SER_DCD (1<<5) +#define SER_CTS (1<<4) +#define SER_DSR (1<<3) + +static __inline__ void rtsdtr_ctrl(int bits) +{ + ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR)); +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + /* disable Tx interrupt and remove any pending interrupts */ + custom.intena = IF_TBE; + mb(); + custom.intreq = IF_TBE; + mb(); + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + custom.intena = IF_SETCLR | IF_TBE; + mb(); + /* set a pending Tx Interrupt, transmitter should restart now */ + custom.intreq = IF_SETCLR | IF_TBE; + mb(); + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info) +{ + int status; + int serdatr; + struct tty_struct *tty = info->tty; + unsigned char ch; + struct async_icount *icount; + + icount = &info->state->icount; + + status = UART_LSR_DR; /* We obviously have a character! */ + serdatr = custom.serdatr; + mb(); + custom.intreq = IF_RBF; + mb(); + + if((serdatr & 0x1ff) == 0) + status |= UART_LSR_BI; + if(serdatr & SDR_OVRUN) + status |= UART_LSR_OE; + + ch = serdatr & 0xff; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, status); +#endif + *tty->flip.flag_buf_ptr = 0; + + /* + * We don't handle parity or frame errors - but I have left + * the code in, since I'm not sure that the errors can't be + * detected. + */ + + if (status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE)) { + /* + * For statistics only + */ + if (status & UART_LSR_BI) { + status &= ~(UART_LSR_FE | UART_LSR_PE); + icount->brk++; + } else if (status & UART_LSR_PE) + icount->parity++; + else if (status & UART_LSR_FE) + icount->frame++; + if (status & UART_LSR_OE) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (status & info->ignore_status_mask) + goto ignore_char; + + status &= info->read_status_mask; + + if (status & (UART_LSR_BI)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (status & UART_LSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & UART_LSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (status & UART_LSR_OE) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + + tty_flip_buffer_push(tty); +} + +static _INLINE_ void transmit_chars(struct async_struct *info) +{ + custom.intreq = IF_TBE; + mb(); + if (info->x_char) { + custom.serdat = info->x_char | 0x100; + mb(); + info->state->icount.tx++; + info->x_char = 0; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; + custom.intena = IF_TBE; + mb(); + return; + } + + custom.serdat = info->xmit_buf[info->xmit_tail++] | 0x100; + mb(); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + --info->xmit_cnt; + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (info->xmit_cnt <= 0) { + custom.intena = IF_TBE; + mb(); + info->IER &= ~UART_IER_THRI; + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); + unsigned char dstatus; + struct async_icount *icount; + + /* Determine bits that have changed */ + dstatus = status ^ current_ctl_bits; + current_ctl_bits = status; + + if (dstatus) { + icount = &info->state->icount; + /* update input line counters */ + if (dstatus & SER_DSR) + icount->dsr++; + if (dstatus & SER_DCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + !(status & SER_DCD)) + hardpps(); +#endif + } + if (dstatus & SER_CTS) + icount->cts++; + wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttyS%02d CD now %s...", info->line, + (!(status & SER_DCD)) ? "on" : "off"); +#endif + if (!(status & SER_DCD)) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("doing serial hangup..."); +#endif + if (info->tty) + tty_hangup(info->tty); + } + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (!(status & SER_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + custom.intena = IF_SETCLR | IF_TBE; + mb(); + /* set a pending Tx Interrupt, transmitter should restart now */ + custom.intreq = IF_SETCLR | IF_TBE; + mb(); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if ((status & SER_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + /* disable Tx interrupt and remove any pending interrupts */ + custom.intena = IF_TBE; + mb(); + custom.intreq = IF_TBE; + mb(); + } + } + } +} + +static void ser_vbl_int( int irq, void *data, struct pt_regs *regs) +{ + /* vbl is just a periodic interrupt we tie into to update modem status */ + struct async_struct * info = IRQ_ports; + /* + * TBD - is it better to unregister from this interrupt or to + * ignore it if MSI is clear ? + */ + if(info->IER & UART_IER_MSI) + check_modem_status(info); +} + +static void ser_rx_int(int irq, void *dev_id, struct pt_regs * regs) +{ + struct async_struct * info; + +#ifdef SERIAL_DEBUG_INTR + printk("ser_rx_int..."); +#endif + + info = IRQ_ports; + if (!info || !info->tty) + return; + + receive_chars(info); + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +static void ser_tx_int(int irq, void *dev_id, struct pt_regs * regs) +{ + struct async_struct * info; + + if (custom.serdatr & SDR_TBE) { +#ifdef SERIAL_DEBUG_INTR + printk("ser_tx_int..."); +#endif + + info = IRQ_ports; + if (!info || !info->tty) + return; + + transmit_chars(info); + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif + } +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d ...", info->line); +#endif + + /* Clear anything in the input buffer */ + + custom.intreq = IF_RBF; + mb(); + + retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); + if (retval) { + if (serial_isroot()) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + + /* enable both Rx and Tx interrupts */ + custom.intena = IF_SETCLR | IF_RBF | IF_TBE; + mb(); + info->IER = UART_IER_MSI; + + /* remember current state of the DCD and CTS bits */ + current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); + + IRQ_ports = info; + + info->MCR = 0; + if (info->tty->termios->c_cflag & CBAUD) + info->MCR = SER_DTR | SER_RTS; + rtsdtr_ctrl(info->MCR); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d ....\n", info->line); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + IRQ_ports = NULL; + + /* + * Free the IRQ, if necessary + */ + free_irq(IRQ_AMIGA_VERTB, info); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + info->IER = 0; + custom.intena = IF_RBF | IF_TBE; + mb(); + + /* disable break condition */ + custom.adkcon = AC_UARTBRK; + mb(); + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + info->MCR &= ~(SER_DTR|SER_RTS); + rtsdtr_ctrl(info->MCR); + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval = 0; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + + /* Byte size is always 8 bits plus parity bit if requested */ + + cval = 3; bits = 10; + if (cflag & CSTOPB) { + cval |= 0x04; + bits++; + } + if (cflag & PARENB) { + cval |= UART_LCR_PARITY; + bits++; + } + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + baud_base = info->state->baud_base; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = baud_base / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + if (info->flags & ASYNC_HARDPPS_CD) + info->IER |= UART_IER_MSI; + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + /* TBD: + * Does clearing IER_MSI imply that we should disbale the VBL interrupt ? + */ + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = UART_LSR_OE | UART_LSR_DR; + if (I_INPCK(info->tty)) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_OE; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= UART_LSR_DR; + save_flags(flags); cli(); + + { + short serper; + + /* Set up the baud rate */ + serper = quot - 1; + + /* Enable or disable parity bit */ + + if(cval & UART_LCR_PARITY) + serper |= (SERPER_PARENB); + + custom.serper = serper; + mb(); + } + + info->LCR = cval; /* Save LCR */ + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + custom.intena = IF_SETCLR | IF_TBE; + mb(); + /* set a pending Tx Interrupt, transmitter should restart now */ + custom.intreq = IF_SETCLR | IF_TBE; + mb(); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + } + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + cli(); + custom.intena = IF_SETCLR | IF_TBE; + mb(); + /* set a pending Tx Interrupt, transmitter should restart now */ + custom.intreq = IF_SETCLR | IF_TBE; + mb(); + restore_flags(flags); + } + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + + /* Check this ! */ + save_flags(flags); + cli(); + if(!(custom.intenar & IF_TBE)) { + custom.intena = IF_SETCLR | IF_TBE; + mb(); + /* set a pending Tx Interrupt, transmitter should restart now */ + custom.intreq = IF_SETCLR | IF_TBE; + mb(); + } + restore_flags(flags); + + info->IER |= UART_IER_THRI; + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~SER_RTS; + + save_flags(flags); cli(); + rtsdtr_ctrl(info->MCR); + restore_flags(flags); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) + info->MCR |= SER_RTS; + save_flags(flags); cli(); + rtsdtr_ctrl(info->MCR); + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct serial_state *state = info->state; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = state->type; + tmp.line = state->line; + tmp.port = state->port; + tmp.irq = state->irq; + tmp.flags = state->flags; + tmp.xmit_fifo_size = state->xmit_fifo_size; + tmp.baud_base = state->baud_base; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct serial_state old_state, *state; + unsigned int change_irq,change_port; + int retval = 0; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + state = info->state; + old_state = *state; + + change_irq = new_serial.irq != state->irq; + change_port = (new_serial.port != state->port); + if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) + return -EINVAL; + + if (!serial_isroot()) { + if ((new_serial.baud_base != state->baud_base) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != state->xmit_fifo_size) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (new_serial.baud_base < 9600) + return -EINVAL; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + state->baud_base = new_serial.baud_base; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ/100; + state->closing_wait = new_serial.closing_wait * HZ/100; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + +check_and_exit: + if (info->flags & ASYNC_INITIALIZED) { + if (((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK)) || + (old_state.custom_divisor != state->custom_divisor)) { + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + change_speed(info, 0); + } + } else + retval = startup(info); + return retval; +} + + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + status = custom.serdatr; + mb(); + restore_flags(flags); + result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + unsigned long flags; + + control = info->MCR; + save_flags(flags); cli(); + status = ciab.pra; + restore_flags(flags); + result = ((control & SER_RTS) ? TIOCM_RTS : 0) + | ((control & SER_DTR) ? TIOCM_DTR : 0) + | (!(status & SER_DCD) ? TIOCM_CAR : 0) + | (!(status & SER_DSR) ? TIOCM_DSR : 0) + | (!(status & SER_CTS) ? TIOCM_CTS : 0); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + unsigned long flags; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->MCR |= SER_RTS; + if (arg & TIOCM_DTR) + info->MCR |= SER_DTR; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->MCR &= ~SER_RTS; + if (arg & TIOCM_DTR) + info->MCR &= ~SER_DTR; + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(SER_RTS | SER_DTR)) + | ((arg & TIOCM_RTS) ? SER_RTS : 0) + | ((arg & TIOCM_DTR) ? SER_DTR : 0)); + break; + default: + return -EINVAL; + } + save_flags(flags); cli(); + rtsdtr_ctrl(info->MCR); + restore_flags(flags); + return 0; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + save_flags(flags); cli(); + if (break_state == -1) + custom.adkcon = AC_SETCLR | AC_UARTBRK; + else + custom.adkcon = AC_UARTBRK; + mb(); + restore_flags(flags); +} + + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct icount; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERCONFIG: + return 0; + + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); cli(); + /* note the counters on entry */ + cprev = info->state->icount; + restore_flags(flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->state->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); cli(); + cnow = info->state->icount; + restore_flags(flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + info->MCR &= ~(SER_DTR|SER_RTS); + save_flags(flags); cli(); + rtsdtr_ctrl(info->MCR); + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + info->MCR |= SER_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->MCR |= SER_RTS; + } + save_flags(flags); cli(); + rtsdtr_ctrl(info->MCR); + restore_flags(flags); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~UART_LSR_DR; + if (info->flags & ASYNC_INITIALIZED) { + /* disable receive interrupts */ + custom.intena = IF_RBF; + mb(); + /* clear any pending receive interrupt */ + custom.intreq = IF_RBF; + mb(); + + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while(!((lsr = custom.serdatr) & SDR_TSRE)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("serdatr = %d (jiff=%lu)...", lsr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ +#ifdef DECLARE_WAITQUEUE + DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue wait = { current, NULL }; +#endif + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + rtsdtr_ctrl(SER_DTR|SER_RTS); + restore_flags(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (!(ciab.pra & SER_DCD)) )) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); +#ifdef DECLARE_WAITQUEUE + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); +#endif + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree_s(info, sizeof(struct async_struct)); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + tty->driver_data = info; + info->tty = tty; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:amiga_builtin",state->line); + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + save_flags(flags); cli(); + status = ciab.pra; + control = info ? info->MCR : status; + restore_flags(flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if(!(control & SER_RTS)) + strcat(stat_buf, "|RTS"); + if(!(status & SER_CTS)) + strcat(stat_buf, "|CTS"); + if(!(control & SER_DTR)) + strcat(stat_buf, "|DTR"); + if(!(status & SER_DSR)) + strcat(stat_buf, "|DSR"); + if(!(status & SER_DCD)) + strcat(stat_buf, "|CD"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + l = line_info(page + len, &rs_table[0]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); +} + + +int register_serial(struct serial_struct *req); +void unregister_serial(int line); + + +/* + * The serial driver boot-time initialization code! + */ +int __init rs_init(void) +{ + unsigned long flags; + struct serial_state * state; + + if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL)) + return -ENODEV; + + init_bh(SERIAL_BH, do_serial_bh); + + IRQ_ports = NULL; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "amiserial"; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = 1; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + serial_driver.break_ctl = rs_break; + serial_driver.send_xchar = rs_send_xchar; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + state = rs_table; + state->magic = SSTATE_MAGIC; + state->port = (int)&custom.serdatr; /* Just to give it a value */ + state->line = 0; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + /* + if(state->port && check_region(state->port,REGION_LENGTH(state))) + continue; + */ + + printk(KERN_INFO "ttyS%02d is the amiga builtin serial port\n", + state->line); + + /* Hardware set up */ + + state->baud_base = amiga_colorclock; + state->xmit_fifo_size = 1; + + save_flags (flags); + cli(); + + /* set ISRs, and then disable the rx interrupts */ + request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); + request_irq(IRQ_AMIGA_RBF, ser_rx_int, SA_INTERRUPT, "serial RX", state); + + /* turn off Rx and Tx interrupts */ + custom.intena = IF_RBF | IF_TBE; + mb(); + + /* clear any pending interrupt */ + custom.intreq = IF_RBF | IF_TBE; + mb(); + + restore_flags (flags); + + /* + * set the appropriate directions for the modem control flags, + * and clear RTS and DTR + */ + ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ + ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ + + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return rs_init(); +} + +void cleanup_module(void) +{ + unsigned long flags; + int e1, e2; + struct async_struct *info; + + /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ + save_flags(flags); + cli(); + remove_bh(SERIAL_BH); + if ((e1 = tty_unregister_driver(&serial_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + info = rs_table[0].info; + if (info) { + rs_table[0].info = NULL; + kfree_s(info, sizeof(struct async_struct)); + } + + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } +} +#endif /* MODULE */ + +/* + Local variables: + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + End: +*/ diff -u --recursive --new-file v2.3.44/linux/drivers/char/mac_SCC.c linux/drivers/char/mac_SCC.c --- v2.3.44/linux/drivers/char/mac_SCC.c Fri Dec 18 09:36:05 1998 +++ linux/drivers/char/mac_SCC.c Wed Dec 31 16:00:00 1969 @@ -1,1529 +0,0 @@ -/* - * mac_SCC.c: m68k version of - * - * macserial.c: Serial port driver for Power Macintoshes. - * Extended for the 68K mac by Alan Cox. - * Rewritten to m68k serial design by Michael Schmitz - * - * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras. - * - * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -/* - * Design note for the m68k rewrite: - * The structure of the m68k serial code requires separation of the low-level - * functions that talk directly to the hardware from the Linux serial driver - * code interfacing to the tty layer. The reason for this separation is simply - * the fact that the m68k serial hardware is, unlike the i386, based on a - * variety of chips, and the rs_* serial routines need to be shared. - * - * I've tried to make consistent use of the async_struct info populated in the - * midlevel code, and introduced an async_private struct to hold the Macintosh - * SCC internals (this was added to the async_struct for the PowerMac driver). - * Exception: the console and kgdb hooks still use the zs_soft[] data, and this - * is still filled in by the probe_sccs() routine, which provides some data - * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so - * the console/kgdb stuff probably won't work before proper serial init, and - * I have to rely on keeping info and zs_soft consistent at least for the - * console/kgdb port. - * - * Update (16-11-97): The SCC interrupt handling was suffering from the problem - * that the autovector SCC interrupt was registered only once, hence only one - * async_struct was passed to the interrupt function and only interrupts from - * the corresponding channel could be handled (yes, major design flaw). - * The autovector interrupt is now registered by the main interrupt initfunc, - * and uses a handler that will call the registered SCC specific interrupts in - * turn. The SCC init has to register these as machspec interrupts now, as is - * done for the VIA interrupts elsewhere. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifndef CONFIG_MAC -#include -#endif -#include -#include -#include -#include - -#include "mac_SCC.h" - -/* - * It would be nice to dynamically allocate everything that - * depends on NUM_SERIAL, so we could support any number of - * Z8530s, but for now... - */ -#define NUM_SERIAL 2 /* Max number of ZS chips supported */ -#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */ - -#ifdef CONFIG_MAC -/* - * All the Macintosh 68K boxes that have an MMU also have hardware - * recovery delays. - */ -#define RECOVERY_DELAY -#else -/* On PowerMacs, the hardware takes care of the SCC recovery time, - but we need the eieio to make sure that the accesses occur - in the order we want. */ -#define RECOVERY_DELAY eieio() -#endif - -struct mac_zschannel *zs_kgdbchan; -struct mac_zschannel zs_channels[NUM_CHANNELS]; - -struct m68k_async_struct zs_soft[NUM_CHANNELS]; -struct m68k_async_private zs_soft_private[NUM_CHANNELS]; -int zs_channels_found; -struct m68k_async_struct *zs_chain; /* list of all channels */ - -struct tty_struct zs_ttys[NUM_CHANNELS]; -/** struct tty_struct *zs_constty; **/ - -/* Console hooks... */ -static int zs_cons_chanout = 0; -static int zs_cons_chanin = 0; -struct m68k_async_struct *zs_consinfo = 0; -struct mac_zschannel *zs_conschan; - -static unsigned char kgdb_regs[16] = { - 0, 0, 0, /* write 0, 1, 2 */ - (Rx8 | RxENABLE), /* write 3 */ - (X16CLK | SB1 | PAR_EVEN), /* write 4 */ - (Tx8 | TxENAB), /* write 5 */ - 0, 0, 0, /* write 6, 7, 8 */ - (NV), /* write 9 */ - (NRZ), /* write 10 */ - (TCBR | RCBR), /* write 11 */ - 1, 0, /* 38400 baud divisor, write 12 + 13 */ - (BRENABL), /* write 14 */ - (DCDIE) /* write 15 */ -}; - -#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */ - -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( - */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW - -#define RS_STROBE_TIME 10 -#define RS_ISR_PASS_LIMIT 256 - -#define _INLINE_ inline - -static void probe_sccs(void); - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - - -/***************************** Prototypes *****************************/ - -static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ); -#if 0 -#ifdef MODULE -static void SCC_deinit_port( struct m68k_async_struct *info, int channel ); -#endif -#endif - -/* FIXME !!! Currently, only autovector interrupt used! */ -#if 0 -static void SCC_rx_int (int irq, void *data, struct pt_regs *fp); -static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp); -static void SCC_tx_int (int irq, void *data, struct pt_regs *fp); -static void SCC_stat_int (int irq, void *data, struct pt_regs *fp); -static void SCC_ri_int (int irq, void *data, struct pt_regs *fp); -#endif - -static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct - *tty, struct file *file ); -static void SCC_init( struct m68k_async_struct *info ); -static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr ); -static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag ); -static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base, - int divisor ); -static void SCC_change_speed( struct m68k_async_struct *info ); -#if 0 -static int SCC_clocksrc( unsigned baud_base, unsigned channel ); -#endif -static void SCC_throttle( struct m68k_async_struct *info, int status ); -static void SCC_set_break( struct m68k_async_struct *info, int break_flag ); -static void SCC_get_serial_info( struct m68k_async_struct *info, struct - serial_struct *retinfo ); -static unsigned int SCC_get_modem_info( struct m68k_async_struct *info ); -static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int - new_rts ); -static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct - m68k_async_struct *info, unsigned int cmd, unsigned long arg ); -static void SCC_stop_receive (struct m68k_async_struct *info); -static int SCC_trans_empty (struct m68k_async_struct *info); - -/************************* End of Prototypes **************************/ - - -static SERIALSWITCH SCC_switch = { - SCC_init, SCC_deinit, SCC_enab_tx_int, - SCC_check_custom_divisor, SCC_change_speed, - SCC_throttle, SCC_set_break, - SCC_get_serial_info, SCC_get_modem_info, - SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty, - SCC_check_open -}; - -/* - * This is used to figure out the divisor speeds and the timeouts - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 0 }; - -/* - * Reading and writing Z8530 registers. - */ -static inline unsigned char read_zsreg(struct mac_zschannel *channel, - unsigned char reg) -{ - unsigned char retval; - - if (reg != 0) { - *channel->control = reg; - RECOVERY_DELAY; - } - retval = *channel->control; - RECOVERY_DELAY; - return retval; -} - -static inline void write_zsreg(struct mac_zschannel *channel, - unsigned char reg, unsigned char value) -{ - if (reg != 0) { - *channel->control = reg; - RECOVERY_DELAY; - } - *channel->control = value; - RECOVERY_DELAY; - return; -} - -static inline unsigned char read_zsdata(struct mac_zschannel *channel) -{ - unsigned char retval; - - retval = *channel->data; - RECOVERY_DELAY; - return retval; -} - -static inline void write_zsdata(struct mac_zschannel *channel, - unsigned char value) -{ - *channel->data = value; - RECOVERY_DELAY; - return; -} - -static inline void load_zsregs(struct mac_zschannel *channel, - unsigned char *regs) -{ - ZS_CLEARERR(channel); - ZS_CLEARFIFO(channel); - /* Load 'em up */ - write_zsreg(channel, R4, regs[R4]); - write_zsreg(channel, R10, regs[R10]); - write_zsreg(channel, R3, regs[R3] & ~RxENABLE); - write_zsreg(channel, R5, regs[R5] & ~TxENAB); - write_zsreg(channel, R1, regs[R1]); - write_zsreg(channel, R9, regs[R9]); - write_zsreg(channel, R11, regs[R11]); - write_zsreg(channel, R12, regs[R12]); - write_zsreg(channel, R13, regs[R13]); - write_zsreg(channel, R14, regs[R14]); - write_zsreg(channel, R15, regs[R15]); - write_zsreg(channel, R3, regs[R3]); - write_zsreg(channel, R5, regs[R5]); - return; -} - -/* Sets or clears DTR/RTS on the requested line */ -static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set) -{ - if (set) - ss->private->curregs[5] |= (RTS | DTR); - else - ss->private->curregs[5] &= ~(RTS | DTR); - write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]); - return; -} - -static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps) -{ - int brg; - - if (intson) { - kgdb_regs[R1] = INT_ALL_Rx; - kgdb_regs[R9] |= MIE; - } else { - kgdb_regs[R1] = 0; - kgdb_regs[R9] &= ~MIE; - } - brg = BPS_TO_BRG(bps, ZS_CLOCK/16); - kgdb_regs[R12] = brg; - kgdb_regs[R13] = brg >> 8; - load_zsregs(ss->private->zs_channel, kgdb_regs); -} - -/* Utility routines for the Zilog */ -static inline int get_zsbaud(struct m68k_async_struct *ss) -{ - struct mac_zschannel *channel = ss->private->zs_channel; - int brg; - - /* The baud rate is split up between two 8-bit registers in - * what is termed 'BRG time constant' format in my docs for - * the chip, it is a function of the clk rate the chip is - * receiving which happens to be constant. - */ - brg = (read_zsreg(channel, 13) << 8); - brg |= read_zsreg(channel, 12); - return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor))); -} - -/* On receive, this clears errors and the receiver interrupts */ -static inline void SCC_recv_clear(struct mac_zschannel *zsc) -{ - write_zsreg(zsc, 0, ERR_RES); - write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */ -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -extern void breakpoint(void); /* For the KGDB frame character */ - -static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info, - struct pt_regs *regs) -{ - struct tty_struct *tty = info->tty; - unsigned char ch, stat, flag; - - while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) { - - stat = read_zsreg(info->private->zs_channel, R1); - ch = read_zsdata(info->private->zs_channel); - -#ifdef SCC_DEBUG - printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch); -#endif - -#if 0 /* KGDB not yet supported */ - /* Look for kgdb 'stop' character, consult the gdb documentation - * for remote target debugging and arch/sparc/kernel/sparc-stub.c - * to see how all this works. - */ - if ((info->kgdb_channel) && (ch =='\003')) { - breakpoint(); - continue; - } -#endif - - if (!tty) - continue; - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - tty_flip_buffer_push(tty); - - if (stat & Rx_OVR) { - flag = TTY_OVERRUN; - /* reset the error indication */ - write_zsreg(info->private->zs_channel, 0, ERR_RES); - } else if (stat & FRM_ERR) { - /* this error is not sticky */ - flag = TTY_FRAME; - } else if (stat & PAR_ERR) { - flag = TTY_PARITY; - /* reset the error indication */ - write_zsreg(info->private->zs_channel, 0, ERR_RES); - } else - flag = 0; - - if (tty->flip.buf_num - && tty->flip.count >= TTY_FLIPBUF_SIZE) { -#ifdef SCC_DEBUG_OVERRUN - printk("mac_SCC: flip buffer overrun!\n"); -#endif - return; - } - - if (!tty->flip.buf_num - && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) { - printk("mac_SCC: double flip buffer overrun!\n"); - return; - } - - tty->flip.count++; - *tty->flip.flag_buf_ptr++ = flag; - *tty->flip.char_buf_ptr++ = ch; - info->icount.rx++; - tty_flip_buffer_push(tty); - } -#if 0 -clear_and_exit: - SCC_recv_clear(info->private->zs_channel); -#endif -} - -/* that's SCC_enable_tx_int, basically */ - -static void transmit_chars(struct m68k_async_struct *info) -{ - if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0) - return; - info->private->tx_active = 0; - - if (info->x_char) { - /* Send next char */ - write_zsdata(info->private->zs_channel, info->x_char); - info->x_char = 0; - info->private->tx_active = 1; - return; - } - - if ((info->xmit_cnt <= 0) || info->tty->stopped - || info->private->tx_stopped) { - write_zsreg(info->private->zs_channel, 0, RES_Tx_P); - return; - } - - /* Send char */ - write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->icount.tx++; - info->xmit_cnt--; - info->private->tx_active = 1; - - if (info->xmit_cnt < WAKEUP_CHARS) - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); -} - -static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info) -{ - unsigned char status; - - /* Get status from Read Register 0 */ - status = read_zsreg(info->private->zs_channel, 0); - - /* Check for DCD transitions */ - if (((status ^ info->private->read_reg_zero) & DCD) != 0 - && info->tty && C_CLOCAL(info->tty)) { - if (status & DCD) { - wake_up_interruptible(&info->open_wait); - } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) { - if (info->tty) - tty_hangup(info->tty); - } - } - - /* Check for CTS transitions */ - if (info->tty && C_CRTSCTS(info->tty)) { - /* - * For some reason, on the Power Macintosh, - * it seems that the CTS bit is 1 when CTS is - * *negated* and 0 when it is asserted. - * The DCD bit doesn't seem to be inverted - * like this. - */ - if ((status & CTS) == 0) { - if (info->private->tx_stopped) { - info->private->tx_stopped = 0; - if (!info->private->tx_active) - transmit_chars(info); - } - } else { - info->private->tx_stopped = 1; - } - } - - /* Clear status condition... */ - write_zsreg(info->private->zs_channel, 0, RES_EXT_INT); - info->private->read_reg_zero = status; -} - -/* - * This is the serial driver's generic interrupt routine - */ -void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id; - unsigned char zs_intreg; - int shift; - - /* NOTE: The read register 3, which holds the irq status, - * does so for both channels on each chip. Although - * the status value itself must be read from the A - * channel and is only valid when read from channel A. - * Yes... broken hardware... - */ -#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) - -#ifdef SCC_DEBUG - printk("mac_SCC: interrupt; port: %lx channel: %lx \n", - info->port, info->private->zs_channel); -#endif - - if (info->private->zs_chan_a == info->private->zs_channel) - shift = 3; /* Channel A */ - else - shift = 0; /* Channel B */ - - for (;;) { - zs_intreg = read_zsreg(info->private->zs_chan_a, 3); -#ifdef SCC_DEBUG - printk("mac_SCC: status %x shift %d shifted %x \n", - zs_intreg, shift, zs_intreg >> shift); -#endif - zs_intreg = zs_intreg >> shift; - if ((zs_intreg & CHAN_IRQMASK) == 0) - break; - - if (zs_intreg & CHBRxIP) - receive_chars(info, regs); - if (zs_intreg & CHBTxIP) - transmit_chars(info); - if (zs_intreg & CHBEXT) - status_handle(info); - } -} - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * ------------------------------------------------------------ - */ - -static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag ) -{ - unsigned long flags; - - if (enab_flag) { -#if 0 - save_flags(flags); cli(); - if (info->private->curregs[5] & TxENAB) { - info->private->curregs[5] &= ~TxENAB; - info->private->pendregs[5] &= ~TxENAB; - write_zsreg(info->private->zs_channel, 5, - info->private->curregs[5]); - } - restore_flags(flags); -#endif - /* FIXME: should call transmit_chars here ??? */ - transmit_chars(info); - } else { - save_flags(flags); cli(); -#if 0 - if ( info->xmit_cnt && info->xmit_buf && - !(info->private->curregs[5] & TxENAB)) { - info->private->curregs[5] |= TxENAB; - info->private->pendregs[5] = info->private->curregs[5]; - write_zsreg(info->private->zs_channel, 5, - info->private->curregs[5]); - } -#else - if ( info->xmit_cnt && info->xmit_buf && - !info->private->tx_active) { - transmit_chars(info); - } -#endif - restore_flags(flags); - } - -} - -#if 0 -/* - * leftover from original driver ... - */ -static int SCC_startup(struct m68k_async_struct * info) -{ - unsigned long flags; - - save_flags(flags); cli(); - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (irq %d)...", info->line, info->irq); -#endif - - /* - * Clear the receive FIFO. - */ - ZS_CLEARFIFO(info->private->zs_channel); - info->xmit_fifo_size = 1; - - /* - * Clear the interrupt registers. - */ - write_zsreg(info->private->zs_channel, 0, ERR_RES); - write_zsreg(info->private->zs_channel, 0, RES_H_IUS); - - /* - * Turn on RTS and DTR. - */ - zs_rtsdtr(info, 1); - - /* - * Finally, enable sequencing and interrupts - */ - info->private->curregs[1] = (info->private->curregs[1] & ~0x18) - | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); - info->private->pendregs[1] = info->private->curregs[1]; - info->private->curregs[3] |= (RxENABLE | Rx8); - info->private->pendregs[3] = info->private->curregs[3]; - info->private->curregs[5] |= (TxENAB | Tx8); - info->private->pendregs[5] = info->private->curregs[5]; - info->private->curregs[9] |= (NV | MIE); - info->private->pendregs[9] = info->private->curregs[9]; - write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); - write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); - write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]); - - /* - * Set the speed of the serial port - */ - SCC_change_speed(info); - - /* Save the current value of RR0 */ - info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0); - - restore_flags(flags); - return 0; -} -#endif - -/* FIXME: are these required ?? */ -static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty, - struct file *file ) -{ - /* check on the basis of info->whatever ?? */ - if (info->private->kgdb_channel || info->private->is_cons) - return -EBUSY; - return( 0 ); -} - -static void SCC_init( struct m68k_async_struct *info ) -{ - /* FIXME: init currently done in probe_sccs() */ - - /* BUT: startup part needs to be done here! */ - -#ifdef SCC_DEBUG - printk("mac_SCC: init, info %lx, info->port %lx \n", info, info->port); -#endif - /* - * Clear the receive FIFO. - */ - ZS_CLEARFIFO(info->private->zs_channel); - info->xmit_fifo_size = 1; - - /* - * Clear the interrupt registers. - */ - write_zsreg(info->private->zs_channel, 0, ERR_RES); - write_zsreg(info->private->zs_channel, 0, RES_H_IUS); - - /* - * Turn on RTS and DTR. - */ - zs_rtsdtr(info, 1); - - /* - * Finally, enable sequencing and interrupts - */ - info->private->curregs[1] = (info->private->curregs[1] & ~0x18) - | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); - info->private->pendregs[1] = info->private->curregs[1]; - info->private->curregs[3] |= (RxENABLE | Rx8); - info->private->pendregs[3] = info->private->curregs[3]; - info->private->curregs[5] |= (TxENAB | Tx8); - info->private->pendregs[5] = info->private->curregs[5]; - info->private->curregs[9] |= (NV | MIE); - info->private->pendregs[9] = info->private->curregs[9]; - write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); - write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); - write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]); - - /* - * Set the speed of the serial port - done in startup() !! - */ -#if 0 - SCC_change_speed(info); -#endif - - /* Save the current value of RR0 */ - info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0); - -} - -static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ) -{ - static int got_autovector = 0; - -#ifdef SCC_DEBUG - printk("mac_SCC: init_port, info %x \n", info); -#endif - info->sw = &SCC_switch; - info->private = &zs_soft_private[channel]; - info->private->zs_channel = &zs_channels[channel]; - info->irq = IRQ4; - info->private->clk_divisor = 16; - info->private->zs_baud = get_zsbaud(info); - info->port = (int) info->private->zs_channel->control; - - /* - * MSch: Extended interrupt scheme: - * The generic m68k interrupt code can't use multiple handlers for - * the same interrupt source (no chained interrupts). - * We have to plug in a 'master' interrupt handler instead, calling - * mac_SCC_interrupt with the proper arguments ... - */ - - if (!got_autovector) { - if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info)) - panic("macserial: can't get irq %d", IRQ4); -#ifdef SCC_DEBUG - printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n", - IRQ4, channel, info); -#endif - got_autovector = 1; - } - - if (info->private->zs_chan_a == info->private->zs_channel) { - /* Channel A */ - if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info)) - panic("mac_SCC: can't get irq %d", IRQ_SCCA); -#ifdef SCC_DEBUG - printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n", - IRQ_SCCA, channel, info); -#endif - } else { - /* Channel B */ - if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info)) - panic("mac_SCC: can't get irq %d", IRQ_SCCB); -#ifdef SCC_DEBUG - printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n", - IRQ_SCCB, channel, info); -#endif - } - - /* If console serial line, then enable interrupts. */ - if (info->private->is_cons) { - printk("mac_SCC: console line %d; enabling interrupt!\n", info->line); - write_zsreg(info->private->zs_channel, R1, - (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB)); - write_zsreg(info->private->zs_channel, R9, (NV | MIE)); - write_zsreg(info->private->zs_channel, R10, (NRZ)); - write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE)); - write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB)); - } - /* If this is the kgdb line, enable interrupts because we - * now want to receive the 'control-c' character from the - * client attached to us asynchronously. - */ - if (info->private->kgdb_channel) { - printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line); - kgdb_chaninit(info, 1, info->private->zs_baud); - } - /* Report settings (in m68kserial.c) */ -#ifndef CONFIG_MAC - printk("ttyS%d at 0x%08x (irq = %d)", info->line, - info->port, info->irq); - printk(" is a Z8530 SCC\n"); -#endif - -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr) -{ - unsigned long flags; - - save_flags(flags); cli(); /* Disable interrupts */ - - info->private->pendregs[1] = info->private->curregs[1] = 0; - write_zsreg(info->private->zs_channel, 1, 0); /* no interrupts */ - - info->private->curregs[3] &= ~RxENABLE; - info->private->pendregs[3] = info->private->curregs[3]; - write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); - - info->private->curregs[5] &= ~TxENAB; - - if (!leave_dtr) - info->private->curregs[5] &= ~(DTR | RTS); - else - info->private->curregs[5] &= ~(RTS); - - info->private->pendregs[5] = info->private->curregs[5]; - write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); - - restore_flags(flags); -} - -/* FIXME !!! */ -static int SCC_check_custom_divisor( struct m68k_async_struct *info, - int baud_base, int divisor ) -{ - return 0; -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void SCC_change_speed(struct m68k_async_struct *info) -{ - unsigned short port; - unsigned cflag; - int i; - int brg; - unsigned long flags; - - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; - if (!(port = info->port)) - return; - i = cflag & CBAUD; - - if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) { - /* speed == 0 -> drop DTR */ - save_flags(flags); - cli(); - info->private->curregs[5] &= ~(DTR | RTS); - write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); - restore_flags(flags); - return; - } - - - if (i & CBAUDEX) { - /* XXX CBAUDEX is not obeyed. - * It is impossible at a 32bits PPC. XXX?? - * But we have to report this to user ... someday. - */ - i = B9600; - } - - save_flags(flags); cli(); - info->private->zs_baud = baud_table[i]; - info->private->clk_divisor = 16; - - info->private->curregs[4] = X16CLK; - info->private->curregs[11] = TCBR | RCBR; - brg = BPS_TO_BRG(info->private->zs_baud, - ZS_CLOCK/info->private->clk_divisor); - info->private->curregs[12] = (brg & 255); - info->private->curregs[13] = ((brg >> 8) & 255); - info->private->curregs[14] = BRENABL; - - /* byte size and parity */ - info->private->curregs[3] &= ~RxNBITS_MASK; - info->private->curregs[5] &= ~TxNBITS_MASK; - switch (cflag & CSIZE) { - case CS5: - info->private->curregs[3] |= Rx5; - info->private->curregs[5] |= Tx5; - break; - case CS6: - info->private->curregs[3] |= Rx6; - info->private->curregs[5] |= Tx6; - break; - case CS7: - info->private->curregs[3] |= Rx7; - info->private->curregs[5] |= Tx7; - break; - case CS8: - default: /* defaults to 8 bits */ - info->private->curregs[3] |= Rx8; - info->private->curregs[5] |= Tx8; - break; - } - info->private->pendregs[3] = info->private->curregs[3]; - info->private->pendregs[5] = info->private->curregs[5]; - - info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN); - if (cflag & CSTOPB) { - info->private->curregs[4] |= SB2; - } else { - info->private->curregs[4] |= SB1; - } - if (cflag & PARENB) { - info->private->curregs[4] |= PAR_ENA; - } - if (!(cflag & PARODD)) { - info->private->curregs[4] |= PAR_EVEN; - } - info->private->pendregs[4] = info->private->curregs[4]; - - info->private->curregs[15] &= ~(DCDIE | CTSIE); - if (!(cflag & CLOCAL)) { - info->private->curregs[15] |= DCDIE; - } - if (cflag & CRTSCTS) { - info->private->curregs[15] |= CTSIE; - if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0) - info->private->tx_stopped = 1; - } else - info->private->tx_stopped = 0; - info->private->pendregs[15] = info->private->curregs[15]; - - /* Load up the new values */ - load_zsregs(info->private->zs_channel, info->private->curregs); - - restore_flags(flags); -} - -/* This is for console output over ttya/ttyb */ -static void SCC_put_char(char ch) -{ - struct mac_zschannel *chan = zs_conschan; - int loops = 0; - unsigned long flags; - - if(!chan) - return; - - save_flags(flags); cli(); - while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) { - loops++; - udelay(5); - } - write_zsdata(chan, ch); - restore_flags(flags); -} - -/* These are for receiving and sending characters under the kgdb - * source level kernel debugger. - */ -void putDebugChar(char kgdb_char) -{ - struct mac_zschannel *chan = zs_kgdbchan; - - while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0) - udelay(5); - write_zsdata(chan, kgdb_char); -} - -char getDebugChar(void) -{ - struct mac_zschannel *chan = zs_kgdbchan; - - while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0) - udelay(5); - return read_zsdata(chan); -} - -/* - * Fair output driver allows a process to speak. - */ -static void SCC_fair_output(void) -{ - int left; /* Output no more than that */ - unsigned long flags; - struct m68k_async_struct *info = zs_consinfo; - char c; - - if (info == 0) return; - if (info->xmit_buf == 0) return; - - save_flags(flags); cli(); - left = info->xmit_cnt; - while (left != 0) { - c = info->xmit_buf[info->xmit_tail]; - info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt--; - restore_flags(flags); - - SCC_put_char(c); - - save_flags(flags); cli(); - left = MIN(info->xmit_cnt, left-1); - } - - restore_flags(flags); - return; -} - -/* - * zs_console_print is registered for printk. - */ -static void zs_console_print(const char *p) -{ - char c; - - while ((c = *(p++)) != 0) { - if (c == '\n') - SCC_put_char('\r'); - SCC_put_char(c); - } - - /* Comment this if you want to have a strict interrupt-driven output */ - SCC_fair_output(); -} - -/* FIXME: check with SCC_enab_tx_int!! */ -#if 0 -static void rs_flush_chars(struct tty_struct *tty) -{ - struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) - return; - - if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped || - !info->xmit_buf) - return; - - /* Enable transmitter */ - save_flags(flags); cli(); - transmit_chars(info); - restore_flags(flags); -} - -static int rs_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int c, total = 0; - struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_write")) - return 0; - - if (!tty || !info->xmit_buf) - return 0; - - save_flags(flags); - while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - if (from_user) { - down(&tmp_buf_sem); - memcpy_fromfs(tmp_buf, buf, c); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - up(&tmp_buf_sem); - } else - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; - } - if (info->xmit_cnt && !tty->stopped && !info->tx_stopped - && !info->tx_active) - transmit_chars(info); - restore_flags(flags); - return total; -} -#endif - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void SCC_throttle(struct m68k_async_struct *info, int status) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - if (status) { - /* - * Here we want to turn off the RTS line. On Macintoshes, - * we only get the DTR line, which goes to both DTR and - * RTS on the modem. RTS doesn't go out to the serial - * port socket. So you should make sure your modem is - * set to ignore DTR if you're using CRTSCTS. - */ - info->private->curregs[5] &= ~(DTR | RTS); - info->private->pendregs[5] &= ~(DTR | RTS); - write_zsreg(info->private->zs_channel, 5, - info->private->curregs[5]); - } else { - /* Assert RTS and DTR lines */ - info->private->curregs[5] |= DTR | RTS; - info->private->pendregs[5] |= DTR | RTS; - write_zsreg(info->private->zs_channel, 5, - info->private->curregs[5]); - } - - restore_flags(flags); - -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static void SCC_get_serial_info(struct m68k_async_struct * info, - struct serial_struct * retinfo) -{ - retinfo->baud_base = info->baud_base; - retinfo->custom_divisor = info->custom_divisor; -} - -/* FIXME: set_serial_info needs check_custom_divisor !!! */ - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value) -{ - unsigned char status; - - cli(); - status = read_zsreg(info->private->zs_channel, 0); - sti(); - return status; -} - -static unsigned int SCC_get_modem_info(struct m68k_async_struct *info) -{ - unsigned char control, status; - unsigned int result; - - cli(); - control = info->private->curregs[5]; - status = read_zsreg(info->private->zs_channel, 0); - sti(); - result = ((control & RTS) ? TIOCM_RTS: 0) - | ((control & DTR) ? TIOCM_DTR: 0) - | ((status & DCD) ? TIOCM_CAR: 0) - | ((status & CTS) ? 0: TIOCM_CTS); - return result; -} - -/* FIXME: zs_setdtr was used in rs_open ... */ - -static int SCC_set_modem_info(struct m68k_async_struct *info, - int new_dtr, int new_rts) -{ - unsigned int bits; - - bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0); - info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits; - info->private->pendregs[5] = info->private->curregs[5]; - write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]); - sti(); - return 0; -} - -/* - * This routine sends a break character out the serial port. - */ -static void SCC_set_break(struct m68k_async_struct * info, int break_flag) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - if (break_flag) { - info->private->curregs[5] |= SND_BRK; - write_zsreg(info->private->zs_channel, 5, - info->private->curregs[5]); - } else { - info->private->curregs[5] &= ~SND_BRK; - write_zsreg(info->private->zs_channel, 5, - info->private->curregs[5]); - } - - restore_flags(flags); -} - -/* FIXME: these have to be enabled in rs_ioctl !! */ - -static int SCC_ioctl(struct tty_struct *tty, struct file * file, - struct m68k_async_struct * info, unsigned int cmd, - unsigned long arg) -{ - int error; - - switch (cmd) { - case TIOCSERGETLSR: /* Get line status register */ - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int)); - if (error) - return error; - else - return SCC_get_lsr_info(info, (unsigned int *) arg); - - case TIOCSERGSTRUCT: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct m68k_async_struct)); - if (error) - return error; - copy_to_user((struct m68k_async_struct *) arg, - info, sizeof(struct m68k_async_struct)); - return 0; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void SCC_stop_receive (struct m68k_async_struct *info) -{ - /* disable Rx */ - info->private->curregs[3] &= ~RxENABLE; - info->private->pendregs[3] = info->private->curregs[3]; - write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]); - /* disable Rx interrupts */ - info->private->curregs[1] &= ~(0x18); /* disable any rx ints */ - info->private->pendregs[1] = info->private->curregs[1]; - write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]); - ZS_CLEARFIFO(info->private->zs_channel); -} - -static int SCC_trans_empty (struct m68k_async_struct *info) -{ - return (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0; -} - -/* Finally, routines used to initialize the serial driver. */ - -#ifdef CONFIG_MAC - -/* - * Mac: use boot_info data; assume 2 channels - */ - -static void probe_sccs(void) -{ - int n; - -#define ZS_CONTROL 0x50F04000 -#define ZS_DATA (ZS_CONTROL+4) -#define ZS_IRQ 5 -#define ZS_MOVE -2 -#define ZS_DATA_MOVE 4 -#define ZS_CH_A_FIRST 2 - - /* last-ditch fixup for NetBSD booter case */ - if (mac_bi_data.sccbase == 0) - mac_bi_data.sccbase = ZS_CONTROL; - - /* testing: fix up broken 24 bit addresses (ClassicII) */ - if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase) - mac_bi_data.sccbase |= 0x50000000; - - if ( !hwreg_present((void *)mac_bi_data.sccbase)) - { - printk(KERN_WARNING "z8530: Serial devices not accessible. Check serial switch.\n"); - return; - } - - for(n=0;n<2;n++) - { -#if 0 - zs_channels[n].control = (volatile unsigned char *) - ZS_CONTROL+ZS_MOVE*n; - zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n; -#else - zs_channels[n].control = (volatile unsigned char *) /* 2, 0 */ - (mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n; - zs_channels[n].data = (volatile unsigned char *) /* 6, 4 */ - (mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n; -#endif - zs_soft[n].private = &zs_soft_private[n]; - zs_soft[n].private->zs_channel = &zs_channels[n]; - zs_soft[n].irq = IRQ4; -#if 0 - if (request_irq(ch->intrs[0], rs_interrupt, 0, - "SCC", &zs_soft[n])) - panic("macserial: can't get irq %d", - ch->intrs[0]); -#endif - if (n & 1) - zs_soft[n].private->zs_chan_a = &zs_channels[n-1]; - else - zs_soft[n].private->zs_chan_a = &zs_channels[n]; - } - - zs_channels_found=2; -} - -#else - -/* - * PowerMAC - query the PROM - */ - -static void show_serial_version(void) -{ - printk("PowerMac Z8530 serial driver version 1.00\n"); -} - -/* Ask the PROM how many Z8530s we have and initialize their zs_channels */ -static void -probe_sccs() -{ - struct device_node *dev, *ch; - struct m68k_async_struct **pp; - int n; - - n = 0; - pp = &zs_chain; - for (dev = find_devices("escc"); dev != 0; dev = dev->next) { - if (n >= NUM_CHANNELS) { - printk("Sorry, can't use %s: no more channels\n", - dev->full_name); - continue; - } - for (ch = dev->child; ch != 0; ch = ch->sibling) { - if (ch->n_addrs < 1 || ch ->n_intrs < 1) { - printk("Can't use %s: %d addrs %d intrs\n", - ch->full_name, ch->n_addrs, ch->n_intrs); - continue; - } - zs_channels[n].control = (volatile unsigned char *) - ch->addrs[0].address; - zs_channels[n].data = zs_channels[n].control - + ch->addrs[0].size / 2; - zs_soft[n].private = &zs_soft_private[n]; - zs_soft[n].private->zs_channel = &zs_channels[n]; - zs_soft[n].irq = ch->intrs[0]; - if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0, - "SCC", &zs_soft[n])) - panic("macserial: can't get irq %d", - ch->intrs[0]); - /* XXX this assumes the prom puts chan A before B */ - if (n & 1) - zs_soft[n].private->zs_chan_a = &zs_channels[n-1]; - else - zs_soft[n].private->zs_chan_a = &zs_channels[n]; - - *pp = &zs_soft[n]; - pp = &zs_soft[n].private->zs_next; - ++n; - } - } - *pp = 0; - zs_channels_found = n; -} - -#endif - -extern void register_console(void (*proc)(const char *)); - -static inline void -rs_cons_check(struct m68k_async_struct *ss, int channel) -{ - int i, o, io; - static int consout_registered = 0; - static int msg_printed = 0; - - i = o = io = 0; - - /* Is this one of the serial console lines? */ - if ((zs_cons_chanout != channel) && - (zs_cons_chanin != channel)) - return; - zs_conschan = ss->private->zs_channel; - zs_consinfo = ss; - - /* Register the console output putchar, if necessary */ - if (zs_cons_chanout == channel) { - o = 1; - /* double whee.. */ - if (!consout_registered) { - register_console(zs_console_print); - consout_registered = 1; - } - } - - if (zs_cons_chanin == channel) { - i = 1; - } - if (o && i) - io = 1; - if (ss->private->zs_baud != 9600) - panic("Console baud rate weirdness"); - - /* Set flag variable for this port so that it cannot be - * opened for other uses by accident. - */ - ss->private->is_cons = 1; - - if (io) { - if(!msg_printed) { - printk("zs%d: console I/O\n", ((channel>>1)&1)); - msg_printed = 1; - } - } else { - printk("zs%d: console %s\n", ((channel>>1)&1), - (i==1 ? "input" : (o==1 ? "output" : "WEIRD"))); - } - - /* FIXME : register interrupt here??? */ -} - -volatile int test_done; - -/* rs_init inits the driver */ -int mac_SCC_init(void) -{ - int channel, line, nr = 0; - unsigned long flags; - struct serial_struct req; - - printk("Mac68K Z8530 serial driver version 1.01\n"); - - /* SCC present at all? */ - if (!MACH_IS_MAC) - return( -ENODEV ); - - if (zs_chain == 0) - probe_sccs(); - - save_flags(flags); - cli(); - - /* - * FIXME: init of rs_table entry and register_serial now done, - * but possible clash of zs_soft[channel] and rs_table[channel]!! - * zs_soft initialized in probe_sccs(), some settings copied to - * info = &rs_table[channel], which is used by the mid-level code. - * The info->private part is shared among both! - */ - - for (channel = 0; channel < zs_channels_found; ++channel) { - req.line = channel; - req.type = SER_SCC_MAC; - req.port = (int) zs_soft[channel].private->zs_channel->control; - - if ((line = register_serial( &req )) >= 0) { - SCC_init_port( &rs_table[line], req.type, line ); - ++nr; - } - else - printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line ); - } - - restore_flags(flags); - - return( nr > 0 ? 0 : -ENODEV ); -} - -/* Hooks for running a serial console. con_init() calls this if the - * console is being run over one of the serial ports. - * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored. - */ -void -rs_cons_hook(int chip, int out, int channel) -{ - if (zs_chain == 0) - probe_sccs(); - zs_soft[channel].private->clk_divisor = 16; - zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]); - rs_cons_check(&zs_soft[channel], channel); - if (out) - zs_cons_chanout = channel; - else - zs_cons_chanin = channel; - - /* FIXME : register interrupt here??? */ -} - -/* This is called at boot time to prime the kgdb serial debugging - * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1 - * for /dev/ttyS1 which is determined in setup_arch() from the - * boot command line flags. - */ -void -rs_kgdb_hook(int tty_num) -{ - if (zs_chain == 0) - probe_sccs(); - zs_kgdbchan = zs_soft[tty_num].private->zs_channel; - zs_soft[tty_num].private->clk_divisor = 16; - zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]); - zs_soft[tty_num].private->kgdb_channel = 1; /* This runs kgdb */ - zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */ - /* Turn on transmitter/receiver at 8-bits/char */ - kgdb_chaninit(&zs_soft[tty_num], 0, 9600); - ZS_CLEARERR(zs_kgdbchan); - ZS_CLEARFIFO(zs_kgdbchan); - - /* FIXME : register interrupt here??? */ -} - diff -u --recursive --new-file v2.3.44/linux/drivers/char/mac_SCC.h linux/drivers/char/mac_SCC.h --- v2.3.44/linux/drivers/char/mac_SCC.h Sat Jun 13 13:44:30 1998 +++ linux/drivers/char/mac_SCC.h Wed Dec 31 16:00:00 1969 @@ -1,321 +0,0 @@ -/* - * macserial.h: Definitions for the Macintosh Z8530 serial driver. - * - * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras. - * - * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ -#ifndef _MAC_SCC_H -#define _MAC_SCC_H - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define ZILOG_CLOSING_WAIT_INF 0 -#define ZILOG_CLOSING_WAIT_NONE 65535 - -/* - * Definitions for ZILOG_struct (and serial_struct) flags field - */ -#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define ZILOG_SPD_MASK 0x0030 -#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */ -#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ -#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -/* MSch: gone to */ - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -#endif /* __KERNEL__ */ - -/* Conversion routines to/from brg time constants from/to bits - * per second. - */ -#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) -#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) - -/* The Zilog register set */ - -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ -#define RxNBITS_MASK 0xc0 - -/* Write Register 4 */ - -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ -#define SB_MASK 0xc - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ -#define XCLK_MASK 0xC0 - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define TxNBITS_MASK 0x60 -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define FRM_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ - -/* Misc macros */ -#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES)) -#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ - garbage = read_zsdata(channel); \ - garbage = read_zsdata(channel); \ - garbage = read_zsdata(channel); \ - } while(0) - -#endif /* !(_MAC_SCC_H) */ diff -u --recursive --new-file v2.3.44/linux/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.3.44/linux/drivers/char/nvram.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/nvram.c Sun Feb 13 10:47:01 2000 @@ -38,7 +38,7 @@ /* select machine configuration */ #if defined(CONFIG_ATARI) #define MACH ATARI -#elif defined(__i386__) /* and others?? */ +#elif defined(__i386__) || defined(__arm__) /* and others?? */ #define MACH PC #else #error Cannot build nvram driver for this machine configuration. diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile --- v2.3.44/linux/drivers/macintosh/Makefile Thu Feb 10 17:11:09 2000 +++ linux/drivers/macintosh/Makefile Sun Feb 13 11:21:42 2000 @@ -68,6 +68,10 @@ L_OBJS += via-pmu.o endif +ifdef CONFIG_ADB_PMU68K + L_OBJS += via-pmu68k.o +endif + ifdef CONFIG_ADB_MACIO L_OBJS += macio-adb.o endif diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/adb-iop.c linux/drivers/macintosh/adb-iop.c --- v2.3.44/linux/drivers/macintosh/adb-iop.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/adb-iop.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,284 @@ +/* + * I/O Processor (IOP) ADB Driver + * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org) + * Based on via-cuda.c by Paul Mackerras. + * + * 1999-07-01 (jmt) - First implementation for new driver architecture. + * + * 1999-07-31 (jmt) - First working version. + * + * TODO: + * + * o Implement SRQ handling. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/*#define DEBUG_ADB_IOP*/ + +extern void iop_ism_irq(int, void *, struct pt_regs *); + +static struct adb_request *current_req; +static struct adb_request *last_req; +#if 0 +static unsigned char reply_buff[16]; +static unsigned char *reply_ptr; +#endif + +static enum adb_iop_state { + idle, + sending, + awaiting_reply +} adb_iop_state; + +static void adb_iop_start(void); +static int adb_iop_probe(void); +static int adb_iop_init(void); +static int adb_iop_send_request(struct adb_request *, int); +static int adb_iop_write(struct adb_request *); +static int adb_iop_autopoll(int); +static void adb_iop_poll(void); +static int adb_iop_reset_bus(void); + +struct adb_driver adb_iop_driver = { + "ISM IOP", + adb_iop_probe, + adb_iop_init, + adb_iop_send_request, + adb_iop_autopoll, + adb_iop_poll, + adb_iop_reset_bus +}; + +static void adb_iop_end_req(struct adb_request *req, int state) +{ + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); + adb_iop_state = state; +} + +/* + * Completion routine for ADB commands sent to the IOP. + * + * This will be called when a packet has been successfully sent. + */ + +static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs) +{ + struct adb_request *req; + uint flags; + + save_flags(flags); + cli(); + + req = current_req; + if ((adb_iop_state == sending) && req && req->reply_expected) { + adb_iop_state = awaiting_reply; + } + + restore_flags(flags); +} + +/* + * Listen for ADB messages from the IOP. + * + * This will be called when unsolicited messages (usually replies to TALK + * commands or autopoll packets) are received. + */ + +static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs) +{ + struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; + struct adb_request *req; + uint flags; + + save_flags(flags); + cli(); + + req = current_req; + +#ifdef DEBUG_ADB_IOP + printk("adb_iop_listen: rcvd packet, %d bytes: %02X %02X", + (uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd); + i = 0; + while (i < amsg->count) { + printk(" %02X", (uint) amsg->data[i++]); + } + printk("\n"); +#endif + + /* Handle a timeout. Timeout packets seem to occur even after */ + /* we've gotten a valid reply to a TALK, so I'm assuming that */ + /* a "timeout" is actually more like an "end-of-data" signal. */ + /* We need to send back a timeout packet to the IOP to shut */ + /* it up, plus complete the current request, if any. */ + + if (amsg->flags & ADB_IOP_TIMEOUT) { + msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL; + msg->reply[1] = 0; + msg->reply[2] = 0; + if (req && (adb_iop_state != idle)) { + adb_iop_end_req(req, idle); + } + } else { + /* TODO: is it possible for more tha one chunk of data */ + /* to arrive before the timeout? If so we need to */ + /* use reply_ptr here like the other drivers do. */ + if ((adb_iop_state == awaiting_reply) && + (amsg->flags & ADB_IOP_EXPLICIT)) { + req->reply_len = amsg->count + 1; + memcpy(req->reply, &amsg->cmd, req->reply_len); + } else { + adb_input(&amsg->cmd, amsg->count + 1, regs, + amsg->flags & ADB_IOP_AUTOPOLL); + } + memcpy(msg->reply, msg->message, IOP_MSG_LEN); + } + iop_complete_message(msg); + restore_flags(flags); +} + +/* + * Start sending an ADB packet, IOP style + * + * There isn't much to do other than hand the packet over to the IOP + * after encapsulating it in an adb_iopmsg. + */ + +static void adb_iop_start(void) +{ + unsigned long flags; + struct adb_request *req; + struct adb_iopmsg amsg; + + /* get the packet to send */ + req = current_req; + if (!req) return; + + save_flags(flags); + cli(); + +#ifdef DEBUG_ADB_IOP + printk("adb_iop_start: sending packet, %d bytes:", req->nbytes); + for (i = 0 ; i < req->nbytes ; i++) + printk(" %02X", (uint) req->data[i]); + printk("\n"); +#endif + + /* The IOP takes MacII-style packets, so */ + /* strip the initial ADB_PACKET byte. */ + + amsg.flags = ADB_IOP_EXPLICIT; + amsg.count = req->nbytes - 2; + + /* amsg.data immediately follows amsg.cmd, effectively making */ + /* amsg.cmd a pointer to the beginning of a full ADB packet. */ + memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1); + + req->sent = 1; + adb_iop_state = sending; + restore_flags(flags); + + /* Now send it. The IOP manager will call adb_iop_complete */ + /* when the packet has been sent. */ + + iop_send_message(ADB_IOP, ADB_CHAN, req, + sizeof(amsg), (__u8 *) &amsg, adb_iop_complete); +} + +int adb_iop_probe(void) +{ + if (!iop_ism_present) return -ENODEV; + return 0; +} + +int adb_iop_init(void) +{ + printk("adb: IOP ISM driver v0.4 for Unified ADB.\n"); + iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB"); + return 0; +} + +int adb_iop_send_request(struct adb_request *req, int sync) +{ + int err; + + err = adb_iop_write(req); + if (err) return err; + + if (sync) { + while (!req->complete) adb_iop_poll(); + } + return 0; +} + +static int adb_iop_write(struct adb_request *req) +{ + unsigned long flags; + + if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) { + req->complete = 1; + return -EINVAL; + } + + save_flags(flags); + cli(); + + req->next = 0; + req->sent = 0; + req->complete = 0; + req->reply_len = 0; + + if (current_req != 0) { + last_req->next = req; + last_req = req; + } else { + current_req = req; + last_req = req; + } + + restore_flags(flags); + if (adb_iop_state == idle) adb_iop_start(); + return 0; +} + +int adb_iop_autopoll(int devs) +{ + /* TODO: how do we enable/disable autopoll? */ + return 0; +} + +void adb_iop_poll(void) +{ + if (adb_iop_state == idle) adb_iop_start(); + iop_ism_irq(0, (void *) ADB_IOP, NULL); +} + +int adb_iop_reset_bus(void) +{ + struct adb_request req; + + req.reply_expected = 0; + req.nbytes = 2; + req.data[0] = ADB_PACKET; + req.data[1] = 0; /* RESET */ + adb_iop_write(&req); + while (!req.complete) adb_iop_poll(); + return 0; +} diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.3.44/linux/drivers/macintosh/mac_keyb.c Thu Feb 10 17:11:09 2000 +++ linux/drivers/macintosh/mac_keyb.c Sun Feb 13 10:47:01 2000 @@ -391,16 +391,17 @@ case 0x39: handle_scancode(0x39, 1); handle_scancode(0x39, 0); - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); return; case 0x47: /*case 0xc7:*/ - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); break; } } handle_scancode(keycode, !up_flag); + tasklet_schedule(&keyboard_tasklet); } static void diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.3.44/linux/drivers/macintosh/macserial.c Thu Feb 10 17:11:09 2000 +++ linux/drivers/macintosh/macserial.c Sun Feb 13 10:47:01 2000 @@ -2796,7 +2796,6 @@ void __init serial_console_init(void) { register_console(&sercons); - return kmem_start; } #endif /* ifdef CONFIG_SERIAL_CONSOLE */ diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/via-macii.c linux/drivers/macintosh/via-macii.c --- v2.3.44/linux/drivers/macintosh/via-macii.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/via-macii.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,679 @@ +/* + * Device driver for the via ADB on (many) Mac II-class machines + * + * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox + * Also derived from code Copyright (C) 1996 Paul Mackerras. + * + * With various updates provided over the years by Michael Schmitz, + * Guideo Koerber and others. + * + * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org) + * + * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile unsigned char *via; + +/* VIA registers - spaced 0x200 bytes apart */ +#define RS 0x200 /* skip between registers */ +#define B 0 /* B-side data */ +#define A RS /* A-side data */ +#define DIRB (2*RS) /* B-side direction (1=output) */ +#define DIRA (3*RS) /* A-side direction (1=output) */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ +#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ +#define SR (10*RS) /* Shift register */ +#define ACR (11*RS) /* Auxiliary control register */ +#define PCR (12*RS) /* Peripheral control register */ +#define IFR (13*RS) /* Interrupt flag register */ +#define IER (14*RS) /* Interrupt enable register */ +#define ANH (15*RS) /* A-side data, no handshake */ + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ +#define ST_MASK 0x30 /* mask for selecting ADB state bits */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define SR_DATA 0x08 /* Shift register data */ +#define SR_CLOCK 0x10 /* Shift register clock */ + +/* ADB transaction states according to GMHW */ +#define ST_CMD 0x00 /* ADB state: command byte */ +#define ST_EVEN 0x10 /* ADB state: even data byte */ +#define ST_ODD 0x20 /* ADB state: odd data byte */ +#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ + +static int macii_init_via(void); +static void macii_start(void); +static void macii_interrupt(int irq, void *arg, struct pt_regs *regs); +static void macii_retransmit(int); +static void macii_queue_poll(void); + +static int macii_probe(void); +static int macii_init(void); +static int macii_send_request(struct adb_request *req, int sync); +static int macii_write(struct adb_request *req); +static int macii_autopoll(int devs); +static void macii_poll(void); +static int macii_reset_bus(void); + +struct adb_driver via_macii_driver = { + "Mac II", + macii_probe, + macii_init, + macii_send_request, + macii_autopoll, + macii_poll, + macii_reset_bus +}; + +static enum macii_state { + idle, + sent_first_byte, + sending, + reading, + read_done, + awaiting_reply +} macii_state; + +static int need_poll = 0; +static int command_byte = 0; +static int last_reply = 0; +static int last_active = 0; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static struct adb_request *retry_req; +static unsigned char reply_buf[16]; +static unsigned char *reply_ptr; +static int reply_len; +static int reading_reply; +static int data_index; +static int first_byte; +static int prefix_len; +static int status = ST_IDLE|TREQ; +static int last_status; +static int driver_running = 0; + +/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ +extern int console_loglevel; + +/* Check for MacII style ADB */ +static int macii_probe(void) +{ + if (macintosh_config->adb_type != MAC_ADB_II) return -ENODEV; + + via = via1; + + printk("adb: Mac II ADB Driver v0.4 for Unified ADB\n"); + return 0; +} + +/* Initialize the driver */ +int macii_init(void) +{ + unsigned long flags; + int err; + + save_flags(flags); + cli(); + + err = macii_init_via(); + if (err) return err; + + err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", + macii_interrupt); + if (err) return err; + + macii_state = idle; + restore_flags(flags); + return 0; +} + +/* initialize the hardware */ +static int macii_init_via(void) +{ + unsigned char x; + + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; + + /* Set up state: idle */ + via[B] |= ST_IDLE; + last_status = via[B] & (ST_MASK|TREQ); + + /* Shift register on input */ + via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; + + /* Wipe any pending data and int */ + x = via[SR]; + + return 0; +} + +/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */ +static void macii_queue_poll(void) +{ + static int device = 0; + static int in_poll=0; + static struct adb_request req; + unsigned long flags; + + if (in_poll) printk("macii_queue_poll: double poll!\n"); + + in_poll++; + if (++device > 15) device = 1; + + adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, + ADB_READREG(device, 0)); + + save_flags(flags); + cli(); + + req.next = current_req; + current_req = &req; + + restore_flags(flags); + macii_start(); + in_poll--; +} + +/* Send an ADB retransmit (Talk, appended to the request queue) */ +static void macii_retransmit(int device) +{ + static int in_retransmit = 0; + static struct adb_request rt; + unsigned long flags; + + if (in_retransmit) printk("macii_retransmit: double retransmit!\n"); + + in_retransmit++; + + adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, + ADB_READREG(device, 0)); + + save_flags(flags); + cli(); + + if (current_req != NULL) { + last_req->next = &rt; + last_req = &rt; + } else { + current_req = &rt; + last_req = &rt; + } + + if (macii_state == idle) macii_start(); + + restore_flags(flags); + in_retransmit--; +} + +/* Send an ADB request; if sync, poll out the reply 'till it's done */ +static int macii_send_request(struct adb_request *req, int sync) +{ + int i; + + i = macii_write(req); + if (i) return i; + + if (sync) { + while (!req->complete) macii_poll(); + } + return 0; +} + +/* Send an ADB request */ +static int macii_write(struct adb_request *req) +{ + unsigned long flags; + + if (req->nbytes < 2 || req->data[0] != ADB_PACKET) { + req->complete = 1; + return -EINVAL; + } + + req->next = 0; + req->sent = 0; + req->complete = 0; + req->reply_len = 0; + + save_flags(flags); cli(); + + if (current_req != NULL) { + last_req->next = req; + last_req = req; + } else { + current_req = req; + last_req = req; + if (macii_state == idle) macii_start(); + } + + restore_flags(flags); + return 0; +} + +/* Start auto-polling */ +static int macii_autopoll(int devs) +{ + /* Just ping a random default address */ + if (!(current_req || retry_req)) + macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3); + return 0; +} + +/* Prod the chip without interrupts */ +static void macii_poll(void) +{ + unsigned long flags; + + save_flags(flags); cli(); + if (via[IFR] & SR_INT) macii_interrupt(0, 0, 0); + restore_flags(flags); +} + +/* Reset the bus */ +static int macii_reset_bus(void) +{ + static struct adb_request req; + + /* Command = 0, Address = ignored */ + adb_request(&req, NULL, 0, 1, ADB_BUSRESET); + + return 0; +} + +/* Start sending ADB packet */ +static void macii_start(void) +{ + unsigned long flags; + struct adb_request *req; + + req = current_req; + if (!req) return; + + /* assert macii_state == idle */ + if (macii_state != idle) { + printk("macii_start: called while driver busy (%p %x %x)!\n", + req, macii_state, (uint) via1[B] & (ST_MASK|TREQ)); + return; + } + + save_flags(flags); cli(); + + /* + * IRQ signaled ?? (means ADB controller wants to send, or might + * be end of packet if we were reading) + */ + if ((via[B] & TREQ) == 0) { + /* + * FIXME - we need to restart this on a timer + * or a collision at boot hangs us. + * Never set macii_state to idle here, or macii_start + * won't be called again from send_request! + * (need to re-check other cases ...) + */ + /* + * if the interrupt handler set the need_poll + * flag, it's hopefully a SRQ poll or re-Talk + * so we try to send here anyway + */ + if (!need_poll) { + if (console_loglevel == 10) + printk("macii_start: device busy - retry %p state %d status %x!\n", + req, macii_state, + (uint) via[B] & (ST_MASK|TREQ)); + retry_req = req; + /* set ADB status here ? */ + restore_flags(flags); + return; + } else { + need_poll = 0; + } + } + /* + * Another retry pending? (sanity check) + */ + if (retry_req) { + retry_req = NULL; + } + + /* Now send it. Be careful though, that first byte of the request */ + /* is actually ADB_PACKET; the real data begins at index 1! */ + + /* store command byte */ + command_byte = req->data[1]; + /* Output mode */ + via[ACR] |= SR_OUT; + /* Load data */ + via[SR] = req->data[1]; + /* set ADB state to 'command' */ + via[B] = (via[B] & ~ST_MASK) | ST_CMD; + + macii_state = sent_first_byte; + data_index = 2; + + restore_flags(flags); +} + +/* + * The notorious ADB interrupt handler - does all of the protocol handling, + * except for starting new send operations. Relies heavily on the ADB + * controller sending and receiving data, thereby generating SR interrupts + * for us. This means there has to be always activity on the ADB bus, otherwise + * the whole process dies and has to be re-kicked by sending TALK requests ... + * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type + * ADB the problem isn't solved yet (retransmit of the latest active TALK seems + * a good choice; either on timeout or on a timer interrupt). + * + * The basic ADB state machine was left unchanged from the original MacII code + * by Alan Cox, which was based on the CUDA driver for PowerMac. + * The syntax of the ADB status lines seems to be totally different on MacII, + * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for + * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start + * and end of a receive packet are signaled by asserting /IRQ on the interrupt + * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on + * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the + * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB + * protocol with a logic analyzer!!) + * + * Note: As of 21/10/97, the MacII ADB part works including timeout detection + * and retransmit (Talk to the last active device). + */ +void macii_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int x, adbdir; + unsigned long flags; + struct adb_request *req; + + last_status = status; + + /* prevent races due to SCSI enabling ints */ + save_flags(flags); cli(); + + if (driver_running) { + restore_flags(flags); + return; + } + + driver_running = 1; + + status = via[B] & (ST_MASK|TREQ); + adbdir = via[ACR] & SR_OUT; + + switch (macii_state) { + case idle: + x = via[SR]; + first_byte = x; + /* set ADB state = even for first data byte */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + + reply_buf[0] = first_byte; /* was command_byte?? */ + reply_ptr = reply_buf + 1; + reply_len = 1; + prefix_len = 1; + reading_reply = 0; + + macii_state = reading; + break; + + case awaiting_reply: + /* handshake etc. for II ?? */ + x = via[SR]; + first_byte = x; + /* set ADB state = even for first data byte */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + + current_req->reply[0] = first_byte; + reply_ptr = current_req->reply + 1; + reply_len = 1; + prefix_len = 1; + reading_reply = 1; + + macii_state = reading; + break; + + case sent_first_byte: + req = current_req; + /* maybe we're already done (Talk, or Poll)? */ + if (data_index >= req->nbytes) { + /* reset to shift in */ + /* If it's a Listen command and we're done, someone's doing weird stuff. */ + if (((command_byte & 0x0C) == 0x08) + && (console_loglevel == 10)) + printk("macii_interrupt: listen command with no data: %x!\n", + command_byte); + /* reset to shift in */ + via[ACR] &= ~SR_OUT; + x = via[SR]; + /* set ADB state idle - might get SRQ */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + + req->sent = 1; + + if (req->reply_expected) { + macii_state = awaiting_reply; + } else { + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); + macii_state = idle; + if (current_req || retry_req) + macii_start(); + else + macii_retransmit((command_byte & 0xF0) >> 4); + } + } else { + /* SR already set to shift out; send byte */ + via[SR] = current_req->data[data_index++]; + /* set state to ST_EVEN (first byte was: ST_CMD) */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + macii_state = sending; + } + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) { + /* reset to shift in */ + via[ACR] &= ~SR_OUT; + x = via[SR]; + /* set ADB state idle - might get SRQ */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + + req->sent = 1; + + if (req->reply_expected) { + macii_state = awaiting_reply; + } else { + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); + macii_state = idle; + if (current_req || retry_req) + macii_start(); + else + macii_retransmit((command_byte & 0xF0) >> 4); + } + } else { + via[SR] = req->data[data_index++]; + + /* invert state bits, toggle ODD/EVEN */ + via[B] ^= ST_MASK; + } + break; + + case reading: + + /* timeout / SRQ handling for II hw */ + if( (first_byte == 0xFF && (reply_len-prefix_len)==2 + && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || + ((reply_len-prefix_len)==3 + && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) + { + /* + * possible timeout (in fact, most probably a + * timeout, since SRQ can't be signaled without + * transfer on the bus). + * The last three bytes seen were FF, together + * with the starting byte (in case we started + * on 'idle' or 'awaiting_reply') this probably + * makes four. So this is mostl likely #5! + * The timeout signal is a pattern 1 0 1 0 0.. + * on /INT, meaning we missed it :-( + */ + x = via[SR]; + if (x != 0xFF) printk("macii_interrupt: mistaken timeout/SRQ!\n"); + + if ((status & TREQ) == (last_status & TREQ)) { + /* Not a timeout. Unsolicited SRQ? weird. */ + /* Terminate the SRQ packet and poll */ + need_poll = 1; + } + /* There's no packet to get, so reply is blank */ + via[B] ^= ST_MASK; + reply_ptr -= (reply_len-prefix_len); + reply_len = prefix_len; + macii_state = read_done; + break; + } /* end timeout / SRQ handling for II hw. */ + + if((reply_len-prefix_len)>3 + && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) + { + /* SRQ tacked on data packet */ + /* Terminate the packet (SRQ never ends) */ + x = via[SR]; + macii_state = read_done; + reply_len -= 3; + reply_ptr -= 3; + need_poll = 1; + /* need to continue; next byte not seen else */ + } else { + /* Sanity check */ + if (reply_len > 15) reply_len = 0; + /* read byte */ + x = via[SR]; + *reply_ptr = x; + reply_ptr++; + reply_len++; + } + /* The usual handshake ... */ + + /* + * NetBSD hints that the next to last byte + * is sent with IRQ !! + * Guido found out it's the last one (0x0), + * but IRQ should be asserted already. + * Problem with timeout detection: First + * transition to /IRQ might be second + * byte of timeout packet! + * Timeouts are signaled by 4x FF. + */ + if (!(status & TREQ) && (x == 0x00)) { /* != 0xFF */ + /* invert state bits, toggle ODD/EVEN */ + via[B] ^= ST_MASK; + + /* adjust packet length */ + reply_len--; + reply_ptr--; + macii_state = read_done; + } else { + /* not caught: ST_CMD */ + /* required for re-entry 'reading'! */ + if ((status & ST_MASK) == ST_IDLE) { + /* (in)sanity check - set even */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + } else { + /* invert state bits */ + via[B] ^= ST_MASK; + } + } + break; + + case read_done: + x = via[SR]; + if (reading_reply) { + req = current_req; + req->reply_len = reply_ptr - req->reply; + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); + } else { + adb_input(reply_buf, reply_ptr - reply_buf, + regs, 0); + } + + /* + * remember this device ID; it's the latest we got a + * reply from! + */ + last_reply = command_byte; + last_active = (command_byte & 0xF0) >> 4; + + /* SRQ seen before, initiate poll now */ + if (need_poll) { + macii_state = idle; + macii_queue_poll(); + need_poll = 0; + break; + } + + /* /IRQ seen, so the ADB controller has data for us */ + if (!(status & TREQ)) { + /* set ADB state to idle */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + + macii_state = reading; + + reply_buf[0] = command_byte; + reply_ptr = reply_buf + 1; + reply_len = 1; + prefix_len = 1; + reading_reply = 0; + } else { + /* no IRQ, send next packet or wait */ + macii_state = idle; + if (current_req) + macii_start(); + else + macii_retransmit(last_active); + } + break; + + default: + break; + } + /* reset mutex and interrupts */ + driver_running = 0; + restore_flags(flags); +} diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/via-maciisi.c linux/drivers/macintosh/via-maciisi.c --- v2.3.44/linux/drivers/macintosh/via-maciisi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/via-maciisi.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,486 @@ +/* + * Device driver for the IIsi-style ADB on some Mac LC and II-class machines + * + * Based on via-cuda.c and via-macii.c, as well as the original + * adb-bus.c, which in turn is somewhat influenced by (but uses no + * code from) the NetBSD HWDIRECT ADB code. Original IIsi driver work + * was done by Robert Thompson and integrated into the old style + * driver by Michael Schmitz. + * + * Original sources (c) Alan Cox, Paul Mackerras, and others. + * + * Rewritten for Unified ADB by David Huggins-Daines */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile unsigned char *via; + +/* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */ +#define RS 0x200 /* skip between registers */ +#define B 0 /* B-side data */ +#define A RS /* A-side data */ +#define DIRB (2*RS) /* B-side direction (1=output) */ +#define DIRA (3*RS) /* A-side direction (1=output) */ +#define SR (10*RS) /* Shift register */ +#define ACR (11*RS) /* Auxiliary control register */ +#define IFR (13*RS) /* Interrupt flag register */ +#define IER (14*RS) /* Interrupt enable register */ + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ +#define ST_MASK 0x30 /* mask for selecting ADB state bits */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define SR_DATA 0x08 /* Shift register data */ +#define SR_CLOCK 0x10 /* Shift register clock */ + +#define ADB_DELAY 150 + +static struct adb_request* current_req = NULL; +static struct adb_request* last_req = NULL; +static unsigned char maciisi_rbuf[16]; +static unsigned char *reply_ptr = NULL; +static int data_index; +static int reading_reply; +static int reply_len; + +static enum maciisi_state { + idle, + sending, + reading, +} maciisi_state; + +static int maciisi_probe(void); +static int maciisi_init(void); +static int maciisi_send_request(struct adb_request* req, int sync); +static int maciisi_write(struct adb_request* req); +static void maciisi_interrupt(int irq, void* arg, struct pt_regs* regs); +static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs); +static int maciisi_init_via(void); +static void maciisi_poll(void); +static void maciisi_start(void); + +struct adb_driver via_maciisi_driver = { + "Mac IIsi", + maciisi_probe, + maciisi_init, + maciisi_send_request, + NULL, /* maciisi_adb_autopoll, */ + maciisi_poll, + NULL /* maciisi_reset_adb_bus */ +}; + +static int +maciisi_probe(void) +{ + if (macintosh_config->adb_type != MAC_ADB_IISI) + return -ENODEV; + + via = via1; + return 0; +} + +static int +maciisi_init(void) +{ + int err; + + if (via == NULL) + return -ENODEV; + + if ((err = maciisi_init_via())) { + printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err); + via = NULL; + return err; + } + + if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK, + "ADB", maciisi_interrupt)) { + printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB); + return -EAGAIN; + } + + printk("adb: Mac IIsi driver v0.1 for Unified ADB.\n"); + return 0; +} + +static void +maciisi_stfu(void) +{ + int status = via[B] & (TIP|TREQ); + + if (status & TREQ) { + printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n"); + return; + } + + /* start transfer */ + via[B] |= TIP; + while (!(status & TREQ)) { + int poll_timeout = ADB_DELAY * 5; + /* Poll for SR interrupt */ + while (!(via[IFR] & SR_INT) && poll_timeout-- > 0) + status = via[B] & (TIP|TREQ); + via[SR]; /* Clear shift register */ + printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d\n", + status, poll_timeout); + + /* ACK on-off */ + via[B] |= TACK; + udelay(ADB_DELAY); + via[B] &= ~TACK; + } + /* end frame */ + via[B] &= ~TIP; +} + +/* All specifically VIA-related initialization goes here */ +static int +maciisi_init_via(void) +{ + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; + /* Shift register on input */ + via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; + printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ)); + /* Set initial state: idle */ + via[B] &= ~(TACK|TIP); + /* Wipe any pending data and int */ + via[SR]; + if (!(via[B] & TREQ)) + maciisi_stfu(); + via[IER] = IER_SET | SR_INT; + maciisi_state = idle; + return 0; +} + +/* Send a request, possibly waiting for a reply */ +static int +maciisi_send_request(struct adb_request* req, int sync) +{ + int i; + static int dump_packet = 1; + + if (via == NULL) { + req->complete = 1; + return -ENXIO; + } + + if (dump_packet) { + printk(KERN_DEBUG "maciisi_send_request:"); + for (i = 0; i < req->nbytes; i++) { + printk(" %.2x", req->data[i]); + } + printk("\n"); + } + req->reply_expected = 1; + + i = maciisi_write(req); + if (i) + return i; + + if (sync) { + while (!req->complete) { + maciisi_poll(); + } + } + return 0; +} + +/* Enqueue a request, and run the queue if possible */ +static int +maciisi_write(struct adb_request* req) +{ + unsigned long flags; + + printk(KERN_DEBUG "maciisi_write called, state=%d ifr=%x\n", maciisi_state, via[IFR]); + /* We will accept CUDA packets - the VIA sends them to us, so + it figures that we should be able to send them to it */ + if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { + printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n"); + req->complete = 1; + return -EINVAL; + } + req->next = 0; + req->sent = 0; + req->complete = 0; + req->reply_len = 0; + save_flags(flags); cli(); + + if (current_req) { + last_req->next = req; + last_req = req; + } else { + current_req = req; + last_req = req; + } + if (maciisi_state == idle) + maciisi_start(); + else + printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state); + + restore_flags(flags); + return 0; +} + +static void +maciisi_start(void) +{ + struct adb_request* req; + int status; + + printk(KERN_DEBUG "maciisi_start called, state=%d, ifr=%x\n", maciisi_state, via[IFR]); + if (maciisi_state != idle) { + /* shouldn't happen */ + printk(KERN_ERR "maciisi_start: maciisi_start called when driver busy!\n"); + return; + } + + req = current_req; + if (req == NULL) + return; + + status = via[B] & (TIP|TREQ); + if (!(status & TREQ)) { + /* Bus is busy, set up for reading */ + printk(KERN_DEBUG "maciisi_start: bus busy - aborting\n"); + return; + } + + /* Okay, send */ + printk(KERN_DEBUG "maciisi_start: sending\n"); + /* Set state to active */ + via[B] |= TIP; + /* ACK off */ + via[B] &= ~TACK; + /* Shift out and send */ + via[ACR] |= SR_OUT; + via[SR] = req->data[0]; + data_index = 1; + /* ACK on */ + via[B] |= TACK; + maciisi_state = sending; +} + +void +maciisi_poll(void) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (via[IFR] & SR_INT) { + maciisi_interrupt(0, 0, 0); + } + restore_flags(flags); +} + +/* Shift register interrupt - this is *supposed* to mean that the + register is either full or empty. In practice, I have no idea what + it means :( */ +static void +maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) +{ + int status; + struct adb_request *req; + static int dump_reply = 1; + + if (!(via[IFR] & SR_INT)) { + /* Shouldn't happen, we hope */ + printk(KERN_DEBUG "maciisi_interrupt: called without interrupt flag set\n"); + return; + } + + status = via[B] & (TIP|TREQ); + printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]); + + switch_start: + switch (maciisi_state) { + case idle: + printk(KERN_DEBUG "maciisi_interrupt: state=idle, status %x\n", status); + if (status & TIP) + printk(KERN_DEBUG "maciisi_interrupt: state is idle but TIP asserted!\n"); + + udelay(ADB_DELAY); + /* Shift in */ + via[ACR] &= ~SR_OUT; + /* Signal start of frame */ + via[B] |= TIP; + /* Clear the interrupt (throw this value on the floor, it's useless) */ + via[SR]; + /* ACK adb chip, high-low */ + via[B] |= TACK; + udelay(ADB_DELAY); + via[B] &= ~TACK; + reply_len = 0; + maciisi_state = reading; + if (reading_reply) { + reply_ptr = current_req->reply; + } else { + printk(KERN_DEBUG "maciisi_interrupt: received unsolicited packet\n"); + reply_ptr = maciisi_rbuf; + } + break; + + case sending: + printk(KERN_DEBUG "maciisi_interrupt: state=sending, status=%x\n", status); + /* Clear interrupt */ + via[SR]; + /* Set ACK off */ + via[B] &= ~TACK; + req = current_req; + + if (!(status & TREQ)) { + /* collision */ + printk(KERN_DEBUG "maciisi_interrupt: send collision\n"); + /* Set idle and input */ + via[B] &= ~TIP; + via[ACR] &= ~SR_OUT; + /* Must re-send */ + reading_reply = 0; + reply_len = 0; + maciisi_state = idle; + /* process this now, because the IFR has been cleared */ + goto switch_start; + } + + if (data_index >= req->nbytes) { + /* Sent the whole packet, put the bus back in idle state */ + /* Shift in, we are about to read a reply (hopefully) */ + via[ACR] &= ~SR_OUT; + /* End of frame */ + via[B] &= ~TIP; + req->sent = 1; + maciisi_state = idle; + if (req->reply_expected) { + /* Note: only set this once we've + successfully sent the packet */ + reading_reply = 1; + } else { + current_req = req->next; + if (req->done) + (*req->done)(req); + } + } else { + /* Sending more stuff */ + /* Shift out */ + via[ACR] |= SR_OUT; + /* Delay */ + udelay(ADB_DELAY); + /* Write */ + via[SR] = req->data[data_index++]; + /* Signal 'byte ready' */ + via[B] |= TACK; + } + break; + + case reading: + printk(KERN_DEBUG "maciisi_interrupt: state=reading, status=%x\n", status); + /* Shift in */ + via[ACR] &= ~SR_OUT; + if (reply_len++ > 16) { + printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n"); + via[B] |= TACK; + udelay(ADB_DELAY); + via[B] &= ~(TACK|TIP); + maciisi_state = idle; + maciisi_start(); + break; + } + *reply_ptr++ = via[SR]; + status = via[B] & (TIP|TREQ); + /* ACK on/off */ + via[B] |= TACK; + udelay(ADB_DELAY); + via[B] &= ~TACK; + if (!(status & TREQ)) + break; /* more stuff to deal with */ + + /* end of frame */ + via[B] &= ~TIP; + + /* end of packet, deal with it */ + if (reading_reply) { + req = current_req; + req->reply_len = reply_ptr - req->reply; + if (req->data[0] == ADB_PACKET) { + /* Have to adjust the reply from ADB commands */ + if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { + /* the 0x2 bit indicates no response */ + req->reply_len = 0; + } else { + /* leave just the command and result bytes in the reply */ + req->reply_len -= 2; + memmove(req->reply, req->reply + 2, req->reply_len); + } + } + if (dump_reply) { + int i; + printk(KERN_DEBUG "maciisi_interrupt: reply is "); + for (i = 0; i < req->reply_len; ++i) + printk(" %.2x", req->reply[i]); + printk("\n"); + } + req->complete = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + /* Obviously, we got it */ + reading_reply = 0; + } else { + maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs); + } + maciisi_state = idle; + status = via[B] & (TIP|TREQ); + if (!(status & TREQ)) { + /* Timeout?! */ + printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n", + status, via[IFR]); + maciisi_stfu(); + } + /* Do any queued requests now if possible */ + maciisi_start(); + break; + + default: + printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state); + } +} + +static void +maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs) +{ + int i; + + switch (buf[0]) { + case ADB_PACKET: + adb_input(buf+2, nb-2, regs, buf[1] & 0x40); + break; + default: + printk(KERN_DEBUG "data from IIsi ADB (%d bytes):", nb); + for (i = 0; i < nb; ++i) + printk(" %.2x", buf[i]); + printk("\n"); + + } +} diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/via-pmu68k.c linux/drivers/macintosh/via-pmu68k.c --- v2.3.44/linux/drivers/macintosh/via-pmu68k.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/via-pmu68k.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,1064 @@ +/* + * Device driver for the PMU on 68K-based Apple PowerBooks + * + * The VIA (versatile interface adapter) interfaces to the PMU, + * a 6805 microprocessor core whose primary function is to control + * battery charging and system power on the PowerBooks. + * The PMU also controls the ADB (Apple Desktop Bus) which connects + * to the keyboard and mouse, as well as the non-volatile RAM + * and the RTC (real time clock) chip. + * + * Adapted for 68K PMU by Joshua M. Thompson + * + * Based largely on the PowerMac PMU code by Paul Mackerras and + * Fabio Riccardi. + * + * Also based on the PMU driver from MkLinux by Apple Computer, Inc. + * and the Open Software Foundation, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Misc minor number allocated for /dev/pmu */ +#define PMU_MINOR 154 + +/* VIA registers - spaced 0x200 bytes apart */ +#define RS 0x200 /* skip between registers */ +#define B 0 /* B-side data */ +#define A RS /* A-side data */ +#define DIRB (2*RS) /* B-side direction (1=output) */ +#define DIRA (3*RS) /* A-side direction (1=output) */ +#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ +#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ +#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ +#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ +#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ +#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ +#define SR (10*RS) /* Shift register */ +#define ACR (11*RS) /* Auxiliary control register */ +#define PCR (12*RS) /* Peripheral control register */ +#define IFR (13*RS) /* Interrupt flag register */ +#define IER (14*RS) /* Interrupt enable register */ +#define ANH (15*RS) /* A-side data, no handshake */ + +/* Bits in B data register: both active low */ +#define TACK 0x02 /* Transfer acknowledge (input) */ +#define TREQ 0x04 /* Transfer request (output) */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#define SR_EXT 0x0c /* Shift on external clock */ +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define CB1_INT 0x10 /* transition on CB1 input */ + +static enum pmu_state { + idle, + sending, + intack, + reading, + reading_intr, +} pmu_state; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static struct adb_request *req_awaiting_reply; +static unsigned char interrupt_data[32]; +static unsigned char *reply_ptr; +static int data_index; +static int data_len; +static int adb_int_pending; +static int pmu_adb_flags; +static int adb_dev_map = 0; +static struct adb_request bright_req_1, bright_req_2, bright_req_3; +static int pmu_kind = PMU_UNKNOWN; +static int pmu_fully_inited = 0; + +int asleep; +struct notifier_block *sleep_notifier_list; + +static int pmu_probe(void); +static int pmu_init(void); +static void pmu_start(void); +static void pmu_interrupt(int irq, void *arg, struct pt_regs *regs); +static int pmu_send_request(struct adb_request *req, int sync); +static int pmu_autopoll(int devs); +void pmu_poll(void); +static int pmu_reset_bus(void); +static int pmu_queue_request(struct adb_request *req); + +static void pmu_start(void); +static void send_byte(int x); +static void recv_byte(void); +static void pmu_done(struct adb_request *req); +static void pmu_handle_data(unsigned char *data, int len, + struct pt_regs *regs); +static void set_volume(int level); + +struct adb_driver via_pmu_driver = { + "68K PMU", + pmu_probe, + pmu_init, + pmu_send_request, + pmu_autopoll, + pmu_poll, + pmu_reset_bus +}; + +/* + * This table indicates for each PMU opcode: + * - the number of data bytes to be sent with the command, or -1 + * if a length byte should be sent, + * - the number of response bytes which the PMU will return, or + * -1 if it will send a length byte. + */ +static s8 pmu_data_len[256][2] = { +/* 0 1 2 3 4 5 6 7 */ +/*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0}, +/*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1}, +/*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0}, +/*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1}, +/*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0}, +/*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1}, +/*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1}, +/*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1}, +/*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0}, +/*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +/*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1}, +/*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0}, +/*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0}, +/*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0}, +/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, +}; + +int pmu_probe() +{ + if (macintosh_config->adb_type == MAC_ADB_PB1) { + pmu_kind = PMU_68K_V1; + } else if (macintosh_config->adb_type == MAC_ADB_PB2) { + pmu_kind = PMU_68K_V2; + } else { + return -ENODEV; + } + + pmu_state = idle; + + return 0; +} + +static int +pmu_init(void) +{ + int timeout; + volatile struct adb_request req; + + via2[B] |= TREQ; /* negate TREQ */ + via2[DIRB] = (via2[DIRB] | TREQ) & ~TACK; /* TACK in, TREQ out */ + + pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB); + timeout = 100000; + while (!req.complete) { + if (--timeout < 0) { + printk(KERN_ERR "pmu_init: no response from PMU\n"); + return -EAGAIN; + } + udelay(10); + pmu_poll(); + } + + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) { + printk(KERN_ERR "pmu_init: timed out acking intrs\n"); + return -EAGAIN; + } + if (pmu_state == idle) { + adb_int_pending = 1; + pmu_interrupt(0, NULL, NULL); + } + pmu_poll(); + udelay(10); + } + + pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, + PMU_INT_ADB_AUTO|PMU_INT_SNDBRT|PMU_INT_ADB); + timeout = 100000; + while (!req.complete) { + if (--timeout < 0) { + printk(KERN_ERR "pmu_init: no response from PMU\n"); + return -EAGAIN; + } + udelay(10); + pmu_poll(); + } + + bright_req_1.complete = 1; + bright_req_2.complete = 1; + bright_req_3.complete = 1; + + if (request_irq(IRQ_MAC_ADB_SR, pmu_interrupt, 0, "pmu-shift", + pmu_interrupt)) { + printk(KERN_ERR "pmu_init: can't get irq %d\n", + IRQ_MAC_ADB_SR); + return -EAGAIN; + } + if (request_irq(IRQ_MAC_ADB_CL, pmu_interrupt, 0, "pmu-clock", + pmu_interrupt)) { + printk(KERN_ERR "pmu_init: can't get irq %d\n", + IRQ_MAC_ADB_CL); + free_irq(IRQ_MAC_ADB_SR, pmu_interrupt); + return -EAGAIN; + } + + pmu_fully_inited = 1; + + /* Enable backlight */ + pmu_enable_backlight(1); + + printk("adb: PMU 68K driver v0.5 for Unified ADB.\n"); + + return 0; +} + +int +pmu_get_model(void) +{ + return pmu_kind; +} + +/* Send an ADB command */ +static int +pmu_send_request(struct adb_request *req, int sync) +{ + int i, ret; + + if (!pmu_fully_inited) + { + req->complete = 1; + return -ENXIO; + } + + ret = -EINVAL; + + switch (req->data[0]) { + case PMU_PACKET: + for (i = 0; i < req->nbytes - 1; ++i) + req->data[i] = req->data[i+1]; + --req->nbytes; + if (pmu_data_len[req->data[0]][1] != 0) { + req->reply[0] = ADB_RET_OK; + req->reply_len = 1; + } else + req->reply_len = 0; + ret = pmu_queue_request(req); + break; + case CUDA_PACKET: + switch (req->data[1]) { + case CUDA_GET_TIME: + if (req->nbytes != 2) + break; + req->data[0] = PMU_READ_RTC; + req->nbytes = 1; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_GET_TIME; + ret = pmu_queue_request(req); + break; + case CUDA_SET_TIME: + if (req->nbytes != 6) + break; + req->data[0] = PMU_SET_RTC; + req->nbytes = 5; + for (i = 1; i <= 4; ++i) + req->data[i] = req->data[i+1]; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_SET_TIME; + ret = pmu_queue_request(req); + break; + case CUDA_GET_PRAM: + if (req->nbytes != 4) + break; + req->data[0] = PMU_READ_NVRAM; + req->data[1] = req->data[2]; + req->data[2] = req->data[3]; + req->nbytes = 3; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_GET_PRAM; + ret = pmu_queue_request(req); + break; + case CUDA_SET_PRAM: + if (req->nbytes != 5) + break; + req->data[0] = PMU_WRITE_NVRAM; + req->data[1] = req->data[2]; + req->data[2] = req->data[3]; + req->data[3] = req->data[4]; + req->nbytes = 4; + req->reply_len = 3; + req->reply[0] = CUDA_PACKET; + req->reply[1] = 0; + req->reply[2] = CUDA_SET_PRAM; + ret = pmu_queue_request(req); + break; + } + break; + case ADB_PACKET: + for (i = req->nbytes - 1; i > 1; --i) + req->data[i+2] = req->data[i]; + req->data[3] = req->nbytes - 2; + req->data[2] = pmu_adb_flags; + /*req->data[1] = req->data[1];*/ + req->data[0] = PMU_ADB_CMD; + req->nbytes += 2; + req->reply_expected = 1; + req->reply_len = 0; + ret = pmu_queue_request(req); + break; + } + if (ret) + { + req->complete = 1; + return ret; + } + + if (sync) { + while (!req->complete) + pmu_poll(); + } + + return 0; +} + +/* Enable/disable autopolling */ +static int +pmu_autopoll(int devs) +{ + struct adb_request req; + + if (!pmu_fully_inited) return -ENXIO; + + if (devs) { + adb_dev_map = devs; + pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86, + adb_dev_map >> 8, adb_dev_map); + pmu_adb_flags = 2; + } else { + pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF); + pmu_adb_flags = 0; + } + while (!req.complete) + pmu_poll(); + return 0; +} + +/* Reset the ADB bus */ +static int +pmu_reset_bus(void) +{ + struct adb_request req; + long timeout; + int save_autopoll = adb_dev_map; + + if (!pmu_fully_inited) return -ENXIO; + + /* anyone got a better idea?? */ + pmu_autopoll(0); + + req.nbytes = 5; + req.done = NULL; + req.data[0] = PMU_ADB_CMD; + req.data[1] = 0; + req.data[2] = 3; /* ADB_BUSRESET ??? */ + req.data[3] = 0; + req.data[4] = 0; + req.reply_len = 0; + req.reply_expected = 1; + if (pmu_queue_request(&req) != 0) + { + printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n"); + return -EIO; + } + while (!req.complete) + pmu_poll(); + timeout = 100000; + while (!req.complete) { + if (--timeout < 0) { + printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n"); + return -EIO; + } + udelay(10); + pmu_poll(); + } + + if (save_autopoll != 0) + pmu_autopoll(save_autopoll); + + return 0; +} + +/* Construct and send a pmu request */ +int +pmu_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i; + + if (nbytes < 0 || nbytes > 32) { + printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes); + req->complete = 1; + return -EINVAL; + } + req->nbytes = nbytes; + req->done = done; + va_start(list, nbytes); + for (i = 0; i < nbytes; ++i) + req->data[i] = va_arg(list, int); + va_end(list); + if (pmu_data_len[req->data[0]][1] != 0) { + req->reply[0] = ADB_RET_OK; + req->reply_len = 1; + } else + req->reply_len = 0; + req->reply_expected = 0; + return pmu_queue_request(req); +} + +static int +pmu_queue_request(struct adb_request *req) +{ + unsigned long flags; + int nsend; + + if (req->nbytes <= 0) { + req->complete = 1; + return 0; + } + nsend = pmu_data_len[req->data[0]][0]; + if (nsend >= 0 && req->nbytes != nsend + 1) { + req->complete = 1; + return -EINVAL; + } + + req->next = 0; + req->sent = 0; + req->complete = 0; + save_flags(flags); cli(); + + if (current_req != 0) { + last_req->next = req; + last_req = req; + } else { + current_req = req; + last_req = req; + if (pmu_state == idle) + pmu_start(); + } + + restore_flags(flags); + return 0; +} + +static void +send_byte(int x) +{ + via1[ACR] |= SR_CTRL; + via1[SR] = x; + via2[B] &= ~TREQ; /* assert TREQ */ +} + +static void +recv_byte() +{ + char c; + + via1[ACR] = (via1[ACR] | SR_EXT) & ~SR_OUT; + c = via1[SR]; /* resets SR */ + via2[B] &= ~TREQ; +} + +static void +pmu_start() +{ + unsigned long flags; + struct adb_request *req; + + /* assert pmu_state == idle */ + /* get the packet to send */ + save_flags(flags); cli(); + req = current_req; + if (req == 0 || pmu_state != idle + || (req->reply_expected && req_awaiting_reply)) + goto out; + + pmu_state = sending; + data_index = 1; + data_len = pmu_data_len[req->data[0]][0]; + + /* set the shift register to shift out and send a byte */ + send_byte(req->data[0]); + +out: + restore_flags(flags); +} + +void +pmu_poll() +{ + unsigned long cpu_flags; + + save_flags(cpu_flags); + cli(); + if (via1[IFR] & SR_INT) { + via1[IFR] = SR_INT; + pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL); + } + if (via1[IFR] & CB1_INT) { + via1[IFR] = CB1_INT; + pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL); + } + restore_flags(cpu_flags); +} + +static void +pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct adb_request *req; + int timeout, bite = 0; /* to prevent compiler warning */ + +#if 0 + printk("pmu_interrupt: irq %d state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n", + irq, pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending); +#endif + + if (irq == IRQ_MAC_ADB_CL) { /* CB1 interrupt */ + adb_int_pending = 1; + } else if (irq == IRQ_MAC_ADB_SR) { /* SR interrupt */ + if (via2[B] & TACK) { + printk(KERN_DEBUG "PMU: SR_INT but ack still high! (%x)\n", via2[B]); + } + + /* if reading grab the byte */ + if ((via1[ACR] & SR_OUT) == 0) bite = via1[SR]; + + /* reset TREQ and wait for TACK to go high */ + via2[B] |= TREQ; + timeout = 3200; + while (!(via2[B] & TACK)) { + if (--timeout < 0) { + printk(KERN_ERR "PMU not responding (!ack)\n"); + goto finish; + } + udelay(10); + } + + switch (pmu_state) { + case sending: + req = current_req; + if (data_len < 0) { + data_len = req->nbytes - 1; + send_byte(data_len); + break; + } + if (data_index <= data_len) { + send_byte(req->data[data_index++]); + break; + } + req->sent = 1; + data_len = pmu_data_len[req->data[0]][1]; + if (data_len == 0) { + pmu_state = idle; + current_req = req->next; + if (req->reply_expected) + req_awaiting_reply = req; + else + pmu_done(req); + } else { + pmu_state = reading; + data_index = 0; + reply_ptr = req->reply + req->reply_len; + recv_byte(); + } + break; + + case intack: + data_index = 0; + data_len = -1; + pmu_state = reading_intr; + reply_ptr = interrupt_data; + recv_byte(); + break; + + case reading: + case reading_intr: + if (data_len == -1) { + data_len = bite; + if (bite > 32) + printk(KERN_ERR "PMU: bad reply len %d\n", + bite); + } else { + reply_ptr[data_index++] = bite; + } + if (data_index < data_len) { + recv_byte(); + break; + } + + if (pmu_state == reading_intr) { + pmu_handle_data(interrupt_data, data_index, regs); + } else { + req = current_req; + current_req = req->next; + req->reply_len += data_index; + pmu_done(req); + } + pmu_state = idle; + + break; + + default: + printk(KERN_ERR "pmu_interrupt: unknown state %d?\n", + pmu_state); + } + } +finish: + if (pmu_state == idle) { + if (adb_int_pending) { + pmu_state = intack; + send_byte(PMU_INT_ACK); + adb_int_pending = 0; + } else if (current_req) { + pmu_start(); + } + } + +#if 0 + printk("pmu_interrupt: exit state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n", + pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending); +#endif +} + +static void +pmu_done(struct adb_request *req) +{ + req->complete = 1; + if (req->done) + (*req->done)(req); +} + +/* Interrupt data could be the result data from an ADB cmd */ +static void +pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) +{ + static int show_pmu_ints = 1; + + asleep = 0; + if (len < 1) { + adb_int_pending = 0; + return; + } + if (data[0] & PMU_INT_ADB) { + if ((data[0] & PMU_INT_ADB_AUTO) == 0) { + struct adb_request *req = req_awaiting_reply; + if (req == 0) { + printk(KERN_ERR "PMU: extra ADB reply\n"); + return; + } + req_awaiting_reply = 0; + if (len <= 2) + req->reply_len = 0; + else { + memcpy(req->reply, data + 1, len - 1); + req->reply_len = len - 1; + } + pmu_done(req); + } else { + adb_input(data+1, len-1, regs, 1); + } + } else { + if (data[0] == 0x08 && len == 3) { + /* sound/brightness buttons pressed */ + pmu_set_brightness(data[1] >> 3); + set_volume(data[2]); + } else if (show_pmu_ints + && !(data[0] == PMU_INT_TICK && len == 1)) { + int i; + printk(KERN_DEBUG "pmu intr"); + for (i = 0; i < len; ++i) + printk(" %.2x", data[i]); + printk("\n"); + } + } +} + +int backlight_level = -1; +int backlight_enabled = 0; + +#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) + +void +pmu_enable_backlight(int on) +{ + struct adb_request req; + + if (on) { + /* first call: get current backlight value */ + if (backlight_level < 0) { + switch(pmu_kind) { + case PMU_68K_V1: + case PMU_68K_V2: + pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); + while (!req.complete) + pmu_poll(); + printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]); + backlight_level = req.reply[1]; + break; + default: + backlight_enabled = 0; + return; + } + } + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, + LEVEL_TO_BRIGHT(backlight_level)); + while (!req.complete) + pmu_poll(); + } + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); + while (!req.complete) + pmu_poll(); + backlight_enabled = on; +} + +void +pmu_set_brightness(int level) +{ + int bright; + + backlight_level = level; + bright = LEVEL_TO_BRIGHT(level); + if (!backlight_enabled) + return; + if (bright_req_1.complete) + pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + bright); + if (bright_req_2.complete) + pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); +} + +void +pmu_enable_irled(int on) +{ + struct adb_request req; + + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED | + (on ? PMU_POW_ON : PMU_POW_OFF)); + while (!req.complete) + pmu_poll(); +} + +static void +set_volume(int level) +{ +} + +int +pmu_present(void) +{ + return (pmu_kind != PMU_UNKNOWN); +} + +#if 0 /* needs some work for 68K */ + +/* + * This struct is used to store config register values for + * PCI devices which may get powered off when we sleep. + */ +static struct pci_save { + u16 command; + u16 cache_lat; + u16 intr; +} *pbook_pci_saves; +static int n_pbook_pci_saves; + +static inline void __openfirmware +pbook_pci_save(void) +{ + int npci; + struct pci_dev *pd; + struct pci_save *ps; + + npci = 0; + for (pd = pci_devices; pd != NULL; pd = pd->next) + ++npci; + n_pbook_pci_saves = npci; + if (npci == 0) + return; + ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL); + pbook_pci_saves = ps; + if (ps == NULL) + return; + + for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) { + pci_read_config_word(pd, PCI_COMMAND, &ps->command); + pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); + pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); + ++ps; + --npci; + } +} + +static inline void __openfirmware +pbook_pci_restore(void) +{ + u16 cmd; + struct pci_save *ps = pbook_pci_saves; + struct pci_dev *pd; + int j; + + for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) { + if (ps->command == 0) + continue; + pci_read_config_word(pd, PCI_COMMAND, &cmd); + if ((ps->command & ~cmd) == 0) + continue; + switch (pd->hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + for (j = 0; j < 6; ++j) + pci_write_config_dword(pd, + PCI_BASE_ADDRESS_0 + j*4, + pd->resource[j].start); + pci_write_config_dword(pd, PCI_ROM_ADDRESS, + pd->resource[PCI_ROM_RESOURCE].start); + pci_write_config_word(pd, PCI_CACHE_LINE_SIZE, + ps->cache_lat); + pci_write_config_word(pd, PCI_INTERRUPT_LINE, + ps->intr); + pci_write_config_word(pd, PCI_COMMAND, ps->command); + break; + /* other header types not restored at present */ + } + } +} + +/* + * Put the powerbook to sleep. + */ +#define IRQ_ENABLE ((unsigned int *)0xf3000024) +#define MEM_CTRL ((unsigned int *)0xf8000070) + +int __openfirmware powerbook_sleep(void) +{ + int ret, i, x; + static int save_backlight; + static unsigned int save_irqen; + unsigned long msr; + unsigned int hid0; + unsigned long p, wait; + struct adb_request sleep_req; + + /* Notify device drivers */ + ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL); + if (ret & NOTIFY_STOP_MASK) + return -EBUSY; + + /* Sync the disks. */ + /* XXX It would be nice to have some way to ensure that + * nobody is dirtying any new buffers while we wait. */ + fsync_dev(0); + + /* Turn off the display backlight */ + save_backlight = backlight_enabled; + if (save_backlight) + pmu_enable_backlight(0); + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); + + /* Disable all interrupts except pmu */ + save_irqen = in_le32(IRQ_ENABLE); + for (i = 0; i < 32; ++i) + if (i != vias->intrs[0].line && (save_irqen & (1 << i))) + disable_irq(i); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* Save the state of PCI config space for some slots */ + pbook_pci_save(); + + /* Set the memory controller to keep the memory refreshed + while we're asleep */ + for (i = 0x403f; i >= 0x4000; --i) { + out_be32(MEM_CTRL, i); + do { + x = (in_be32(MEM_CTRL) >> 16) & 0x3ff; + } while (x == 0); + if (x >= 0x100) + break; + } + + /* Ask the PMU to put us to sleep */ + pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!sleep_req.complete) + mb(); + /* displacement-flush the L2 cache - necessary? */ + for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) + i = *(volatile int *)p; + asleep = 1; + + /* Put the CPU into sleep mode */ + asm volatile("mfspr %0,1008" : "=r" (hid0) :); + hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; + asm volatile("mtspr 1008,%0" : : "r" (hid0)); + save_flags(msr); + msr |= MSR_POW | MSR_EE; + restore_flags(msr); + udelay(10); + + /* OK, we're awake again, start restoring things */ + out_be32(MEM_CTRL, 0x3f); + pbook_pci_restore(); + + /* wait for the PMU interrupt sequence to complete */ + while (asleep) + mb(); + + /* reenable interrupts */ + for (i = 0; i < 32; ++i) + if (i != vias->intrs[0].line && (save_irqen & (1 << i))) + enable_irq(i); + + /* Notify drivers */ + notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); + + /* reenable ADB autopoll */ + pmu_adb_autopoll(adb_dev_map); + + /* Turn on the screen backlight, if it was on before */ + if (save_backlight) + pmu_enable_backlight(1); + + /* Wait for the hard disk to spin up */ + + return 0; +} + +/* + * Support for /dev/pmu device + */ +static int __openfirmware pmu_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t __openfirmware pmu_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t __openfirmware pmu_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +/* Note: removed __openfirmware here since it causes link errors */ +static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + int error; + __u32 value; + + switch (cmd) { + case PMU_IOC_SLEEP: + return -ENOSYS; + case PMU_IOC_GET_BACKLIGHT: + return put_user(backlight_level, (__u32 *)arg); + case PMU_IOC_SET_BACKLIGHT: + error = get_user(value, (__u32 *)arg); + if (!error) + pmu_set_brightness(value); + return error; + case PMU_IOC_GET_MODEL: + return put_user(pmu_kind, (__u32 *)arg); + } + return -EINVAL; +} + +static struct file_operations pmu_device_fops = { + NULL, /* no seek */ + pmu_read, + pmu_write, + NULL, /* no readdir */ + NULL, /* no poll yet */ + pmu_ioctl, + NULL, /* no mmap */ + pmu_open, + NULL, /* flush */ + NULL /* no release */ +}; + +static struct miscdevice pmu_device = { + PMU_MINOR, "pmu", &pmu_device_fops +}; + +void pmu_device_init(void) +{ + if (via) + misc_register(&pmu_device); +} +#endif /* CONFIG_PMAC_PBOOK */ + diff -u --recursive --new-file v2.3.44/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.3.44/linux/drivers/net/3c505.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/3c505.c Sun Feb 13 18:20:21 2000 @@ -101,6 +101,7 @@ #include #include #include +#include #include #include #include @@ -374,7 +375,7 @@ static inline void prime_rx(struct net_device *dev) { elp_device *adapter = dev->priv; - while (adapter->rx_active < ELP_RX_PCBS && dev->start) { + while (adapter->rx_active < ELP_RX_PCBS && test_bit(LINK_STATE_START, &dev->state)) { if (!start_receive(dev, &adapter->itx_pcb)) break; } @@ -672,23 +673,10 @@ elp_device *adapter; int timeout; - if (irq < 0 || irq > 15) { - printk("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq); - return; - } dev = dev_id; - - if (dev == NULL) { - printk("elp_interrupt(): irq %d for unknown device.\n", irq); - return; - } adapter = (elp_device *) dev->priv; - - if (dev->interrupt) { - printk("%s: re-entering the interrupt handler!\n", dev->name); - return; - } - dev->interrupt = 1; + + spin_lock(&adapter->lock); do { /* @@ -702,20 +690,19 @@ printk("%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr)); } - outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), - dev); + outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev); if (adapter->current_dma.direction) { dev_kfree_skb_irq(adapter->current_dma.skb); } else { struct sk_buff *skb = adapter->current_dma.skb; if (skb) { - if (adapter->current_dma.target) { - /* have already done the skb_put() */ - memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length); - } - skb->protocol = eth_type_trans(skb,dev); - adapter->stats.rx_bytes += skb->len; - netif_rx(skb); + if (adapter->current_dma.target) { + /* have already done the skb_put() */ + memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length); + } + skb->protocol = eth_type_trans(skb,dev); + adapter->stats.rx_bytes += skb->len; + netif_rx(skb); } } adapter->dmaing = 0; @@ -733,15 +720,14 @@ check_3c505_dma(dev); } - sti(); - /* * receive a PCB from the adapter */ timeout = jiffies + 3*HZ/100; while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) { if (receive_pcb(dev, &adapter->irx_pcb)) { - switch (adapter->irx_pcb.command) { + switch (adapter->irx_pcb.command) + { case 0: break; /* @@ -750,19 +736,15 @@ case 0xff: case CMD_RECEIVE_PACKET_COMPLETE: /* if the device isn't open, don't pass packets up the stack */ - if (dev->start == 0) + if (test_bit(LINK_STATE_START, &dev->state) == 0) break; - cli(); len = adapter->irx_pcb.data.rcv_resp.pkt_len; dlen = adapter->irx_pcb.data.rcv_resp.buf_len; if (adapter->irx_pcb.data.rcv_resp.timeout != 0) { - printk("%s: interrupt - packet not received correctly\n", dev->name); - sti(); + printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name); } else { if (elp_debug >= 3) { - sti(); printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen); - cli(); } if (adapter->irx_pcb.command == 0xff) { if (elp_debug >= 2) @@ -772,7 +754,6 @@ } else { receive_packet(dev, dlen); } - sti(); if (elp_debug >= 3) printk("%s: packet received\n", dev->name); } @@ -839,7 +820,7 @@ case CMD_TRANSMIT_PACKET_COMPLETE: if (elp_debug >= 3) printk("%s: interrupt - packet sent\n", dev->name); - if (dev->start == 0) + if (test_bit(LINK_STATE_START, &dev->state) == 0) break; switch (adapter->irx_pcb.data.xmit_resp.c_stat) { case 0xffff: @@ -851,8 +832,7 @@ printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name); break; } - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); break; /* @@ -875,7 +855,7 @@ /* * indicate no longer in interrupt routine */ - dev->interrupt = 0; + spin_unlock(&adapter->lock); } @@ -913,16 +893,6 @@ adapter_reset(dev); /* - * interrupt routine not entered - */ - dev->interrupt = 0; - - /* - * transmitter not busy - */ - dev->tbusy = 0; - - /* * no receive PCBs active */ adapter->rx_active = 0; @@ -931,6 +901,8 @@ adapter->send_pcb_semaphore = 0; adapter->rx_backlog.in = 0; adapter->rx_backlog.out = 0; + + spin_lock_init(&adapter->lock); /* * install our interrupt service routine @@ -1008,8 +980,8 @@ /* * device is now officially open! */ - dev->start = 1; + netif_wake_queue(dev); MOD_INC_USE_COUNT; return 0; /* Always succeed */ @@ -1085,6 +1057,25 @@ return TRUE; } +/* + * The upper layer thinks we timed out + */ + +static void elp_timeout(struct net_device *dev) +{ + unsigned long flags; + elp_device *adapter = dev->priv; + int stat; + + stat = inb_status(dev->base_addr); + printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command"); + if (elp_debug >= 1) + printk("%s: status %#02x\n", dev->name, stat); + dev->trans_start = jiffies; + adapter->stats.tx_dropped++; + netif_wake_queue(dev); +} + /****************************************************** * * start the transmitter @@ -1094,40 +1085,17 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) { - if (dev->interrupt) { - printk("%s: start_xmit aborted (in irq)\n", dev->name); - return 1; - } - + unsigned long flags; + elp_device *adapter = dev->priv; + + spin_lock_irqsave(&adapter->lock, flags); check_3c505_dma(dev); - /* - * if the transmitter is still busy, we have a transmit timeout... - */ - if (dev->tbusy) { - elp_device *adapter = dev->priv; - int tickssofar = jiffies - dev->trans_start; - int stat; - - if (tickssofar < 1000) - return 1; - - stat = inb_status(dev->base_addr); - printk("%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command"); - if (elp_debug >= 1) - printk("%s: status %#02x\n", dev->name, stat); - dev->trans_start = jiffies; - dev->tbusy = 0; - adapter->stats.tx_dropped++; - } - if (elp_debug >= 3) printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len); - if (test_and_set_bit(0, (void *) &dev->tbusy)) { - printk("%s: transmitter access conflict\n", dev->name); - return 1; - } + netif_stop_queue(dev); + /* * send the packet at skb->data for skb->len */ @@ -1135,7 +1103,7 @@ if (elp_debug >= 2) { printk("%s: failed to transmit packet\n", dev->name); } - dev->tbusy = 0; + spin_unlock_irqrestore(&adapter->lock, flags); return 1; } if (elp_debug >= 3) @@ -1147,7 +1115,8 @@ dev->trans_start = jiffies; prime_rx(dev); - + spin_unlock_irqrestore(&adapter->lock, flags); + netif_start_queue(dev); return 0; } @@ -1166,7 +1135,7 @@ /* If the device is closed, just return the latest stats we have, - we cannot ask from the adapter without interrupts */ - if (!dev->start) + if (!test_bit(LINK_STATE_START, &dev->state)) return &adapter->stats; /* send a get statistics command to the board */ @@ -1203,6 +1172,8 @@ if (elp_debug >= 3) printk("%s: request to close device\n", dev->name); + netif_stop_queue(dev); + /* Someone may request the device statistic information even when * the interface is closed. The following will update the statistics * structure in the driver, so we'll be able to give current statistics. @@ -1215,16 +1186,6 @@ outb_control(0, dev); /* - * flag transmitter as busy (i.e. not available) - */ - dev->tbusy = 1; - - /* - * indicate device is closed - */ - dev->start = 0; - - /* * release the IRQ */ free_irq(dev->irq, dev); @@ -1252,10 +1213,13 @@ elp_device *adapter = (elp_device *) dev->priv; struct dev_mc_list *dmi = dev->mc_list; int i; + unsigned long flags; if (elp_debug >= 3) printk("%s: request to set multicast list\n", dev->name); + spin_lock_irqsave(&adapter->lock, flags); + if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { /* send a "load multicast list" command to the board, max 10 addrs/cmd */ /* if num_addrs==0 the list will be cleared */ @@ -1291,9 +1255,13 @@ adapter->tx_pcb.length = 2; adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(dev, &adapter->tx_pcb)) + { + spin_unlock_irqrestore(&lp->lock, flags); printk("%s: couldn't send 82586 configure command\n", dev->name); + } else { int timeout = jiffies + TIMEOUT; + spin_unlock_irqrestore(&lp->lock, flags); while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout)); if (time_after_eq(jiffies, timeout)) TIMEOUT_MSG(__LINE__); @@ -1313,10 +1281,12 @@ /* * set ptrs to various functions */ - dev->open = elp_open; /* local */ - dev->stop = elp_close; /* local */ - dev->get_stats = elp_get_stats; /* local */ - dev->hard_start_xmit = elp_start_xmit; /* local */ + dev->open = elp_open; /* local */ + dev->stop = elp_close; /* local */ + dev->get_stats = elp_get_stats; /* local */ + dev->hard_start_xmit = elp_start_xmit; /* local */ + dev->tx_timeout = elp_timeout; /* local */ + dev->watchdog_timeo = 10*HZ; dev->set_multicast_list = elp_set_mc_list; /* local */ /* Setup the generic properties */ diff -u --recursive --new-file v2.3.44/linux/drivers/net/3c505.h linux/drivers/net/3c505.h --- v2.3.44/linux/drivers/net/3c505.h Thu Aug 13 10:03:00 1998 +++ linux/drivers/net/3c505.h Sun Feb 13 18:20:21 2000 @@ -289,4 +289,5 @@ unsigned int rx_active; /* number of receive PCBs */ volatile unsigned char hcr_val; /* what we think the HCR contains */ + spinlock_t lock; /* Interrupt v tx lock */ } elp_device; diff -u --recursive --new-file v2.3.44/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.3.44/linux/drivers/net/3c59x.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/3c59x.c Sun Feb 13 10:18:03 2000 @@ -403,8 +403,6 @@ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct net_device *next_module; - void *priv_addr; - dma_addr_t ring_dma; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; @@ -769,13 +767,11 @@ vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn; vp->pdev = pdev; - vp->priv_addr = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE - + sizeof(struct boom_tx_desc) * TX_RING_SIZE - + 15, &vp->ring_dma); - /* Make sure rings are 16 byte aligned. */ - vp->rx_ring = (void *)(((long)vp->priv_addr + 15) & ~15); + /* Makes sure rings are at least 16 byte aligned. */ + vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + &vp->rx_ring_dma); vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); - vp->rx_ring_dma = (vp->ring_dma + 15) & ~15; vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE; /* The lower four bits are the media type. */ @@ -2062,7 +2058,7 @@ kfree(root_vortex_dev); pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE - + 15, vp->priv_addr, vp->ring_dma); + + 15, vp->rx_ring, vp->rx_ring_dma); kfree(vp); root_vortex_dev = next_dev; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.3.44/linux/drivers/net/8139too.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/8139too.c Sun Feb 13 10:23:26 2000 @@ -0,0 +1,1812 @@ +/* + + 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. + + Copyright 2000 Jeff Garzik + Originally: Written 1997-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Contributors: + + Donald Becker - he wrote the original driver, kudos to him! + (but please don't e-mail him for support, this isn't his driver) + + Tigran Aivazian - bug fixes, skbuff free cleanup + + Martin Mares - suggestions for PCI cleanup + + David S. Miller - PCI DMA and softnet updates + +----------------------------------------------------------------------------- + + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the RealTek RTL8139 series, the RealTek +Fast Ethernet controllers for PCI and CardBus. This chip is used on many +low-end boards, sometimes with its markings changed. + + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS will assign the +PCI INTA signal to a (preferably otherwise unused) system IRQ line. + +III. Driver operation + +IIIa. Rx Ring buffers + +The receive unit uses a single linear ring buffer rather than the more +common (and more efficient) descriptor-based architecture. Incoming frames +are sequentially stored into the Rx region, and the host copies them into +skbuffs. + +Comment: While it is theoretically possible to process many frames in place, +any delay in Rx processing would cause us to drop frames. More importantly, +the Linux protocol stack is not designed to operate in this manner. + +IIIb. Tx operation + +The RTL8139 uses a fixed set of four Tx descriptors in register space. +In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux +aligns the IP header on word boundaries, and 14 byte ethernet header means +that almost all frames will need to be copied to an alignment buffer. + +IVb. References + +http://www.realtek.com.tw/cn/cn.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html + +IVc. Errata + +1) The RTL-8139 has a serious problem with motherboards which do +posted MMIO writes to PCI space. This driver works around the +problem by having an MMIO register write be immediately followed by +an MMIO register read. + +2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define RTL8139_VERSION "0.9.0" +#define RTL8139_MODULE_NAME "8139too" +#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION +#define PFX RTL8139_MODULE_NAME ": " + +#undef RTL8139_DEBUG /* define to 1 to enable copious debugging info */ + +#ifdef RTL8139_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define RTL8139_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ +#if RTL8139_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + + +#ifndef PCI_GET_DRIVER_DATA + #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) + #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) +#endif /* PCI_GET_DRIVER_DATA */ + + +/* A few user-configurable values. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Size of the in-memory receive ring. */ +#define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ +#define TX_BUF_SIZE 1536 + +/* PCI Tuning Parameters + Threshold is bytes transferred to chip before transmission starts. */ +#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ + +/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ +#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ +#define TX_DMA_BURST 4 /* Calculate as 16<if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ +}; + +MODULE_AUTHOR ("Jeff Garzik "); +MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); +MODULE_PARM (multicast_filter_limit, "i"); +MODULE_PARM (max_interrupt_work, "i"); +MODULE_PARM (debug, "i"); + +static int read_eeprom (void *ioaddr, int location, int addr_len); +static int rtl8139_open (struct net_device *dev); +static int mdio_read (struct net_device *dev, int phy_id, int location); +static void mdio_write (struct net_device *dev, int phy_id, int location, + int val); +static void rtl8139_timer (unsigned long data); +static void rtl8139_tx_timeout (struct net_device *dev); +static void rtl8139_init_ring (struct net_device *dev); +static int rtl8139_start_xmit (struct sk_buff *skb, + struct net_device *dev); +static void rtl8139_interrupt (int irq, void *dev_instance, + struct pt_regs *regs); +static int rtl8139_close (struct net_device *dev); +static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); +static inline u32 ether_crc (int length, unsigned char *data); +static void rtl8139_set_rx_mode (struct net_device *dev); + +/* read after write, to avoid rtl8139 bug w/ posted MMIO writes */ +#define RTL_W8(reg, val8) do { writeb (val8, ioaddr + reg); readb (ioaddr + reg); } while (0) +#define RTL_W16(reg, val16) do { writew (val16, ioaddr + reg); readw (ioaddr + reg); } while (0) +#define RTL_W32(reg, val32) do { writel (val32, ioaddr + reg); readl (ioaddr + reg); } while (0) +#define RTL_R8(reg) readb (ioaddr + reg) +#define RTL_R16(reg) readw (ioaddr + reg) +#define RTL_R32(reg) readl (ioaddr + reg) + + +static const char * __devinit rtl8139_name_from_chip (chip_t chip) +{ + int i; + + for (i = 0; i < arraysize (chip_info); i++) + if (chip == chip_info[i].chip) + return chip_info[i].name; + + return "unknown"; +} + + +static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) +{ + void *ioaddr = NULL; + u8 tmp8; + int rc; + u32 pio_start, pio_end, pio_flags; + u32 mmio_start, mmio_end, mmio_flags; + + DPRINTK ("ENTER\n"); + + assert (pdev != NULL); + assert (ioaddr_out != NULL); + + *ioaddr_out = NULL; + + pio_start = pci_resource_start (pdev, 0); + pio_end = pci_resource_end (pdev, 0); + pio_flags = pci_resource_flags (pdev, 0); + + mmio_start = pci_resource_start (pdev, 1); + mmio_end = pci_resource_end (pdev, 1); + mmio_flags = pci_resource_flags (pdev, 1); + + /* make sure PCI base addr 0 is PIO */ + if (pio_start == 0 || pio_end <= pio_start || + (!(pio_flags & IORESOURCE_IO))) { + printk (KERN_ERR PFX "no PIO resource, aborting\n"); + return -ENODEV; + } + + /* make sure PCI base addr 1 is MMIO */ + if (mmio_start == 0 || mmio_end <= mmio_start || + (!(mmio_flags & IORESOURCE_MEM))) { + printk (KERN_ERR PFX "no MMIO resource, aborting\n"); + return -ENODEV; + } + + /* make sure our PIO region in PCI space is available */ + if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { + printk (KERN_ERR PFX "no I/O resource available, aborting\n"); + return -EBUSY; + } + + /* make sure our MMIO region in PCI space is available */ + if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { + release_region (pio_start, RTL_IO_SIZE); + printk (KERN_ERR PFX "no mem resource available, aborting\n"); + return -EBUSY; + } + + /* enable device (incl. PCI PM wakeup), and bus-mastering */ + pci_enable_device (pdev); + pci_set_master (pdev); + + /* ioremap MMIO region */ + ioaddr = ioremap (mmio_start, RTL_IO_SIZE); + if (ioaddr == NULL) { + printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); + rc = -EIO; + goto err_out; + } + + /* Bring the chip out of low-power mode. */ + RTL_W8 (Config1, 0x00); + + /* make sure chip thinks PIO and MMIO are enabled */ + tmp8 = RTL_R8 (Config1); + if ((tmp8 & Cfg1_PIO) == 0) { + printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); + rc = -EIO; + goto err_out; + } + if ((tmp8 & Cfg1_MMIO) == 0) { + printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); + rc = -EIO; + goto err_out; + } + + /* sanity checks -- ensure PIO and MMIO registers agree */ + assert (inb (pio_start+Config0) == RTL_R8 (Config0)); + assert (inb (pio_start+Config1) == RTL_R8 (Config1)); + assert (inb (pio_start+TxConfig) == RTL_R8 (TxConfig)); + assert (inb (pio_start+RxConfig) == RTL_R8 (RxConfig)); + + DPRINTK ("EXIT, returning 0\n"); + *ioaddr_out = ioaddr; + return 0; + +err_out: + if (ioaddr) + iounmap (ioaddr); + release_region (pio_start, RTL_IO_SIZE); + release_mem_region (mmio_start, RTL_IO_SIZE); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + + +static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev; + struct rtl8139_private *tp; + int i, addr_len, option = -1; + void *ioaddr = NULL; + + DPRINTK ("ENTER\n"); + + assert (pdev != NULL); + assert (ent != NULL); + + i = rtl8139_init_pci (pdev, &ioaddr); + if (i < 0) { + DPRINTK ("EXIT, returning %d\n", i); + return i; + } + + assert (ioaddr != NULL); + + /* dev zeroed in init_etherdev */ + dev = init_etherdev (NULL, sizeof (*tp) + PRIV_ALIGN); + if (dev == NULL) { + iounmap (ioaddr); + printk (KERN_ERR PFX "unable to alloc new ethernet\n"); + DPRINTK ("EXIT, returning -ENOMEM\n"); + return -ENOMEM; + } + + addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; + for (i = 0; i < 3; i++) + ((u16 *) (dev->dev_addr))[i] = + le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); + + /* The Rtl8139-specific entries in the device structure. */ + dev->open = rtl8139_open; + dev->hard_start_xmit = rtl8139_start_xmit; + dev->stop = rtl8139_close; + dev->get_stats = rtl8139_get_stats; + dev->set_multicast_list = rtl8139_set_rx_mode; + dev->do_ioctl = mii_ioctl; + dev->tx_timeout = rtl8139_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + dev->irq = pdev->irq; + dev->base_addr = pci_resource_start (pdev, 1); + + dev->priv = tp = (void *) + (((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN); + + printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + dev->name, rtl8139_name_from_chip(ent->driver_data), + dev->base_addr, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + /* tp zeroed in init_etherdev */ + tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | RTL8139_CAPS; + tp->pci_dev = pdev; + tp->chip = ent->driver_data; + tp->mmio_addr = ioaddr; + tp->lock = SPIN_LOCK_UNLOCKED; + + PCI_SET_DRIVER_DATA (pdev, dev); + + tp->phys[0] = 32; + + /* Put the chip into low-power mode. */ + RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */ + RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + + /* The lower four bits are the media type. */ + if (option > 0) { + tp->full_duplex = (option & 0x200) ? 1 : 0; + tp->default_port = option & 15; + if (tp->default_port) + tp->medialock = 1; + } + + if (tp->full_duplex) { + printk (KERN_INFO + "%s: Media type forced to Full Duplex.\n", + dev->name); + mdio_write (dev, tp->phys[0], 4, 0x141); + tp->duplex_lock = 1; + } + + DPRINTK ("EXIT - returning 0\n"); + return 0; +} + + +static void __devexit rtl8139_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct rtl8139_private *np; + + DPRINTK ("ENTER\n"); + + assert (dev != NULL); + + np = (struct rtl8139_private *) (dev->priv); + assert (np != NULL); + + unregister_netdev (dev); + + iounmap (np->mmio_addr); + release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE); + release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE); + +#ifndef RTL8139_NDEBUG + /* poison memory before freeing */ + memset (dev, 0xC0, + sizeof (struct net_device) + + sizeof (struct rtl8139_private) + + PRIV_ALIGN); +#endif + + kfree (dev); + + DPRINTK ("EXIT\n"); +} + + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x08 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x00 +#define EE_WRITE_1 0x02 +#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ +#define EE_ENB (0x80 | EE_CS) + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. + */ + +#define eeprom_delay() readl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5) +#define EE_READ_CMD (6) +#define EE_ERASE_CMD (7) + +static int __devinit read_eeprom (void *ioaddr, int location, int addr_len) +{ + int i; + unsigned retval = 0; + void *ee_addr = ioaddr + Cfg9346; + int read_cmd = location | (EE_READ_CMD << addr_len); + + DPRINTK ("ENTER\n"); + + writeb (EE_ENB & ~EE_CS, ee_addr); + writeb (EE_ENB, ee_addr); + eeprom_delay (); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + writeb (EE_ENB | dataval, ee_addr); + eeprom_delay (); + writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay (); + } + writeb (EE_ENB, ee_addr); + eeprom_delay (); + + for (i = 16; i > 0; i--) { + writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay (); + retval = + (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 : + 0); + writeb (EE_ENB, ee_addr); + eeprom_delay (); + } + + /* Terminate the EEPROM access. */ + writeb (~EE_CS, ee_addr); + eeprom_delay (); + + DPRINTK ("EXIT - returning %d\n", retval); + return retval; +} + +/* MII serial management: mostly bogus for now. */ +/* Read and write the MII management registers using software-generated + serial MDIO protocol. + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues. */ +#define MDIO_DIR 0x80 +#define MDIO_DATA_OUT 0x04 +#define MDIO_DATA_IN 0x02 +#define MDIO_CLK 0x01 +#define MDIO_WRITE0 (MDIO_DIR) +#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) + +#define mdio_delay() readb(mdio_addr) + + +static char mii_2_8139_map[8] = { + BasicModeCtrl, + BasicModeStatus, + 0, + 0, + NWayAdvert, + NWayLPAR, + NWayExpansion, + 0 +}; + + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void mdio_sync (void *mdio_addr) +{ + int i; + + DPRINTK ("ENTER\n"); + + for (i = 32; i >= 0; i--) { + writeb (MDIO_WRITE1, mdio_addr); + mdio_delay (); + writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); + mdio_delay (); + } + + DPRINTK ("EXIT\n"); +} + + +static int mdio_read (struct net_device *dev, int phy_id, int location) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *mdio_addr = tp->mmio_addr + Config4; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + int i; + + DPRINTK ("ENTER\n"); + + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ + DPRINTK ("EXIT after directly using 8139 internal regs\n"); + return location < 8 && mii_2_8139_map[location] ? + readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; + } + mdio_sync (mdio_addr); + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; + + writeb (MDIO_DIR | dataval, mdio_addr); + mdio_delay (); + writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); + mdio_delay (); + } + + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + writeb (0, mdio_addr); + mdio_delay (); + retval = + (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 + : 0); + writeb (MDIO_CLK, mdio_addr); + mdio_delay (); + } + + DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); + return (retval >> 1) & 0xffff; +} + + +static void mdio_write (struct net_device *dev, int phy_id, int location, + int value) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *mdio_addr = tp->mmio_addr + Config4; + int mii_cmd = + (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int i; + + DPRINTK ("ENTER\n"); + + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ + if (location < 8 && mii_2_8139_map[location]) { + writew (value, + tp->mmio_addr + mii_2_8139_map[location]); + readw (tp->mmio_addr + mii_2_8139_map[location]); + } + DPRINTK ("EXIT after directly using 8139 internal regs\n"); + return; + } + mdio_sync (mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = + (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + writeb (dataval, mdio_addr); + mdio_delay (); + writeb (dataval | MDIO_CLK, mdio_addr); + mdio_delay (); + } + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + writeb (0, mdio_addr); + mdio_delay (); + writeb (MDIO_CLK, mdio_addr); + mdio_delay (); + } + + DPRINTK ("EXIT\n"); +} + + +static int rtl8139_open (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int i; + + DPRINTK ("ENTER\n"); + + MOD_INC_USE_COUNT; + + /* Soft reset the chip. */ + RTL_W8 (ChipCmd, CmdReset); + + if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) { + DPRINTK ("EXIT, returning -EBUSY\n"); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC, + &tp->tx_bufs_dma); + tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_LEN + 16, + &tp->rx_ring_dma); + if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { + free_irq(dev->irq, dev); + + if (tp->tx_bufs) + pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC, + tp->tx_bufs, tp->tx_bufs_dma); + if (tp->rx_ring) + pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16, + tp->rx_ring, tp->rx_ring_dma); + + DPRINTK ("EXIT, returning -ENOMEM\n"); + MOD_DEC_USE_COUNT; + return -ENOMEM; + + } + + rtl8139_init_ring (dev); + tp->full_duplex = tp->duplex_lock; + tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; + tp->rx_config = + (RX_FIFO_THRESH << 13) | + (RX_BUF_LEN_IDX << 11) | + (RX_DMA_BURST << 8); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) + if ((RTL_R8 (ChipCmd) & CmdReset) == 0) + break; + + RTL_W32 (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); + RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); + + /* Must enable Tx/Rx before setting transfer thresholds! */ + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + RTL_W32 (RxConfig, tp->rx_config); + RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000); + + /* Reset N-Way to chipset defaults */ + RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9)); + for (i = 1000; i > 0; i--) + if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0) + break; + + /* Set N-Way to sane defaults */ + RTL_W16 (FIFOTMS, 0x0000); + RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1); + RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); + + RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, 0x00); + + RTL_W32 (RxBuf, tp->rx_ring_dma); + + /* Start the chip's Tx and Rx process. */ + RTL_W32 (RxMissed, 0); + rtl8139_set_rx_mode (dev); + + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + + /* Enable all known interrupts by setting the interrupt mask. */ + RTL_W16 (IntrMask, + PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver + | TxErr | TxOK | RxErr | RxOK); + + DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" + " GP Pins %2.2x %s-duplex.\n", + dev->name, pci_resource_start (tp->pci_dev, 1), + dev->irq, RTL_R8 (GPPinData), + tp->full_duplex ? "full" : "half"); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer (&tp->timer); + tp->timer.expires = jiffies + 3 * HZ; + tp->timer.data = (unsigned long) dev; + tp->timer.function = &rtl8139_timer; + add_timer (&tp->timer); + + netif_start_queue (dev); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + +/* Start the hardware at open or resume. */ +static void rtl8139_hw_start (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int i; + + DPRINTK ("ENTER\n"); + + /* Soft reset the chip. */ + RTL_W8 (ChipCmd, CmdReset); + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) + if ((RTL_R8 (ChipCmd) & CmdReset) == 0) + break; + + /* Restore our idea of the MAC address. */ + RTL_W32 (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); + RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); + + /* Hmmm, do these belong here? */ + RTL_W8 (Cfg9346, 0x00); + tp->cur_rx = 0; + + /* Must enable Tx/Rx before setting transfer thresholds! */ + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + RTL_W32 (RxConfig, tp->rx_config); + /* Check this value: the documentation contradicts ifself. Is the + IFG correct with bit 28:27 zero, or with |0x03000000 ? */ + RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000); + + /* Reset N-Way to chipset defaults */ + RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9)); + for (i = 1000; i > 0; i--) + if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0) + break; + + /* Set N-Way to sane defaults */ + RTL_W16 (FIFOTMS, 0x0000); + RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1); + RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); + + /* check_duplex() here. */ + RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, 0x00); + + RTL_W32 (RxBuf, tp->rx_ring_dma); + /* Start the chip's Tx and Rx process. */ + RTL_W32 (RxMissed, 0); + rtl8139_set_rx_mode (dev); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + /* Enable all known interrupts by setting the interrupt mask. */ + RTL_W16 (IntrMask, + PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver + | TxErr | TxOK | RxErr | RxOK); + + netif_start_queue (dev); + + DPRINTK ("EXIT\n"); +} + + +#ifndef RTL_TUNE_TWISTER +static inline void rtl8139_tune_twister (struct net_device *dev, + struct rtl8139_private *tp) {} +#else +static void rtl8139_tune_twister (struct net_device *dev, + struct rtl8139_private *tp) +{ + int linkcase; + + DPRINTK ("ENTER\n"); + + /* This is a complicated state machine to configure the "twister" for + impedance/echos based on the cable length. + All of this is magic and undocumented. + */ + switch (tp->twistie) { + case 1: + if (RTL_R16 (CSCR) & CSCR_LinkOKBit) { + /* We have link beat, let us tune the twister. */ + RTL_W16 (CSCR, CSCR_LinkDownOffCmd); + tp->twistie = 2; /* Change to state 2. */ + next_tick = HZ / 10; + } else { + /* Just put in some reasonable defaults for when beat returns. */ + RTL_W16 (CSCR, CSCR_LinkDownCmd); + RTL_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */ + RTL_W32 (PARA78, PARA78_default); + RTL_W32 (PARA7c, PARA7c_default); + tp->twistie = 0; /* Bail from future actions. */ + } + break; + case 2: + /* Read how long it took to hear the echo. */ + linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits; + if (linkcase == 0x7000) + tp->twist_row = 3; + else if (linkcase == 0x3000) + tp->twist_row = 2; + else if (linkcase == 0x1000) + tp->twist_row = 1; + else + tp->twist_row = 0; + tp->twist_col = 0; + tp->twistie = 3; /* Change to state 2. */ + next_tick = HZ / 10; + break; + case 3: + /* Put out four tuning parameters, one per 100msec. */ + if (tp->twist_col == 0) + RTL_W16 (FIFOTMS, 0); + RTL_W32 (PARA7c, param[(int) tp->twist_row] + [(int) tp->twist_col]); + next_tick = HZ / 10; + if (++tp->twist_col >= 4) { + /* For short cables we are done. + For long cables (row == 3) check for mistune. */ + tp->twistie = + (tp->twist_row == 3) ? 4 : 0; + } + break; + case 4: + /* Special case for long cables: check for mistune. */ + if ((RTL_R16 (CSCR) & + CSCR_LinkStatusBits) == 0x7000) { + tp->twistie = 0; + break; + } else { + RTL_W32 (PARA7c, 0xfb38de03); + tp->twistie = 5; + next_tick = HZ / 10; + } + break; + case 5: + /* Retune for shorter cable (column 2). */ + RTL_W32 (FIFOTMS, 0x20); + RTL_W32 (PARA78, PARA78_default); + RTL_W32 (PARA7c, PARA7c_default); + RTL_W32 (FIFOTMS, 0x00); + tp->twist_row = 2; + tp->twist_col = 0; + tp->twistie = 3; + next_tick = HZ / 10; + break; + + default: + /* do nothing */ + break; + } + + DPRINTK ("EXIT\n"); +} +#endif /* RTL_TUNE_TWISTER */ + + +static void rtl8139_timer (unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int next_tick = 60 * HZ; + int mii_reg5 = mdio_read (dev, tp->phys[0], 5); + + DPRINTK ("ENTER\n"); + + if (!tp->duplex_lock && mii_reg5 != 0xffff) { + int duplex = (mii_reg5 & 0x0100) + || (mii_reg5 & 0x01C0) == 0x0040; + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + printk (KERN_INFO + "%s: Setting %s-duplex based on MII #%d link" + " partner ability of %4.4x.\n", dev->name, + tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, 0x00); + } + } + + rtl8139_tune_twister (dev, tp); + + DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", + dev->name, RTL_R16 (NWayLPAR)); + DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" + " RxStatus %4.4x.\n", dev->name, + RTL_R16 (IntrMask), + RTL_R16 (IntrStatus), + RTL_R32 (RxEarlyStatus)); + DPRINTK ("%s: Chip config %2.2x %2.2x.\n", + dev->name, RTL_R8 (Config0), + RTL_R8 (Config1)); + + tp->timer.expires = jiffies + next_tick; + add_timer (&tp->timer); + + DPRINTK ("EXIT\n"); +} + + +static void rtl8139_tx_timeout (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int mii_reg, i; + + DPRINTK ("ENTER\n"); + + netif_stop_queue (dev); + + DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " + "media %2.2x.\n", dev->name, + readb (ioaddr + ChipCmd), + readw (ioaddr + IntrStatus), + readb (ioaddr + GPPinData)); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0x0000); + /* Emit info to figure out what went wrong. */ + printk (KERN_DEBUG + "%s: Tx queue start entry %d dirty entry %d.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + for (i = 0; i < NUM_TX_DESC; i++) + printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n", + dev->name, i, readl (ioaddr + TxStatus0 + i * 4), + i == + tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); + printk (KERN_DEBUG "%s: MII #%d registers are:", dev->name, + tp->phys[0]); + for (mii_reg = 0; mii_reg < 8; mii_reg++) + printk (" %4.4x", mdio_read (dev, tp->phys[0], mii_reg)); + printk (".\n"); + + /* Stop a shared interrupt from scavenging while we are. */ + tp->dirty_tx = tp->cur_tx = 0; + + /* Dump the unsent Tx packets. */ + for (i = 0; i < NUM_TX_DESC; i++) { + struct ring_info *rp = &tp->tx_info[i]; + if (rp->skb) { + dev_kfree_skb (rp->skb); + rp->skb = NULL; + tp->stats.tx_dropped++; + } + if (rp->mapping != 0) { + pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len); + rp->mapping = 0; + } + } + + rtl8139_hw_start (dev); + + DPRINTK ("EXIT\n"); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void rtl8139_init_ring (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + int i; + + DPRINTK ("ENTER\n"); + + tp->cur_rx = 0; + tp->dirty_tx = tp->cur_tx = 0; + + for (i = 0; i < NUM_TX_DESC; i++) { + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; + tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; + } + + DPRINTK ("EXIT\n"); +} + +static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int entry; + unsigned long flags; + + DPRINTK ("ENTER\n"); + + netif_stop_queue (dev); + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % NUM_TX_DESC; + + spin_lock_irqsave (&tp->lock, flags); + + tp->tx_info[entry].skb = skb; + if ((long) skb->data & 3) { /* Must use alignment buffer. */ + tp->tx_info[entry].mapping = 0; + memcpy (tp->tx_buf[entry], skb->data, skb->len); + + assert (tp->tx_bufs_dma > 0); + RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); + } else { + tp->tx_info[entry].mapping = + pci_map_single(tp->pci_dev, skb->data, skb->len); + + assert (tp->tx_info[entry].mapping > 0); + RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping); + } + + /* Note: the chip doesn't have auto-pad! */ + RTL_W32 (TxStatus0 + entry * 4, + tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + + dev->trans_start = jiffies; + if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */ + netif_start_queue (dev); + + spin_unlock_irqrestore (&tp->lock, flags); + + DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n", + dev->name, skb->data, skb->len, entry); + + DPRINTK ("EXIT\n"); + return 0; +} + + +static inline void rtl8139_tx_interrupt (struct net_device *dev, + struct rtl8139_private *tp) +{ + void *ioaddr; + unsigned int dirty_tx; + + assert (dev != NULL); + assert (tp != NULL); + + dirty_tx = tp->dirty_tx; + ioaddr = tp->mmio_addr; + + while (tp->cur_tx - dirty_tx > 0) { + int entry = dirty_tx % NUM_TX_DESC; + int txstatus = readl (ioaddr + TxStatus0 + entry * 4); + + if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) + break; /* It still hasn't been Txed */ + + /* Note: TxCarrierLost is always asserted at 100mbps. */ + if (txstatus & (TxOutOfWindow | TxAborted)) { + /* There was an major error, log it. */ + DPRINTK ("%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); + tp->stats.tx_errors++; + if (txstatus & TxAborted) { + tp->stats.tx_aborted_errors++; + RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x03000001); + } + if (txstatus & TxCarrierLost) + tp->stats.tx_carrier_errors++; + if (txstatus & TxOutOfWindow) + tp->stats.tx_window_errors++; +#ifdef ETHER_STATS + if ((txstatus & 0x0f000000) == 0x0f000000) + tp->stats.collisions16++; +#endif + } else { + if (txstatus & TxUnderrun) { + /* Add 64 to the Tx FIFO threshold. */ + if (tp->tx_flag < 0x00300000) + tp->tx_flag += 0x00020000; + tp->stats.tx_fifo_errors++; + } + tp->stats.collisions += (txstatus >> 24) & 15; + tp->stats.tx_bytes += txstatus & 0x7ff; + tp->stats.tx_packets++; + } + + if (tp->tx_info[entry].mapping != 0) { + pci_unmap_single (tp->pci_dev, + tp->tx_info[entry].mapping, + tp->tx_info[entry].skb->len); + tp->tx_info[entry].mapping = 0; + } + /* Free the original skb. */ + dev_kfree_skb_irq (tp->tx_info[entry].skb); + tp->tx_info[entry].skb = NULL; + dirty_tx++; + if (tp->cur_tx - dirty_tx < NUM_TX_DESC) + netif_wake_queue (dev); + else + netif_stop_queue (dev); + } + +#ifndef RTL8139_NDEBUG + if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { + printk (KERN_ERR + "%s: Out-of-sync dirty pointer, %d vs. %d.\n", + dev->name, dirty_tx, tp->cur_tx); + dirty_tx += NUM_TX_DESC; + } +#endif + + tp->dirty_tx = dirty_tx; +} + + +/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the + field alignments and semantics. */ +static inline void rtl8139_rx_interrupt (struct net_device *dev, + struct rtl8139_private *tp) +{ + void *ioaddr = tp->mmio_addr; + unsigned char *rx_ring = tp->rx_ring; + u16 cur_rx = tp->cur_rx; + + DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," + " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + readw (ioaddr + RxBufAddr), + readw (ioaddr + RxBufPtr), + readb (ioaddr + ChipCmd)); + + while ((readb (ioaddr + ChipCmd) & RxBufEmpty) == 0) { + int ring_offset = cur_rx % RX_BUF_LEN; + u32 rx_status = + le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); + int rx_size = rx_status >> 16; + +#ifdef RTL8139_DEBUG + int i; + DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," + " cur %4.4x.\n", dev->name, rx_status, + rx_size, cur_rx); + DPRINTK ("%s: Frame contents ", dev->name); + for (i = 0; i < 70; i++) + printk (" %2.2x", rx_ring[ring_offset + i]); + printk (".\n"); +#endif + + if (rx_status & + (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | + RxBadAlign)) { + DPRINTK ("%s: Ethernet frame had errors," + " status %8.8x.\n", dev->name, + rx_status); + if (rx_status & RxTooLong) { + DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", + dev->name, rx_status); + /* A.C.: The chip hangs here. */ + } + tp->stats.rx_errors++; + if (rx_status & (RxBadSymbol | RxBadAlign)) + tp->stats.rx_frame_errors++; + if (rx_status & (RxRunt | RxTooLong)) + tp->stats.rx_length_errors++; + if (rx_status & RxCRCErr) + tp->stats.rx_crc_errors++; + /* Reset the receiver, based on RealTek recommendation. (Bug?) */ + tp->cur_rx = 0; + RTL_W8 (ChipCmd, CmdTxEnb); + /* A.C.: Reset the multicast list. */ + rtl8139_set_rx_mode (dev); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + } else { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + struct sk_buff *skb; + + skb = dev_alloc_skb (rx_size + 2); + if (skb == NULL) { + printk (KERN_WARNING + "%s: Memory squeeze, deferring packet.\n", + dev->name); + /* We should check that some rx space is free. + If not, free one and mark stats->rx_dropped++. */ + tp->stats.rx_dropped++; + break; + } + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + if (ring_offset + rx_size + 4 > RX_BUF_LEN) { + int semi_count = + RX_BUF_LEN - ring_offset - 4; + /* This could presumably use two calls to copy_and_sum()? */ + memcpy (skb_put (skb, semi_count), + &rx_ring[ring_offset + 4], + semi_count); + memcpy (skb_put + (skb, rx_size - semi_count), + rx_ring, rx_size - semi_count); +#ifdef RTL8139_DEBUG + { + int i; + printk (KERN_DEBUG + "%s: Frame wrap @%d", + dev->name, semi_count); + for (i = 0; i < 16; i++) + printk (" %2.2x", + rx_ring[i]); + printk (".\n"); + memset (rx_ring, 0xcc, 16); + } +#endif /* RTL8139_DEBUG */ + + } else { + eth_copy_and_sum (skb, + &rx_ring[ring_offset + + 4], rx_size, 0); + skb_put (skb, rx_size); + } + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); + tp->stats.rx_bytes += rx_size; + tp->stats.rx_packets++; + } + + cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; + RTL_W16 (RxBufPtr, cur_rx - 16); + } + DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," + " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + readw (ioaddr + RxBufAddr), + readw (ioaddr + RxBufPtr), + readb (ioaddr + ChipCmd)); + tp->cur_rx = cur_rx; +} + + +static inline int rtl8139_weird_interrupt (struct net_device *dev, + struct rtl8139_private *tp, + int status, int link_changed) +{ + void *ioaddr; + + DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); + + assert (dev != NULL); + assert (tp != NULL); + + ioaddr = tp->mmio_addr; + + if (status == 0xffffffff) { + printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n"); + return -1; + } + + /* Update the error count. */ + tp->stats.rx_missed_errors += + readl (ioaddr + RxMissed); + RTL_W32 (RxMissed, 0); + + if ((status & RxUnderrun) && link_changed && + (tp->drv_flags & HAS_LNK_CHNG)) { + /* Really link-change on new chips. */ + int lpar = readw (ioaddr + NWayLPAR); + int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040 + || tp->duplex_lock; + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); + RTL_W8 (Cfg9346, 0x00); + } + status &= ~RxUnderrun; + } + if (status & + (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) + tp->stats.rx_errors++; + + if (status & (PCSTimeout)) + tp->stats.rx_length_errors++; + if (status & (RxUnderrun | RxFIFOOver)) + tp->stats.rx_fifo_errors++; + if (status & RxOverflow) { + tp->stats.rx_over_errors++; + tp->cur_rx = readw (ioaddr + RxBufAddr) % RX_BUF_LEN; + RTL_W16 (RxBufPtr, tp->cur_rx - 16); + } + if (status & PCIErr) { + u16 pci_cmd_status; + pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); + + printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", + dev->name, pci_cmd_status); + } + + return 0; +} + + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void rtl8139_interrupt (int irq, void *dev_instance, + struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_instance; + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + int boguscnt = max_interrupt_work; + void *ioaddr = tp->mmio_addr; + int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */ + + spin_lock_irq (&tp->lock); + + do { + int status = readw (ioaddr + IntrStatus); + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if (status & RxUnderrun) + link_changed = readw (ioaddr + CSCR) & CSCR_LinkChangeBit; + RTL_W16 (IntrStatus, status); + + DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", + dev->name, status, + readw (ioaddr + IntrStatus)); + + if ((status & + (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | + RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) + break; + + /* Check uncommon events with one test. */ + if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | + RxFIFOOver | TxErr | RxErr)) + if (rtl8139_weird_interrupt (dev, tp, status, + link_changed) == -1) + break; + + if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ + rtl8139_rx_interrupt (dev, tp); + + if (status & (TxOK | TxErr)) + rtl8139_tx_interrupt (dev, tp); + + if (--boguscnt < 0) { + printk (KERN_WARNING + "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", dev->name, + status); + /* Clear all interrupt sources. */ + RTL_W16 (IntrStatus, 0xffff); + break; + } + } while (1); + + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, readw (ioaddr + IntrStatus)); + + spin_unlock_irq (&tp->lock); + return; +} + +static int rtl8139_close (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + int i; + + DPRINTK ("ENTER\n"); + + netif_stop_queue (dev); + + DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, readw (ioaddr + IntrStatus)); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 (IntrMask, 0x0000); + + /* Stop the chip's Tx and Rx DMA processes. */ + RTL_W8 (ChipCmd, 0x00); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + + del_timer (&tp->timer); + + free_irq (dev->irq, dev); + + for (i = 0; i < NUM_TX_DESC; i++) { + struct sk_buff *skb = tp->tx_info[i].skb; + dma_addr_t mapping = tp->tx_info[i].mapping; + + if (skb) { + if (mapping) + pci_unmap_single (tp->pci_dev, mapping, skb->len); + dev_kfree_skb (skb); + } + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; + } + + pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16, + tp->rx_ring, tp->rx_ring_dma); + pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC, + tp->tx_bufs, tp->tx_bufs_dma); + tp->rx_ring = NULL; + tp->tx_bufs = NULL; + + /* Green! Put the chip in low-power mode. */ + RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Config1, 0x03); + RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + + MOD_DEC_USE_COUNT; + + DPRINTK ("EXIT\n"); + return 0; +} + +static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + u16 *data = (u16 *) & rq->ifr_data; + + DPRINTK ("ENTER\n"); + + switch (cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = tp->phys[0] & 0x3f; + /* Fall Through */ + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + data[3] = mdio_read (dev, data[0], data[1] & 0x1f); + DPRINTK ("EXIT\n"); + return 0; + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ + if (!capable (CAP_NET_ADMIN)) + return -EPERM; + mdio_write (dev, data[0], data[1] & 0x1f, data[2]); + DPRINTK ("EXIT\n"); + return 0; + default: + DPRINTK ("EXIT\n"); + return -EOPNOTSUPP; + } + + DPRINTK ("EXIT\n"); +} + +static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + + DPRINTK ("ENTER\n"); + + assert (tp != NULL); + + if (test_bit(LINK_STATE_START, &dev->state)) { + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); + } + + DPRINTK ("EXIT\n"); + return &tp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + This routine is not state sensitive and need not be SMP locked. */ + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc (int length, unsigned char *data) +{ + int crc = -1; + + DPRINTK ("ENTER\n"); + + while (--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? + ethernet_polynomial : 0); + } + + DPRINTK ("EXIT\n"); + return crc; +} + +static void rtl8139_set_rx_mode (struct net_device *dev) +{ + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + u32 mc_filter[2]; /* Multicast hash filter */ + int i, rx_mode; + + DPRINTK ("ENTER\n"); + + DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", + dev->name, dev->flags, readl (ioaddr + RxConfig)); + + /* Note: do not reorder, GCC is clever about common statements. */ + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); + rx_mode = + AcceptBroadcast | AcceptMulticast | AcceptMyPhys | + AcceptAllPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else { + struct dev_mc_list *mclist; + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; + mclist && i < dev->mc_count; + i++, mclist = + mclist->next) set_bit (ether_crc (ETH_ALEN, + mclist-> + dmi_addr) >> 26, + mc_filter); + } + /* We can safely update without stopping the chip. */ + RTL_W32 (RxConfig, tp->rx_config | rx_mode); + RTL_W32 (MAR0 + 0, mc_filter[0]); + RTL_W32 (MAR0 + 4, mc_filter[1]); + + DPRINTK ("EXIT\n"); +} + + +static void rtl8139_suspend (struct pci_dev *pdev) +{ + struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; + + netif_stop_queue (dev); + + /* Disable interrupts, stop Tx and Rx. */ + RTL_W16 (IntrMask, 0x0000); + RTL_W8 (ChipCmd, 0x00); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); + RTL_W32 (RxMissed, 0); +} + + +static void rtl8139_resume (struct pci_dev *pdev) +{ + struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + + rtl8139_hw_start(dev); +} + + +static struct pci_driver rtl8139_pci_driver = { + name: RTL8139_MODULE_NAME, + id_table: rtl8139_pci_tbl, + probe: rtl8139_init_one, + remove: rtl8139_remove_one, + suspend: rtl8139_suspend, + resume: rtl8139_resume, +}; + + +static int __init rtl8139_init_module (void) +{ + int rc; + + DPRINTK ("ENTER\n"); + + rc = pci_register_driver (&rtl8139_pci_driver); + + if (rc > 0) { + printk (KERN_INFO RTL8139_DRIVER_NAME + " loaded (%d device%s registered)\n", + rc, rc > 1 ? "s" : ""); + } + + DPRINTK ("EXIT\n"); + return rc > 0 ? 0 : -ENODEV; +} + + +static void __exit rtl8139_cleanup_module (void) +{ + pci_unregister_driver (&rtl8139_pci_driver); +} + + +module_init(rtl8139_init_module); +module_exit(rtl8139_cleanup_module); diff -u --recursive --new-file v2.3.44/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.44/linux/drivers/net/Config.in Thu Feb 10 17:11:09 2000 +++ linux/drivers/net/Config.in Sun Feb 13 18:47:31 2000 @@ -73,7 +73,9 @@ fi tristate ' SMC Ultra support' CONFIG_ULTRA tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 - tristate ' SMC 9194 support' CONFIG_SMC9194 + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' SMC 9194 support' CONFIG_SMC9194 + fi fi bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then @@ -83,10 +85,6 @@ tristate ' NI5210 support' CONFIG_NI52 tristate ' NI6510 support' CONFIG_NI65 fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139 - tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 - fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700 fi @@ -94,18 +92,22 @@ bool ' Other ISA cards' CONFIG_NET_ISA if [ "$CONFIG_NET_ISA" = "y" ]; then tristate ' Cabletron E21xx support' CONFIG_E2100 - tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3 + fi tristate ' EtherExpress 16 support' CONFIG_EEXPRESS tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO - tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X + fi tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I fi tristate ' NE2000/NE1000 support' CONFIG_NE2000 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_OBSOLETE" = "y" ]; then tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 fi bool ' SK_G16 support' CONFIG_SK_G16 @@ -114,8 +116,8 @@ tristate ' SKnet MCA support' CONFIG_SKMC tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA fi - bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA - if [ "$CONFIG_NET_EISA" = "y" ]; then + bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI + if [ "$CONFIG_NET_PCI" = "y" ]; then tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE @@ -125,10 +127,15 @@ fi tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT - tristate ' CS89x0 support' CONFIG_CS89x0 + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' CS89x0 support' CONFIG_CS89x0 + fi tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 + fi tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 @@ -136,18 +143,24 @@ fi tristate ' PCI NE2000 support' CONFIG_NE2K_PCI # tristate ' Sundance Alta support' CONFIG_ALTA + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 + fi + tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 tristate ' TI ThunderLAN support' CONFIG_TLAN tristate ' VIA Rhine support' CONFIG_VIA_RHINE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 tristate ' SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 + fi + if [ "$CONFIG_OBSOLETE" = "y" ]; then bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi fi bool ' Pocket and portable adapters' CONFIG_NET_POCKET if [ "$CONFIG_NET_POCKET" = "y" ]; then - bool ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP + tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600 tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620 fi @@ -234,7 +247,9 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET - tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN + fi tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500 dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500 diff -u --recursive --new-file v2.3.44/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.44/linux/drivers/net/Makefile Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/Makefile Sun Feb 13 10:23:26 2000 @@ -228,7 +228,8 @@ obj-$(CONFIG_3C515) += 3c515.o obj-$(CONFIG_EEXPRESS) += eexpress.o obj-$(CONFIG_EEXPRESS_PRO) += eepro.o -obj-$(CONFIG_RTL8139) += rtl8139.o +obj-$(CONFIG_RTL8129) += rtl8129.o +obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o obj-$(CONFIG_ZNET) += znet.o diff -u --recursive --new-file v2.3.44/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.3.44/linux/drivers/net/a2065.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/a2065.c Sun Feb 13 10:42:42 2000 @@ -164,7 +164,6 @@ #define ZERO 0 /* Setup the Lance Rx and Tx rings */ -/* Sets dev->tbusy */ static void lance_init_ring (struct net_device *dev) { struct lance_private *lp = (struct lance_private *) dev->priv; @@ -176,7 +175,7 @@ aib = lp->lance_init_block; /* Lock out other processes while setting up hardware */ - dev->tbusy = 1; + netif_stop_queue(dev); lp->rx_new = lp->tx_new = 0; lp->rx_old = lp->tx_old = 0; @@ -442,11 +441,6 @@ if (!(csr0 & LE_C0_INTR)) /* Check if any interrupt has */ return; /* been generated by the Lance. */ - if (dev->interrupt) - printk ("%s: again", dev->name); - - dev->interrupt = 1; - /* Acknowledge all the interrupt sources ASAP */ ll->rdp = csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT| LE_C0_INIT); @@ -473,15 +467,14 @@ ll->rdp = LE_C0_STRT; } - if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { - dev->tbusy = 0; - mark_bh (NET_BH); - } + if (test_bit(LINK_STATE_XOFF, &dev->state) && + TX_BUFFS_AVAIL > 0) + netif_wake_queue(dev); + ll->rap = LE_CSR0; ll->rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR| LE_C0_IDON|LE_C0_INEA; - dev->interrupt = 0; } struct net_device *last_dev = 0; @@ -506,9 +499,7 @@ load_csrs (lp); lance_init_ring (dev); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); status = init_restart_lance (lp); @@ -522,9 +513,8 @@ struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_regs *ll = lp->ll; - dev->start = 0; - dev->tbusy = 1; - del_timer(&lp->multicast_timer); + netif_stop_queue(dev); + del_timer_sync(&lp->multicast_timer); /* Stop the card */ ll->rap = LE_CSR0; @@ -548,11 +538,11 @@ ll->rdp = LE_C0_STOP; load_csrs (lp); + lance_init_ring (dev); dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; - dev->tbusy = 0; + netif_start_queue(dev); + status = init_restart_lance (lp); #ifdef DEBUG_DRIVER printk ("Lance restart=%d\n", status); @@ -560,6 +550,17 @@ return status; } +static void lance_tx_timeout(struct net_device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; + + printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", + dev->name, ll->rdp); + lance_reset(dev); + netif_wake_queue(dev); +} + static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = (struct lance_private *)dev->priv; @@ -570,26 +571,6 @@ static int outs; unsigned long flags; - /* Transmitter timeout, serious problems */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - - if (tickssofar < 100) { - status = -1; - } else { - printk ("%s: transmit timed out, status %04x, resetting\n", - dev->name, ll->rdp); - lance_reset (dev); - } - return status; - } - - /* Block a timer-based transmit from overlapping. */ - if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) { - printk ("Transmitter access conflict.\n"); - return -1; - } - skblen = skb->len; save_flags(flags); @@ -628,13 +609,15 @@ lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; outs++; + + if (TX_BUFFS_AVAIL <= 0) + netif_stop_queue(dev); + /* Kick the lance: transmit now */ ll->rdp = LE_C0_INEA | LE_C0_TDMD; dev->trans_start = jiffies; dev_kfree_skb (skb); - if (TX_BUFFS_AVAIL) - dev->tbusy = 0; restore_flags(flags); return status; @@ -704,21 +687,17 @@ volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; - if (!dev->start) + if (!test_bit(LINK_STATE_START, &dev->state)) return; - if (dev->tbusy) { - mod_timer(&lp->multicast_timer, jiffies + 2); - return; - } - set_bit (0, (void *) &dev->tbusy); - if (lp->tx_old != lp->tx_new) { mod_timer(&lp->multicast_timer, jiffies + 4); - dev->tbusy = 0; + netif_wake_queue(dev); return; } + netif_stop_queue(dev); + ll->rap = LE_CSR0; ll->rdp = LE_C0_STOP; lance_init_ring (dev); @@ -731,14 +710,19 @@ } load_csrs (lp); init_restart_lance (lp); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); } -int __init a2065_probe(struct net_device *dev) +static int __init a2065_probe(void) { + struct net_device *dev = NULL; + static int called = 0; struct zorro_dev *z = NULL; + if (called) + return -ENODEV; + called++; + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { unsigned long board, base_addr, ram_start; int is_cbm; @@ -765,6 +749,18 @@ continue; } strcpy(z->name, "A2065 Ethernet Card"); + + dev = init_etherdev(NULL, sizeof(struct lance_private)); + + if (dev == NULL) { + release_mem_region(base_addr, + sizeof(struct lance_regs)); + release_mem_region(ram_start, A2065_RAM_SIZE); + return -ENOMEM; + } + priv = (struct lance_private *)dev->priv; + memset(priv, 0, sizeof(struct lance_private)); + if (is_cbm) { /* Commodore */ dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x80; @@ -782,18 +778,6 @@ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - init_etherdev(dev, 0); - - dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL); - if (dev->priv == NULL) { - release_mem_region(base_addr, - sizeof(struct lance_regs)); - release_mem_region(ram_start, A2065_RAM_SIZE); - return -ENOMEM; - } - priv = (struct lance_private *)dev->priv; - memset(priv, 0, sizeof(struct lance_private)); - dev->base_addr = ZTWO_VADDR(base_addr); dev->mem_start = ZTWO_VADDR(ram_start); dev->mem_end = dev->mem_start+A2065_RAM_SIZE; @@ -812,6 +796,8 @@ dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; + dev->tx_timeout = &lance_tx_timeout; + dev->watchdog_timeo = 5*HZ; dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; dev->dma = 0; @@ -828,31 +814,9 @@ } -#ifdef MODULE -static char devicename[9] = { 0, }; - -static struct net_device a2065_dev = -{ - devicename, /* filled in by register_netdev() */ - 0, 0, 0, 0, /* memory */ - 0, 0, /* base, irq */ - 0, 0, 0, NULL, a2065_probe, -}; - -int init_module(void) -{ - int err; - - if ((err = register_netdev(&a2065_dev))) { - if (err == -EIO) - printk("No A2065 board found. Module not loaded.\n"); - return(err); - } - return(0); -} - -void cleanup_module(void) +static void __exit a2065_cleanup(void) { +#ifdef MODULE struct lance_private *priv = (struct lance_private *)a2065_dev.priv; unregister_netdev(&a2065_dev); @@ -860,6 +824,8 @@ sizeof(struct lance_regs)); release_mem_region(ZTWO_PADDR(a2065_dev.mem_start), A2065_RAM_SIZE); kfree(priv); +#endif } -#endif /* MODULE */ +module_init(a2065_probe); +module_exit(a2065_cleanup); diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/arc-rimi.c linux/drivers/net/arcnet/arc-rimi.c --- v2.3.44/linux/drivers/net/arcnet/arc-rimi.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/arc-rimi.c Sun Feb 13 10:38:11 2000 @@ -2,7 +2,7 @@ * Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards * * Written 1994-1999 by Avery Pennarun. - * Written 1999 by Martin Mares . + * Written 1999-2000 by Martin Mares . * Derived from skeleton.c by Donald Becker. * * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) @@ -325,20 +325,11 @@ { struct net_device *dev = my_dev; struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - void *ioaddr = lp->mem_start + 0x800; - - if (dev->start) - dev->stop(dev); - - /* Flush TX and disable RX */ - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ + unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(lp->mem_start); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - unregister_netdev(dev); kfree(dev->priv); kfree(dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c --- v2.3.44/linux/drivers/net/arcnet/arcnet.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/arcnet.c Sun Feb 13 10:38:11 2000 @@ -3,7 +3,7 @@ * * Written 1997 by David Woodhouse. * Written 1994-1999 by Avery Pennarun. - * Written 1999 by Martin Mares . + * Written 1999-2000 by Martin Mares . * Derived from skeleton.c by Donald Becker. * * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) @@ -41,7 +41,7 @@ * */ -#define VERSION "arcnet: v3.91 BETA 99/12/18 - by Avery Pennarun et al.\n" +#define VERSION "arcnet: v3.92 BETA 2000/02/13 - by Avery Pennarun et al.\n" #include #include @@ -97,6 +97,7 @@ static int arcnet_open(struct net_device *dev); static int arcnet_close(struct net_device *dev); static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev); +static void arcnet_timeout(struct net_device *dev); static int arcnet_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); @@ -347,6 +348,7 @@ dev->addr_len = 1; dev->tx_queue_len = 30; dev->broadcast[0] = 0x00; /* for us, broadcasts are address 0 */ + dev->watchdog_timeo = TX_TIMEOUT; /* New-style flags. */ dev->flags = IFF_BROADCAST; @@ -358,6 +360,7 @@ dev->open = arcnet_open; dev->stop = arcnet_close; dev->hard_start_xmit = arcnet_send_packet; + dev->tx_timeout = arcnet_timeout; dev->get_stats = arcnet_get_stats; dev->hard_header = arcnet_header; dev->rebuild_header = arcnet_rebuild_header; @@ -397,10 +400,6 @@ if (ARCRESET(0) && ARCRESET(1)) return -ENODEV; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 0; - newmtu = choose_mtu(); if (newmtu < dev->mtu) dev->mtu = newmtu; @@ -441,9 +440,6 @@ if (ASTATUS() & RESETflag) ACOMMAND(CFLAGScmd | RESETclear); - /* we're started */ - dev->start = 1; - /* make sure we're ready to receive IRQ's. */ AINTMASK(0); udelay(1); /* give it time to set the mask before @@ -453,6 +449,8 @@ lp->intmask = NORXflag | RECONflag; AINTMASK(lp->intmask); + netif_start_queue(dev); + return 0; } @@ -462,16 +460,14 @@ { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + netif_stop_queue(dev); + /* flush TX and disable RX */ AINTMASK(0); ACOMMAND(NOTXcmd); /* stop transmit */ ACOMMAND(NORXcmd); /* disable receive */ mdelay(1); - dev->tbusy = 1; - dev->start = 0; - dev->interrupt = 0; - /* shut down the card */ ARCOPEN(0); @@ -584,48 +580,6 @@ "transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n", ASTATUS(), lp->cur_tx, lp->next_tx, skb->len); - if (dev->tbusy) { - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - */ - unsigned long flags; - int tickssofar = jiffies - dev->trans_start, status = ASTATUS(); - - if (tickssofar < TX_TIMEOUT) { - BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d)\n", - status, tickssofar); - return 1; /* means "try again" */ - } - save_flags(flags); - cli(); - - if (status & TXFREEflag) { /* transmit _DID_ finish */ - BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", - status, tickssofar, lp->intmask, lp->lasttrans_dest); - lp->stats.tx_errors++; - } else { - BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", - status, tickssofar, lp->intmask, lp->lasttrans_dest); - lp->stats.tx_errors++; - lp->stats.tx_aborted_errors++; - - ACOMMAND(NOTXcmd | (lp->cur_tx << 3)); - } - - /* - * interrupt handler will set dev->tbusy = 0 when it notices the - * transmit has been canceled. - */ - - /* make sure we didn't miss a TX IRQ */ - AINTMASK(0); - lp->intmask |= TXFREEflag; - AINTMASK(lp->intmask); - - restore_flags(flags); - return 1; - } pkt = (struct archdr *) skb->data; soft = &pkt->soft.rfc1201; proto = arc_proto_map[soft->proto]; @@ -638,18 +592,10 @@ dev_kfree_skb(skb); return 0; /* don't try again */ } - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - if (test_and_set_bit(0, (int *) &dev->tbusy)) { - BUGMSG(D_NORMAL, "transmitter called with busy bit set! " - "(status=%Xh, tickssofar=%ld)\n", - ASTATUS(), jiffies - dev->trans_start); - lp->stats.tx_errors++; - lp->stats.tx_fifo_errors++; - return 0; /* don't try again */ - } + + /* We're busy transmitting a packet... */ + netif_stop_queue(dev); + AINTMASK(0); txbuf = get_arcbuf(dev); @@ -718,6 +664,37 @@ } +/* Called by the kernel when transmit times out */ +static void arcnet_timeout(struct net_device *dev) +{ + unsigned long flags; + struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + int status = ASTATUS(); + + save_flags(flags); + cli(); + + if (status & TXFREEflag) { /* transmit _DID_ finish */ + BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, mask=%Xh, dest=%02Xh)\n", + status, lp->intmask, lp->lasttrans_dest); + lp->stats.tx_errors++; + } else { + BUGMSG(D_EXTRA, "tx timed out (status=%Xh, intmask=%Xh, dest=%02Xh)\n", + status, lp->intmask, lp->lasttrans_dest); + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + ACOMMAND(NOTXcmd | (lp->cur_tx << 3)); + } + + /* make sure we didn't miss a TX IRQ */ + AINTMASK(0); + lp->intmask |= TXFREEflag; + AINTMASK(lp->intmask); + + restore_flags(flags); +} + + /* * The typical workload of the driver: Handle the network interface * interrupts. Establish which device needs attention, and call the correct @@ -743,25 +720,20 @@ return; } /* - * RESET flag was enabled - if !dev->start, we must clear it right + * RESET flag was enabled - if device is not running, we must clear it right * away (but nothing else). */ - if (!dev->start) { + if (!test_bit(LINK_STATE_START, &dev->state)) { if (ASTATUS() & RESETflag) ACOMMAND(CFLAGScmd | RESETclear); AINTMASK(0); return; } - if (dev->interrupt) { - BUGMSG(D_NORMAL, "DRIVER PROBLEM! Nested arcnet interrupts!\n"); - return; /* don't even try. */ - } - dev->interrupt = 1; BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", ASTATUS(), lp->intmask); - boguscount = 3; + boguscount = 5; do { status = ASTATUS(); didsomething = 0; @@ -839,17 +811,15 @@ if (lp->outgoing.proto->continue_tx(dev, txbuf)) { /* that was the last segment */ lp->stats.tx_bytes += lp->outgoing.skb->len; - dev_kfree_skb(lp->outgoing.skb); + dev_kfree_skb_irq(lp->outgoing.skb); lp->outgoing.proto = NULL; } lp->next_tx = txbuf; } } /* inform upper layers of idleness, if necessary */ - if (lp->cur_tx == -1) { - dev->tbusy = 0; - mark_bh(NET_BH); - } + if (lp->cur_tx == -1) + netif_wake_queue(dev); } /* now process the received packet, if any */ if (recbuf != -1) { @@ -922,8 +892,6 @@ AINTMASK(0); udelay(1); AINTMASK(lp->intmask); - - dev->interrupt = 0; } @@ -987,11 +955,6 @@ } /* call the protocol-specific receiver. */ arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length); - - /* - * If any worthwhile packets have been received, a mark_bh(NET_BH) has - * been done by netif_rx and Linux will handle them after we return. - */ } diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com20020-isa.c linux/drivers/net/arcnet/com20020-isa.c --- v2.3.44/linux/drivers/net/arcnet/com20020-isa.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/com20020-isa.c Sun Feb 13 10:38:11 2000 @@ -3,7 +3,7 @@ * * Written 1997 by David Woodhouse. * Written 1994-1999 by Avery Pennarun. - * Written 1999 by Martin Mares . + * Written 1999-2000 by Martin Mares . * Derived from skeleton.c by Donald Becker. * * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) @@ -176,12 +176,9 @@ { struct net_device *dev = my_dev; - if (dev->start) - dev->stop(dev); - + unregister_netdev(dev); free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - unregister_netdev(dev); kfree(dev->priv); kfree(dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c --- v2.3.44/linux/drivers/net/arcnet/com20020-pci.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/com20020-pci.c Sun Feb 13 10:38:11 2000 @@ -3,7 +3,7 @@ * * Written 1994-1999 by Avery Pennarun, * based on an ISA version by David Woodhouse. - * Written 1999 by Martin Mares . + * Written 1999-2000 by Martin Mares . * Derived from skeleton.c by Donald Becker. * * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) @@ -148,13 +148,9 @@ for (count = 0; count < numcards; count++) { dev = cards[count]; - - if (dev->start) - dev->stop(dev); - + unregister_netdev(dev); free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - unregister_netdev(dev); kfree(dev->priv); kfree(dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c --- v2.3.44/linux/drivers/net/arcnet/com90io.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/com90io.c Sun Feb 13 10:38:11 2000 @@ -3,7 +3,7 @@ * * Written 1997 by David Woodhouse. * Written 1994-1999 by Avery Pennarun. - * Written 1999 by Martin Mares . + * Written 1999-2000 by Martin Mares . * Derived from skeleton.c by Donald Becker. * * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) @@ -406,20 +406,13 @@ struct net_device *dev = my_dev; int ioaddr = dev->base_addr; - if (dev->start) - dev->stop(dev); - - /* Flush TX and disable RX */ - AINTMASK(0); /* disable IRQ's */ - ACOMMAND(NOTXcmd); /* stop transmit */ - ACOMMAND(NORXcmd); /* disable receive */ + unregister_netdev(dev); /* Set the thing back to MMAP mode, in case the old driver is loaded later */ outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG); free_irq(dev->irq, dev); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - unregister_netdev(dev); kfree(dev->priv); kfree(dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com90xx.c linux/drivers/net/arcnet/com90xx.c --- v2.3.44/linux/drivers/net/arcnet/com90xx.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/com90xx.c Sun Feb 13 10:38:11 2000 @@ -143,7 +143,7 @@ numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "S1: "); + BUGMSG2(D_INIT, "S1: "); } BUGMSG2(D_INIT, "%Xh ", *port); @@ -151,7 +151,7 @@ if (check_region(*port, ARCNET_TOTAL_SIZE)) { BUGMSG2(D_INIT_REASONS, "(check_region)\n"); - BUGMSG(D_INIT_REASONS, "S1: "); + BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; *port = ports[numports - 1]; numports--; @@ -160,7 +160,7 @@ } if (ASTATUS() == 0xFF) { BUGMSG2(D_INIT_REASONS, "(empty)\n"); - BUGMSG(D_INIT_REASONS, "S1: "); + BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; *port = ports[numports - 1]; numports--; @@ -170,13 +170,13 @@ inb(_RESET); /* begin resetting card */ BUGMSG2(D_INIT_REASONS, "\n"); - BUGMSG(D_INIT_REASONS, "S1: "); + BUGMSG2(D_INIT_REASONS, "S1: "); BUGLVL(D_INIT_REASONS) numprint = 0; } BUGMSG2(D_INIT, "\n"); if (!numports) { - BUGMSG(D_NORMAL, "S1: No ARCnet cards found.\n"); + BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); return -ENODEV; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't @@ -189,7 +189,7 @@ numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "S2: "); + BUGMSG2(D_INIT, "S2: "); } BUGMSG2(D_INIT, "%Xh ", *port); } @@ -207,13 +207,13 @@ numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "S3: "); + BUGMSG2(D_INIT, "S3: "); } BUGMSG2(D_INIT, "%lXh ", *shmem); if (check_mem_region(*shmem, BUFFER_SIZE)) { BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n"); - BUGMSG(D_INIT_REASONS, "Stage 3: "); + BUGMSG2(D_INIT_REASONS, "Stage 3: "); BUGLVL(D_INIT_REASONS) numprint = 0; *shmem = shmems[numshmems - 1]; numshmems--; @@ -223,7 +223,7 @@ if (isa_readb(ptr) != TESTvalue) { BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n", isa_readb(ptr), TESTvalue); - BUGMSG(D_INIT_REASONS, "S3: "); + BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; *shmem = shmems[numshmems - 1]; numshmems--; @@ -238,20 +238,20 @@ isa_writeb(0x42, ptr); if (isa_readb(ptr) != 0x42) { BUGMSG2(D_INIT_REASONS, "(read only)\n"); - BUGMSG(D_INIT_REASONS, "S3: "); + BUGMSG2(D_INIT_REASONS, "S3: "); *shmem = shmems[numshmems - 1]; numshmems--; shmem--; continue; } BUGMSG2(D_INIT_REASONS, "\n"); - BUGMSG(D_INIT_REASONS, "S3: "); + BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; } BUGMSG2(D_INIT, "\n"); if (!numshmems) { - BUGMSG(D_NORMAL, "S3: No ARCnet cards found.\n"); + BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); return -ENODEV; } /* Stage 4: something of a dummy, to report the shmems that are @@ -263,7 +263,7 @@ numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "S4: "); + BUGMSG2(D_INIT, "S4: "); } BUGMSG2(D_INIT, "%lXh ", *shmem); } @@ -282,7 +282,7 @@ numprint %= 8; if (!numprint) { BUGMSG2(D_INIT, "\n"); - BUGMSG(D_INIT, "S5: "); + BUGMSG2(D_INIT, "S5: "); } BUGMSG2(D_INIT, "%Xh ", *port); @@ -292,7 +292,7 @@ if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status); - BUGMSG(D_INIT_REASONS, "S5: "); + BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; *port = ports[numports - 1]; numports--; @@ -304,7 +304,7 @@ if (status & RESETflag) { BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", status); - BUGMSG(D_INIT_REASONS, "S5: "); + BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; *port = ports[numports - 1]; numports--; @@ -327,7 +327,7 @@ if (airq <= 0) { BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq); - BUGMSG(D_INIT_REASONS, "S5: "); + BUGMSG2(D_INIT_REASONS, "S5: "); BUGLVL(D_INIT_REASONS) numprint = 0; *port = ports[numports - 1]; numports--; @@ -398,7 +398,7 @@ isa_writeb(TESTvalue, *shmem); if (retval && dev && !numcards) - BUGMSG(D_NORMAL, "S5: No ARCnet cards found.\n"); + BUGMSG2(D_NORMAL, "S5: No ARCnet cards found.\n"); return retval; } @@ -416,7 +416,7 @@ /* allocate struct net_device if we don't have one yet */ if (!dev && !(dev = dev_alloc("arc%d", &err))) { - BUGMSG(D_NORMAL, "Can't allocate device!\n"); + BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n"); return err; } lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); @@ -546,8 +546,7 @@ struct arcnet_local *lp = (struct arcnet_local *) dev->priv; short ioaddr = dev->base_addr; - BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", - dev->name, ASTATUS()); + BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS()); if (really_reset) { /* reset the card */ @@ -653,13 +652,11 @@ dev = cards[count]; lp = (struct arcnet_local *) dev->priv; - if (dev->start) - dev->stop(dev); + unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(lp->mem_start); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); - unregister_netdev(dev); kfree(dev->priv); kfree(dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/rfc1201.c linux/drivers/net/arcnet/rfc1201.c --- v2.3.44/linux/drivers/net/arcnet/rfc1201.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/arcnet/rfc1201.c Sun Feb 13 10:38:11 2000 @@ -171,7 +171,7 @@ BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", in->sequence, soft->split_flag, soft->sequence); lp->rfc1201.aborted_seq = soft->sequence; - kfree_skb(in->skb); + dev_kfree_skb_irq(in->skb); lp->stats.rx_errors++; lp->stats.rx_missed_errors++; in->skb = NULL; @@ -255,7 +255,7 @@ BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", saddr, in->sequence, soft->sequence, soft->split_flag); - kfree_skb(in->skb); + dev_kfree_skb_irq(in->skb); in->skb = NULL; lp->stats.rx_errors++; lp->stats.rx_missed_errors++; @@ -271,7 +271,7 @@ soft->sequence); lp->stats.rx_errors++; lp->stats.rx_missed_errors++; - kfree_skb(in->skb); + dev_kfree_skb_irq(in->skb); } in->sequence = soft->sequence; in->numpackets = ((unsigned) soft->split_flag >> 1) + 2; @@ -332,7 +332,7 @@ "(seq=%d) aborted (splitflag=%d, seq=%d)\n", in->sequence, soft->split_flag, soft->sequence); lp->rfc1201.aborted_seq = soft->sequence; - kfree_skb(in->skb); + dev_kfree_skb_irq(in->skb); in->skb = NULL; lp->stats.rx_errors++; lp->stats.rx_missed_errors++; diff -u --recursive --new-file v2.3.44/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c --- v2.3.44/linux/drivers/net/ariadne.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/ariadne.c Sun Feb 13 11:21:42 2000 @@ -160,6 +160,16 @@ continue; } strcpy(z->name, "Ariadne Ethernet Card and Parallel Ports"); + + dev = init_etherdev(NULL, sizeof(struct ariadne_private)); + + if (dev == NULL) { + release_mem_region(base_addr, sizeof(struct Am79C960)); + release_mem_region(ram_start, ARIADNE_RAM_SIZE); + return -ENOMEM; + } + memset(dev->priv, 0, sizeof(struct ariadne_private)); + dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x60; dev->dev_addr[2] = 0x30; @@ -170,16 +180,6 @@ "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - - init_etherdev(dev, 0); - - dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL); - if (dev->priv == NULL) { - release_mem_region(base_addr, sizeof(struct Am79C960)); - release_mem_region(ram_start, ARIADNE_RAM_SIZE); - return -ENOMEM; - } - memset(dev->priv, 0, sizeof(struct ariadne_private)); dev->base_addr = ZTWO_VADDR(base_addr); dev->mem_start = ZTWO_VADDR(ram_start); diff -u --recursive --new-file v2.3.44/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.3.44/linux/drivers/net/atp.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/atp.c Sun Feb 13 18:20:21 2000 @@ -16,6 +16,8 @@ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 The timer-based reset code was written by Bill Carlson, wwc@super.org. + + Modular support/softnet added by Alan Cox. */ static const char *version = @@ -82,6 +84,7 @@ */ #include +#include #include #include #include @@ -101,6 +104,7 @@ #include #include #include +#include #include "atp.h" @@ -133,9 +137,10 @@ static unsigned short eeprom_op(short ioaddr, unsigned int cmd); static int net_open(struct net_device *dev); static void hardware_init(struct net_device *dev); +static void tx_timeout(struct net_device *dev); static void write_packet(short ioaddr, int length, unsigned char *packet, int mode); static void trigger_send(short ioaddr, int length); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void net_rx(struct net_device *dev); static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode); @@ -150,8 +155,8 @@ If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ -int __init -atp_init(struct net_device *dev) + +int __init atp_init(struct net_device *dev) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; int base_addr = dev->base_addr; @@ -220,7 +225,7 @@ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Leave the hardware in a reset state. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET); + write_reg_high(ioaddr, CMR1, CMR1h_RESET); if (net_debug) printk(version); @@ -231,11 +236,10 @@ if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); - - { struct net_local *lp = (struct net_local *)dev->priv; lp->addr_mode = CMR2h_Normal; + spin_lock_init(&lp->lock); } /* For the ATP adapter the "if_port" is really the data transfer mode. */ @@ -245,9 +249,11 @@ dev->open = net_open; dev->stop = net_close; - dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; - dev->set_multicast_list = &set_multicast_list; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->tx_timeout = tx_timeout; + dev->watchdog_timeo = HZ/20; #ifdef TIMED_CHECKER del_timer(&atp_timer); @@ -327,12 +333,12 @@ /* The interrupt line is turned off (tri-stated) when the device isn't in use. That's especially important for "attached" interfaces where the port or interrupt may be shared. */ + if (request_irq(dev->irq, &net_interrupt, 0, "ATP", dev)) { return -EAGAIN; } - hardware_init(dev); - dev->start = 1; + netif_start_queue(dev); return 0; } @@ -342,11 +348,11 @@ { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; - int i; + int i; write_reg_high(ioaddr, CMR1, CMR1h_RESET); - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); write_reg_high(ioaddr, CMR2, lp->addr_mode); @@ -356,22 +362,19 @@ (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f); } - write_reg(ioaddr, CMR2, CMR2_IRQOUT); - write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); /* Enable the interrupt line from the serial port. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* Unmask the interesting interrupts. */ - write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); - write_reg_high(ioaddr, IMR, ISRh_RxErr); + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); lp->tx_unit_busy = 0; - lp->pac_cnt_in_tx_buf = 0; + lp->pac_cnt_in_tx_buf = 0; lp->saved_tx_size = 0; - - dev->tbusy = 0; - dev->interrupt = 0; } static void trigger_send(short ioaddr, int length) @@ -383,15 +386,15 @@ static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode) { - length = (length + 1) & ~1; /* Round up to word length. */ - outb(EOC+MAR, ioaddr + PAR_DATA); - if ((data_mode & 1) == 0) { + length = (length + 1) & ~1; /* Round up to word length. */ + outb(EOC+MAR, ioaddr + PAR_DATA); + if ((data_mode & 1) == 0) { /* Write the packet out, starting with the write addr. */ outb(WrAddr+MAR, ioaddr + PAR_DATA); do { write_byte_mode0(ioaddr, *packet++); } while (--length > 0) ; - } else { + } else { /* Write the packet out in slow mode. */ unsigned char outbyte = *packet++; @@ -405,70 +408,61 @@ outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); while (--length > 0) write_byte_mode1(ioaddr, *packet++); - } - /* Terminate the Tx frame. End of write: ECB. */ - outb(0xff, ioaddr + PAR_DATA); - outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL); + } + /* Terminate the Tx frame. End of write: ECB. */ + outb(0xff, ioaddr + PAR_DATA); + outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL); } -static int -net_send_packet(struct sk_buff *skb, struct net_device *dev) +static void tx_timeout(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; + /* If we get here, some higher level has decided we are broken. */ + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" + : "IRQ conflict"); + lp->stats.tx_errors++; + /* Try to restart the adapter. */ + hardware_init(dev); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} - if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk("%s: transmit timed out, %s?\n", dev->name, - inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" - : "IRQ conflict"); - lp->stats.tx_errors++; - /* Try to restart the adapter. */ - hardware_init(dev); - dev->tbusy=0; - dev->trans_start = jiffies; - } +static int net_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + unsigned long flags; + + netif_stop_queue(dev); + + /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. + This sequence must not be interrupted by an incoming packet. */ + + spin_lock_irqsave(&lp->lock, flags); + write_reg(ioaddr, IMR, 0); + write_reg_high(ioaddr, IMR, 0); + spin_unlock_irqrestore(&lp->lock, flags); + + write_packet(ioaddr, length, buf, dev->if_port); - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - int flags; - - /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. - This sequence must not be interrupted by an incoming packet. */ - save_flags(flags); - cli(); - write_reg(ioaddr, IMR, 0); - write_reg_high(ioaddr, IMR, 0); - restore_flags(flags); - - write_packet(ioaddr, length, buf, dev->if_port); - - lp->pac_cnt_in_tx_buf++; - if (lp->tx_unit_busy == 0) { - trigger_send(ioaddr, length); - lp->saved_tx_size = 0; /* Redundant */ - lp->re_tx = 0; + lp->pac_cnt_in_tx_buf++; + if (lp->tx_unit_busy == 0) { + trigger_send(ioaddr, length); + lp->saved_tx_size = 0; /* Redundant */ + lp->re_tx = 0; lp->tx_unit_busy = 1; - } else - lp->saved_tx_size = length; - - dev->trans_start = jiffies; - /* Re-enable the LPT interrupts. */ - write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); - write_reg_high(ioaddr, IMR, ISRh_RxErr); - } + } else + lp->saved_tx_size = length; + dev->trans_start = jiffies; + /* Re-enable the LPT interrupts. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); dev_kfree_skb (skb); - return 0; } @@ -482,14 +476,10 @@ int ioaddr, status, boguscount = 20; static int num_tx_since_rx = 0; - if (dev == NULL) { - printk ("ATP_interrupt(): irq %d for unknown device.\n", irq); - return; - } - dev->interrupt = 1; - ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; + + spin_lock(&lp->lock); /* Disable additional spurious interrupts. */ outb(Ctrl_SelData, ioaddr + PAR_CONTROL); @@ -498,10 +488,14 @@ write_reg(ioaddr, CMR2, CMR2_NULL); write_reg(ioaddr, IMR, 0); - if (net_debug > 5) printk("%s: In interrupt ", dev->name); - while (--boguscount > 0) { + if (net_debug > 5) + printk("%s: In interrupt ", dev->name); + + while (--boguscount > 0) + { status = read_nibble(ioaddr, ISR); - if (net_debug > 5) printk("loop status %02x..", status); + if (net_debug > 5) + printk("loop status %02x..", status); if (status & (ISR_RxOK<<3)) { write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */ @@ -539,7 +533,8 @@ break; } /* Attempt to retransmit. */ - if (net_debug > 6) printk("attempting to ReTx"); + if (net_debug > 6) + printk("attempting to ReTx"); write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); } else { /* Finish up the transmit. */ @@ -551,8 +546,7 @@ lp->re_tx = 0; } else lp->tx_unit_busy = 0; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue(dev); /* Inform upper layers. */ } num_tx_since_rx++; } else if (num_tx_since_rx > 8 @@ -568,7 +562,7 @@ break; } else break; - } + } /* This following code fixes a rare (and very difficult to track down) problem where the adapter forgets its ethernet address. */ @@ -584,17 +578,17 @@ } /* Tell the adapter that it can go back to using the output line as IRQ. */ - write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Enable the physical interrupt line, which is sure to be low until.. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* .. we enable the interrupt sources. */ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */ - if (net_debug > 5) printk("exiting interrupt.\n"); - - dev->interrupt = 0; - + if (net_debug > 5) + printk("exiting interrupt.\n"); + + spin_unlock(&lp->lock); return; } @@ -603,33 +597,17 @@ problem where the adapter forgets its ethernet address. */ static void atp_timed_checker(unsigned long ignored) { - int i; - int ioaddr = atp_timed_dev->base_addr; + int i; + struct net_local *lp = (struct net_local *)atp_timed_dev->priv; + int ioaddr = atp_timed_dev->base_addr; - if (!atp_timed_dev->interrupt) - { - for (i = 0; i < 6; i++) -#if 0 - if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i]) - { - struct net_local *lp = (struct net_local *)atp_timed_dev->priv; - write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); - if (i == 2) - lp->stats.tx_errors++; - else if (i == 3) - lp->stats.tx_dropped++; - else if (i == 4) - lp->stats.collisions++; - else - lp->stats.rx_errors++; - } -#else - write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); -#endif - } - del_timer(&atp_timer); - atp_timer.expires = jiffies + TIMED_CHECKER; - add_timer(&atp_timer); + spin_lock(&lp->lock); + for (i = 0; i < 6; i++) + write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); + spin_unlock(&lp->lock); + del_timer(&atp_timer); + atp_timer.expires = jiffies + TIMED_CHECKER; + add_timer(&atp_timer); } #endif @@ -707,19 +685,17 @@ else do *p++ = read_byte_mode6(ioaddr); while (--length > 0); - outb(EOC+HNib+MAR, ioaddr + PAR_DATA); + outb(EOC+HNib+MAR, ioaddr + PAR_DATA); outb(Ctrl_SelData, ioaddr + PAR_CONTROL); } /* The inverse routine to net_open(). */ -static int -net_close(struct net_device *dev) +static int net_close(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); /* Flush the Tx and disable Rx here. */ lp->addr_mode = CMR2h_OFF; @@ -730,7 +706,7 @@ free_irq(dev->irq, dev); /* Leave the hardware in a reset state. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET); + write_reg_high(ioaddr, CMR1, CMR1h_RESET); return 0; } @@ -774,3 +750,27 @@ * tab-width: 4 * End: */ + +#ifdef MODULE + +static int io = 0; +static char nullname[8] = ""; +static struct net_device atp_dev = { + nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_probe }; + +MODULE_PARM(io, "I/O port of the pocket adapter"); + +int init_module(void) +{ + atp_dev.base_addr = io; + if (register_netdev(&atp_dev) != 0) + return -EIO; + return 0; +} + +void cleanup_module(void) +{ + unregister_netdev(&atp_dev); +} + +#endif diff -u --recursive --new-file v2.3.44/linux/drivers/net/atp.h linux/drivers/net/atp.h --- v2.3.44/linux/drivers/net/atp.h Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/atp.h Sun Feb 13 18:20:21 2000 @@ -4,15 +4,14 @@ struct net_local { -#ifdef __KERNEL__ struct net_device_stats stats; -#endif ushort saved_tx_size; unsigned char re_tx, /* Number of packet retransmissions. */ tx_unit_busy, addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ pac_cnt_in_tx_buf; + spinlock_t lock; /* Safety lock */ }; struct rx_header { @@ -52,8 +51,7 @@ CMR2_h = 0x1d, }; -enum eepage_regs -{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ +enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ #define ISR_TxOK 0x01 diff -u --recursive --new-file v2.3.44/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.3.44/linux/drivers/net/bmac.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/bmac.c Sun Feb 13 10:47:01 2000 @@ -65,6 +65,7 @@ volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */ volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */ struct device_node *node; + int is_bmac_plus; struct sk_buff *rx_bufs[N_RX_RING]; int rx_fill; int rx_empty; @@ -80,6 +81,7 @@ int tx_allocated; unsigned short hash_use_count[64]; unsigned short hash_table_mask[4]; + struct net_device *next_bmac; }; typedef struct bmac_reg_entry { @@ -124,7 +126,6 @@ }; struct net_device *bmac_devs = NULL; -static int is_bmac_plus; #ifdef CONFIG_PMAC_PBOOK int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when); @@ -133,13 +134,6 @@ }; #endif -#if 0 -/* - * If we can't get a skbuff when we need it, we use this area for DMA. - */ -static unsigned char dummy_buf[RX_BUFLEN]; -#endif - /* * Number of bytes of private data per BMAC: allow enough for * the rx and tx dma commands plus a branch dma command each, @@ -151,6 +145,7 @@ + sizeof(struct sk_buff_head)) static unsigned char bitrev(unsigned char b); +static void bmac_probe1(struct device_node *bmac, int is_bmac_plus); static int bmac_open(struct net_device *dev); static int bmac_close(struct net_device *dev); static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); @@ -192,9 +187,10 @@ void dbdma_stop(volatile struct dbdma_regs *dmap) { - dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH)); + dbdma_st32((volatile unsigned long *)&dmap->control, + DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH)); eieio(); - + while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH)) eieio(); } @@ -210,10 +206,11 @@ static void dbdma_reset(volatile struct dbdma_regs *dmap) { - dbdma_st32((volatile unsigned long *)&dmap->control, - DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)); + dbdma_st32((volatile unsigned long *)&dmap->control, + DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)); eieio(); - while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio(); + while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) + eieio(); } static void @@ -239,7 +236,7 @@ static __inline__ volatile unsigned short bmread(struct net_device *dev, unsigned long reg_offset ) { - return in_le16((void *)dev->base_addr + reg_offset); + return in_le16((void *)dev->base_addr + reg_offset); } static void @@ -248,7 +245,7 @@ struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; - + dbdma_reset(rd); dbdma_reset(td); @@ -349,7 +346,7 @@ regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */ } while ((regValue & TxResetBit) && i > 0); - if (!is_bmac_plus) { + if (!bp->is_bmac_plus) { regValue = bmread(dev, XCVRIF); regValue |= ClkBit | SerialMode | COLActiveLow; bmwrite(dev, XCVRIF, regValue); @@ -385,7 +382,7 @@ /* set rx fifo information */ bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ - bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); + bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); //bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */ bmread(dev, STATUS); /* read it just to clear it */ @@ -433,13 +430,13 @@ /* enable rx dma channel */ dbdma_continue(rd); - + oldConfig = bmread(dev, TXCFG); - bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); - + bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); + /* turn on rx plus any other bits already on (promiscuous possibly) */ oldConfig = bmread(dev, RXCFG); - bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); + bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); udelay(20000); } @@ -447,6 +444,7 @@ bmac_init_phy(struct net_device *dev) { unsigned int addr; + struct bmac_data *bp = (struct bmac_data *) dev->priv; printk(KERN_DEBUG "phy registers:"); for (addr = 0; addr < 32; ++addr) { @@ -455,7 +453,7 @@ printk(" %.4x", bmac_mif_read(dev, addr)); } printk("\n"); - if (is_bmac_plus) { + if (bp->is_bmac_plus) { unsigned int capable, ctrl; ctrl = bmac_mif_read(dev, 0); @@ -622,7 +620,8 @@ if (!bp->rx_allocated) { for (i = 0; i < N_RX_RING; i++) { bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2); - if (bp->rx_bufs[i] == NULL) return 0; + if (bp->rx_bufs[i] == NULL) + return 0; skb_reserve(bp->rx_bufs[i], 2); } bp->rx_allocated = 1; @@ -657,9 +656,10 @@ /* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */ /* bp->tx_empty, bp->tx_fill)); */ i = bp->tx_fill + 1; - if (i >= N_TX_RING) i = 0; + if (i >= N_TX_RING) + i = 0; if (i == bp->tx_empty) { - dev->tbusy = 1; + netif_stop_queue(dev); bp->tx_fullup = 1; XXDEBUG(("bmac_transmit_packet: tx ring full\n")); return -1; /* can't take it at the moment */ @@ -776,16 +776,15 @@ if (bp->tx_bufs[bp->tx_empty]) { ++bp->stats.tx_packets; - dev_kfree_skb(bp->tx_bufs[bp->tx_empty]); + dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]); } bp->tx_bufs[bp->tx_empty] = NULL; bp->tx_fullup = 0; - dev->tbusy = 0; - /* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */ - /* i, bp->tx_fill)); */ - mark_bh(NET_BH); - if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0; - if (bp->tx_empty == bp->tx_fill) break; + netif_wake_queue(dev); + if (++bp->tx_empty >= N_TX_RING) + bp->tx_empty = 0; + if (bp->tx_empty == bp->tx_fill) + break; } restore_flags(flags); @@ -831,7 +830,7 @@ /* is high CRC bit set? */ if ((cur & 0x80000000) == 0) high_crc_set = 0; else high_crc_set = 1; - + cur = cur << 1; if ((next & 0x0001) == 0) low_data_set = 0; @@ -859,8 +858,8 @@ } /* - * Add requested mcast addr to BMac's hash table filter. - * + * Add requested mcast addr to BMac's hash table filter. + * */ static void @@ -925,7 +924,7 @@ else rx_cfg &= ~RxPromiscEnable; bmwrite(dev, RXRST, RxResetValue); bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ - bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); + bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); bmwrite(dev, RXCFG, rx_cfg ); return rx_cfg; } @@ -1020,13 +1019,7 @@ int i, j, bit, byte; unsigned short rx_cfg; u32 crc, poly = CRC_POLYNOMIAL_LE; - - /* Let the transmits drain. */ - /* while(dev->tbusy) schedule(); */ - - /* Lock out others. */ - /* set_bit(0, (void *) &dev->tbusy); */ - + if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { bmwrite(dev, BHASH0, 0xffff); bmwrite(dev, BHASH1, 0xffff); @@ -1048,15 +1041,15 @@ for(i = 0; i < dev->mc_count; i++) { addrs = dmi->dmi_addr; dmi = dmi->next; - + if(!(*addrs & 1)) continue; - + crc = 0xffffffffU; for(byte = 0; byte < 6; byte++) { for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { int test; - + test = ((bit ^ crc) & 0x01); crc >>= 1; if(test) @@ -1071,9 +1064,6 @@ bmwrite(dev, BHASH2, hash_table[2]); bmwrite(dev, BHASH3, hash_table[3]); } - - /* Let us get going again. */ - /* dev->tbusy = 0; */ } #endif /* SUNHME_MULTICAST */ @@ -1103,7 +1093,7 @@ } /* - * Procedure for reading EEPROM + * Procedure for reading EEPROM */ #define SROMAddressLength 5 #define DataInOn 0x0008 @@ -1126,28 +1116,28 @@ bmwrite(dev, SROMCSR, ChipSelect | Clk); udelay(DelayValue); - + data = bmread(dev, SROMCSR); udelay(DelayValue); val = (data >> SD0ShiftCount) & 1; bmwrite(dev, SROMCSR, ChipSelect); udelay(DelayValue); - + return val; } static void bmac_clock_in_bit(struct net_device *dev, unsigned int val) { - unsigned short data; + unsigned short data; if (val != 0 && val != 1) return; - + data = (val << SDIShiftCount); bmwrite(dev, SROMCSR, data | ChipSelect ); udelay(DelayValue); - + bmwrite(dev, SROMCSR, data | ChipSelect | Clk ); udelay(DelayValue); @@ -1161,7 +1151,7 @@ /* first reset */ bmwrite(dev, SROMCSR, 0); udelay(DelayValue); - + /* send it the read command (110) */ bmac_clock_in_bit(dev, 1); bmac_clock_in_bit(dev, 1); @@ -1173,13 +1163,13 @@ { unsigned short data, val; int i; - + /* send out the address we want to read from */ for (i = 0; i < addr_len; i++) { val = addr >> (addr_len-i-1); bmac_clock_in_bit(dev, val & 1); } - + /* Now read in the 16-bit data */ data = 0; for (i = 0; i < 16; i++) { @@ -1188,24 +1178,24 @@ data |= val; } bmwrite(dev, SROMCSR, 0); - + return data; } /* * It looks like Cogent and SMC use different methods for calculating - * checksums. What a pain.. + * checksums. What a pain.. */ static int bmac_verify_checksum(struct net_device *dev) { unsigned short data, storedCS; - + reset_and_select_srom(dev); data = read_srom(dev, 3, SROMAddressBits); storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00); - + return 0; } @@ -1236,8 +1226,10 @@ bp->reset_and_enabled = 0; bmac_reset_chip(dev); if (enable) { - if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0; - if (!bmac_init_chip(dev)) return 0; + if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) + return 0; + if (!bmac_init_chip(dev)) + return 0; bmac_start_chip(dev); bmwrite(dev, INTDISABLE, EnableNormal); bp->reset_and_enabled = 1; @@ -1257,70 +1249,55 @@ return 1; } -static int __init bmac_probe (void) +static int __init bmac_probe(void) { - int j, rev; - struct bmac_data *bp; - struct device_node *bmacs; - unsigned char *addr; - static struct device_node *all_bmacs = NULL, *next_bmac; - struct net_device *dev = NULL; + struct device_node *bmac; -#ifdef MODULE - if(bmac_devs != NULL) - return -EBUSY; -#endif + for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next) + bmac_probe1(bmac, 0); + for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0; + bmac = bmac->next) + bmac_probe1(bmac, 1); - if (all_bmacs == NULL) { - all_bmacs = find_devices("bmac"); - is_bmac_plus = 0; - if (all_bmacs == NULL) { - all_bmacs = find_compatible_devices("network", "bmac+"); - if (all_bmacs) - is_bmac_plus = 1; - } - next_bmac = all_bmacs; - } - bmacs = next_bmac; - if (bmacs == NULL) return -ENODEV; - next_bmac = bmacs->next; - - if (bmac_devs == 0) { - bmac_devs = dev; /* KLUDGE!! */ + if (bmac_devs != 0) { + proc_net_create ("bmac", 0, bmac_proc_info); #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&bmac_sleep_notifier); #endif } + return 0; +} - if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) { - printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n", - bmacs->full_name); - return -EINVAL; +static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) +{ + int j, rev; + struct bmac_data *bp; + unsigned char *addr; + struct net_device *dev; + + if (bmac->n_addrs != 3 || bmac->n_intrs != 3) { + printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n", + bmac->full_name); + return; + } + addr = get_property(bmac, "mac-address", NULL); + if (addr == NULL) { + addr = get_property(bmac, "local-mac-address", NULL); + if (addr == NULL) { + printk(KERN_ERR "Can't get mac-address for BMAC %s\n", + bmac->full_name); + return; + } } dev = init_etherdev(NULL, PRIV_BYTES); - bmac_devs = dev; /*KLUDGE!!*/ -#ifdef MODULE - bmac_devs = dev; -#endif - dev->base_addr = (unsigned long) - ioremap(bmacs->addrs[0].address, bmacs->addrs[0].size); - dev->irq = bmacs->intrs[0].line; + ioremap(bmac->addrs[0].address, bmac->addrs[0].size); + dev->irq = bmac->intrs[0].line; bmwrite(dev, INTDISABLE, DisableAll); - - addr = get_property(bmacs, "mac-address", NULL); - if (addr == NULL) { - addr = get_property(bmacs, "local-mac-address", NULL); - if (addr == NULL) { - printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n", - dev->base_addr); - return -EAGAIN; - } - } - + printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": "")); rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) { @@ -1329,7 +1306,7 @@ } XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); - + dev->open = bmac_open; dev->stop = bmac_close; dev->hard_start_xmit = bmac_output; @@ -1338,61 +1315,55 @@ dev->set_mac_address = bmac_set_address; bmac_get_station_address(dev, addr); - if (bmac_verify_checksum(dev) != 0) return -EINVAL; - + if (bmac_verify_checksum(dev) != 0) + return; + ether_setup(dev); - + bp = (struct bmac_data *) dev->priv; memset(bp, 0, sizeof(struct bmac_data)); + bp->is_bmac_plus = is_bmac_plus; bp->tx_dma = (volatile struct dbdma_regs *) - ioremap(bmacs->addrs[1].address, bmacs->addrs[1].size); - bp->tx_dma_intr = bmacs->intrs[1].line; + ioremap(bmac->addrs[1].address, bmac->addrs[1].size); + bp->tx_dma_intr = bmac->intrs[1].line; bp->rx_dma = (volatile struct dbdma_regs *) - ioremap(bmacs->addrs[2].address, bmacs->addrs[2].size); - bp->rx_dma_intr = bmacs->intrs[2].line; - + ioremap(bmac->addrs[2].address, bmac->addrs[2].size); + bp->rx_dma_intr = bmac->intrs[2].line; + bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1); bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1; bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1); skb_queue_head_init(bp->queue); - - bp->node = bmacs; + + bp->node = bmac; memset(&bp->stats, 0, sizeof(bp->stats)); memset((char *) bp->tx_cmds, 0, (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); /* init_timer(&bp->tx_timeout); */ /* bp->timeout_active = 0; */ - if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) { + if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq); - return -EAGAIN; - } - if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", - dev)) { - printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line); - return -EAGAIN; - } - if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", - dev)) { - printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line); - return -EAGAIN; - } - - if (!bmac_reset_and_enable(dev, 0)) return -ENOMEM; - - proc_net_create ("bmac", 0, bmac_proc_info); + if (request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", + dev)) + printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line); + if (request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", + dev)) + printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line); - return 0; + bp->next_bmac = bmac_devs; + bmac_devs = dev; } static int bmac_open(struct net_device *dev) { /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ - bmac_reset_and_enable(dev, 1); + if (!bmac_reset_and_enable(dev, 1)) + return -ENOMEM; - dev->flags |= IFF_UP | IFF_RUNNING; + dev->flags |= IFF_RUNNING; MOD_INC_USE_COUNT; return 0; @@ -1452,14 +1423,17 @@ int i; struct sk_buff *skb; unsigned long flags; - + save_flags(flags); cli(); while (1) { i = bp->tx_fill + 1; - if (i >= N_TX_RING) i = 0; - if (i == bp->tx_empty) break; + if (i >= N_TX_RING) + i = 0; + if (i == bp->tx_empty) + break; skb = skb_dequeue(bp->queue); - if (skb == NULL) break; + if (skb == NULL) + break; bmac_transmit_packet(skb, dev); } restore_flags(flags); @@ -1525,9 +1499,7 @@ bp->tx_empty = i; } bp->tx_fullup = 0; - dev->tbusy = 0; - mark_bh(NET_BH); - XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n")); + netif_wake_queue(dev); if (i != bp->tx_fill) { cp = &bp->tx_cmds[i]; out_le16(&cp->xfer_status, 0); @@ -1540,9 +1512,9 @@ /* turn it back on */ oldConfig = bmread(dev, RXCFG); - bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); + bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); oldConfig = bmread(dev, TXCFG); - bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); + bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); restore_flags(flags); } @@ -1573,7 +1545,8 @@ off_t begin = 0; int i; - if (bmac_devs == NULL) return (-ENOSYS); + if (bmac_devs == NULL) + return (-ENOSYS); len += sprintf(buffer, "BMAC counters & registers\n"); @@ -1582,20 +1555,20 @@ reg_entries[i].name, bmread(bmac_devs, reg_entries[i].reg_offset)); pos = begin + len; - + if (pos < offset) { len = 0; begin = pos; } - + if (pos > offset+length) break; } - + *start = buffer + (offset - begin); len -= (offset - begin); - + if (len > length) len = length; - + return len; } @@ -1606,26 +1579,28 @@ static void __exit bmac_cleanup (void) { -#ifdef MODULE - struct bmac_data *bp; - - if (bmac_devs == 0) - return; - - bp = (struct bmac_data *) bmac_devs->priv; - unregister_netdev(bmac_devs); - proc_net_remove("bmac"); - - free_irq(bmac_devs->irq, bmac_misc_intr); - free_irq(bp->tx_dma_intr, bmac_txdma_intr); - free_irq(bp->rx_dma_intr, bmac_rxdma_intr); + struct bmac_data *bp; + struct net_device *dev; + if (bmac_devs == 0) + return; #ifdef CONFIG_PMAC_PBOOK - pmu_unregister_sleep_notifier(&bmac_sleep_notifier); -#endif - kfree(bmac_devs); - bmac_devs = NULL; + pmu_unregister_sleep_notifier(&bmac_sleep_notifier); #endif + proc_net_remove("bmac"); + + do { + dev = bmac_devs; + bp = (struct bmac_data *) dev->priv; + bmac_devs = bp->next_bmac; + + free_irq(dev->irq, dev); + free_irq(bp->tx_dma_intr, dev); + free_irq(bp->rx_dma_intr, dev); + + unregister_netdev(dev); + kfree(dev); + } while (bmac_devs != NULL); } module_init(bmac_probe); diff -u --recursive --new-file v2.3.44/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.3.44/linux/drivers/net/de4x5.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/de4x5.c Sat Feb 12 15:44:09 2000 @@ -1761,7 +1761,7 @@ pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf), le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1); if ((u_long) lp->tx_skb[entry] > 1) - dev_kfree_skb(lp->tx_skb[entry]); + dev_kfree_skb_irq(lp->tx_skb[entry]); lp->tx_skb[entry] = NULL; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.3.44/linux/drivers/net/defxx.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/defxx.c Sun Feb 13 18:20:21 2000 @@ -253,7 +253,7 @@ static void dfx_int_pr_halt_id(DFX_board_t *bp); static void dfx_int_type_0_process(DFX_board_t *bp); -static void dfx_int_common(DFX_board_t *bp); +static void dfx_int_common(struct net_device *dev); static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev); @@ -272,7 +272,7 @@ static void dfx_rcv_queue_process(DFX_board_t *bp); static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev); -static void dfx_xmt_done(DFX_board_t *bp); +static int dfx_xmt_done(DFX_board_t *bp); static void dfx_xmt_flush(DFX_board_t *bp); /* Define module-wide (static) variables */ @@ -1423,9 +1423,7 @@ /* Set device structure info */ - dev->tbusy = 0; - dev->interrupt = DFX_UNMASK_INTERRUPTS; - dev->start = 1; + netif_start_queue(dev); return(0); } @@ -1511,9 +1509,8 @@ /* Clear device structure flags */ - dev->start = 0; - dev->tbusy = 1; - + netif_stop_queue(dev); + /* Deregister (free) IRQ */ free_irq(dev->irq, dev); @@ -1804,16 +1801,15 @@ * or updating completion indices. */ -void dfx_int_common( - DFX_board_t *bp - ) - - { +void dfx_int_common(struct net_device *dev) +{ + DFX_board_t *bp = (DFX_board_t *) dev->priv; PI_UINT32 port_status; /* Port Status register */ /* Process xmt interrupts - frequent case, so always call this routine */ - dfx_xmt_done(bp); /* free consumed xmt packets */ + if(dfx_xmt_done(bp)) /* free consumed xmt packets */ + netif_wake_queue(dev); /* Process rcv interrupts - frequent case, so always call this routine */ @@ -1889,21 +1885,12 @@ /* Get board pointer only if device structure is valid */ - if (dev == NULL) - { - printk("dfx_interrupt(): irq %d for unknown device!\n", irq); - return; - } bp = (DFX_board_t *) dev->priv; spin_lock(&bp->lock); /* See if we're already servicing an interrupt */ - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler!\n", dev->name); - dev->interrupt = DFX_MASK_INTERRUPTS; /* ensure non reentrancy */ - /* Service adapter interrupts */ if (bp->bus_type == DFX_BUS_TYPE_PCI) @@ -1914,7 +1901,7 @@ /* Call interrupt service routine for this adapter */ - dfx_int_common(bp); + dfx_int_common(dev); /* Clear PDQ interrupt status bit and reenable interrupts */ @@ -1932,7 +1919,7 @@ /* Call interrupt service routine for this adapter */ - dfx_int_common(bp); + dfx_int_common(dev); /* Reenable interrupts at the ESIC */ @@ -1941,7 +1928,6 @@ dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp); } - dev->interrupt = DFX_UNMASK_INTERRUPTS; spin_unlock(&bp->lock); return; } @@ -3199,6 +3185,8 @@ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ unsigned long flags; + netif_stop_queue(dev); + /* * Verify that incoming transmit request is OK * @@ -3213,7 +3201,7 @@ printk("%s: Invalid packet length - %u bytes\n", dev->name, skb->len); bp->xmt_length_errors++; /* bump error counter */ - mark_bh(NET_BH); + netif_wake_queue(dev); dev_kfree_skb(skb); return(0); /* return "success" */ } @@ -3237,6 +3225,7 @@ { bp->xmt_discards++; /* bump error counter */ dev_kfree_skb(skb); /* free sk_buff now */ + netif_wake_queue(dev); return(0); /* return "success" */ } } @@ -3339,6 +3328,7 @@ bp->rcv_xmt_reg.index.xmt_prod = prod; dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); spin_unlock_irqrestore(&bp->lock, flags); + netif_wake_queue(dev); return(0); /* packet queued to adapter */ } @@ -3375,13 +3365,14 @@ * None */ -void dfx_xmt_done( +int dfx_xmt_done( DFX_board_t *bp ) { XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + int freed = 0; /* buffers freed */ /* Service all consumed transmit frames */ @@ -3413,8 +3404,9 @@ */ bp->rcv_xmt_reg.index.xmt_comp += 1; + freed++; } - return; + return freed; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.44/linux/drivers/net/eepro100.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/eepro100.c Sun Feb 13 18:24:12 2000 @@ -1,7 +1,9 @@ -/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */ /* - NOTICE: this version tested with kernels 1.3.72 and later only! + + drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux + Written 1996-1999 by Donald Becker. + Modified 2000 by Linux Kernel Team This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -20,132 +22,15 @@ http://cesdis.gsfc.nasa.gov/linux/misc/modules.html There is a Majordomo mailing list based at linux-eepro100@cesdis.gsfc.nasa.gov -*/ -static const char *version = -"eepro100.c:v1.09j 7/27/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"; -/* A few user-configurable values that apply to all boards. - First set is undocumented and spelled per Intel recommendations. */ -static int congenb = 0; /* Enable congestion control in the DP83840. */ -static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ -static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ -/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */ -static int txdmacount = 128; -static int rxdmacount = 0; - -/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. - Lower values use more memory, but are faster. */ -static int rx_copybreak = 200; + Version history: + v1.09j+LK1.0 - Jeff Garzik + Convert to new PCI driver interface -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ -static int multicast_filter_limit = 64; -/* 'options' is used to pass a transceiver override or full-duplex flag - e.g. "options=16" for FD, "options=32" for 100mbps-only. */ -static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int debug = -1; /* The debug level */ - -/* A few values that may be tweaked. */ -/* The ring sizes should be a power of two for efficiency. */ -#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */ -#define RX_RING_SIZE 32 -/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */ -#define TX_QUEUE_LIMIT 12 - -/* Operational parameters that usually are not changed. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) -/* Size of an pre-allocated Rx buffer: + slack.*/ -#define PKT_BUF_SZ 1536 - -#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - -#include -#include -#ifdef MODVERSIONS -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#ifdef HAS_PCI_NETIF -#include "pci-netif.h" -#else -#include -#if LINUX_VERSION_CODE < 0x20155 -#include /* Ignore the bogus warning in 2.1.100+ */ -#endif -#endif -#include -#include -#include -#include - -#include -#include -#include -#include - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver"); -MODULE_PARM(debug, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(congenb, "i"); -MODULE_PARM(txfifo, "i"); -MODULE_PARM(rxfifo, "i"); -MODULE_PARM(txdmacount, "i"); -MODULE_PARM(rxdmacount, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(multicast_filter_limit, "i"); - -#define RUN_AT(x) (jiffies + (x)) - -#if (LINUX_VERSION_CODE < 0x20123) -#define test_and_set_bit(val, addr) set_bit(val, addr) -#define le16_to_cpu(val) (val) -#define cpu_to_le16(val) (val) -#define le32_to_cpu(val) (val) -#define cpu_to_le32(val) (val) -#define spin_lock_irqsave(&sp->lock, flags) save_flags(flags); cli(); -#define spin_unlock_irqrestore(&sp->lock, flags); restore_flags(flags); -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE); -#else -#define dev_free_skb(skb) dev_kfree_skb(skb); -#endif -#if ! defined(CAP_NET_ADMIN) -#define capable(CAP_XXX) (suser()) -#endif -#if ! defined(HAS_NETIF_QUEUE) -#define netif_wake_queue(dev) mark_bh(NET_BH); -#endif - -/* The total I/O port extent of the board. - The registers beyond 0x18 only exist on the i82558. */ -#define SPEEDO3_TOTAL_SIZE 0x20 - -int speedo_debug = 1; - -/* Theory of Operation I. Board Compatibility @@ -277,40 +162,108 @@ */ -/* This table drives the PCI probe routines. */ -static struct net_device *speedo_found1(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); -#ifdef USE_IO -#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1 -#define SPEEDO_SIZE 32 -#else -#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0 -#define SPEEDO_SIZE 0x1000 +static const char *version = +"eepro100.c:v1.09j+LK1.0 Feb 13, 2000 Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"; + +/* A few user-configurable values that apply to all boards. + First set is undocumented and spelled per Intel recommendations. */ + +static int congenb = 0; /* Enable congestion control in the DP83840. */ +static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ +static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ +/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */ +static int txdmacount = 128; +static int rxdmacount = 0; + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. + Lower values use more memory, but are faster. */ +static int rx_copybreak = 200; + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; + +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ +static int multicast_filter_limit = 64; + +/* 'options' is used to pass a transceiver override or full-duplex flag + e.g. "options=16" for FD, "options=32" for 100mbps-only. */ +#if MODULE_SETUP_FIXED +static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; #endif +static int debug = -1; /* The debug level */ + +/* A few values that may be tweaked. */ +/* The ring sizes should be a power of two for efficiency. */ +#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */ +#define RX_RING_SIZE 32 +/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */ +#define TX_QUEUE_LIMIT 12 + +/* Operational parameters that usually are not changed. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) +/* Size of an pre-allocated Rx buffer: + slack.*/ +#define PKT_BUF_SZ 1536 + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver"); +MODULE_PARM(debug, "i"); + +#if MODULE_OPTIONS_FIXED +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +#endif + +MODULE_PARM(congenb, "i"); +MODULE_PARM(txfifo, "i"); +MODULE_PARM(rxfifo, "i"); +MODULE_PARM(txdmacount, "i"); +MODULE_PARM(rxdmacount, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(multicast_filter_limit, "i"); + +#define EEPRO100_MODULE_NAME "eepro100" +#define PFX EEPRO100_MODULE_NAME ": " + +#define RUN_AT(x) (jiffies + (x)) + +int speedo_debug = 1; + -#if defined(HAS_PCI_NETIF) -struct pci_id_info static pci_tbl[] = { - { "Intel PCI EtherExpress Pro100", - { 0x12298086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE, - 0, speedo_found1 }, - {0,}, /* 0 terminated list. */ -}; -#else enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, }; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); -} static pci_tbl[] = { - { "Intel PCI EtherExpress Pro100", - 0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 }, - {0,}, /* 0 terminated list. */ -}; -#endif #ifndef USE_IO #define inb readb @@ -362,54 +315,75 @@ #endif enum SCBCmdBits { - SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, - SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, - SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, - /* The rest are Rx and Tx commands. */ - CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, - CUCmdBase=0x0060, /* CU Base address (set to zero) . */ - CUDumpStats=0x0070, /* Dump then reset stats counters. */ - RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, - RxResumeNoResources=0x0007, + SCBMaskCmdDone = 0x8000, + SCBMaskRxDone = 0x4000, + SCBMaskCmdIdle = 0x2000, + SCBMaskRxSuspend = 0x1000, + SCBMaskEarlyRx = 0x0800, + SCBMaskFlowCtl = 0x0400, + SCBTriggerIntr = 0x0200, + SCBMaskAll = 0x0100, + /* The rest are Rx and Tx commands. */ + CUStart = 0x0010, + CUResume = 0x0020, + CUStatsAddr = 0x0040, + CUShowStats = 0x0050, + CUCmdBase = 0x0060, /* CU Base address (set to zero) . */ + CUDumpStats = 0x0070, /* Dump then reset stats counters. */ + RxStart = 0x0001, + RxResume = 0x0002, + RxAbort = 0x0004, + RxAddrLoad = 0x0006, + RxResumeNoResources = 0x0007, }; enum SCBPort_cmds { - PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3, + PortReset = 0, + PortSelfTest = 1, + PortPartialReset = 2, + PortDump = 3, }; /* The Speedo3 Rx and Tx frame/buffer descriptors. */ -struct descriptor { /* A generic descriptor. */ - s32 cmd_status; /* All command and status fields. */ - u32 link; /* struct descriptor * */ +struct descriptor { /* A generic descriptor. */ + s32 cmd_status; /* All command and status fields. */ + u32 link; /* struct descriptor * */ unsigned char params[0]; }; /* The Speedo3 Rx and Tx buffer descriptors. */ -struct RxFD { /* Receive frame descriptor. */ +struct RxFD { /* Receive frame descriptor. */ s32 status; - u32 link; /* struct RxFD * */ - u32 rx_buf_addr; /* void * */ + u32 link; /* struct RxFD * */ + u32 rx_buf_addr; /* void * */ u32 count; }; /* Selected elements of the Tx/RxFD.status word. */ enum RxFD_bits { - RxComplete=0x8000, RxOK=0x2000, - RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010, - RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002, - TxUnderrun=0x1000, StatusComplete=0x8000, + RxComplete = 0x8000, + RxOK = 0x2000, + RxErrCRC = 0x0800, + RxErrAlign = 0x0400, + RxErrTooBig = 0x0200, + RxErrSymbol = 0x0010, + RxEth2Type = 0x0020, + RxNoMatch = 0x0004, + RxNoIAMatch = 0x0002, + TxUnderrun = 0x1000, + StatusComplete = 0x8000, }; -struct TxFD { /* Transmit frame descriptor set. */ +struct TxFD { /* Transmit frame descriptor set. */ s32 status; - u32 link; /* void * */ - u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ - s32 count; /* # of TBD (=1), Tx start thresh., etc. */ + u32 link; /* void * */ + u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ + s32 count; /* # of TBD (=1), Tx start thresh., etc. */ /* This constitutes two "TBD" entries -- we only use one. */ - u32 tx_buf_addr0; /* void *, frame to be transmitted. */ - s32 tx_buf_size0; /* Length of Tx frame. */ - u32 tx_buf_addr1; /* void *, frame to be transmitted. */ - s32 tx_buf_size1; /* Length of Tx frame. */ + u32 tx_buf_addr0; /* void *, frame to be transmitted. */ + s32 tx_buf_size0; /* Length of Tx frame. */ + u32 tx_buf_addr1; /* void *, frame to be transmitted. */ + s32 tx_buf_size1; /* Length of Tx frame. */ }; /* Elements of the dump_statistics block. This block must be lword aligned. */ @@ -436,46 +410,43 @@ /* Do not change the position (alignment) of the first few elements! The later elements are grouped for cache locality. */ struct speedo_private { - struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ - struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */ + struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ + struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */ /* The addresses of a Tx/Rx-in-place packets/buffers. */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - dma_addr_t rx_ring_dma[RX_RING_SIZE]; - dma_addr_t tx_ring_dma; - struct descriptor *last_cmd; /* Last command sent. */ + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + dma_addr_t rx_ring_dma[RX_RING_SIZE]; + dma_addr_t tx_ring_dma; + struct descriptor *last_cmd; /* Last command sent. */ unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */ - spinlock_t lock; /* Group with Tx control cache line. */ - u32 tx_threshold; /* The value for txdesc.count. */ - struct RxFD *last_rxf; /* Last command sent. */ - unsigned int cur_rx, dirty_rx; /* The next free ring entry */ - long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ + spinlock_t lock; /* Group with Tx control cache line. */ + u32 tx_threshold; /* The value for txdesc.count. */ + struct RxFD *last_rxf; /* Last command sent. */ + unsigned int cur_rx, dirty_rx; /* The next free ring entry */ + long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ const char *product_name; - struct net_device *next_module; - void *priv_addr; /* Unaligned address for kfree */ struct enet_statistics stats; struct speedo_stats *lstats; int chip_id; - unsigned char pci_bus, pci_devfn, acpi_pwr; + unsigned char acpi_pwr; struct pci_dev *pdev; struct timer_list timer; /* Media selection timer. */ - int mc_setup_frm_len; /* The length of an allocated.. */ - struct descriptor *mc_setup_frm; /* ..multicast setup frame. */ - int mc_setup_busy; /* Avoid double-use of setup frame. */ + int mc_setup_frm_len; /* The length of an allocated.. */ + struct descriptor *mc_setup_frm;/* ..multicast setup frame. */ + int mc_setup_busy; /* Avoid double-use of setup frame. */ dma_addr_t mc_setup_dma; - char rx_mode; /* Current PROMISC/ALLMULTI setting. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ - unsigned int rx_bug:1; /* Work around receiver hang errata. */ - unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */ - unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */ - unsigned char default_port:8; /* Last dev->if_port value. */ - unsigned short phy[2]; /* PHY media interfaces available. */ - unsigned short advertising; /* Current PHY advertised caps. */ - unsigned short partner; /* Link partner caps. */ + char rx_mode; /* Current PROMISC/ALLMULTI setting. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ + unsigned int rx_bug:1; /* Work around receiver hang errata. */ + unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */ + unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */ + unsigned char default_port:8; /* Last dev->if_port value. */ + unsigned short phy[2]; /* PHY media interfaces available. */ + unsigned short advertising; /* Current PHY advertised caps. */ + unsigned short partner; /* Link partner caps. */ }; - /* The parameters for a CmdConfigure operation. There are so many options that it would be difficult to document each bit. We mostly use the default or recommended settings. */ @@ -526,151 +497,93 @@ 0x2000, 0x2100, 0x0400, 0x3100}; #endif -/* A list of all installed Speedo devices, for removing the driver module. */ -static struct net_device *root_speedo_dev = NULL; - -#if ! defined(HAS_PCI_NETIF) -int eepro100_init(void) -{ - int cards_found = 0; - static int pci_index = 0; - - if (! pcibios_present()) - return cards_found; - - for (; pci_index < 8; pci_index++) { - unsigned char pci_bus, pci_device_fn, pci_latency; - long ioaddr; - int irq; - - u16 pci_command, new_command; - - if (pcibios_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82557, - pci_index, &pci_bus, - &pci_device_fn)) - break; -#if LINUX_VERSION_CODE >= 0x20155 || PCI_SUPPORT_1 - { - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); -#ifdef USE_IO - ioaddr = pdev->resource[1].start; -#else - ioaddr = pdev->resource[0].start; -#endif - irq = pdev->irq; - } -#else - { - u32 pciaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */ -#ifdef USE_IO - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &pciaddr); - pciaddr &= ~3UL; -#else - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pciaddr); -#endif - ioaddr = pciaddr; - irq = pci_irq_line; - } -#endif - /* Remove I/O space marker in bit 0. */ -#ifdef USE_IO - if (check_region(ioaddr, 32)) - continue; -#else - { - unsigned long orig_ioaddr = ioaddr; - - if ((ioaddr = (long)ioremap(ioaddr & ~0xfUL, 0x1000)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#lx.\n", - orig_ioaddr); - continue; - } - } -#endif - if (speedo_debug > 2) - printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n", - ioaddr, irq); - - /* Get and check the bus-master and latency values. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled this" - " device! Updating PCI command %4.4x->%4.4x.\n", - pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printk(" PCI latency timer (CFLT) is unreasonably low at %d." - " Setting to 32 clocks.\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 32); - } else if (speedo_debug > 1) - printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); - - if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0,cards_found)) - cards_found++; - } - return cards_found; -} -#endif -static struct net_device *speedo_found1(int pci_bus, int pci_devfn, - long ioaddr, int irq, int chip_idx, int card_idx) +static int __devinit eepro100_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { struct net_device *dev; struct speedo_private *sp; - struct pci_dev *pdev; unsigned char *tx_ring; dma_addr_t tx_ring_dma; const char *product; int i, option; u16 eeprom[0x100]; - int acpi_idle_state = 0; + int acpi_idle_state = 0, pm, irq; + unsigned long ioaddr; static int did_version = 0; /* Already printed version info. */ + +#ifdef USE_IO + ioaddr = pci_resource_start (pdev, 0); +#else + ioaddr = pci_resource_start (pdev, 1); +#endif + irq = pdev->irq; + + if (!request_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1), + EEPRO100_MODULE_NAME)) { + printk (KERN_ERR PFX "cannot reserve I/O ports\n"); + goto err_out_none; + } + if (!request_mem_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0), + EEPRO100_MODULE_NAME)) { + printk (KERN_ERR PFX "cannot reserve MMIO region\n"); + goto err_out_free_pio_region; + } + +#ifndef USE_IO + ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + if (!ioaddr) { + printk (KERN_ERR PFX "cannot remap MMIO region %lx @ %lx\n", + pci_resource_len (pdev, 0), + pci_resource_start (pdev, 0)); + goto err_out_free_mmio_region; + } +#endif + if (speedo_debug > 0 && did_version++ == 0) printk(version); - pdev = pci_find_slot(pci_bus, pci_devfn); - tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), &tx_ring_dma); if (!tx_ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); - return NULL; + printk(KERN_ERR PFX "Could not allocate DMA memory.\n"); + goto err_out_iounmap; } dev = init_etherdev(NULL, sizeof(struct speedo_private)); if (dev == NULL) { - pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) - + sizeof(struct speedo_stats), - tx_ring, tx_ring_dma); - return NULL; + printk(KERN_ERR PFX "Could not allocate ethernet device.\n"); + goto err_out_free_tx_ring; + } + if (dev->priv == NULL) { + printk(KERN_ERR PFX "Could not allocate ethernet device private info.\n"); + goto err_out_free_netdev; } if (dev->mem_start > 0) option = dev->mem_start; +#if MODULE_SETUP_FIXED else if (card_idx >= 0 && options[card_idx] >= 0) option = options[card_idx]; +#endif else option = 0; -#if defined(HAS_PCI_NETIF) - acpi_idle_state = acpi_set_pwr_state(pci_bus, pci_devfn, ACPI_D0); -#endif + /* save power state b4 pci_enable_device overwrites it */ + pm = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm) { + u16 pwr_command; + pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); + acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; + } + + pci_enable_device (pdev); + pci_set_master (pdev); /* Read the station address EEPROM before doing the reset. Nominally his should even be done before accepting the device, but @@ -716,7 +629,7 @@ if (eeprom[3] & 0x0100) product = "OEM i82557/i82558 10/100 Ethernet"; else - product = pci_tbl[chip_idx].name; + product = "Intel PCI EtherExpress Pro100"; printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr); @@ -724,7 +637,7 @@ printk("%2.2X:", dev->dev_addr[i]); printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq); -#ifndef kernel_bloat +#if 1 /* OK, this is pure kernel bloat. I don't like it when other drivers waste non-pageable kernel space to emit similar messages, but I need them for bug reports. */ @@ -793,41 +706,31 @@ #endif /* kernel_bloat */ outl(PortReset, ioaddr + SCBPort); -#if defined(HAS_PCI_NETIF) - /* Return the chip to its original power state. */ - acpi_set_pwr_state(pci_bus, pci_devfn, acpi_idle_state); -#endif - /* We do a request_region() only to register /proc/ioports info. */ - request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet"); + /* Return the chip to its original power state. */ + pci_set_power_state (pdev, acpi_idle_state); dev->base_addr = ioaddr; dev->irq = irq; sp = dev->priv; - if (dev->priv == NULL) { - void *mem = kmalloc(sizeof(*sp), GFP_KERNEL); - dev->priv = sp = mem; /* Cache align here if kmalloc does not. */ - sp->priv_addr = mem; - } memset(sp, 0, sizeof(*sp)); - sp->next_module = root_speedo_dev; - root_speedo_dev = dev; - sp->pci_bus = pci_bus; - sp->pci_devfn = pci_devfn; sp->pdev = pdev; - sp->chip_id = chip_idx; sp->acpi_pwr = acpi_idle_state; sp->tx_ring = (struct TxFD *)tx_ring; sp->tx_ring_dma = tx_ring_dma; sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE); sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; + +#if MODULE_SETUP_FIXED if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) sp->full_duplex = full_duplex[card_idx]; } +#endif + sp->default_port = option >= 0 ? (option & 0x0f) : 0; sp->phy[0] = eeprom[6]; @@ -847,9 +750,30 @@ dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; - return dev; + return 0; + +err_out_free_netdev: + unregister_netdevice (dev); + kfree (dev); +err_out_free_tx_ring: + pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + + sizeof(struct speedo_stats), + tx_ring, tx_ring_dma); +err_out_iounmap: +#ifndef USE_IO + iounmap ((void *)ioaddr); +#endif +err_out_free_mmio_region: + release_mem_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); +err_out_free_pio_region: + release_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); +err_out_none: + return -ENODEV; } - + + /* Serial EEPROM section. A "bit" grungy, but we work our way through bit-by-bit :->. */ /* EEPROM_Ctrl bits. */ @@ -925,13 +849,11 @@ struct speedo_private *sp = (struct speedo_private *)dev->priv; long ioaddr = dev->base_addr; -#if defined(HAS_PCI_NETIF) - acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0); -#endif - if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); + pci_set_power_state(sp->pdev, 0); + /* Set up the Tx queue early.. */ sp->cur_tx = 0; sp->dirty_tx = 0; @@ -940,9 +862,9 @@ spin_lock_init(&sp->lock); /* .. we can safely take handler calls during init. */ - if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) { - return -EAGAIN; - } + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) + return -EBUSY; + MOD_INC_USE_COUNT; dev->if_port = sp->default_port; @@ -1059,6 +981,8 @@ + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD), ioaddr + SCBPointer); outw(CUStart, ioaddr + SCBCmd); + + netif_start_queue (dev); } /* Media monitoring and control. */ @@ -1220,6 +1144,7 @@ } sp->stats.tx_errors++; dev->trans_start = jiffies; + netif_start_queue (dev); return; } @@ -1230,6 +1155,8 @@ long ioaddr = dev->base_addr; int entry; + netif_stop_queue (dev); + /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -1270,13 +1197,15 @@ } if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) { sp->tx_full = 1; - netif_stop_queue(dev); } spin_unlock_irqrestore(&sp->lock, flags); } wait_for_cmd_done(ioaddr + SCBCmd); outw(CUResume, ioaddr + SCBCmd); dev->trans_start = jiffies; + + if (! sp->tx_full) + netif_start_queue (dev); return 0; } @@ -1300,6 +1229,8 @@ ioaddr = dev->base_addr; sp = (struct speedo_private *)dev->priv; + spin_lock (&sp->lock); + do { status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ @@ -1330,7 +1261,6 @@ /* User interrupt, Command/Tx unit interrupt or CU not active. */ if (status & 0xA400) { unsigned int dirty_tx; - spin_lock(&sp->lock); dirty_tx = sp->dirty_tx; while (sp->cur_tx - dirty_tx > 0) { @@ -1380,10 +1310,12 @@ && sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; - spin_unlock(&sp->lock); - netif_wake_queue(dev); - } else - spin_unlock(&sp->lock); + } + + if (sp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); } if (--boguscnt < 0) { @@ -1399,7 +1331,7 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); - return; + spin_unlock (&sp->lock); } static int @@ -1546,7 +1478,7 @@ #if LINUX_VERSION_CODE < 0x20100 skb->free = 1; #endif - dev_free_skb(skb); + dev_kfree_skb(skb); } } @@ -1559,7 +1491,7 @@ pci_unmap_single(sp->pdev, le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), skb->len); - dev_free_skb(skb); + dev_kfree_skb(skb); } } if (sp->mc_setup_frm) { @@ -1571,10 +1503,9 @@ if (speedo_debug > 3) speedo_show_state(dev); -#if defined(HAS_PCI_NETIF) /* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */ - acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D2); -#endif + pci_set_power_state (sp->pdev, 2); + MOD_DEC_USE_COUNT; return 0; @@ -1626,32 +1557,22 @@ long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; -#if defined(HAS_PCI_NETIF) int saved_acpi; -#endif switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = phy; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ -#if defined(HAS_PCI_NETIF) - saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0); - data[3] = mdio_read(ioaddr, data[0], data[1]); - acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi); -#else - data[3] = mdio_read(ioaddr, data[0], data[1]); -#endif + saved_acpi = pci_set_power_state (sp->pdev, 0); + data[3] = mdio_read (ioaddr, data[0], data[1]); + pci_set_power_state (sp->pdev, saved_acpi); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; -#if defined(HAS_PCI_NETIF) - saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0); - mdio_write(ioaddr, data[0], data[1], data[2]); - acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi); -#else + saved_acpi = pci_set_power_state(sp->pdev, 0); mdio_write(ioaddr, data[0], data[1], data[2]); -#endif + pci_set_power_state(sp->pdev, saved_acpi); return 0; default: return -EOPNOTSUPP; @@ -1836,54 +1757,94 @@ } +static void eepro100_suspend (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + long ioaddr = dev->base_addr; + + netif_stop_queue (dev); + outl(PortPartialReset, ioaddr + SCBPort); +} + + +static void eepro100_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct speedo_private *np = (struct speedo_private *)dev->priv; + + speedo_resume(dev); + np->rx_mode = -1; + np->flow_ctrl = np->partner = 0; + set_rx_mode(dev); +} + + +static void __devexit eepro100_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + struct speedo_private *sp = (struct speedo_private *)dev->priv; + + unregister_netdev (dev); + + release_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); + release_mem_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + +#ifndef USE_IO + iounmap ((char *) dev->base_addr); +#endif + + pci_set_power_state (pdev, sp->acpi_pwr); + + kfree (dev); +} + + +static struct pci_device_id eepro100_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,}, +}; +MODULE_DEVICE_TABLE (pci, eepro100_pci_tbl); + + +static struct pci_driver eepro100_driver = { + name: EEPRO100_MODULE_NAME, + id_table: eepro100_pci_tbl, + probe: eepro100_init_one, + remove: eepro100_remove_one, + suspend: eepro100_suspend, + resume: eepro100_resume, +}; + + static int __init eepro100_init_module(void) { int cards_found; if (debug >= 0) speedo_debug = debug; + /* Always emit the version message. */ if (speedo_debug) printk(KERN_INFO "%s", version); -#if defined(HAS_PCI_NETIF) - cards_found = netif_pci_probe(pci_tbl); - if (cards_found < 0) - printk(KERN_INFO "eepro100: No cards found, driver not installed.\n"); - return cards_found; -#else - cards_found = eepro100_init(); + cards_found = pci_register_driver (&eepro100_driver); if (cards_found <= 0) { - printk(KERN_INFO "eepro100: No cards found, driver not installed.\n"); + printk(KERN_INFO PFX "No cards found, driver not installed.\n"); return -ENODEV; } -#endif + return 0; } + static void __exit eepro100_cleanup_module(void) { - struct net_device *next_dev; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_speedo_dev) { - struct speedo_private *sp = (void *)root_speedo_dev->priv; - unregister_netdev(root_speedo_dev); -#ifdef USE_IO - release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE); -#else - iounmap((char *)root_speedo_dev->base_addr); -#endif -#if defined(HAS_PCI_NETIF) - acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, sp->acpi_pwr); -#endif - next_dev = sp->next_module; - if (sp->priv_addr) - kfree(sp->priv_addr); - kfree(root_speedo_dev); - root_speedo_dev = next_dev; - } + pci_unregister_driver (&eepro100_driver); } + module_init(eepro100_init_module); module_exit(eepro100_cleanup_module); diff -u --recursive --new-file v2.3.44/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.3.44/linux/drivers/net/epic100.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/epic100.c Sun Feb 13 18:24:12 2000 @@ -79,7 +79,6 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); /* The I/O extent. */ #define EPIC_TOTAL_SIZE 0x100 @@ -425,6 +424,8 @@ dev->do_ioctl = &mii_ioctl; dev->tx_timeout = epic_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + + netif_stop_queue (dev); return dev; } @@ -527,13 +528,15 @@ int mii_reg5; ep->full_duplex = ep->force_fd; + MOD_INC_USE_COUNT; + /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); - if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev)) - return -EAGAIN; - - MOD_INC_USE_COUNT; + if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } epic_init_ring(dev); @@ -581,8 +584,6 @@ set_rx_mode(dev); outl(0x000A, ioaddr + COMMAND); - netif_start_queue(dev); - /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170) | CntFull | TxUnderrun | TxDone @@ -595,10 +596,12 @@ dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL), ep->full_duplex ? "full" : "half"); + netif_start_queue(dev); + /* Set the timer to switch to check for link beat and perhaps switch to an alternate media type. */ init_timer(&ep->timer); - ep->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + ep->timer.expires = RUN_AT(3*HZ); /* 3 sec. */ ep->timer.data = (unsigned long)dev; ep->timer.function = &epic_timer; /* timer handler */ add_timer(&ep->timer); @@ -613,6 +616,8 @@ long ioaddr = dev->base_addr; struct epic_private *ep = (struct epic_private *)dev->priv; + netif_stop_queue (dev); + /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + INTMASK); /* Stop the chip's Tx and Rx DMA processes. */ @@ -671,11 +676,13 @@ | CntFull | TxUnderrun | TxDone | RxError | RxOverflow | RxFull | RxHeader | RxDone, ioaddr + INTMASK); + + netif_start_queue (dev); + printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" " interrupt %4.4x.\n", dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL), inl(ioaddr + INTSTAT)); - return; } static void epic_timer(unsigned long data) @@ -738,7 +745,8 @@ dev->trans_start = jiffies; ep->stats.tx_errors++; - return; + + netif_start_queue (dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ @@ -790,6 +798,8 @@ int entry; u32 flag; + netif_stop_queue (dev); + /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -806,13 +816,10 @@ if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ flag = 0x10; /* No interrupt */ - netif_start_queue(dev); } else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) { flag = 0x14; /* Tx-done intr. */ - netif_start_queue(dev); } else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) { flag = 0x10; /* No Tx-done intr. */ - netif_start_queue(dev); } else { /* Leave room for two additional entries. */ flag = 0x14; /* Tx-done intr. */ @@ -826,6 +833,10 @@ outl(0x0004, dev->base_addr + COMMAND); dev->trans_start = jiffies; + + if (! ep->tx_full) + netif_start_queue (dev); + if (epic_debug > 4) printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, " "flag %2.2x Tx status %8.8x.\n", @@ -895,7 +906,7 @@ } /* Free the original skb. */ - DEV_FREE_SKB(ep->tx_skbuff[entry]); + dev_kfree_skb_irq(ep->tx_skbuff[entry]); ep->tx_skbuff[entry] = 0; } @@ -912,8 +923,12 @@ dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; - netif_wake_queue (dev); } + + if (ep->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); ep->dirty_tx = dirty_tx; } @@ -1073,12 +1088,12 @@ ep->rx_ring[i].buflength = 0; ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ if (skb) { - DEV_FREE_SKB(skb); + dev_kfree_skb(skb); } } for (i = 0; i < TX_RING_SIZE; i++) { if (ep->tx_skbuff[i]) - DEV_FREE_SKB(ep->tx_skbuff[i]); + dev_kfree_skb(ep->tx_skbuff[i]); ep->tx_skbuff[i] = 0; } @@ -1224,13 +1239,14 @@ struct net_device *dev; u16 dev_id; u32 io; - u8 bus, devfn, irq; + u8 irq; struct pci_dev *pdev; if (loc->bus != LOC_PCI) return NULL; pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); if (!pdev) return NULL; - printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn); + printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", + pdev->bus->number, pdev->devfn); io = pdev->resource[0].start; irq = pdev->irq; dev_id = pdev->device; @@ -1241,7 +1257,7 @@ io == 0 ? "I/O address" : "IRQ"); return NULL; } - dev = epic_probe1(bus, devfn, io, irq, 2, -1); + dev = epic_probe1(pdev, io, irq, 2, -1); if (dev) { dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); strcpy(node->dev_name, dev->name); diff -u --recursive --new-file v2.3.44/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.3.44/linux/drivers/net/eth16i.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/eth16i.c Sun Feb 13 18:20:21 2000 @@ -158,6 +158,8 @@ #include #include #include +#include +#include #include #include @@ -168,26 +170,7 @@ #include #include -#ifndef LINUX_VERSION_CODE -#include -#endif - -#if LINUX_VERSION_CODE >= 0x20123 -#include -#else -#define __init -#define __initdata -#endif -#if LINUX_VERSION_CODE < 0x20138 -#define test_and_set_bit(val,addr) set_bit(val,addr) -#endif - -#if LINUX_VERSION_CODE < 0x020100 -typedef struct enet_statistics eth16i_stats_type; -#else -typedef struct net_device_stats eth16i_stats_type; -#endif /* Few macros */ #define BIT(a) ( (1 << (a)) ) @@ -371,12 +354,14 @@ #define RESET ID_ROM_0 /* This is the I/O address list to be probed when seeking the card */ -static unsigned int eth16i_portlist[] = - { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; +static unsigned int eth16i_portlist[] = { + 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 +}; -static unsigned int eth32i_portlist[] = - { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, - 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 }; +static unsigned int eth32i_portlist[] = { + 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, + 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 +}; /* This is the Interrupt lookup table for Eth16i card */ static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 }; @@ -399,7 +384,7 @@ /* Information for each board */ struct eth16i_local { - eth16i_stats_type stats; + struct net_device_stats stats; unsigned char tx_started; unsigned char tx_buf_busy; unsigned short tx_queue; /* Number of packets in transmit buffer */ @@ -409,6 +394,7 @@ unsigned long tx_buffered_packets; unsigned long tx_buffered_bytes; unsigned long col_16; + spinlock_t lock; }; /* Function prototypes */ @@ -429,8 +415,10 @@ static int eth16i_close(struct net_device *dev); static int eth16i_tx(struct sk_buff *skb, struct net_device *dev); static void eth16i_rx(struct net_device *dev); +static void eth16i_timeout(struct net_device *dev); static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void eth16i_reset(struct net_device *dev); +static void eth16i_timeout(struct net_device *dev); static void eth16i_skip_packet(struct net_device *dev); static void eth16i_multicast(struct net_device *dev); static void eth16i_select_regbank(unsigned char regbank, int ioaddr); @@ -444,18 +432,10 @@ static ushort eth16i_parse_mediatype(const char* s); #endif -static struct enet_statistics *eth16i_get_stats(struct net_device *dev); +static struct net_device_stats *eth16i_get_stats(struct net_device *dev); static char *cardname = "ICL EtherTeam 16i/32"; -#ifdef HAVE_DEVLIST - -/* Support for alternate probe manager */ -/struct netdev_entry eth16i_drv = - {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list}; - -#else /* Not HAVE_DEVLIST */ - int __init eth16i_probe(struct net_device *dev) { int i; @@ -488,10 +468,11 @@ return ENODEV; } -#endif /* Not HAVE_DEVLIST */ static int __init eth16i_probe1(struct net_device *dev, int ioaddr) { + struct eth16i_local *lp; + static unsigned version_printed = 0; boot = 1; /* To inform initilization that we are in boot probe */ @@ -535,17 +516,6 @@ printk(KERN_INFO "%s", version); dev->base_addr = ioaddr; - -#if 0 - if(dev->irq) { - if(eth16i_set_irq(dev)) { - dev->irq = eth16i_get_irq(ioaddr); - } - - } - else { -#endif - dev->irq = eth16i_get_irq(ioaddr); /* Try to obtain interrupt vector */ @@ -556,10 +526,6 @@ return -EAGAIN; } -#if 0 - irq2dev_map[dev->irq] = dev; -#endif - printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ", dev->name, cardname, ioaddr, dev->irq); @@ -583,12 +549,16 @@ } memset(dev->priv, 0, sizeof(struct eth16i_local)); - dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; dev->get_stats = eth16i_get_stats; - dev->set_multicast_list = ð16i_multicast; + dev->set_multicast_list = eth16i_multicast; + dev->tx_timeout = eth16i_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + lp = (struct eth16i_local *)dev->priv; + spin_lock_init(&lp->lock); /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); @@ -1004,10 +974,7 @@ /* Turn on interrupts*/ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; @@ -1023,9 +990,8 @@ /* Turn off interrupts*/ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - dev->start = 0; - dev->tbusy = 1; - + netif_stop_queue(dev); + lp->open_time = 0; /* Disable transmit and receive */ @@ -1042,153 +1008,115 @@ return 0; } -static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) +static void eth16i_timeout(struct net_device *dev) { struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; - int status = 0; + /* + If we get here, some higher level has decided that + we are broken. There should really be a "kick me" + function call instead. + */ - if(dev->tbusy) { - - /* - If we get here, some higher level has decided that - we are broken. There should really be a "kick me" - function call instead. - */ - - int tickssofar = jiffies - dev->trans_start; - if(tickssofar < TX_TIMEOUT) - return 1; - - outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - - printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", - dev->name, - inw(ioaddr + TX_STATUS_REG), - (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? + outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); + printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", + dev->name, + inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? "IRQ conflict" : "network cable problem"); - dev->trans_start = jiffies; - - /* Let's dump all registers */ - if(eth16i_debug > 0) { - printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n", - dev->name, inb(ioaddr + 0), - inb(ioaddr + 1), inb(ioaddr + 2), - inb(ioaddr + 3), inb(ioaddr + 4), - inb(ioaddr + 5), - inb(ioaddr + 6), inb(ioaddr + 7)); - - printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n", - dev->name, inb(ioaddr + TRANSMIT_START_REG), - inb(ioaddr + COL_16_REG)); + dev->trans_start = jiffies; + /* Let's dump all registers */ + if(eth16i_debug > 0) { + printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n", + dev->name, inb(ioaddr + 0), + inb(ioaddr + 1), inb(ioaddr + 2), + inb(ioaddr + 3), inb(ioaddr + 4), + inb(ioaddr + 5), + inb(ioaddr + 6), inb(ioaddr + 7)); + + printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n", + dev->name, inb(ioaddr + TRANSMIT_START_REG), + inb(ioaddr + COL_16_REG)); printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue); - printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len); - printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started); - - } - - lp->stats.tx_errors++; - - eth16i_reset(dev); - - dev->trans_start = jiffies; - - outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - + printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len); + printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started); } + lp->stats.tx_errors++; + eth16i_reset(dev); + dev->trans_start = jiffies; + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + netif_wake_queue(dev); +} - /* - If some higher layer thinks we've missed an tx-done interrupt - we are passed NULL. Caution: dev_tint() handles the cli()/sti() - itself - */ - - if(skb == NULL) { -#if LINUX_VERSION_CODE < 0x020100 - dev_tint(dev); -#endif - if(eth16i_debug > 0) - printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name); - return 0; - } +static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + int ioaddr = dev->base_addr; + int status = 0; + ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + unsigned long flags; - /* Block a timer based transmitter from overlapping. - This could better be done with atomic_swap(1, dev->tbusy), - but set_bit() works as well. */ - set_bit(0, (void *)&lp->tx_buf_busy); - + netif_stop_queue(dev); + /* Turn off TX interrupts */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); + + /* We would be better doing the disable_irq tricks the 3c509 does, + that would make this suck a lot less */ + + spin_lock_irqsave(&lp->lock, flags); - if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - status = -1; - } + if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) { + if(eth16i_debug > 0) + printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name); + } else { - ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; + outw(length, ioaddr + DATAPORT); - if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) { - if(eth16i_debug > 0) - printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name); - } + if( ioaddr < 0x1000 ) + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); else { - outw(length, ioaddr + DATAPORT); - - if( ioaddr < 0x1000 ) - outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); - else { - unsigned char frag = length % 4; - - outsl(ioaddr + DATAPORT, buf, length >> 2); - - if( frag != 0 ) { - outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1); - if( frag == 3 ) - outsw(ioaddr + DATAPORT, - (buf + (length & 0xFFFC) + 2), 1); - } + unsigned char frag = length % 4; + outsl(ioaddr + DATAPORT, buf, length >> 2); + if( frag != 0 ) { + outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1); + if( frag == 3 ) + outsw(ioaddr + DATAPORT, + (buf + (length & 0xFFFC) + 2), 1); } - - lp->tx_buffered_packets++; - lp->tx_buffered_bytes = length; - lp->tx_queue++; - lp->tx_queue_len += length + 2; } - - lp->tx_buf_busy = 0; + lp->tx_buffered_packets++; + lp->tx_buffered_bytes = length; + lp->tx_queue++; + lp->tx_queue_len += length + 2; + } + lp->tx_buf_busy = 0; - if(lp->tx_started == 0) { - /* If the transmitter is idle..always trigger a transmit */ - outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG); - lp->tx_queue = 0; - lp->tx_queue_len = 0; - dev->trans_start = jiffies; - lp->tx_started = 1; - dev->tbusy = 0; - } - else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) { - /* There is still more room for one more packet in tx buffer */ - dev->tbusy = 0; - } - - outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + if(lp->tx_started == 0) { + /* If the transmitter is idle..always trigger a transmit */ + outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG); + lp->tx_queue = 0; + lp->tx_queue_len = 0; + dev->trans_start = jiffies; + lp->tx_started = 1; + netif_wake_queue(dev); + } + else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) { + /* There is still more room for one more packet in tx buffer */ + netif_wake_queue(dev); + } - /* Turn TX interrupts back on */ - /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ - status = 0; - } - -#if LINUX_VERSION_CODE >= 0x020100 + spin_unlock_irqrestore(&lp->lock, flags); + + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + /* Turn TX interrupts back on */ + /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ + status = 0; dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif - - return status; + return 0; } static void eth16i_rx(struct net_device *dev) @@ -1284,51 +1212,23 @@ break; } /* while */ - -#if 0 - { - int i; - - for(i = 0; i < 20; i++) { - if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == - RX_BUFFER_EMPTY) - break; - inw(ioaddr + DATAPORT); - outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG); - } - - if(eth16i_debug > 1) - printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name); - } -#endif - - return; } static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct eth16i_local *lp; - int ioaddr = 0, - status; + int ioaddr = 0, status; - if(dev == NULL) { - printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq); - return; - } + ioaddr = dev->base_addr; + lp = (struct eth16i_local *)dev->priv; /* Turn off all interrupts from adapter */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */ /* eth16i_tx wont be called */ + spin_lock(&lp->lock); - if(dev->interrupt) - printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; - - ioaddr = dev->base_addr; - lp = (struct eth16i_local *)dev->priv; status = inw(ioaddr + TX_STATUS_REG); /* Get the status */ outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */ @@ -1386,13 +1286,11 @@ lp->tx_queue = 0; lp->tx_queue_len = 0; lp->tx_started = 1; - dev->trans_start = jiffies; - mark_bh(NET_BH); } else { lp->tx_started = 0; - mark_bh(NET_BH); } + netif_wake_queue(dev); } } @@ -1401,16 +1299,16 @@ eth16i_rx(dev); /* We have packet in receive buffer */ } - dev->interrupt = 0; - /* Turn interrupts back on */ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) { /* There is still more room for one more packet in tx buffer */ - dev->tbusy = 0; + netif_wake_queue(dev); } + spin_unlock(&lp->lock); + return; } @@ -1442,10 +1340,6 @@ lp->tx_buf_busy = 0; lp->tx_queue = 0; lp->tx_queue_len = 0; - - dev->interrupt = 0; - dev->start = 1; - dev->tbusy = 0; BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); } @@ -1462,10 +1356,9 @@ } } -static struct enet_statistics *eth16i_get_stats(struct net_device *dev) +static struct net_device_stats *eth16i_get_stats(struct net_device *dev) { struct eth16i_local *lp = (struct eth16i_local *)dev->priv; - return &lp->stats; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.3.44/linux/drivers/net/ewrk3.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/net/ewrk3.c Sun Feb 13 18:20:21 2000 @@ -303,6 +303,7 @@ static void ewrk3_init(struct net_device *dev); static int ewrk3_rx(struct net_device *dev); static int ewrk3_tx(struct net_device *dev); +static void ewrk3_timeout(struct net_device *dev); static void EthwrkSignature(char *name, char *eeprom_image); static int DevicePresent(u_long iobase); @@ -601,12 +602,14 @@ printk(version); } /* The EWRK3-specific entries in the device structure. */ - dev->open = &ewrk3_open; - dev->hard_start_xmit = &ewrk3_queue_pkt; - dev->stop = &ewrk3_close; - dev->get_stats = &ewrk3_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &ewrk3_ioctl; + dev->open = ewrk3_open; + dev->hard_start_xmit = ewrk3_queue_pkt; + dev->stop = ewrk3_close; + dev->get_stats = ewrk3_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->do_ioctl = ewrk3_ioctl; + dev->tx_timeout = ewrk3_timeout; + dev->watchdog_timeo = QUEUE_PKT_TIMEOUT; dev->mem_start = 0; @@ -616,7 +619,6 @@ } else { status = -ENXIO; } - return status; } @@ -664,10 +666,7 @@ printk(" cmr: 0x%02x\n", inb(EWRK3_CMR)); printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC)); } - dev->tbusy = 0; - dev->start = 1; - dev->interrupt = UNMASK_INTERRUPTS; - + netif_start_queue(dev); /* ** Unmask EWRK3 board interrupts */ @@ -676,10 +675,9 @@ } } else { - dev->start = 0; - dev->tbusy = 1; - printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name); - printk(" Run the 'ewrk3setup' utility or remove the hard straps.\n"); + printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name); + printk(KERN_ERR " Run the 'ewrk3setup' utility or remove the hard straps.\n"); + return -EINVAL; } MOD_INC_USE_COUNT; @@ -722,149 +720,148 @@ } /* - ** Writes a socket buffer to the free page queue + * Transmit timeout */ -static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev) + +static void ewrk3_timeout(struct net_device *dev) { struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; - u_long iobase = dev->base_addr; - int status = 0; u_char icr, csr; + u_long iobase = dev->base_addr; + + if (!lp->hard_strapped) + { + printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n", + dev->name, inb(EWRK3_CSR)); - /* Transmitter timeout, serious problems. */ - if (dev->tbusy || lp->lock) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < QUEUE_PKT_TIMEOUT) { - status = -1; - } else if (!lp->hard_strapped) { - printk("%s: transmit timed/locked out, status %04x, resetting.\n", - dev->name, inb(EWRK3_CSR)); - - /* - ** Mask all board interrupts - */ - DISABLE_IRQs; - - /* - ** Stop the TX and RX... - */ - STOP_EWRK3; - - ewrk3_init(dev); - - /* - ** Unmask EWRK3 board interrupts - */ - ENABLE_IRQs; - - dev->tbusy = 0; - dev->trans_start = jiffies; - } - } else if (skb->len > 0) { + /* + ** Mask all board interrupts + */ + DISABLE_IRQs; /* - ** Block a timer-based transmit from overlapping. This could better be - ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + ** Stop the TX and RX... */ - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); + STOP_EWRK3; - DISABLE_IRQs; /* So that the page # remains correct */ + ewrk3_init(dev); /* - ** Get a free page from the FMQ when resources are available + ** Unmask EWRK3 board interrupts */ - if (inb(EWRK3_FMQC) > 0) { - u_long buf = 0; - u_char page; + ENABLE_IRQs; - if ((page = inb(EWRK3_FMQ)) < lp->mPage) { - /* - ** Set up shared memory window and pointer into the window - */ - while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ - if (lp->shmem_length == IO_ONLY) { - outb(page, EWRK3_IOPR); - } else if (lp->shmem_length == SHMEM_2K) { - buf = lp->shmem_base; - outb(page, EWRK3_MPR); - } else if (lp->shmem_length == SHMEM_32K) { - buf = ((((short) page << 11) & 0x7800) + lp->shmem_base); - outb((page >> 4), EWRK3_MPR); - } else if (lp->shmem_length == SHMEM_64K) { - buf = ((((short) page << 11) & 0xf800) + lp->shmem_base); - outb((page >> 5), EWRK3_MPR); - } else { - status = -1; - printk("%s: Oops - your private data area is hosed!\n", dev->name); - } + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} - if (!status) { +/* + ** Writes a socket buffer to the free page queue + */ +static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev) +{ + struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv; + u_long iobase = dev->base_addr; + int status = 0; + u_char icr; - /* - ** Set up the buffer control structures and copy the data from - ** the socket buffer to the shared memory . - */ + netif_stop_queue(dev); +#ifdef CONFIG_SMP +#error "This needs spinlocks" +#endif + DISABLE_IRQs; /* So that the page # remains correct */ - if (lp->shmem_length == IO_ONLY) { - int i; - u_char *p = skb->data; + /* + ** Get a free page from the FMQ when resources are available + */ + if (inb(EWRK3_FMQC) > 0) + { + u_long buf = 0; + u_char page; + if ((page = inb(EWRK3_FMQ)) < lp->mPage) { + /* + ** Set up shared memory window and pointer into the window + */ + while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */ + if (lp->shmem_length == IO_ONLY) { + outb(page, EWRK3_IOPR); + } else if (lp->shmem_length == SHMEM_2K) { + buf = lp->shmem_base; + outb(page, EWRK3_MPR); + } else if (lp->shmem_length == SHMEM_32K) { + buf = ((((short) page << 11) & 0x7800) + lp->shmem_base); + outb((page >> 4), EWRK3_MPR); + } else if (lp->shmem_length == SHMEM_64K) { + buf = ((((short) page << 11) & 0xf800) + lp->shmem_base); + outb((page >> 5), EWRK3_MPR); + } else { + status = -1; + printk(KERN_ERR "%s: Oops - your private data area is hosed!\n", dev->name); + } + + if (!status) { + /* + ** Set up the buffer control structures and copy the data from + ** the socket buffer to the shared memory . + */ + if (lp->shmem_length == IO_ONLY) { + int i; + u_char *p = skb->data; outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA); - outb((char) (skb->len & 0xff), EWRK3_DATA); - outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA); - outb((char) 0x04, EWRK3_DATA); - for (i = 0; i < skb->len; i++) { - outb(*p++, EWRK3_DATA); - } + outb((char) (skb->len & 0xff), EWRK3_DATA); + outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA); + outb((char) 0x04, EWRK3_DATA); + for (i = 0; i < skb->len; i++) { + outb(*p++, EWRK3_DATA); + } + outb(page, EWRK3_TQ); /* Start sending pkt */ + } else { + writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */ + buf += 1; + writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */ + buf += 1; + if (lp->txc) { + writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf); + buf += 1; + writeb(0x04, (char *) buf); /* index byte */ + buf += 1; + writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */ + isa_memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */ outb(page, EWRK3_TQ); /* Start sending pkt */ + isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD); + writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */ } else { - writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */ + writeb((char) ((skb->len >> 8) & 0xff), (char *) buf); buf += 1; - writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */ + writeb(0x04, (char *) buf); /* index byte */ buf += 1; - if (lp->txc) { - writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf); - buf += 1; - writeb(0x04, (char *) buf); /* index byte */ - buf += 1; - writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */ - isa_memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */ - outb(page, EWRK3_TQ); /* Start sending pkt */ - isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD); - writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */ - } else { - writeb((char) ((skb->len >> 8) & 0xff), (char *) buf); - buf += 1; - writeb(0x04, (char *) buf); /* index byte */ - buf += 1; - isa_memcpy_toio(buf, skb->data, skb->len); /* Write data bytes */ - outb(page, EWRK3_TQ); /* Start sending pkt */ - } + isa_memcpy_toio(buf, skb->data, skb->len); /* Write data bytes */ + outb(page, EWRK3_TQ); /* Start sending pkt */ } - - dev->trans_start = jiffies; - dev_kfree_skb(skb); - - } else { /* return unused page to the free memory queue */ - outb(page, EWRK3_FMQ); } - lp->lock = 0; /* unlock the page register */ - } else { - printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n", - (u_char) page); + + dev->trans_start = jiffies; + dev_kfree_skb(skb); + } else { /* return unused page to the free memory queue */ + outb(page, EWRK3_FMQ); } + lp->lock = 0; /* unlock the page register */ } else { - printk("ewrk3_queue_pkt(): No free resources...\n"); - printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC)); + printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n", + (u_char) page); } + } else { + printk(KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n", dev->name); + printk(KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", dev->name, inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC)); + } - /* Check for free resources: clear 'tbusy' if there are some */ - if (inb(EWRK3_FMQC) > 0) { - dev->tbusy = 0; - } - ENABLE_IRQs; + /* Check for free resources: clear 'tbusy' if there are some */ + if (inb(EWRK3_FMQC) > 0) { + netif_wake_queue(dev); } + ENABLE_IRQs; return status; } @@ -878,60 +875,46 @@ u_long iobase; u_char icr, cr, csr; - if (dev == NULL) { - printk("ewrk3_interrupt(): irq %d for unknown device.\n", irq); - } else { - lp = (struct ewrk3_private *) dev->priv; - iobase = dev->base_addr; - - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - - dev->interrupt = MASK_INTERRUPTS; + lp = (struct ewrk3_private *) dev->priv; + iobase = dev->base_addr; - /* get the interrupt information */ - csr = inb(EWRK3_CSR); - - /* - ** Mask the EWRK3 board interrupts and turn on the LED - */ - DISABLE_IRQs; - - cr = inb(EWRK3_CR); - cr |= CR_LED; - outb(cr, EWRK3_CR); + /* get the interrupt information */ + csr = inb(EWRK3_CSR); - if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */ - ewrk3_rx(dev); + /* + ** Mask the EWRK3 board interrupts and turn on the LED + */ + DISABLE_IRQs; - if (csr & CSR_TNE) /* Tx interrupt (packet sent) */ - ewrk3_tx(dev); + cr = inb(EWRK3_CR); + cr |= CR_LED; + outb(cr, EWRK3_CR); - /* - ** Now deal with the TX/RX disable flags. These are set when there - ** are no more resources. If resources free up then enable these - ** interrupts, otherwise mask them - failure to do this will result - ** in the system hanging in an interrupt loop. - */ - if (inb(EWRK3_FMQC)) { /* any resources available? */ - lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */ - csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */ - outb(csr, EWRK3_CSR); - dev->tbusy = 0; /* clear TX busy flag */ - mark_bh(NET_BH); - } else { - lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */ - } + if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */ + ewrk3_rx(dev); - /* Unmask the EWRK3 board interrupts and turn off the LED */ - cr &= ~CR_LED; - outb(cr, EWRK3_CR); + if (csr & CSR_TNE) /* Tx interrupt (packet sent) */ + ewrk3_tx(dev); - dev->interrupt = UNMASK_INTERRUPTS; - ENABLE_IRQs; + /* + ** Now deal with the TX/RX disable flags. These are set when there + ** are no more resources. If resources free up then enable these + ** interrupts, otherwise mask them - failure to do this will result + ** in the system hanging in an interrupt loop. + */ + if (inb(EWRK3_FMQC)) { /* any resources available? */ + lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */ + csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */ + outb(csr, EWRK3_CSR); + netif_wake_queue(dev); + } else { + lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */ } - return; + /* Unmask the EWRK3 board interrupts and turn off the LED */ + cr &= ~CR_LED; + outb(cr, EWRK3_CR); + ENABLE_IRQs; } static int ewrk3_rx(struct net_device *dev) @@ -1120,9 +1103,8 @@ u_long iobase = dev->base_addr; u_char icr, csr; - dev->start = 0; - dev->tbusy = 1; - + netif_stop_queue(dev); + if (ewrk3_debug > 1) { printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inb(EWRK3_CSR)); @@ -1369,8 +1351,7 @@ ** are not available then insert a new device structure at the end of ** the current list. */ -static struct net_device * __init -alloc_device(struct net_device *dev, u_long iobase) +static struct net_device * __init alloc_device(struct net_device *dev, u_long iobase) { struct net_device *adev = NULL; int fixed = 0, new_dev = 0; diff -u --recursive --new-file v2.3.44/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c --- v2.3.44/linux/drivers/net/fc/iph5526.c Thu Nov 11 20:11:40 1999 +++ linux/drivers/net/fc/iph5526.c Sun Feb 13 18:20:21 2000 @@ -919,7 +919,8 @@ /* An IP frame was transmitted to a Bad AL_PA. Free up * the skb used. */ - dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id))); + dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id))); + netif_wake_queue(fi->dev); } } /* End of IP frame timing out. */ } /* End of frame timing out. */ @@ -977,7 +978,8 @@ * Free the skb that was used for this IP frame. */ if ((status == 0) && (seq_count > 1)) { - dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id))); + dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id))); + netif_wake_queue(fi->dev); } } } @@ -2914,65 +2916,59 @@ static int iph5526_open(struct net_device *dev) { - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; } static int iph5526_close(struct net_device *dev) { - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); MOD_DEC_USE_COUNT; return 0; } +static void iph5526_timeout(struct net_device *dev) +{ + struct fc_info *fi = (struct fc_info*)dev->priv; + printk(KERN_WARNING "%s: timed out on send.\n", dev->name); + fi->fc_stats.rx_dropped++; + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev) { -struct fc_info *fi = (struct fc_info*)dev->priv; -int status = 0; -short type = 0; -u_long flags; + struct fc_info *fi = (struct fc_info*)dev->priv; + int status = 0; + short type = 0; + u_long flags; + struct fcllc *fcllc; + ENTER("iph5526_send_packet"); - if (dev->tbusy) { - printk(KERN_WARNING "%s: DEVICE BUSY\n", dev->name); - dev->tbusy = 0; - fi->fc_stats.rx_dropped++; - dev->trans_start = jiffies; - return 0; - } - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", -dev->name); - fi->fc_stats.rx_dropped++; - return 1; - } - else { - struct fcllc *fcllc; - /* Strip off the pseudo header. - */ - skb->data = skb->data + 2*FC_ALEN; - skb->len = skb->len - 2*FC_ALEN; - fcllc = (struct fcllc *)skb->data; - type = ntohs(fcllc->ethertype); - - spin_lock_irqsave(&fi->fc_lock, flags); - switch(type) { - case ETH_P_IP: - status = tx_ip_packet(skb, skb->len, fi); - break; - case ETH_P_ARP: - status = tx_arp_packet(skb->data, skb->len, fi); - break; - default: - T_MSG("WARNING!!! Received Unknown Packet Type... Discarding..."); - fi->fc_stats.rx_dropped++; - break; - } - spin_unlock_irqrestore(&fi->fc_lock, flags); + + netif_stop_queue(dev); + /* Strip off the pseudo header. + */ + skb->data = skb->data + 2*FC_ALEN; + skb->len = skb->len - 2*FC_ALEN; + fcllc = (struct fcllc *)skb->data; + type = ntohs(fcllc->ethertype); + + spin_lock_irqsave(&fi->fc_lock, flags); + switch(type) { + case ETH_P_IP: + status = tx_ip_packet(skb, skb->len, fi); + break; + case ETH_P_ARP: + status = tx_arp_packet(skb->data, skb->len, fi); + break; + default: + T_MSG("WARNING!!! Received Unknown Packet Type... Discarding..."); + fi->fc_stats.rx_dropped++; + break; } + spin_unlock_irqrestore(&fi->fc_lock, flags); if (status) { fi->fc_stats.tx_bytes += skb->len; @@ -2981,14 +2977,14 @@ else fi->fc_stats.rx_dropped++; dev->trans_start = jiffies; - dev->tbusy = 0; /* We free up the IP buffers in the OCI_interrupt handler. * status == 0 implies that the frame was not transmitted. So the * skb is freed here. */ if ((type == ETH_P_ARP) || (status == 0)) dev_kfree_skb(skb); - mark_bh(NET_BH); + else + netif_wake_queue(dev); LEAVE("iph5526_send_packet"); return 0; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.3.44/linux/drivers/net/fmv18x.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/fmv18x.c Sun Feb 13 18:20:21 2000 @@ -58,8 +58,9 @@ #include #include -static int fmv18x_probe_list[] __initdata = -{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0}; +static int fmv18x_probe_list[] __initdata = { + 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0 +}; /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG @@ -127,14 +128,8 @@ If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ -#ifdef HAVE_DEVLIST -/* Support for an alternate probe manager, which will eliminate the - boilerplate below. */ -struct netdev_entry fmv18x_drv = -{"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list}; -#else -int __init -fmv18x_probe(struct net_device *dev) + +int __init fmv18x_probe(struct net_device *dev) { int i; int base_addr = dev ? dev->base_addr : 0; @@ -154,7 +149,6 @@ return ENODEV; } -#endif /* The Fujitsu datasheet suggests that the NIC be probed for by checking its "signature", the default bit pattern after a reset. This *doesn't* work -- @@ -584,11 +578,6 @@ static struct net_device_stats *net_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - - cli(); - /* ToDo: Update the statistics from the device registers. */ - sti(); - return &lp->stats; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/gmac.c linux/drivers/net/gmac.c --- v2.3.44/linux/drivers/net/gmac.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/gmac.c Sun Feb 13 10:47:01 2000 @@ -51,6 +51,7 @@ int phy_addr; int full_duplex; struct net_device_stats stats; + struct net_device *next_gmac; }; #define GM_OUT(r, v) out_le32(gm->regs + (r)/4, (v)) @@ -80,6 +81,7 @@ static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct net_device_stats *gmac_stats(struct net_device *dev); static int gmac_probe(void); +static void gmac_probe1(struct device_node *gmac); /* Stuff for talking to the physical-layer chip */ static int @@ -383,7 +385,7 @@ i = gm->next_tx; if (gm->tx_buff[i] != 0) { /* buffer is full, can't send this packet at the moment */ - dev->tbusy = 1; + netif_stop_queue(dev); gm->tx_full = 1; restore_flags(flags); return 1; @@ -421,7 +423,7 @@ gm->stats.tx_bytes += skb->len; ++gm->stats.tx_packets; gm->tx_buff[i] = NULL; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); if (++i >= NTX) i = 0; } @@ -452,7 +454,7 @@ ++gm->stats.rx_dropped; } else if (ld_le32(&dp->status) & 0x40000000) { ++gm->stats.rx_errors; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); } else { skb_put(skb, len); skb->dev = dev; @@ -486,14 +488,11 @@ status = GM_IN(INTR_STATUS); GM_OUT(INTR_ACK, status); - if (status & GMAC_IRQ_MIF) { + if (status & GMAC_IRQ_MIF) mii_interrupt(gm); - } gmac_receive(dev); - if (gmac_tx_cleanup(gm)){ - dev->tbusy = 0; - mark_bh(NET_BH); - } + if (gmac_tx_cleanup(gm)) + netif_wake_queue(dev); } static struct net_device_stats *gmac_stats(struct net_device *dev) @@ -505,33 +504,44 @@ static int __init gmac_probe(void) { - static int gmacs_found; - static struct device_node *next_gmac; struct device_node *gmac; - struct gmac *gm; - unsigned long descpage; - unsigned char *addr; - int i; - - if (gmacs != NULL) - return -EBUSY; /* * We could (and maybe should) do this using PCI scanning * for vendor/net_device ID 0x106b/0x21. */ - if (!gmacs_found) { - next_gmac = find_compatible_devices("network", "gmac"); - gmacs_found = 1; - } - if ((gmac = next_gmac) == 0) - return -ENODEV; - next_gmac = gmac->next; + for (gmac = find_compatible_devices("network", "gmac"); gmac != 0; + gmac = gmac->next) + gmac_probe1(gmac); + + return 0; +} + +static void gmac_probe1(struct device_node *gmac) +{ + struct gmac *gm; + unsigned long descpage; + unsigned char *addr; + struct net_device *dev; + int i; if (gmac->n_addrs < 1 || gmac->n_intrs < 1) { printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n", gmac->full_name, gmac->n_addrs, gmac->n_intrs); - return -ENODEV; + return; + } + + addr = get_property(gmac, "local-mac-address", NULL); + if (addr == NULL) { + printk(KERN_ERR "Can't get mac-address for GMAC %s\n", + gmac->full_name); + return; + } + + descpage = get_free_page(GFP_KERNEL); + if (descpage == 0) { + printk(KERN_ERR "GMAC: can't get a page for descriptors\n"); + return; } dev = init_etherdev(0, sizeof(struct gmac)); @@ -544,13 +554,6 @@ gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000); dev->irq = gmac->intrs[0].line; - addr = get_property(gmac, "local-mac-address", NULL); - if (addr == NULL) { - printk(KERN_ERR "Can't get mac-address for GMAC %s\n", - gmac->full_name); - return -EAGAIN; - } - printk(KERN_INFO "%s: GMAC at", dev->name); for (i = 0; i < 6; ++i) { dev->dev_addr[i] = addr[i]; @@ -558,12 +561,6 @@ } printk("\n"); - descpage = get_free_page(GFP_KERNEL); - if (descpage == 0) { - printk(KERN_ERR "GMAC: can't get a page for descriptors\n"); - return -EAGAIN; - } - gm->desc_page = descpage; gm->rxring = (volatile struct gmac_dma_desc *) descpage; gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800); @@ -577,34 +574,29 @@ ether_setup(dev); - if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) { + if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq); - return -EAGAIN; - } + gm->next_gmac = gmacs; gmacs = dev; - - return 0; } -MODULE_AUTHOR("Paul Mackerras"); +MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); MODULE_DESCRIPTION("PowerMac GMAC driver."); - static void __exit gmac_cleanup_module(void) { struct gmac *gm; + struct net_device *dev; - /* XXX should handle more than one */ - if (gmacs == NULL) - return; - - gm = (struct gmac *) gmacs->priv; - free_irq(gmacs->irq, gmac_interrupt); - free_page(gm->descpage); - unregister_netdev(gmacs); - kfree(gmacs); - gmacs = NULL; + while ((dev = gmacs) != NULL) { + gm = (struct gmac *) dev->priv; + gmacs = gm->next_gmac; + free_irq(dev->irq, dev); + free_page(gm->desc_page); + unregister_netdev(dev); + kfree(dev); + } } module_init(gmac_probe); diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c --- v2.3.44/linux/drivers/net/hamradio/bpqether.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/hamradio/bpqether.c Sun Feb 13 18:20:21 2000 @@ -222,7 +222,7 @@ dev = bpq_get_ax25_dev(dev); - if (dev == NULL || dev->start == 0) { + if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) { kfree_skb(skb); return 0; } @@ -275,7 +275,7 @@ * Just to be *really* sure not to send anything if the interface * is down, the ethernet device may have gone. */ - if (!dev->start) { + if (!test_bit(LINK_STATE_START, &dev->state)) { bpq_check_devices(dev); kfree_skb(skb); return -ENODEV; @@ -407,22 +407,15 @@ { if (bpq_check_devices(dev)) return -ENODEV; /* oops, it's gone */ - - dev->tbusy = 0; - dev->start = 1; - MOD_INC_USE_COUNT; - + netif_start_queue(dev); return 0; } static int bpq_close(struct net_device *dev) { - dev->tbusy = 1; - dev->start = 0; - + netif_stop_queue(dev); MOD_DEC_USE_COUNT; - return 0; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c --- v2.3.44/linux/drivers/net/hamradio/dmascc.c Wed Aug 18 11:38:51 1999 +++ linux/drivers/net/hamradio/dmascc.c Sun Feb 13 18:20:21 2000 @@ -643,7 +643,6 @@ } /* Initialize local variables */ - dev->tbusy = 0; priv->rx_ptr = 0; priv->rx_over = 0; priv->rx_head = priv->rx_tail = priv->rx_count = 0; @@ -732,7 +731,7 @@ /* Configure PI2 DMA */ if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK); - dev->start = 1; + netif_start_queue(dev); info->open++; MOD_INC_USE_COUNT; @@ -747,9 +746,8 @@ int io = dev->base_addr; int cmd = priv->cmd; - dev->start = 0; + netif_stop_queue(dev); info->open--; - MOD_DEC_USE_COUNT; if (info->type == TYPE_TWIN) /* Drop DTR */ @@ -768,6 +766,7 @@ if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK); free_irq(dev->irq, info); } + MOD_DEC_USE_COUNT; return 0; } @@ -779,16 +778,16 @@ switch (cmd) { case SIOCGSCCPARAM: - rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param)); - if (rc) return rc; - copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param)); + if(copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param))) + return -EFAULT; return 0; case SIOCSSCCPARAM: - if (!suser()) return -EPERM; - rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param)); - if (rc) return rc; - if (dev->start) return -EAGAIN; - copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (test_bit(LINK_STATE_START, &dev->state)) + return -EAGAIN; + if(copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param))) + return -EFAULT; dev->dma = priv->param.dma; return 0; default: @@ -806,18 +805,8 @@ int i; /* Block a timer-based transmit from overlapping */ - if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) { - atomic_inc((void *) &priv->stats.tx_dropped); - dev_kfree_skb(skb); - return 0; - } - - /* Return with an error if we cannot accept more data */ - if (dev->tbusy) { - priv->tx_sem = 0; - return -1; - } - + netif_stop_queue(dev); + /* Transfer data to DMA buffer */ i = priv->tx_head; memcpy(priv->tx_buf[i], skb->data+1, skb->len-1); @@ -829,7 +818,8 @@ /* Set the busy flag if we just filled up the last buffer */ priv->tx_head = (i + 1) % NUM_TX_BUF; priv->tx_count++; - if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1; + if (priv->tx_count != NUM_TX_BUF) + netif_wake_queue(dev); /* Set new TX state */ if (priv->tx_state == TX_IDLE) { @@ -1139,7 +1129,6 @@ /* Remove frame from FIFO */ priv->tx_tail = (i + 1) % NUM_TX_BUF; priv->tx_count--; - dev->tbusy = 0; /* Check if another frame is available and we are allowed to transmit */ if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) { if (dev->dma) { @@ -1171,7 +1160,7 @@ priv->stats.tx_packets++; } /* Inform upper layers */ - mark_bh(NET_BH); + netif_wake_queue(dev); } /* DCD transition */ diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.3.44/linux/drivers/net/hamradio/scc.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/hamradio/scc.c Sun Feb 13 18:20:21 2000 @@ -317,12 +317,12 @@ static inline void scc_lock_dev(struct scc_channel *scc) { - scc->dev->tbusy = 1; + netif_stop_queue(scc->dev); } static inline void scc_unlock_dev(struct scc_channel *scc) { - scc->dev->tbusy = 0; + netif_wake_queue(scc->dev); } static inline void scc_discard_buffers(struct scc_channel *scc) @@ -1660,9 +1660,7 @@ init_channel(scc); - dev->tbusy = 0; - dev->start = 1; - + netif_start_queue(dev); return 0; } @@ -1692,9 +1690,7 @@ scc_discard_buffers(scc); - dev->tbusy = 1; - dev->start = 0; - + netif_stop_queue(dev); return 0; } @@ -1727,7 +1723,7 @@ unsigned long flags; char kisscmd; - if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy) + if (scc == NULL || scc->magic != SCC_MAGIC) { dev_kfree_skb(skb); return 0; @@ -1753,7 +1749,7 @@ return 0; } - save_flags(flags); + save_flags(flags); cli(); if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len) diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c --- v2.3.44/linux/drivers/net/hamradio/yam.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/hamradio/yam.c Sun Feb 13 18:20:21 2000 @@ -649,7 +649,7 @@ for (i = 0; i < NR_PORTS; i++) { struct net_device *dev = &yam_ports[i].dev; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) yam_arbitrate(dev); } yam_timer.expires = jiffies + HZ / 100; @@ -748,7 +748,7 @@ yp = &yam_ports[i]; dev = &yp->dev; - if (!dev->start) + if (!test_bit(LINK_STATE_START, &dev->state)) continue; while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) { @@ -794,7 +794,7 @@ if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0) continue; len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name); - len += sprintf(buffer + len, " Up %d\n", yam_ports[i].dev.start); + len += sprintf(buffer + len, " Up %d\n", test_bit(LINK_STATE_START, &yam_ports[i].dev.state)); len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate); len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase); len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate); @@ -903,7 +903,9 @@ request_region(dev->base_addr, YAM_EXTENT, dev->name); yam_set_uart(dev); - dev->start = 1; + + netif_start_queue(dev); + yp->slotcnt = yp->slot / 10; /* Reset overruns for all ports - FPGA programming makes overruns */ @@ -935,8 +937,7 @@ /* Remove IRQ handler if last */ free_irq(dev->irq, NULL); release_region(dev->base_addr, YAM_EXTENT); - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); while ((skb = skb_dequeue(&yp->send_queue))) dev_kfree_skb(skb); @@ -973,7 +974,7 @@ return -EINVAL; /* unused */ case SIOCYAMSMCS: - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) return -EINVAL; /* Cannot change this parameter when up */ ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC); ym->bitrate = 9600; @@ -989,13 +990,13 @@ if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg))) return -EFAULT; - if ((yi.cfg.mask & YAM_IOBASE) && dev->start) + if ((yi.cfg.mask & YAM_IOBASE) && test_bit(LINK_STATE_START, &dev->state)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_IRQ) && dev->start) + if ((yi.cfg.mask & YAM_IRQ) && test_bit(LINK_STATE_START, &dev->state)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BITRATE) && dev->start) + if ((yi.cfg.mask & YAM_BITRATE) && test_bit(LINK_STATE_START, &dev->state)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start) + if ((yi.cfg.mask & YAM_BAUDRATE) && test_bit(LINK_STATE_START, &dev->state)) return -EINVAL; /* Cannot change this parameter when up */ if (yi.cfg.mask & YAM_IOBASE) { @@ -1164,8 +1165,6 @@ dev->irq = yam_ports[i].irq; dev->init = yam_probe; dev->if_port = 0; - dev->start = 0; - dev->tbusy = 1; if (register_netdev(dev)) { printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name); @@ -1211,7 +1210,7 @@ struct net_device *dev = &yam_ports[i].dev; if (!dev->priv) continue; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) yam_close(dev); unregister_netdev(dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/hydra.c linux/drivers/net/hydra.c --- v2.3.44/linux/drivers/net/hydra.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/hydra.c Sun Feb 13 11:21:42 2000 @@ -175,17 +175,16 @@ } strcpy(z->name, "Hydra Ethernet Card"); + dev = init_etherdev(NULL, sizeof(struct hydra_private)); + memset(dev->priv, 0, sizeof(struct hydra_private)); + for(j = 0; j < ETHER_ADDR_LEN; j++) dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j)); printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - init_etherdev(dev, 0); - - dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(struct hydra_private)); - + dev->base_addr = ZTWO_VADDR(base_addr); dev->mem_start = ZTWO_VADDR(board); dev->mem_end = dev->mem_start+0x4000; diff -u --recursive --new-file v2.3.44/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.3.44/linux/drivers/net/mace.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/mace.c Sun Feb 13 10:47:01 2000 @@ -20,9 +20,7 @@ #include #include "mace.h" -#ifdef MODULE static struct net_device *mace_devs = NULL; -#endif #define N_RX_RING 8 #define N_TX_RING 6 @@ -55,6 +53,7 @@ struct net_device_stats stats; struct timer_list tx_timeout; int timeout_active; + struct net_device *next_mace; }; /* @@ -67,6 +66,8 @@ + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd)) static int bitrev(int); +static int mace_probe(void); +static void mace_probe1(struct device_node *mace); static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); @@ -99,34 +100,36 @@ return d; } -static int __init mace_probe (void) +static int __init mace_probe(void) +{ + struct device_node *mace; + + for (mace = find_devices("mace"); mace != NULL; mace = mace->next) + mace_probe1(mace); + return 0; +} + +static void __init mace_probe1(struct device_node *mace) { int j, rev; struct net_device *dev; struct mace_data *mp; - struct device_node *mace; unsigned char *addr; - static int maces_found = 0; - static struct device_node *next_mace; - -#ifdef MODULE - if(mace_devs != NULL) - return -EBUSY; -#endif - - if (!maces_found) { - next_mace = find_devices("mace"); - maces_found = 1; - } - mace = next_mace; - if (mace == 0) - return -ENODEV; - next_mace = mace->next; if (mace->n_addrs != 3 || mace->n_intrs != 3) { - printk(KERN_ERR "can't use MACE %s: expect 3 addrs and 3 intrs\n", + printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", mace->full_name); - return -ENODEV; + return; + } + + addr = get_property(mace, "mac-address", NULL); + if (addr == NULL) { + addr = get_property(mace, "local-mac-address", NULL); + if (addr == NULL) { + printk(KERN_ERR "Can't get mac-address for MACE %s\n", + mace->full_name); + return; + } } dev = init_etherdev(0, PRIV_BYTES); @@ -138,16 +141,6 @@ ioremap(mace->addrs[0].address, 0x1000); dev->irq = mace->intrs[0].line; - addr = get_property(mace, "mac-address", NULL); - if (addr == NULL) { - addr = get_property(mace, "local-mac-address", NULL); - if (addr == NULL) { - printk(KERN_ERR "Can't get mac-address for MACE at %lx\n", - dev->base_addr); - return -EAGAIN; - } - } - printk(KERN_INFO "%s: MACE at", dev->name); rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) { @@ -186,22 +179,17 @@ mace_reset(dev); - if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { + if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); - return -EAGAIN; - } if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", - dev)) { + dev)) printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); - return -EAGAIN; - } if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", - dev)) { + dev)) printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); - return -EAGAIN; - } - return 0; + mp->next_mace = mace_devs; + mace_devs = dev; } static void dbdma_reset(volatile struct dbdma_regs *dma) @@ -365,9 +353,7 @@ /* enable all interrupts except receive interrupts */ out_8(&mb->imr, RCVINT); -#ifdef MOD_INC_USE_COUNT MOD_INC_USE_COUNT; -#endif return 0; } @@ -406,9 +392,7 @@ mace_clean_rings(mp); -#ifdef MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT; -#endif return 0; } @@ -683,7 +667,7 @@ mp->stats.tx_bytes += mp->tx_bufs[i]->len; ++mp->stats.tx_packets; } - dev_kfree_skb(mp->tx_bufs[i]); + dev_kfree_skb_irq(mp->tx_bufs[i]); --mp->tx_active; if (++i >= N_TX_RING) i = 0; @@ -895,23 +879,25 @@ } } - MODULE_AUTHOR("Paul Mackerras"); MODULE_DESCRIPTION("PowerMac MACE driver."); static void __exit mace_cleanup (void) { -#ifdef MODULE - struct mace_data *mp = (struct mace_data *) mace_devs->priv; - unregister_netdev(mace_devs); - - free_irq(mace_devs->irq, mace_interrupt); - free_irq(mp->tx_dma_intr, mace_txdma_intr); - free_irq(mp->rx_dma_intr, mace_rxdma_intr); + struct net_device *dev; + struct mace_data *mp; - kfree(mace_devs); - mace_devs = NULL; -#endif + while ((dev = mace_devs) != 0) { + mp = (struct mace_data *) mace_devs->priv; + mace_devs = mp->next_mace; + + free_irq(dev->irq, dev); + free_irq(mp->tx_dma_intr, dev); + free_irq(mp->rx_dma_intr, dev); + + unregister_netdev(dev); + kfree(dev); + } } module_init(mace_probe); diff -u --recursive --new-file v2.3.44/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c --- v2.3.44/linux/drivers/net/ncr885e.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/ncr885e.c Sun Feb 13 10:47:01 2000 @@ -11,9 +11,10 @@ */ static const char *version = -"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n"; +"ncr885e.c:v1.0 02/10/00 dan@synergymicro.com, cort@fsmlabs.com\n"; #include + #include #include #include @@ -81,8 +82,6 @@ int ncr885e_debug = NCR885E_DEBUG; static int print_version = 0; -static int debug = NCR885E_DEBUG; /* module parm */ - struct ncr885e_private { @@ -426,7 +425,6 @@ if ( xfer ) { dev_kfree_skb( sp->tx_skbufs[i] ); - mark_bh( NET_BH ); if ( txbits & TX_STATUS_TXOK ) { sp->stats.tx_packets++; @@ -443,7 +441,7 @@ } - dev->tbusy = 0; + netif_start_queue(dev); return; } @@ -626,12 +624,6 @@ sp = (struct ncr885e_private *) dev->priv; spin_lock( &sp->lock ); - if ( dev->interrupt ) { - printk( KERN_ERR "%s: Re-entering interrupt handler...\n", - dev->name ); - } - - dev->interrupt = 1; status = inw( ioaddr + INTERRUPT_CLEAR ); if (ncr885e_debug > 2) @@ -671,7 +663,6 @@ ncr885e_rx( dev ); } - dev->interrupt = 0; spin_unlock( &sp->lock ); return; @@ -779,8 +770,7 @@ /* start anew from the beginning of the ring buffer (why not?) */ sp->tx_current = 0; - dev->tbusy = 0; - mark_bh( NET_BH ); + netif_wake_queue(dev); /* restart rx dma */ outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN, @@ -958,9 +948,7 @@ outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN, ioaddr + RX_CHANNEL_CONTROL ); - dev->start = 1; - dev->tbusy = 0; - dev->interrupt = 0; + netif_start_queue(dev); MOD_INC_USE_COUNT; @@ -990,7 +978,7 @@ next = 0; /* mark ourselves as busy, even if we have too many packets waiting */ - dev->tbusy = 1; + netif_stop_queue(dev); /* see if it's necessary to defer this packet */ if ( sp->tx_active >= MAX_TX_ACTIVE ) { @@ -1058,8 +1046,7 @@ struct ncr885e_private *np = (struct ncr885e_private *) dev->priv; unsigned long ioaddr = dev->base_addr; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); spin_lock( &np->lock ); @@ -1148,8 +1135,7 @@ * configuration. */ -static int -ncr885e_probe1(unsigned long ioaddr, unsigned char irq ) +static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq ) { struct net_device *dev; @@ -1158,9 +1144,6 @@ unsigned char *p; int i; - if (!request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name)) - return -EBUSY; - dev = init_etherdev(NULL, 0 ); /* construct private data for the 885 ethernet */ @@ -1413,12 +1396,16 @@ #endif /* NCR885E_DEBUG_MII */ -MODULE_AUTHOR("dan@synergymicro.com"); -MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver"); -MODULE_PARM(debug, "i"); +int +init_module(void) +{ + if ( debug >= 0) + ncr885e_debug = debug; + return ncr885e_probe(); +} -static void __exit ncr885e_cleanup (void) +static void __exit cleanup_module(void) { struct ncr885e_private *np; @@ -1434,7 +1421,6 @@ module_init(ncr885e_probe); module_exit(ncr885e_cleanup); - /* * Local variables: diff -u --recursive --new-file v2.3.44/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.3.44/linux/drivers/net/ni65.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/ni65.c Sun Feb 13 18:20:21 2000 @@ -228,6 +228,7 @@ static int ni65_lance_reinit(struct net_device *dev); static void ni65_init_lance(struct priv *p,unsigned char*,int,int); static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev); +static void ni65_timeout(struct net_device *dev); static int ni65_close(struct net_device *dev); static int ni65_alloc_buffer(struct net_device *dev); static void ni65_free_buffer(struct priv *p); @@ -278,16 +279,13 @@ if(ni65_lance_reinit(dev)) { - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; } else { free_irq(dev->irq,dev); - dev->start = 0; return -EAGAIN; } } @@ -299,6 +297,8 @@ { struct priv *p = (struct priv *) dev->priv; + netif_stop_queue(dev); + outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */ #ifdef XMT_VIA_SKB @@ -314,8 +314,6 @@ } #endif free_irq(dev->irq,dev); - dev->tbusy = 1; - dev->start = 0; MOD_DEC_USE_COUNT; return 0; } @@ -482,15 +480,13 @@ dev->open = ni65_open; dev->stop = ni65_close; dev->hard_start_xmit = ni65_send_packet; + dev->tx_timeout = ni65_timeout; + dev->watchdog_timeo = HZ/2; dev->get_stats = ni65_get_stats; dev->set_multicast_list = set_multicast_list; ether_setup(dev); - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 0; - return 0; /* everything is OK */ } @@ -714,7 +710,8 @@ } p->rmdnum = p->tmdlast = 0; if(!p->lock) - dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1; + if (p->tmdnum || !p->xmit_queued) + netif_wake_queue(dev); dev->trans_start = jiffies; } else @@ -813,15 +810,6 @@ struct priv *p; int bcnt = 32; - if (dev == NULL) { - printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq); - return; - } - - if(test_and_set_bit(0,(int *) &dev->interrupt)) { - printk("ni65: oops .. interrupt while proceeding interrupt\n"); - return; - } p = (struct priv *) dev->priv; while(--bcnt) { @@ -916,8 +904,6 @@ else writedatareg(CSR0_INEA); - dev->interrupt = 0; - return; } @@ -974,7 +960,7 @@ #ifdef XMT_VIA_SKB if(p->tmd_skb[p->tmdlast]) { - dev_kfree_skb(p->tmd_skb[p->tmdlast]); + dev_kfree_skb_irq(p->tmd_skb[p->tmdlast]); p->tmd_skb[p->tmdlast] = NULL; } #endif @@ -983,8 +969,7 @@ if(p->tmdlast == p->tmdnum) p->xmit_queued = 0; } - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); } /* @@ -1082,32 +1067,31 @@ /* * kick xmitter .. */ -static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) + +static void ni65_timeout(struct net_device *dev) { + int i; struct priv *p = (struct priv *) dev->priv; - if(dev->tbusy) - { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 50) - return 1; + printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); + for(i=0;itmdhead[i].u.s.status); + printk("\n"); + ni65_lance_reinit(dev); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} - printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); - { - int i; - for(i=0;itmdhead[i].u.s.status); - printk("\n"); - } - ni65_lance_reinit(dev); - dev->tbusy=0; - dev->trans_start = jiffies; - } +/* + * Send a packet + */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); - return 1; - } +static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + + netif_stop_queue(dev); + if (test_and_set_bit(0, (void*)&p->lock)) { printk(KERN_ERR "%s: Queue was locked.\n", dev->name); return 1; @@ -1152,7 +1136,9 @@ p->xmit_queued = 1; p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1); - dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0; + if(p->tmdnum != p->tmdlast) + netif_wake_queue(dev); + p->lock = 0; dev->trans_start = jiffies; @@ -1183,7 +1169,7 @@ { if(!ni65_lance_reinit(dev)) printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name); - dev->tbusy = 0; + netif_wake_queue(dev); } #ifdef MODULE diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c --- v2.3.44/linux/drivers/net/pcmcia/3c574_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/3c574_cs.c Sun Feb 13 10:23:26 2000 @@ -220,6 +220,7 @@ u_short media_status; u_short fast_poll; u_long last_irq; + spinlock_t lock; }; /* Set iff a MII transceiver on any interface requires mdio preamble. @@ -261,6 +262,7 @@ static int el3_close(struct net_device *dev); static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); +static void el3_tx_timeout(struct net_device *dev); static dev_info_t dev_info = "3c574_cs"; @@ -320,6 +322,8 @@ lp = kmalloc(sizeof(*lp), GFP_KERNEL); if (!lp) return NULL; memset(lp, 0, sizeof(*lp)); + + lp->lock = SPIN_LOCK_UNLOCKED; link = &lp->link; dev = &lp->dev; link->priv = dev->priv = link->irq.Instance = lp; @@ -351,7 +355,10 @@ dev->init = &tc574_init; dev->open = &el3_open; dev->stop = &el3_close; - dev->tbusy = 1; + dev->tx_timeout = el3_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + netif_start_queue (dev); /* Register with Card Services */ link->next = dev_list; @@ -398,13 +405,12 @@ if (*linkp == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&lp->lock, flags); if (link->state & DEV_RELEASE_PENDING) { del_timer(&link->release); link->state &= ~DEV_RELEASE_PENDING; } - restore_flags(flags); + spin_unlock_irqrestore(&lp->lock, flags); if (link->state & DEV_CONFIG) { tc574_release((u_long)link); @@ -502,7 +508,7 @@ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); goto failed; @@ -667,7 +673,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -682,7 +688,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -695,7 +701,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { tc574_reset(dev); - dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); } } break; @@ -913,7 +919,7 @@ link->open++; MOD_INC_USE_COUNT; - dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); tc574_reset(dev); lp->media.function = &media_check; @@ -939,7 +945,7 @@ /* Issue TX_RESET and TX_START commands. */ wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); - dev->tbusy = 0; + netif_start_queue (dev); } static void pop_tx_status(struct net_device *dev) @@ -972,22 +978,16 @@ long flags = 0; #endif - /* Transmitter timeout, serious problems. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - el3_tx_timeout(dev); - } - DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, inw(ioaddr + EL3_STATUS)); + netif_stop_queue (dev); + #ifdef BROKEN_FEATURES if (use_fifo_buffer) { /* Avoid other accesses to the chip while RunnerWrCtrl is non-zero. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lp->lock, flags); outw((((skb->len + 7)>>2)<<1), ioaddr + RunnerWrCtrl); DEBUG(0, "TxFree %x, tx length %x, RunnerWrCtrl is %4.4x.\n", inw(ioaddr+TxFree), skb->len, inw(ioaddr+RunnerWrCtrl)); @@ -1009,7 +1009,7 @@ DEBUG(0, " RunnerWr/RdCtrl is %4.4x/%4.4x, TxFree %x.\n", inw(ioaddr + RunnerWrCtrl), inw(ioaddr + RunnerRdCtrl), inw(ioaddr + TxFree)); - restore_flags(flags); + spin_unlock_irqrestore (&lp->lock, flags); } #else outw(skb->len, ioaddr + TX_FIFO); @@ -1021,7 +1021,7 @@ /* TxFree appears only in Window 1, not offset 0x1c. */ if (inw(ioaddr + TxFree) > 1536) { - dev->tbusy = 0; + netif_start_queue (dev); } else /* Interrupt us when the FIFO has room for max-sized packet. The threshold is in units of dwords. */ @@ -1041,26 +1041,27 @@ ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; - if ((lp == NULL) || !dev->start) + if (lp == NULL) return; + + spin_lock (&lp->lock); + ioaddr = dev->base_addr; #ifdef PCMCIA_DEBUG - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n", - dev->name); - return; - } DEBUG(3, "%s: interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); #endif while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | RxEarly | StatsFull)) { + +#if 0 if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: Interrupt from dead card\n", dev->name); break; } +#endif if (status & RxComplete) work_budget = el3_rx(dev, work_budget); @@ -1069,8 +1070,9 @@ DEBUG(3, " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue (dev); + } else { + netif_stop_queue (dev); } if (status & TxComplete) @@ -1120,9 +1122,9 @@ #ifdef PCMCIA_DEBUG DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); - dev->interrupt = 0; #endif - return; + + spin_unlock (&lp->lock); } /* @@ -1138,7 +1140,9 @@ u_long flags; u_short /* cable, */ media, partner; +#if 0 if (dev->start == 0) goto reschedule; +#endif /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ @@ -1208,7 +1212,7 @@ { struct el3_private *lp = (struct el3_private *)dev->priv; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) update_stats(dev); return &lp->stats; } @@ -1404,6 +1408,8 @@ DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + netif_stop_queue (dev); + if (DEV_OK(link)) { /* Turn off statistics ASAP. We update lp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -1419,7 +1425,6 @@ } link->open--; - dev->start = 0; del_timer(&lp->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c --- v2.3.44/linux/drivers/net/pcmcia/3c575_cb.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/3c575_cb.c Sun Feb 13 10:23:26 2000 @@ -53,18 +53,7 @@ #error You must compile this driver with "-O". #endif -#include -#include -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -89,13 +78,6 @@ #include -#define PCI_SUPPORT_VER2 -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#if ! defined(CAP_NET_ADMIN) -#define capable(CAP_XXX) (suser()) -#endif - -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); MODULE_PARM(debug, "i"); @@ -106,7 +88,6 @@ MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); -#endif /* Operational parameter that usually are not changed. */ @@ -209,15 +190,15 @@ const char *name; u16 vendor_id, device_id, device_id_mask, flags; int drv_flags, io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev, - long ioaddr, int irq, int chip_idx, int fnd_cnt); + struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev, + long ioaddr, int irq, int chip_idx, int fnd_cnt); }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; -static struct net_device *vortex_probe1(int pci_bus, int pci_devfn, - struct net_device *dev, long ioaddr, - int irq, int dev_id, int card_idx); +static struct net_device *vortex_probe1(struct pci_dev *pdev, + struct net_device *dev, long ioaddr, + int irq, int dev_id, int card_idx); static struct pci_id_info pci_tbl[] = { {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1}, @@ -427,7 +408,7 @@ struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ /* PCI configuration space information. */ - u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ + struct pci_dev *pdev; char *cb_fn_base; /* CardBus function status addr space. */ int chip_id; @@ -451,6 +432,7 @@ u16 advertising; /* NWay media advertisement */ unsigned char phys[2]; /* MII device addresses. */ u16 deferred; + spinlock_t lock; }; /* The action to take with a media selection timer tick. @@ -501,7 +483,8 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void acpi_wake(int pci_bus, int pci_devfn); +static void vortex_tx_timeout(struct net_device *dev); +static void acpi_wake(struct pci_dev *pdev); static void acpi_set_WOL(struct net_device *dev); /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ @@ -542,20 +525,21 @@ { u16 dev_id, vendor_id; u32 io; - u8 bus, devfn, irq; + u8 irq; struct net_device *dev; int chip_idx; + struct pci_dev *pdev; vortex_reap(); if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); - pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); + pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); + if (!pdev) return NULL; + io = pci_resource_start (pdev, 0); + irq = pdev->irq; + vendor_id = pdev->vendor; + dev_id = pdev->device; printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - bus, devfn, dev_id); - io &= ~3; + pdev->bus->number, pdev->devfn, dev_id); if (io == 0 || irq == 0) { printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " "assigned an %s.\n" KERN_ERR " It will not be activated.\n", @@ -572,7 +556,7 @@ "vortex_attach().\n", vendor_id, dev_id); return NULL; } - dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1); + dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1); if (dev) { dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); strcpy(node->dev_name, dev->name); @@ -663,44 +647,6 @@ int cards_found = 0; /* Allow an EISA-only driver. */ -#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI)) - /* Ideally we would detect all cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well with the current structure. So instead we detect 3Com cards - in slot order. */ - if (pcibios_present()) { - static int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - - for (;pci_index < 0xff; pci_index++) { - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - /* The Cyclone requires config space re-write if powered down. */ - acpi_wake(pci_bus, pci_device_fn); - - { - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; - irq = pdev->irq; -#elif LINUX_VERSION_CODE >= 0x20155 struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & ~3; irq = pdev->irq; @@ -751,7 +697,6 @@ } } } -#endif /* NO_PCI */ /* Now check all slots of the EISA bus. */ if (EISA_bus) { @@ -787,9 +732,9 @@ } #endif /* ! Cardbus */ -static struct net_device *vortex_probe1(int pci_bus, int pci_devfn, - struct net_device *dev, long ioaddr, - int irq, int chip_idx, int card_idx) +static struct net_device *vortex_probe1(struct pci_dev *pdev, + struct net_device *dev, long ioaddr, + int irq, int chip_idx, int card_idx) { struct vortex_private *vp; int option; @@ -817,9 +762,9 @@ vp->next_module = root_vortex_dev; root_vortex_dev = dev; + vp->lock = SPIN_LOCK_UNLOCKED; vp->chip_id = chip_idx; - vp->pci_bus = pci_bus; - vp->pci_devfn = pci_devfn; + vp->pdev = pdev; /* The lower four bits are the media type. */ if (dev->mem_start) @@ -892,10 +837,9 @@ if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ - pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2, - &fn_st_addr); + fn_st_addr = pci_resource_start (pdev, 2); if (fn_st_addr) - vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128); + vp->cb_fn_base = ioremap(fn_st_addr, 128); printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n", dev->name, fn_st_addr, vp->cb_fn_base); } @@ -988,6 +932,8 @@ dev->get_stats = &vortex_get_stats; dev->do_ioctl = &vortex_ioctl; dev->set_multicast_list = &set_rx_mode; + dev->tx_timeout = vortex_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; return dev; } @@ -1013,7 +959,7 @@ int i; /* Should be if(HAS_ACPI) */ - acpi_wake(vp->pci_bus, vp->pci_devfn); + acpi_wake(vp->pdev); /* Before initializing select the active media port. */ EL3WINDOW(3); @@ -1157,9 +1103,7 @@ outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ vp->in_interrupt = 0; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue (dev); outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ @@ -1377,8 +1321,10 @@ ioaddr + DownListPtr); if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { vp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue (dev); } + if (vp->tx_full) + netif_stop_queue (dev); outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); } else @@ -1478,12 +1424,8 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start >= TX_TIMEOUT) - vortex_tx_timeout(dev); - return 1; - } - + netif_stop_queue (dev); + /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); if (vp->bus_master) { @@ -1496,9 +1438,9 @@ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - DEV_FREE_SKB(skb); + dev_kfree_skb (skb); if (inw(ioaddr + TxFree) > 1536) { - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue (dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); @@ -1535,11 +1477,8 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start >= TX_TIMEOUT) - vortex_tx_timeout(dev); - return 1; - } else { + netif_stop_queue (dev); + if (1) { /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry = @@ -1561,8 +1500,7 @@ vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); - save_flags(flags); - cli(); + spin_lock_irqsave(&vp->lock, flags); /* Wait for the stall to complete. */ wait_for_completion(dev, DownStall); prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry])); @@ -1571,16 +1509,17 @@ queued_packet++; } outw(DownUnstall, ioaddr + EL3_CMD); - restore_flags(flags); + spin_unlock_irqrestore(&vp->lock, flags); vp->cur_tx++; - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) + if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { vp->tx_full = 1; - else { /* Clear previous interrupt enable. */ + netif_stop_queue (dev); + } else { /* Clear previous interrupt enable. */ #if defined(tx_interrupt_mitigation) prev_entry->status &= cpu_to_le32(~TxIntrUploaded); #endif - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue (dev); } dev->trans_start = jiffies; return 0; @@ -1597,23 +1536,8 @@ int latency, status; int work_done = max_interrupt_work; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif - - dev->interrupt = 1; + spin_lock (&vp->lock); + ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); status = inw(ioaddr + EL3_STATUS); @@ -1643,8 +1567,7 @@ printk(KERN_DEBUG " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } if (status & DownComplete) { @@ -1657,7 +1580,7 @@ virt_to_bus(&vp->tx_ring[entry])) break; /* It still hasn't been processed. */ if (vp->tx_skbuff[entry]) { - DEV_FREE_SKB(vp->tx_skbuff[entry]); + dev_kfree_skb_irq(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; } /* vp->stats.tx_packets++; Counted below. */ @@ -1666,19 +1589,21 @@ vp->dirty_tx = dirty_tx; if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { vp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } } + if (vp->tx_full) + netif_stop_queue (dev); if (status & DMADone) { if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ + dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */ if (inw(ioaddr + TxFree) > 1536) { - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); - } else /* Interrupt when FIFO has room for max-sized packet. */ + netif_wake_queue (dev); + } else { /* Interrupt when FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + netif_stop_queue (dev); + } } } /* Check for all uncommon interrupts at once. */ @@ -1715,12 +1640,7 @@ printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif - return; + spin_unlock (&vp->lock); } static int vortex_rx(struct net_device *dev) @@ -1891,8 +1811,7 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue (dev); del_timer(&vp->timer); @@ -1926,7 +1845,7 @@ long ioaddr = dev->base_addr; int i; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) vortex_down(dev); if (vortex_debug > 1) { @@ -1942,14 +1861,14 @@ if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { - DEV_FREE_SKB(vp->rx_skbuff[i]); + dev_kfree_skb(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - DEV_FREE_SKB(vp->tx_skbuff[i]); + dev_kfree_skb(vp->tx_skbuff[i]); vp->tx_skbuff[i] = 0; } } @@ -1964,11 +1883,10 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - if (dev->start) { - save_flags(flags); - cli(); + if (test_bit(LINK_STATE_START, &dev->state)) { + spin_lock_irqsave (&vp->lock, flags); update_stats(dev->base_addr, dev); - restore_flags(flags); + spin_unlock_irqrestore (&vp->lock, flags); } return &vp->stats; } @@ -2168,35 +2086,35 @@ outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); outw(RxEnable, ioaddr + EL3_CMD); /* Change the power state to D3; RxEnable doesn't take effect. */ - pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103); + pci_write_config_word(vp->pdev, 0xe0, 0x8103); } /* Change from D3 (sleep) to D0 (active). Problem: The Cyclone forgets all PCI config info during the transition! */ -static void acpi_wake(int bus, int devfn) +static void acpi_wake(struct pci_dev *pdev) { u32 base0, base1, romaddr; u16 pci_command, pwr_command; u8 pci_latency, pci_cacheline, irq; - pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command); + pci_read_config_word(pdev, 0xe0, &pwr_command); if ((pwr_command & 3) == 0) return; - pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command); - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0); - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1); - pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr); - pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency); - pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline); - pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq); - - pcibios_write_config_word( bus, devfn, 0xe0, 0x0000); - pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0); - pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1); - pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr); - pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq); - pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency); - pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline); - pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5); + pci_read_config_word( pdev, PCI_COMMAND, &pci_command); + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0); + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1); + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr); + pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); + pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq); + + pci_write_config_word( pdev, 0xe0, 0x0000); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr); + pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq); + pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency); + pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); + pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5); } #ifdef MODULE diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.3.44/linux/drivers/net/pcmcia/3c589_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/3c589_cs.c Sun Feb 13 10:23:26 2000 @@ -155,6 +155,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev); static int el3_close(struct net_device *dev); +static void el3_tx_timeout(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -257,7 +258,10 @@ dev->init = &tc589_init; dev->open = &el3_open; dev->stop = &el3_close; - dev->tbusy = 1; + dev->tx_timeout = el3_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + netif_start_queue (dev); /* Register with Card Services */ link->next = dev_list; @@ -399,7 +403,7 @@ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "3c589_cs: register_netdev() failed\n"); goto failed; @@ -508,7 +512,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -523,7 +527,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -536,7 +540,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { tc589_reset(dev); - dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); } } break; @@ -683,7 +687,7 @@ link->open++; MOD_INC_USE_COUNT; - dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); tc589_reset(dev); lp->media.function = &media_check; @@ -709,7 +713,7 @@ /* Issue TX_RESET and TX_START commands. */ wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); - dev->tbusy = 0; + netif_start_queue (dev); } static void pop_tx_status(struct net_device *dev) @@ -739,22 +743,12 @@ { ioaddr_t ioaddr = dev->base_addr; - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - el3_tx_timeout(dev); - } - DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " "status %4.4x.\n", dev->name, (long)skb->len, inw(ioaddr + EL3_STATUS)); - /* Avoid timer-based retransmission conflicts. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk(KERN_NOTICE "%s: transmitter access conflict.\n", - dev->name); - else { + netif_stop_queue (dev); + if (1) { struct el3_private *lp = (struct el3_private *)dev->priv; lp->stats.tx_bytes += skb->len; /* Put out the doubleword header... */ @@ -765,7 +759,7 @@ dev->trans_start = jiffies; if (inw(ioaddr + TX_FREE) > 1536) { - dev->tbusy = 0; + netif_start_queue (dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); @@ -785,7 +779,7 @@ ioaddr_t ioaddr, status; int i = 0; - if ((lp == NULL) || !dev->start) + if (lp == NULL) return; ioaddr = dev->base_addr; @@ -802,10 +796,12 @@ while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { +#if 0 if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); break; } +#endif if (status & RxComplete) el3_rx(dev); @@ -814,8 +810,9 @@ DEBUG(3, " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue (dev); + } else { + netif_stop_queue (dev); } if (status & TxComplete) @@ -879,7 +876,9 @@ u_short media, errs; u_long flags; +#if 0 if (dev->start == 0) goto reschedule; +#endif EL3WINDOW(1); /* Check for pending interrupt with expired latency timer: with @@ -1093,6 +1092,8 @@ ioaddr_t ioaddr = dev->base_addr; DEBUG(1, "%s: shutting down ethercard.\n", dev->name); + + netif_stop_queue (dev); if (DEV_OK(link)) { /* Turn off statistics ASAP. We update lp->stats below. */ @@ -1122,7 +1123,6 @@ } link->open--; - dev->start = 0; del_timer(&lp->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c --- v2.3.44/linux/drivers/net/pcmcia/aironet4500_cs.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/net/pcmcia/aironet4500_cs.c Sun Feb 13 10:23:26 2000 @@ -231,8 +231,7 @@ dev->init = &awc_pcmcia_init; dev->open = &awc_pcmcia_open; dev->stop = &awc_pcmcia_close; - dev->tbusy = 1; - dev->start = 0; + netif_start_queue (dev); link->priv = dev; #if CS_RELEASE_CODE > 0x2911 @@ -567,7 +566,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); link->release.expires = RUN_AT( HZ/20 ); add_timer(&link->release); } @@ -582,7 +581,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -595,7 +594,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { // awc_reset(dev); - dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); } } break; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c --- v2.3.44/linux/drivers/net/pcmcia/fmvj18x_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/fmvj18x_cs.c Sun Feb 13 18:24:12 2000 @@ -115,6 +115,7 @@ static void fjn_reset(struct net_device *dev); static struct net_device_stats *fjn_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); +static void fjn_tx_timeout (struct net_device *dev); static dev_info_t dev_info = "fmvj18x_cs"; static dev_link_t *dev_list = NULL; @@ -139,6 +140,7 @@ cardtype_t cardtype; u_short sent; u_char mc_filter[8]; + spinlock_t lock; } local_info_t; #define MC_FILTERBREAK 64 @@ -235,6 +237,8 @@ #define INTR_OFF 0x0d /* LAN controler ignores interrupts */ #define INTR_ON 0x1d /* LAN controler will catch interrupts */ +#define TX_TIMEOUT 10 + /*====================================================================== This bit of code is used to avoid unregistering network devices @@ -278,6 +282,8 @@ lp = kmalloc(sizeof(*lp), GFP_KERNEL); if (!lp) return NULL; memset(lp, 0, sizeof(*lp)); + + lp->lock = SPIN_LOCK_UNLOCKED; link = &lp->link; dev = &lp->dev; link->priv = dev->priv = link->irq.Instance = lp; @@ -314,7 +320,9 @@ dev->init = &fmvj18x_init; dev->open = &fjn_open; dev->stop = &fjn_close; - dev->tbusy = 0xFF; + dev->tx_timeout = fjn_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + netif_start_queue (dev); /* Register with Card Services */ link->next = dev_list; @@ -462,7 +470,7 @@ CS_CHECK(RequestConfiguration, link->handle, &link->conf); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); goto failed; @@ -585,8 +593,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 0xFF; - dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -601,8 +608,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 0xFF; - dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -614,9 +620,8 @@ if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { - dev->tbusy = 0; - dev->start = 1; fjn_reset(dev); + netif_start_queue (dev); } } break; @@ -670,12 +675,9 @@ "unknown device.\n", irq); return; } - if (dev->interrupt) { - printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n", - dev->name); - return; - } - dev->interrupt = 1; + + spin_lock (&lp->lock); + ioaddr = dev->base_addr; /* avoid multiple interrupts */ @@ -708,71 +710,65 @@ lp->tx_queue = 0; lp->tx_queue_len = 0; dev->trans_start = jiffies; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue (dev); } else { lp->tx_started = 0; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_stop_queue (dev); } } DEBUG(4, "%s: exiting interrupt,\n", dev->name); DEBUG(4, " tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat); - dev->interrupt = 0; outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); - return; + spin_unlock (&lp->lock); + } /* fjn_interrupt */ /*====================================================================*/ - -static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void fjn_tx_timeout (struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; - ioaddr_t ioaddr = dev->base_addr; - - if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 10) - return 1; - printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n", - dev->name, htons(inw(ioaddr + TX_STATUS)), - inb(ioaddr + TX_STATUS) & F_TMT_RDY - ? "IRQ conflict" : "network cable problem"); - printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x " - "%04x %04x %04x %04x %04x.\n", - dev->name, htons(inw(ioaddr + 0)), - htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)), - htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)), - htons(inw(ioaddr +10)), htons(inw(ioaddr +12)), - htons(inw(ioaddr +14))); + struct local_info_t *lp = (struct local_info_t *) dev->priv; + ioaddr_t ioaddr = dev->base_addr; + unsigned long flags; + + printk (KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n", + dev->name, htons (inw (ioaddr + TX_STATUS)), + inb (ioaddr + TX_STATUS) & F_TMT_RDY + ? "IRQ conflict" : "network cable problem"); + printk (KERN_NOTICE "%s: timeout registers: %04x %04x %04x " + "%04x %04x %04x %04x %04x.\n", + dev->name, htons (inw (ioaddr + 0)), + htons (inw (ioaddr + 2)), htons (inw (ioaddr + 4)), + htons (inw (ioaddr + 6)), htons (inw (ioaddr + 8)), + htons (inw (ioaddr + 10)), htons (inw (ioaddr + 12)), + htons (inw (ioaddr + 14))); lp->stats.tx_errors++; + /* ToDo: We should try to restart the adaptor... */ - cli(); + spin_lock_irqsave (&lp->lock, flags); - fjn_reset(dev); + fjn_reset (dev); lp->tx_started = 0; lp->tx_queue = 0; lp->tx_queue_len = 0; lp->sent = 0; lp->open_time = jiffies; - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - - sti(); - } + netif_start_queue (dev); + + spin_unlock_irqrestore (&lp->lock, flags); +} + + +static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct local_info_t *lp = (struct local_info_t *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name); - else { + netif_stop_queue (dev); + if (1) { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; @@ -806,17 +802,17 @@ lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; - dev->tbusy = 0; + netif_start_queue (dev); } else { if( sram_config == 0 ) { if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) ) /* Yes, there is room for one more packet. */ - dev->tbusy = 0; + netif_start_queue (dev); } else { if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && lp->tx_queue < 127 ) /* Yes, there is room for one more packet. */ - dev->tbusy = 0; + netif_start_queue (dev); } } @@ -1025,9 +1021,7 @@ lp->tx_queue = 0; lp->tx_queue_len = 0; lp->open_time = jiffies; - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; + netif_start_queue (dev); MOD_INC_USE_COUNT; @@ -1045,8 +1039,7 @@ DEBUG(4, "fjn_close('%s').\n", dev->name); lp->open_time = 0; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); /* Set configuration register 0 to disable Tx and Rx. */ if( sram_config == 0 ) @@ -1064,7 +1057,6 @@ outb(INTR_OFF, ioaddr + LAN_CTRL); link->open--; - dev->start = 0; if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c --- v2.3.44/linux/drivers/net/pcmcia/netwave_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/netwave_cs.c Sun Feb 13 10:23:26 2000 @@ -151,7 +151,7 @@ static const unsigned int txConfKey = 0x02; /* Scramble data packets */ static const unsigned int txConfLoop = 0x01; /* Loopback mode */ -/*static int netwave_debug = 0;*/ +static int netwave_debug = 0; /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If @@ -223,6 +223,7 @@ static int netwave_open(struct net_device *dev); /* Open the device */ static int netwave_close(struct net_device *dev); /* Close the device */ static int netwave_config(struct net_device *dev, struct ifmap *map); +static void netwave_tx_timeout (struct net_device *dev); /* Packet transmission and Packet reception */ static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev); @@ -308,6 +309,7 @@ u_char *ramBase; int timeoutCounter; int lastExec; + spinlock_t lock; struct timer_list watchdog; /* To avoid blocking state */ struct site_survey nss; struct enet_statistics stats; @@ -454,6 +456,7 @@ priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return NULL; memset(priv, 0, sizeof(*priv)); + priv->lock = SPIN_LOCK_UNLOCKED; link = &priv->link; dev = &priv->dev; link->priv = dev->priv = priv; link->release.function = &netwave_release; @@ -503,7 +506,9 @@ dev->init = &netwave_init; dev->open = &netwave_open; dev->stop = &netwave_close; - dev->tbusy = 1; + dev->tx_timeout = netwave_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + netif_start_queue (dev); link->irq.Instance = dev; /* Register with Card Services */ @@ -835,7 +840,7 @@ struct net_device *dev = &priv->dev; tuple_t tuple; cisparse_t parse; - int i, j, last_ret, last_fn; + int i=0, j, last_ret, last_fn; u_char buf[64]; win_req_t req; memreq_t mem; @@ -910,7 +915,7 @@ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); if (register_netdev(dev) != 0) { printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); goto failed; @@ -1014,7 +1019,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + 5; add_timer(&link->release); } @@ -1029,7 +1034,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -1042,7 +1047,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { netwave_reset(dev); - dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); } } break; @@ -1229,6 +1234,18 @@ return 0; } + +static void netwave_tx_timeout (struct net_device *dev) +{ + if (netwave_debug > 0) + printk (KERN_DEBUG "%s timed out.\n", dev->name); + netwave_reset (dev); + dev->trans_start = jiffies; + netif_start_queue (dev); +} + + + static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) { /* This flag indicate that the hardware can't perform a transmission. * Theoritically, NET3 check it before sending a packet to the driver, @@ -1236,29 +1253,6 @@ * As the watchdog will abort too long transmissions, we are quite safe... */ - if (dev->tbusy) { - /* Handled by watchdog */ - return 1; - - /* If we get here, some higher level has decided we are broken. - There should really be a 'kick me' function call instead. - */ - /*int tickssofar = jiffies - dev->trans_start;*/ - /* printk("xmit called with busy. tickssofar %d\n", tickssofar); */ - /*if (tickssofar < TX_TIMEOUT) - return 1; - */ - /* Should also detect if the kernel tries to xmit - * on a stopped card. - */ - - /*if (netwave_debug > 0) - printk(KERN_DEBUG "%s timed out.\n", dev->name); - netwave_reset(dev); - dev->trans_start = jiffies; - dev->tbusy = 0;*/ - } - /* Sending a NULL skb means some higher layer thinks we've missed an * tx-done interrupt. Caution: dev_tint() handles the cli()/sti() * itself. @@ -1268,15 +1262,14 @@ * better be done with atomic_swap(1, dev->tbusy, but set_bit() * works as well */ - if ( test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { + netif_stop_queue (dev); + if (1) { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char* buf = skb->data; if (netwave_hw_xmit( buf, length, dev) == 1) { /* Some error, let's make them call us another time? */ - dev->tbusy = 0; + netif_start_queue (dev); } dev->trans_start = jiffies; } @@ -1303,14 +1296,10 @@ dev_link_t *link = &priv->link; int i; - if ((dev == NULL) | (!dev->start)) + if (dev == NULL) return; - if (dev->interrupt) { - printk("%s: re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; + spin_lock (&priv->lock); iobase = dev->base_addr; ramBase = priv->ramBase; @@ -1409,8 +1398,7 @@ /* If watchdog was activated, kill it ! */ del_timer(&priv->watchdog); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue (dev); } /* TxBA, this would trigger on all error packets received */ /* if (status & 0x01) { @@ -1420,8 +1408,7 @@ */ } /* done.. */ - dev->interrupt = 0; - return; + spin_unlock (&priv->lock); } /* netwave_interrupt */ /* @@ -1444,7 +1431,7 @@ netwave_reset(dev); /* We are not waiting anymore... */ - dev->tbusy = 0; + netif_start_queue (dev); } /* netwave_watchdog */ @@ -1584,7 +1571,7 @@ link->open++; MOD_INC_USE_COUNT; - dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); netwave_reset(dev); return 0; @@ -1596,11 +1583,12 @@ DEBUG(1, "netwave_close: finishing.\n"); + netif_stop_queue (dev); + /* If watchdog was activated, kill it ! */ del_timer(&priv->watchdog); link->open--; - dev->start = 0; if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + 5; link->state |= DEV_RELEASE_PENDING; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c --- v2.3.44/linux/drivers/net/pcmcia/nmclan_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/nmclan_cs.c Sun Feb 13 10:23:26 2000 @@ -307,6 +307,10 @@ #undef MACE_IMR_DEFAULT #define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */ +#define TX_TIMEOUT (5*HZ) + + + /* ---------------------------------------------------------------------------- Type Definitions ---------------------------------------------------------------------------- */ @@ -360,6 +364,7 @@ dev_link_t link; struct net_device dev; dev_node_t node; + spinlock_t lock; struct net_device_stats linux_stats; /* Linux statistics counters */ mace_statistics mace_stats; /* MACE chip statistics counters */ @@ -432,6 +437,7 @@ static struct net_device_stats *mace_get_stats(struct net_device *dev); static int mace_rx(struct net_device *dev, unsigned char RxCnt); static void restore_multicast_list(struct net_device *dev); +static void mace_tx_timeout (struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -498,6 +504,8 @@ lp = kmalloc(sizeof(*lp), GFP_KERNEL); if (!lp) return NULL; memset(lp, 0, sizeof(*lp)); + + lp->lock = SPIN_LOCK_UNLOCKED; link = &lp->link; dev = &lp->dev; link->priv = dev->priv = link->irq.Instance = lp; @@ -531,7 +539,10 @@ dev->init = &nmclan_init; dev->open = &mace_open; dev->stop = &mace_close; - dev->tbusy = 0xFF; + dev->tx_timeout = mace_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + netif_start_queue (dev); /* Register with Card Services */ link->next = dev_list; @@ -752,7 +763,7 @@ CS_CHECK(RequestConfiguration, handle, &link->conf); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); i = register_netdev(dev); if (i != 0) { printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); @@ -859,7 +870,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 0xFF; dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -874,7 +885,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 0xFF; dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -886,9 +897,8 @@ if (link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { - dev->tbusy = 0; - dev->start = 1; nmclan_reset(dev); + netif_start_queue (dev); } } break; @@ -987,10 +997,7 @@ MACEBANK(0); - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - + netif_start_queue (dev); nmclan_reset(dev); return 0; /* Always succeed */ @@ -1007,12 +1014,13 @@ dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); + + netif_stop_queue (dev); /* Mask off all interrupts from the MACE chip. */ outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR); link->open--; - dev->start = 0; if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; @@ -1024,6 +1032,24 @@ return 0; } /* mace_close */ + +static void mace_tx_timeout (struct net_device *dev) +{ + mace_private *lp = (mace_private *)dev->priv; + dev_link_t *link = &lp->link; + + printk (KERN_NOTICE "%s: transmit timed out -- ", dev->name); +#if RESET_ON_TIMEOUT + printk ("resetting card\n"); + CardServices (ResetCard, link->handle); +#else /* #if RESET_ON_TIMEOUT */ + printk ("NOT resetting card\n"); +#endif /* #if RESET_ON_TIMEOUT */ + dev->trans_start = jiffies; + netif_start_queue (dev); +} + + /* ---------------------------------------------------------------------------- mace_start_xmit This routine begins the packet transmit function. When completed, @@ -1038,39 +1064,11 @@ { mace_private *lp = (mace_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link = &lp->link; - -#if TIMEOUT_TX - /* Transmitter timeout. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - - if (tickssofar < (HZ/5)) - return 1; - printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name); -#if RESET_ON_TIMEOUT - printk("resetting card\n"); - CardServices(ResetCard, link->handle); -#else /* #if RESET_ON_TIMEOUT */ - printk("NOT resetting card\n"); -#endif /* #if RESET_ON_TIMEOUT */ - dev->trans_start = jiffies; - return 1; - } -#else /* #if TIMEOUT_TX */ - if (dev->tbusy) - return 1; -#endif /* #if TIMEOUT_TX */ DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n", dev->name, (long)skb->len); - /* Avoid timer-based retransmission conflicts. */ - if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) { - printk(KERN_NOTICE "%s: transmitter access conflict.\n", - dev->name); - return 1; - } + netif_stop_queue (dev); #if (!TX_INTERRUPTABLE) /* Disable MACE TX interrupts. */ @@ -1085,11 +1083,9 @@ the upper layers. The interrupt handler is guaranteed never to service a transmit interrupt while we are in here. */ - set_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy); lp->linux_stats.tx_bytes += skb->len; lp->tx_free_frames--; - set_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy); /* WARNING: Write the _exact_ number of bytes written in the header! */ /* Put out the word header [must be an outw()] . . . */ @@ -1105,11 +1101,10 @@ if (lp->tx_free_frames > 0) { #if MULTI_TX - clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy); + netif_start_queue (dev); #endif /* #if MULTI_TX */ } - clear_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy); } #if (!TX_INTERRUPTABLE) @@ -1140,8 +1135,10 @@ irq); return; } + + spin_lock (&lp->lock); - if (dev->interrupt || lp->tx_irq_disabled) { + if (lp->tx_irq_disabled) { printk( (lp->tx_irq_disabled? KERN_NOTICE "%s: Interrupt with tx_irq_disabled " @@ -1155,12 +1152,6 @@ /* WARNING: MACE_IR has been read! */ return; } - dev->interrupt = 1; - - if (dev->start == 0) { - DEBUG(2, "%s: interrupt from dead card\n", dev->name); - goto exception; - } do { /* WARNING: MACE_IR is a READ/CLEAR port! */ @@ -1230,8 +1221,7 @@ lp->linux_stats.tx_packets++; lp->tx_free_frames++; - clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } /* if (status & MACE_IR_XMTINT) */ if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) { @@ -1266,8 +1256,7 @@ } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); exception: - dev->interrupt = 0; - return; + spin_unlock (&lp->lock); } /* mace_interrupt */ /* ---------------------------------------------------------------------------- diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c --- v2.3.44/linux/drivers/net/pcmcia/smc91c92_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/smc91c92_cs.c Sun Feb 13 10:23:40 2000 @@ -125,6 +125,8 @@ u_short media_status; u_short fast_poll; u_long last_rx; + + spinlock_t lock; }; /* Special definitions for Megahertz multifunction cards */ @@ -281,6 +283,7 @@ static int smc91c92_event(event_t event, int priority, event_callback_args_t *args); +static void smc91c92_tx_timeout (struct net_device *dev); static int smc91c92_open(struct net_device *dev); static int smc91c92_close(struct net_device *dev); static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -379,9 +382,12 @@ dev->init = &smc91c92_init; dev->open = &smc91c92_open; dev->stop = &smc91c92_close; - dev->tbusy = 1; + dev->tx_timeout = smc91c92_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; dev->priv = link->priv = link->irq.Instance = smc; + netif_start_queue (dev); + /* Register with Card Services */ link->next = dev_list; dev_list = link; @@ -663,7 +669,7 @@ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; ioaddr_t ioaddr = dev->base_addr; - int i, wait, loop; + int i, wait=0, loop; unsigned int addr; /* Read Ethernet address from Serial EEPROM */ @@ -775,7 +781,7 @@ struct smc_private *smc = link->priv; struct net_device *dev = &smc->dev; static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; - int i, j; + int i=0, j; link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; @@ -977,7 +983,7 @@ dev->if_port = if_port; else printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n"); - dev->tbusy = 0; + netif_start_queue (dev); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); @@ -1106,8 +1112,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; add_timer(&link->release); @@ -1123,7 +1128,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -1147,7 +1152,7 @@ } if (link->open) { smc_reset(dev); - dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); } } break; @@ -1201,7 +1206,7 @@ link->open++; MOD_INC_USE_COUNT; - dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); smc->saved_skb = 0; smc->packets_waiting = 0; @@ -1225,8 +1230,7 @@ DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n", dev->name, inw(ioaddr + BANK_SELECT)); - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); /* Shut off all interrupts, and turn off the Tx and Rx sections. Don't bother to check for chip present. */ @@ -1240,7 +1244,7 @@ SMC_SELECT_BANK( 1 ); outw(CTL_POWERDOWN, ioaddr + CONTROL ); - link->open--; dev->start = 0; + link->open--; del_timer(&smc->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; @@ -1281,7 +1285,7 @@ " failed, status %#2.2x.\n", dev->name, packet_no); dev_kfree_skb (skb); smc->saved_skb = NULL; - dev->tbusy = 0; + netif_start_queue (dev); return; } @@ -1329,12 +1333,30 @@ smc->saved_skb = NULL; dev_kfree_skb (skb); dev->trans_start = jiffies; - dev->tbusy = 0; + netif_start_queue (dev); return; } /*====================================================================*/ +static void smc91c92_tx_timeout (struct net_device *dev) +{ + struct smc_private *smc = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + + printk (KERN_NOTICE "%s: SMC91c92 transmit timed out, " + "Tx_status %2.2x status %4.4x.\n", + dev->name, inw (ioaddr) & 0xff, inw (ioaddr + 2)); + smc->stats.tx_errors++; + smc_reset (dev); + dev->trans_start = jiffies; + smc->saved_skb = NULL; + netif_start_queue (dev); +} + + +/*====================================================================*/ + static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc_private *smc = dev->priv; @@ -1342,29 +1364,10 @@ unsigned short num_pages; short time_out, ir; - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < TX_TIMEOUT) - return 1; - printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, " - "Tx_status %2.2x status %4.4x.\n", - dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2)); - smc->stats.tx_errors++; - smc_reset(dev); - dev->trans_start = jiffies; - dev->tbusy = 0; - smc->saved_skb = NULL; - } - DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called," " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2)); - - /* Avoid timer-based retransmission conflicts. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_ERR "%s: transmitter access conflict.\n", dev->name); - return 1; - } + + netif_stop_queue (dev); if ( smc->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ @@ -1500,18 +1503,13 @@ u_short saved_bank, saved_pointer, mask, status; char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ - if ((smc == NULL) || !dev->start) + if (smc == NULL) return; ioaddr = dev->base_addr; -#ifdef PCMCIA_DEBUG - if (dev->interrupt) { - printk(KERN_ERR "%s: re-entering the interrupt handler.\n", - dev->name); - return; - } - dev->interrupt = 1; + spin_lock (&smc->lock); +#ifdef PCMCIA_DEBUG DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name, irq, ioaddr); #endif @@ -1569,7 +1567,7 @@ mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); /* and let the card send more packets to me */ - mark_bh( NET_BH ); + netif_wake_queue (dev); } if (status & IM_RX_OVRN_INT) { smc->stats.rx_errors++; @@ -1588,8 +1586,9 @@ outw(saved_pointer, ioaddr + POINTER); SMC_SELECT_BANK( saved_bank ); + spin_unlock (&smc->lock); + #ifdef PCMCIA_DEBUG - dev->interrupt = 0; DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq); #endif @@ -1913,8 +1912,10 @@ ioaddr_t ioaddr = dev->base_addr; u_short i, media, saved_bank; +#if 0 if (dev->start == 0) goto reschedule; - +#endif + saved_bank = inw(ioaddr + BANK_SELECT); SMC_SELECT_BANK(2); i = inw(ioaddr + INTERRUPT); diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c --- v2.3.44/linux/drivers/net/pcmcia/tulip_cb.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/tulip_cb.c Sun Feb 13 18:24:53 2000 @@ -96,16 +96,7 @@ #endif #include -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -128,7 +119,6 @@ /* Kernel compatibility defines, some common to David Hinds' PCMCIA package. This is only in the support-all-kernels source code. */ -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); MODULE_PARM(debug, "i"); @@ -138,14 +128,9 @@ MODULE_PARM(csr0, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif #define RUN_AT(x) (jiffies + (x)) -#define NETSTATS_VER2 -#define PCI_SUPPORT_VER3 -#define dev_free_skb(skb) dev_kfree_skb(skb); - #define tulip_debug debug #ifdef TULIP_DEBUG static int tulip_debug = TULIP_DEBUG; @@ -438,7 +423,8 @@ struct mediatable *mtable; int cur_index; /* Current media index. */ int saved_if_port; - unsigned char pci_bus, pci_devfn; + struct pci_dev *pdev; + spinlock_t lock; int pad0, pad1; /* Used for 8-byte alignment */ }; @@ -515,9 +501,9 @@ restore_flags(flags); } -static struct net_device *tulip_probe1(int pci_bus, int pci_devfn, - struct net_device *dev, long ioaddr, int irq, - int chip_idx, int board_idx) +static struct net_device *tulip_probe1(struct pci_dev *pdev, + struct net_device *dev, long ioaddr, int irq, + int chip_idx, int board_idx) { static int did_version = 0; /* Already printed version info. */ struct tulip_private *tp; @@ -534,11 +520,11 @@ dev = init_etherdev(dev, 0); - pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev); + pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); /* Bring the 21143 out of sleep mode. Caution: Snooze mode does not work with some boards! */ if (tulip_tbl[chip_idx].flags & HAS_ACPI) - pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000); + pci_write_config_dword(pdev, 0x40, 0x00000000); printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); @@ -691,8 +677,8 @@ memset(tp, 0, sizeof(*tp)); dev->priv = tp; - tp->pci_bus = pci_bus; - tp->pci_devfn = pci_devfn; + tp->lock = SPIN_LOCK_UNLOCKED; + tp->pdev = pdev; tp->chip_id = chip_idx; tp->revision = chip_rev; tp->csr0 = csr0; @@ -807,6 +793,8 @@ #ifdef HAVE_MULTICAST dev->set_multicast_list = &set_rx_mode; #endif + dev->tx_timeout = tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; /* Reset the xcvr interface and turn on heartbeat. */ switch (chip_idx) { @@ -1302,7 +1290,7 @@ udelay(2); if (tulip_tbl[tp->chip_id].flags & HAS_ACPI) - pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x00000000); + pci_write_config_dword(tp->pdev, 0x40, 0x00000000); /* Clear the tx ring */ for (i = 0; i < TX_RING_SIZE; i++) { @@ -1461,15 +1449,13 @@ outl_CSR6(tp->csr6, ioaddr, tp->chip_id); outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id); - dev->tbusy = 0; - tp->interrupt = 0; - dev->start = 1; - /* Enable interrupts by setting the interrupt mask. */ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); outl(0, ioaddr + CSR2); /* Rx poll demand */ + + netif_start_queue (dev); if (tulip_debug > 2) { printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", @@ -2354,8 +2340,8 @@ outl(0, ioaddr + CSR1); dev->trans_start = jiffies; + netif_wake_queue (dev); tp->stats.tx_errors++; - return; } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ @@ -2413,15 +2399,6 @@ int entry; u32 flag; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - tulip_tx_timeout(dev); - return 1; - } - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -2454,8 +2431,10 @@ tp->tx_ring[entry].length = skb->len | flag; tp->tx_ring[entry].status = DescOwned; /* Pass ownership to the chip. */ tp->cur_tx++; - if ( ! tp->tx_full) - clear_bit(0, (void*)&dev->tbusy); + if (tp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); @@ -2474,21 +2453,7 @@ long ioaddr = dev->base_addr; int csr5, work_budget = max_interrupt_work; -#if defined(__i386__) && defined(SMP_CHECK) - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by " - "processor %d.\n", - dev->name, smp_processor_id()); - dev->interrupt = 0; - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif + spin_lock (&tp->lock); do { csr5 = inl(ioaddr + CSR5); @@ -2549,7 +2514,7 @@ } /* Free the original skb. */ - dev_free_skb(tp->tx_skbuff[entry]); + dev_kfree_skb_irq(tp->tx_skbuff[entry]); tp->tx_skbuff[entry] = 0; } @@ -2561,13 +2526,15 @@ } #endif - if (tp->tx_full && dev->tbusy - && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { - /* The ring is no longer full, clear tbusy. */ + if (tp->tx_full && + tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) + /* The ring is no longer full */ tp->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); - } + + if (tp->tx_full) + netif_stop_queue (dev); + else + netif_wake_queue (dev); tp->dirty_tx = dirty_tx; if (csr5 & TxDied) { @@ -2630,12 +2597,7 @@ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", dev->name, inl(ioaddr + CSR5)); -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif - return; + spin_unlock (&tp->lock); } static int @@ -2751,8 +2713,7 @@ long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue (dev); /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + CSR7); @@ -2781,7 +2742,7 @@ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) tulip_down(dev); free_irq(dev->irq, dev); @@ -2794,12 +2755,12 @@ tp->rx_ring[i].length = 0; tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ if (skb) { - dev_free_skb(skb); + dev_kfree_skb(skb); } } for (i = 0; i < TX_RING_SIZE; i++) { if (tp->tx_skbuff[i]) - dev_free_skb(tp->tx_skbuff[i]); + dev_kfree_skb(tp->tx_skbuff[i]); tp->tx_skbuff[i] = 0; } @@ -2813,7 +2774,7 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; return &tp->stats; @@ -3075,8 +3036,8 @@ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); tp->tx_ring[entry].status = DescOwned; if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { - set_bit(0, (void*)&dev->tbusy); tp->tx_full = 1; + netif_stop_queue (dev); } if (dummy >= 0) tp->tx_ring[dummy].status = DescOwned; @@ -3114,10 +3075,11 @@ printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name); - pci_set_master(pdev); - dev = tulip_probe1(pdev->bus->number, pdev->devfn, NULL, - pdev->resource[0].start, pdev->irq, - id->driver_data, board_idx++); + pci_enable_device (pdev); + pci_set_master (pdev); + dev = tulip_probe1(pdev, NULL, + pci_resource_start (pdev, 0), pdev->irq, + id->driver_data, board_idx++); if (dev) { pdev->driver_data = dev; return 0; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c --- v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/wavelan_cs.c Sun Feb 13 10:25:33 2000 @@ -66,31 +66,6 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts. - */ -static inline unsigned long -wv_splhi(void) -{ - unsigned long flags; - - save_flags(flags); - cli(); - - return(flags); -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper for re-enabling interrupts. - */ -static inline void -wv_splx(unsigned long flags) -{ - restore_flags(flags); -} - -/*------------------------------------------------------------------*/ -/* * Wrapper for reporting error to cardservices */ static void cs_error(client_handle_t handle, int func, int ret) @@ -581,20 +556,20 @@ void wv_nwid_filter(unsigned char mode, net_local *lp) { mm_t m; - unsigned long x; + unsigned long flags; #ifdef WAVELAN_ROAMING_DEBUG printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name); #endif /* Disable interrupts & save flags */ - x = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); /* ReEnable interrupts & restore flags */ - wv_splx(x); + spin_unlock_irqrestore (&lp->lock, flags); if(mode==NWID_PROMISC) lp->cell_search=1; @@ -755,7 +730,7 @@ { ioaddr_t base = lp->dev->base_addr; mm_t m; - unsigned long x; + unsigned long flags; if(wavepoint==lp->curr_point) /* Sanity check... */ { @@ -768,7 +743,7 @@ #endif /* Disable interrupts & save flags */ - x = wv_splhi(); + spin_lock_irqsave(&lp->lock, flags); m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; @@ -776,7 +751,7 @@ mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); /* ReEnable interrupts & restore flags */ - wv_splx(x); + spin_unlock_irqrestore (&lp->lock, flags); wv_nwid_filter(!NWID_PROMISC,lp); lp->curr_point=wavepoint; @@ -863,15 +838,15 @@ net_local * lp = (net_local *)dev->priv; int status; long spin; - u_long opri; + u_long flags; /* Spin until the chip finishes executing its current command (if any) */ do { - opri = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - wv_splx(opri); + spin_unlock_irqrestore (&lp->lock, flags); } while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); @@ -1009,27 +984,25 @@ * wavelan_interrupt is not an option...), so you may experience * some delay sometime... */ -static inline void -wv_82593_reconfig(device * dev) +static inline void wv_82593_reconfig (device * dev) { - net_local * lp = (net_local *)dev->priv; - dev_link_t * link = ((net_local *) dev->priv)->link; + net_local *lp = (net_local *) dev->priv; + dev_link_t *link = ((net_local *) dev->priv)->link; - /* Check if we can do it now ! */ - if(!(link->open) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0)) - { - lp->reconfig_82593 = TRUE; + /* Check if we can do it now ! */ + if (!(link->open)) { + lp->reconfig_82593 = TRUE; #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "%s: wv_82593_reconfig(): delayed (busy = %ld, link = %d)\n", - dev->name, dev->tbusy, link->open); + printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n", + dev->name, link->open); #endif - } - else - { - lp->reconfig_82593 = FALSE; - wv_82593_config(dev); - dev->tbusy = 0; - } + } else { + netif_stop_queue (dev); + + lp->reconfig_82593 = FALSE; + wv_82593_config (dev); + netif_start_queue (dev); + } } #ifdef OLDIES @@ -1286,9 +1259,6 @@ wv_dev_show(device * dev) { printk(KERN_DEBUG "dev:"); - printk(" start=%d,", dev->start); - printk(" tbusy=%ld,", dev->tbusy); - printk(" interrupt=%d,", dev->interrupt); printk(" trans_start=%ld,", dev->trans_start); printk(" flags=0x%x,", dev->flags); printk("\n"); @@ -1908,7 +1878,7 @@ struct iwreq * wrq = (struct iwreq *) rq; psa_t psa; mm_t m; - unsigned long x; + unsigned long flags; int ret = 0; #ifdef DEBUG_IOCTL_TRACE @@ -1916,7 +1886,7 @@ #endif /* Disable interrupts & save flags */ - x = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); /* Look what is the request */ switch(cmd) @@ -2528,7 +2498,7 @@ } /* ReEnable interrupts & restore flags */ - wv_splx(x); + spin_unlock_irqrestore (&lp->lock, flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); @@ -2548,14 +2518,14 @@ net_local * lp = (net_local *) dev->priv; mmr_t m; iw_stats * wstats; - unsigned long x; + unsigned long flags; #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); #endif /* Disable interrupts & save flags */ - x = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); if(lp == (net_local *) NULL) return (iw_stats *) NULL; @@ -2583,7 +2553,7 @@ wstats->discard.misc = 0L; /* ReEnable interrupts & restore flags */ - wv_splx(x); + spin_unlock_irqrestore (&lp->lock, flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); @@ -2917,7 +2887,7 @@ { net_local * lp = (net_local *) dev->priv; ioaddr_t base = dev->base_addr; - unsigned long x; + unsigned long flags; int clen = length; register u_short xmtdata_base = TX_BASE; @@ -2925,7 +2895,7 @@ printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); #endif - x = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); /* Check if we need some padding */ if(clen < ETH_ZLEN) @@ -2963,7 +2933,7 @@ add_timer(&lp->watchdog); } - wv_splx(x); + spin_unlock_irqrestore (&lp->lock, flags); #ifdef DEBUG_TX_INFO wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); @@ -2972,6 +2942,8 @@ #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif + + netif_start_queue (dev); } /*------------------------------------------------------------------*/ @@ -2981,60 +2953,45 @@ * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ -static int -wavelan_packet_xmit(struct sk_buff * skb, - device * dev) +static int wavelan_packet_xmit (struct sk_buff *skb, + device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = (net_local *) dev->priv; #ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, - (unsigned) skb); + printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); #endif - /* This flag indicate that the hardware can't perform a transmission. - * Theoritically, NET3 check it before sending a packet to the driver, - * but in fact it never do that and pool continuously. - * As the watchdog will abort too long transmissions, we are quite safe... - */ - if(dev->tbusy) - return(1); + /* + * For ethernet, fill in the header. + */ - /* - * For ethernet, fill in the header. - */ - - /* - * Block a timer-based transmit from overlapping a previous transmit. - * In other words, prevent reentering this routine. - */ - if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) -#ifdef DEBUG_TX_ERROR - printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name); -#endif - else - { - /* If somebody has asked to reconfigure the controler, we can do it now */ - if(lp->reconfig_82593) - { - lp->reconfig_82593 = FALSE; - wv_82593_config(dev); - } + netif_stop_queue (dev); + /* + * Block a timer-based transmit from overlapping a previous transmit. + * In other words, prevent reentering this routine. + */ + if (1) { + /* If somebody has asked to reconfigure the controler, we can do it now */ + if (lp->reconfig_82593) { + lp->reconfig_82593 = FALSE; + wv_82593_config (dev); + } #ifdef DEBUG_TX_ERROR - if(skb->next) - printk(KERN_INFO "skb has next\n"); + if (skb->next) + printk (KERN_INFO "skb has next\n"); #endif - - wv_packet_write(dev, skb->data, skb->len); - } - dev_kfree_skb(skb); + wv_packet_write (dev, skb->data, skb->len); + } + dev_kfree_skb (skb); #ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); + printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return(0); + return (0); } /********************** HARDWARE CONFIGURATION **********************/ @@ -3245,7 +3202,8 @@ wv_ru_stop(device * dev) { ioaddr_t base = dev->base_addr; - unsigned long opri; + net_local *lp = (net_local *) dev->priv; + unsigned long flags; int status; int spin; @@ -3262,10 +3220,10 @@ do { udelay(10); - opri = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - wv_splx(opri); + spin_unlock_irqrestore (&lp->lock, flags); } while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300)); @@ -3273,10 +3231,10 @@ do { udelay(10); - opri = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - wv_splx(opri); + spin_unlock_irqrestore (&lp->lock, flags); } while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300)); @@ -3347,16 +3305,16 @@ #ifdef DEBUG_I82593_SHOW { int status; - int opri; + unsigned long flags; int i = 0; /* spin until the chip starts receiving */ do { - opri = wv_splhi(); + spin_lock_irqsave (&lp->lock, flags); outb(OP0_NOP | CR0_STATUS_3, LCCR(base)); status = inb(LCSR(base)); - wv_splx(opri); + spin_unlock_irqrestore (&lp->lock, flags); if(i++ > 10000) break; } @@ -3838,7 +3796,7 @@ /* Feed device with this info... */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n", @@ -3991,13 +3949,7 @@ lp = (net_local *) dev->priv; base = dev->base_addr; - /* Prevent reentrance. What should we do here ? */ -#ifdef DEBUG_INTERRUPT_ERROR - if(dev->interrupt) - printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n", - dev->name); -#endif - dev->interrupt = 1; + spin_lock (&lp->lock); /* Treat all pending interrupts */ while(1) @@ -4201,8 +4153,7 @@ lp->stats.collisions += (tx_status & TX_NCOL_MASK); lp->stats.tx_packets++; - dev->tbusy = FALSE; - mark_bh(NET_BH); + netif_wake_queue (dev); outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ } else /* if interrupt = transmit done or retransmit done */ @@ -4214,7 +4165,8 @@ outb(CR0_INT_ACK | OP0_NOP, LCCR(base)); /* Acknowledge the interrupt */ } } - dev->interrupt = FALSE; + + spin_unlock_irq (&lp->lock); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); @@ -4296,7 +4248,7 @@ #endif /* We are no more waiting for something... */ - dev->tbusy = 0; + netif_start_queue (dev); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -4349,9 +4301,7 @@ return FALSE; if(!wv_ru_start(dev)) wv_hw_reset(dev); /* If problem : reset */ - dev->interrupt = 0; - dev->start = 1; - dev->tbusy = 0; + netif_start_queue (dev); /* Mark the device as used */ link->open++; @@ -4385,6 +4335,8 @@ (unsigned int) dev); #endif + netif_stop_queue (dev); + /* If the device isn't open, then nothing to do */ if(!link->open) { @@ -4408,10 +4360,9 @@ MOD_DEC_USE_COUNT; /* If the card is still present */ - if(dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) { - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4549,7 +4500,7 @@ /* Other specific data */ /* Provide storage area for device name */ dev->name = ((net_local *)dev->priv)->node.dev_name; - dev->tbusy = 1; + netif_start_queue (dev); dev->mtu = WAVELAN_MTU; /* Register with Card Services */ @@ -4711,7 +4662,7 @@ if(link->state & DEV_CONFIG) { /* Accept no more transmissions */ - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); /* Release the card */ wv_pcmcia_release((u_long) link); @@ -4749,8 +4700,7 @@ { if(link->open) { - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); } CardServices(ReleaseConfiguration, link->handle); } @@ -4766,8 +4716,7 @@ if(link->open) /* If RESET -> True, If RESUME -> False ??? */ { wv_hw_reset(dev); - dev->tbusy = 0; - dev->start = 1; + netif_start_queue (dev); } } break; diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h --- v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.h Mon Dec 20 18:48:21 1999 +++ linux/drivers/net/pcmcia/wavelan_cs.h Sun Feb 13 10:25:33 2000 @@ -550,6 +550,7 @@ */ struct net_local { + spinlock_t lock; dev_node_t node; /* ???? What is this stuff ???? */ device * dev; /* Reverse link... */ dev_link_t * link; /* pcmcia structure */ @@ -609,10 +610,6 @@ #endif /* WAVELAN_ROAMING */ /* ----------------------- MISC SUBROUTINES ------------------------ */ -static inline unsigned long /* flags */ - wv_splhi(void); /* Disable interrupts */ -static inline void - wv_splx(unsigned long); /* ReEnable interrupts : flags */ static void cs_error(client_handle_t, /* Report error to cardmgr */ int, diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c --- v2.3.44/linux/drivers/net/pcmcia/xirc2ps_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/xirc2ps_cs.c Sun Feb 13 10:25:33 2000 @@ -410,6 +410,7 @@ int suspended; unsigned last_ptr_value; /* last packets transmitted value */ const char *manf_str; + spinlock_t lock; } local_info_t; /**************** @@ -429,6 +430,7 @@ static int init_mii(struct net_device *dev); static void do_powerdown(struct net_device *dev); static int do_stop(struct net_device *dev); +static void xirc_tx_timeout (struct net_device *dev); /*=============== Helper functions =========================*/ static void @@ -691,6 +693,8 @@ local = kmalloc(sizeof(*local), GFP_KERNEL); if (!local) return NULL; memset(local, 0, sizeof(*local)); + + local->lock = SPIN_LOCK_UNLOCKED; link = &local->link; dev = &local->dev; link->priv = dev->priv = local; @@ -717,7 +721,9 @@ dev->init = &do_init; dev->open = &do_open; dev->stop = &do_stop; - dev->tbusy = 1; + dev->tx_timeout = xirc_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + netif_start_queue (dev); /* Register with Card Services */ link->next = dev_list; @@ -1233,7 +1239,7 @@ /* we can now register the device with the net subsystem */ dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - dev->tbusy = 0; + netif_start_queue (dev); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); goto config_error; @@ -1334,7 +1340,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); link->release.expires = jiffies + HZ / 20; add_timer(&link->release); } @@ -1349,7 +1355,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; dev->start = 0; + netif_stop_queue (dev); lp->suspended=1; do_powerdown(dev); } @@ -1365,7 +1371,7 @@ if (link->open) { do_reset(dev,1); lp->suspended=0; - dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); } } break; @@ -1393,14 +1399,8 @@ * -- on a laptop? */ - if (!dev->start) - return; + spin_lock (&lp->lock); - if (dev->interrupt) { - printk(KERR_XIRC "re-entering isr on irq %d (dev=%p)\n", irq, dev); - return; - } - dev->interrupt = 1; ioaddr = dev->base_addr; if (lp->mohawk) { /* must disable the interrupt */ PutByte(XIRCREG_CR, 0); @@ -1555,8 +1555,7 @@ DEBUG(0, "PTR not changed?\n"); } else lp->stats.tx_packets += lp->last_ptr_value - n; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue (dev); } if (tx_status & 0x0002) { /* Execessive collissions */ DEBUG(0, "tx restarted due to execssive collissions\n"); @@ -1595,7 +1594,9 @@ goto loop_entry; } SelectPage(saved_page); - dev->interrupt = 0; + + spin_unlock (&lp->lock); + PutByte(XIRCREG_CR, EnableIntr); /* re-enable interrupts */ /* Instead of dropping packets during a receive, we could * force an interrupt with this command: @@ -1605,44 +1606,39 @@ /*====================================================================*/ -static int -do_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void xirc_tx_timeout (struct net_device *dev) { - local_info_t *lp = dev->priv; - ioaddr_t ioaddr = dev->base_addr; - int okay; - unsigned freespace; - unsigned pktlen = skb? skb->len : 0; - - DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", - skb, dev, pktlen); - - /* Transmitter timeout, serious problems */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; + local_info_t *lp = dev->priv; if (lp->suspended) { - dev_kfree_skb (skb); dev->trans_start = jiffies; lp->stats.tx_dropped++; - return 0; + netif_start_queue (dev); + return; } - if (tickssofar < TX_TIMEOUT) - return 1; printk(KERN_NOTICE "%s: transmit timed out\n", dev->name); lp->stats.tx_errors++; /* reset the card */ do_reset(dev,1); dev->trans_start = jiffies; - dev->tbusy = 0; - } + netif_start_queue (dev); +} - if (test_and_set_bit(0, (void*)&dev->tbusy)) { - printk(KWRN_XIRC "transmitter access conflict\n"); - dev_kfree_skb (skb); - return 0; - } + +static int +do_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + local_info_t *lp = dev->priv; + ioaddr_t ioaddr = dev->base_addr; + int okay; + unsigned freespace; + unsigned pktlen = skb? skb->len : 0; + + DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n", + skb, dev, pktlen); + + netif_stop_queue (dev); /* adjust the packet length to min. required * and hope that the buffer is large enough @@ -1664,7 +1660,6 @@ DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n", dev->name, freespace, okay ? " (okay)":" (not enough)"); if (!okay) { /* not enough space */ - dev->tbusy = 1; return 1; /* upper layer may decide to requeue this packet */ } /* send the packet */ @@ -1678,7 +1673,7 @@ dev_kfree_skb (skb); dev->trans_start = jiffies; - dev->tbusy = 0; + netif_start_queue (dev); lp->stats.tx_bytes += pktlen; return 0; } @@ -1823,7 +1818,7 @@ link->open++; MOD_INC_USE_COUNT; - dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; + netif_start_queue (dev); lp->suspended = 0; do_reset(dev,1); @@ -2141,8 +2136,7 @@ if (!link) return -ENODEV; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); SelectPage(0); PutByte(XIRCREG_CR, 0); /* disable interrupts */ @@ -2152,7 +2146,7 @@ PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ SelectPage(0); - link->open--; dev->start = 0; + link->open--; if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; diff -u --recursive --new-file v2.3.44/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c --- v2.3.44/linux/drivers/net/rcpci45.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/rcpci45.c Sat Feb 12 15:45:05 2000 @@ -309,7 +309,6 @@ #endif dev->base_addr = (unsigned long)vaddr; dev->irq = irq; - dev->interrupt = 0; /* * Request a shared interrupt line. @@ -430,6 +429,7 @@ printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers); #endif MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -441,29 +441,26 @@ singleTCB tcb; psingleTCB ptcb = &tcb; RC_RETURN status = 0; - - if (dev->tbusy || pDpa->shutdown || pDpa->reboot) - { + + netif_stop_queue(dev); + + if (pDpa->shutdown || pDpa->reboot) + { #ifdef RCDEBUG printk("rc: RC_xmit_packet: tbusy!\n"); #endif - dev->tbusy = 1; return 1; - } - - if ( skb->len <= 0 ) - { - printk("RC_xmit_packet: skb->len less than 0!\n"); - return 0; } - + /* * The user is free to reuse the TCB after RCI2OSendPacket() returns, since * the function copies the necessary info into its own private space. Thus, * our TCB can be a local structure. The skb, on the other hand, will be * freed up in our interrupt handler. */ + ptcb->bcount = 1; + /* * we'll get the context when the adapter interrupts us to tell us that * the transmision is done. At that time, we can free skb. @@ -483,13 +480,12 @@ #ifdef RCDEBUG printk("rc: RC send error 0x%x\n", (uint)status); #endif - dev->tbusy = 1; return 1; } else { dev->trans_start = jiffies; - // dev->tbusy = 0; + netif_wake_queue(dev); } /* * That's it! @@ -546,10 +542,9 @@ printk("rc: skb = 0x%x\n", (uint)skb); #endif BufferContext++; - dev_kfree_skb (skb); + dev_kfree_skb_irq(skb); } - dev->tbusy = 0; - + netif_wake_queue(dev); } static void @@ -811,14 +806,8 @@ (uint)pDpa, (uint)dev, (uint)pDpa->id); printk("dev = 0x%x\n", (uint)dev); #endif - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; RCProcI2OMsgQ(pDpa->id); - dev->interrupt = 0; - - return; } @@ -870,7 +859,7 @@ (uint)pDpa->numOutRcvBuffers); } printk("rc: Initialization done.\n"); - dev->tbusy=0; + netif_wake_queue(dev); retry=0; return; case RC_RTN_FREE_Q_EMPTY: @@ -913,6 +902,8 @@ PDPA pDpa = (PDPA) dev->priv; + netif_stop_queue(dev); + #ifdef RCDEBUG printk("rc: RCclose\r\n"); #endif diff -u --recursive --new-file v2.3.44/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c --- v2.3.44/linux/drivers/net/rtl8129.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/rtl8129.c Sun Feb 13 18:24:53 2000 @@ -0,0 +1,1467 @@ +/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */ +/* + Written 1997-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + All other rights reserved. + + This driver is for boards based on the RTL8129 PCI ethernet chip. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Support and updates available at + http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html + + Twister-tuning table provided by Kinston . +*/ + +static const char *version = +"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; + +/* A few user-configurable values. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; +#define rtl8129_debug debug +static int rtl8129_debug = 1; + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Used to pass the full-duplex flag, etc. */ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Size of the in-memory receive ring. */ +#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */ +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ +#define TX_BUF_SIZE 1536 + +/* PCI Tuning Parameters + Threshold is bytes transferred to chip before transmission starts. */ +#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ + +/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ +#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ +#define TX_DMA_BURST 4 /* Calculate as 16< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +/* Kernel compatibility defines, some common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ + +#define RUN_AT(x) (jiffies + (x)) + +#include + +#if LINUX_VERSION_CODE < 0x20123 +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif +#if LINUX_VERSION_CODE <= 0x20139 +#define net_device_stats enet_statistics +#else +#define NETSTATS_VER2 +#endif +#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) +/* Grrrr, the PCI code changed, but did not consider CardBus... */ +#include +#define PCI_SUPPORT_VER1 +#else +#define PCI_SUPPORT_VER2 +#endif + +/* The I/O extent. */ +#define RTL8129_TOTAL_SIZE 0x80 + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the RealTek RTL8129, the RealTek Fast +Ethernet controllers for PCI. This chip is used on a few clone boards. + + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS will assign the +PCI INTA signal to a (preferably otherwise unused) system IRQ line. +Note: Kernel versions earlier than 1.3.73 do not support shared PCI +interrupt lines. + +III. Driver operation + +IIIa. Rx Ring buffers + +The receive unit uses a single linear ring buffer rather than the more +common (and more efficient) descriptor-based architecture. Incoming frames +are sequentially stored into the Rx region, and the host copies them into +skbuffs. + +Comment: While it is theoretically possible to process many frames in place, +any delay in Rx processing would cause us to drop frames. More importantly, +the Linux protocol stack is not designed to operate in this manner. + +IIIb. Tx operation + +The RTL8129 uses a fixed set of four Tx descriptors in register space. +In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux +aligns the IP header on word boundaries, and 14 byte ethernet header means +that almost all frames will need to be copied to an alignment buffer. + +IVb. References + +http://www.realtek.com.tw/cn/cn.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html + +IVc. Errata + +*/ + + +/* This table drives the PCI probe routines. It's mostly boilerplate in all + of the drivers, and will likely be provided by some future kernel. + Note the matching code -- the first table entry matchs all 56** cards but + second only the 1234 card. +*/ +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, +}; +struct pci_id_info { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int io_size; + struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); +}; + +static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int irq, int chp_idx, int fnd_cnt); + +static struct pci_id_info pci_tbl[] = +{{ "RealTek RTL8129 Fast Ethernet", + 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, +#ifdef USE_8139_SUPPORT_ALSO + { "RealTek RTL8139 Fast Ethernet", + 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", + 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, + { "Accton MPX5030 (RealTek RTL8139)", + 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, +#endif + {0,}, /* 0 terminated list. */ +}; + +/* The capability table matches the chip table above. */ +enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; +static int rtl_cap_tbl[] = { + HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG, +}; + + +/* The rest of these values should never change. */ +#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */ + +/* Symbolic offsets to registers. */ +enum RTL8129_registers { + MAC0=0, /* Ethernet hardware address. */ + MAR0=8, /* Multicast filter. */ + TxStatus0=0x10, /* Transmit status (Four 32bit registers). */ + TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ + RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, + ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, + IntrMask=0x3C, IntrStatus=0x3E, + TxConfig=0x40, RxConfig=0x44, + Timer=0x48, /* A general-purpose counter. */ + RxMissed=0x4C, /* 24 bits valid, write clears. */ + Cfg9346=0x50, Config0=0x51, Config1=0x52, + FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B, + MultiIntr=0x5C, TxSummary=0x60, + MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, + NWayExpansion=0x6A, + /* Undocumented registers, but required for proper operation. */ + FIFOTMS=0x70, /* FIFO Test Mode Select */ + CSCR=0x74, /* Chip Status and Configuration Register. */ + PARA78=0x78, PARA7c=0x7c, /* Magic transceiver parameter register. */ +}; + +enum ChipCmdBits { + CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, }; + +/* Interrupt register bits, using my own meaningful names. */ +enum IntrStatusBits { + PCIErr=0x8000, PCSTimeout=0x4000, + RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10, + TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01, +}; +enum TxStatusBits { + TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000, + TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000, +}; +enum RxStatusBits { + RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000, + RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004, + RxBadAlign=0x0002, RxStatusOK=0x0001, +}; + +/* Twister tuning parameters from RealTek. + Completely undocumented, but required to tune bad links. */ +enum CSCRBits { + CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, + CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, + CSCR_LinkDownCmd=0x0f3c0, +}; +unsigned long param[4][4]={ + {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43}, + {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, + {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, + {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83} +}; + +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct rtl8129_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct net_device *next_module; + struct pci_dev *pdev; + int chip_id; + int chip_revision; + unsigned char pci_bus, pci_devfn; +#if LINUX_VERSION_CODE > 0x20139 + struct net_device_stats stats; +#else + struct enet_statistics stats; +#endif + struct timer_list timer; /* Media selection timer. */ + unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ + unsigned int cur_tx, dirty_tx, tx_flag; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct ring_info tx_info[NUM_TX_DESC]; + unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ + unsigned char *rx_ring; + unsigned char *tx_bufs; /* Tx bounce buffer region. */ + dma_addr_t rx_ring_dma; + dma_addr_t tx_bufs_dma; + char phys[4]; /* MII device addresses. */ + char twistie, twist_cnt; /* Twister tune state. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ +}; + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(multicast_filter_limit, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(debug, "i"); + +static int rtl8129_open(struct net_device *dev); +static int read_eeprom(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int val); +static void rtl8129_timer(unsigned long data); +static void rtl8129_tx_timeout(struct net_device *dev); +static void rtl8129_init_ring(struct net_device *dev); +static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int rtl8129_rx(struct net_device *dev); +static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int rtl8129_close(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static struct enet_statistics *rtl8129_get_stats(struct net_device *dev); +static inline u32 ether_crc(int length, unsigned char *data); +static void set_rx_mode(struct net_device *dev); + + +/* A list of all installed RTL8129 devices, for removing the driver module. */ +static struct net_device *root_rtl8129_dev = NULL; + +/* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well when dynamically adding drivers. So instead we detect just the + Rtl81*9 cards in slot order. */ + +static int __init rtl8129_probe(void) +{ + int cards_found = 0; + int pci_index = 0; + unsigned char pci_bus, pci_device_fn; + struct net_device *dev; + + if ( ! pcibios_present()) + return -ENODEV; + + for (; pci_index < 0xff; pci_index++) { + struct pci_dev *pdev; + u16 vendor, device, pci_command, new_command; + int chip_idx, irq; + long ioaddr; + + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) + break; + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + + for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor == pci_tbl[chip_idx].vendor_id + && (device & pci_tbl[chip_idx].device_id_mask) == + pci_tbl[chip_idx].device_id) + break; + if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ + continue; + + pdev = pci_find_slot(pci_bus, pci_device_fn); + ioaddr = pdev->resource[0].start; + irq = pdev->irq; + + if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && + check_region(ioaddr, pci_tbl[chip_idx].io_size)) + continue; + + /* Activate the card: fix for brain-damaged Win98 BIOSes. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_tbl[chip_idx].flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", + pci_bus, pci_device_fn, pci_command, new_command); + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + + dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); + + if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { + u8 pci_latency; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 32) { + printk(KERN_NOTICE " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to 64 clocks.\n", + pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 64); + } + } + dev = 0; + cards_found++; + } + + return cards_found ? 0 : -ENODEV; +} + +static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int irq, int chip_idx, int found_cnt) +{ + static int did_version = 0; /* Already printed version info. */ + struct rtl8129_private *tp; + int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0; + struct net_device *dev; + + if (rtl8129_debug > 0 && did_version++ == 0) + printk(KERN_INFO "%s", version); + + dev = init_etherdev(NULL, 0); + + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", + dev->name, pci_tbl[chip_idx].name, ioaddr, irq); + + /* Bring the chip out of low-power mode. */ + outb(0x00, ioaddr + Config1); + + if (read_eeprom(ioaddr, 0) != 0xffff) { + for (i = 0; i < 3; i++) { + ((u16 *)(dev->dev_addr))[i] = + le16_to_cpu(read_eeprom(ioaddr, i + 7)); + } + } else { + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + MAC0 + i); + } + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Some data structures must be quadword aligned. */ + tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + + tp->next_module = root_rtl8129_dev; + root_rtl8129_dev = dev; + + tp->pdev = pdev; + tp->chip_id = chip_idx; + tp->pci_bus = pci_bus; + tp->pci_devfn = pci_devfn; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) { + int phy, phy_idx; + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + printk(KERN_INFO "%s: MII transceiver found at address %d.\n", + dev->name, phy); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " + "transceiver.\n", + dev->name); + tp->phys[0] = -1; + } + } else + tp->phys[0] = 32; + + /* Put the chip into low-power mode. */ + outb(0xC0, ioaddr + Cfg9346); + outb(0x03, ioaddr + Config1); + outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ + + /* The lower four bits are the media type. */ + if (option > 0) { + tp->full_duplex = (option & 0x200) ? 1 : 0; + tp->default_port = option & 15; + if (tp->default_port) + tp->medialock = 1; + } + + if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) + tp->full_duplex = full_duplex[found_cnt]; + + if (tp->full_duplex) { + printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + mdio_write(dev, tp->phys[0], 4, 0x141); + tp->duplex_lock = 1; + } + + /* The Rtl8129-specific entries in the device structure. */ + dev->open = &rtl8129_open; + dev->hard_start_xmit = &rtl8129_start_xmit; + dev->tx_timeout = &rtl8129_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = &rtl8129_close; + dev->get_stats = &rtl8129_get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + + return dev; +} + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x08 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x00 +#define EE_WRITE_1 0x02 +#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ +#define EE_ENB (0x80 | EE_CS) + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. + */ + +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int read_eeprom(long ioaddr, int location) +{ + int i; + unsigned retval = 0; + long ee_addr = ioaddr + Cfg9346; + int read_cmd = location | EE_READ_CMD; + + outb(EE_ENB & ~EE_CS, ee_addr); + outb(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outb(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + } + outb(EE_ENB, ee_addr); + eeprom_delay(); + + for (i = 16; i > 0; i--) { + outb(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); + outb(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outb(~EE_CS, ee_addr); + return retval; +} + +/* MII serial management: mostly bogus for now. */ +/* Read and write the MII management registers using software-generated + serial MDIO protocol. + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues. */ +#define MDIO_DIR 0x80 +#define MDIO_DATA_OUT 0x04 +#define MDIO_DATA_IN 0x02 +#define MDIO_CLK 0x01 +#define MDIO_WRITE0 (MDIO_DIR) +#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) + +#define mdio_delay() inb(mdio_addr) + +static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert, + NWayLPAR, NWayExpansion, 0 }; + +/* Syncronize the MII management interface by shifting 32 one bits out. */ +static void mdio_sync(long mdio_addr) +{ + int i; + + for (i = 32; i >= 0; i--) { + outb(MDIO_WRITE1, mdio_addr); + mdio_delay(); + outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); + mdio_delay(); + } + return; +} +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + MII_SMI; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + int i; + + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ + return location < 8 && mii_2_8139_map[location] ? + inw(dev->base_addr + mii_2_8139_map[location]) : 0; + } + mdio_sync(mdio_addr); + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; + + outb(MDIO_DIR | dataval, mdio_addr); + mdio_delay(); + outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr); + mdio_delay(); + } + + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outb(0, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); + outb(MDIO_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + MII_SMI; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int i; + + if (phy_id > 31) { /* Really a 8139. Use internal registers. */ + if (location < 8 && mii_2_8139_map[location]) + outw(value, dev->base_addr + mii_2_8139_map[location]); + return; + } + mdio_sync(mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + outb(dataval, mdio_addr); + mdio_delay(); + outb(dataval | MDIO_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outb(0, mdio_addr); + mdio_delay(); + outb(MDIO_CLK, mdio_addr); + mdio_delay(); + } + return; +} + + +static int +rtl8129_open(struct net_device *dev) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Soft reset the chip. */ + outb(CmdReset, ioaddr + ChipCmd); + + if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) { + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + tp->tx_bufs = pci_alloc_consistent(tp->pdev, + TX_BUF_SIZE * NUM_TX_DESC, + &tp->tx_bufs_dma); + tp->rx_ring = pci_alloc_consistent(tp->pdev, + RX_BUF_LEN + 16, + &tp->rx_ring_dma); + if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { + free_irq(dev->irq, dev); + if (tp->tx_bufs) + pci_free_consistent(tp->pdev, + TX_BUF_SIZE * NUM_TX_DESC, + tp->tx_bufs, tp->tx_bufs_dma); + if (tp->rx_ring) + pci_free_consistent(tp->pdev, + RX_BUF_LEN + 16, + tp->rx_ring, tp->rx_ring_dma); + if (rtl8129_debug > 0) + printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", + dev->name, RX_BUF_LEN); + return -ENOMEM; + } + rtl8129_init_ring(dev); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) + if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) + break; + + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + MAC0 + i); + + /* Must enable Tx/Rx before setting transfer thresholds! */ + outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), + ioaddr + RxConfig); + outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); + tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000; + + tp->full_duplex = tp->duplex_lock; + if (tp->phys[0] >= 0 || (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) { + u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); + if (mii_reg5 == 0xffff) + ; /* Not there */ + else if ((mii_reg5 & 0x0100) == 0x0100 + || (mii_reg5 & 0x00C0) == 0x0040) + tp->full_duplex = 1; + if (rtl8129_debug > 1) + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability %4.4x.\n", dev->name, + mii_reg5 == 0 ? "" : + (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", + tp->full_duplex ? "full" : "half", mii_reg5); + } + + outb(0xC0, ioaddr + Cfg9346); + outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); + outb(0x00, ioaddr + Cfg9346); + + outl(tp->rx_ring_dma, ioaddr + RxBuf); + + /* Start the chip's Tx and Rx process. */ + outl(0, ioaddr + RxMissed); + set_rx_mode(dev); + + outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + + /* Enable all known interrupts by setting the interrupt mask. */ + outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver + | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); + + if (rtl8129_debug > 1) + printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" + " GP Pins %2.2x %s-duplex.\n", + dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData), + tp->full_duplex ? "full" : "half"); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + tp->timer.data = (unsigned long)dev; + tp->timer.function = &rtl8129_timer; + add_timer(&tp->timer); + + return 0; +} + +static void rtl8129_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + int mii_reg5 = mdio_read(dev, tp->phys[0], 5); + + if (! tp->duplex_lock && mii_reg5 != 0xffff) { + int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" + " partner ability of %4.4x.\n", dev->name, + tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); + outb(0xC0, ioaddr + Cfg9346); + outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); + outb(0x00, ioaddr + Cfg9346); + } + } + /* Check for bogusness. */ + if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { + int status = inw(ioaddr + IntrStatus); + if (status & (TxOK | RxOK)) { /* Double check */ + printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n", + dev->name, status); + rtl8129_interrupt(dev->irq, dev, 0); + } + } + if (test_bit(LINK_STATE_XOFF, &dev->state) && + (jiffies - dev->trans_start) >= 2*TX_TIMEOUT) + rtl8129_tx_timeout(dev); + +#if 0 + if (tp->twistie) { + unsigned int CSCRval = inw(ioaddr + CSCR); /* Read link status. */ + if (tp->twistie == 1) { + if (CSCRval & CSCR_LinkOKBit) { + outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); + tp->twistie = 2; + next_tick = HZ/10; + } else { + outw(CSCR_LinkDownCmd, ioaddr + CSCR); + outl(FIFOTMS_default,ioaddr + FIFOTMS); + outl(PARA78_default ,ioaddr + PARA78); + outl(PARA7c_default ,ioaddr + PARA7c); + tp->twistie = 0; + } + } else if (tp->twistie == 2) { + int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12; + int row; + if (linkcase >= 0x7000) row = 3; + else if (linkcase >= 0x3000) row = 2; + else if (linkcase >= 0x1000) row = 1; + else row = 0; + tp->twistie == row + 3; + outw(0,ioaddr+FIFOTMS); + outl(param[row][0], ioaddr+PARA7c); + tp->twist_cnt = 1; + } else { + outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c); + if (++tp->twist_cnt < 4) { + next_tick = HZ/10; + } else if (tp->twistie-3 == 3) { + if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) { + outl(PARA7c_xxx, ioaddr+PARA7c); + next_tick = HZ/10; /* 100ms. */ + outl(FIFOTMS_default, ioaddr+FIFOTMS); + outl(PARA78_default, ioaddr+PARA78); + outl(PARA7c_default, ioaddr+PARA7c); + tp->twistie == 3 + 3; + outw(0,ioaddr+FIFOTMS); + outl(param[3][0], ioaddr+PARA7c); + tp->twist_cnt = 1; + } + } + } + } +#endif + + if (rtl8129_debug > 2) { + if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR) + printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n", + dev->name, inb(ioaddr + GPPinData)); + else + printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n", + dev->name, inw(ioaddr + NWayLPAR)); + printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x" + " RxStatus %4.4x.\n", + dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus), + inl(ioaddr + RxEarlyStatus)); + printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n", + dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); + } + + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + +static void rtl8129_tx_timeout(struct net_device *dev) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + long ioaddr = dev->base_addr; + int mii_reg, i; + + if (rtl8129_debug > 0) + printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x " + "media %2.2x.\n", + dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus), + inb(ioaddr + GPPinData)); + + /* Disable interrupts by clearing the interrupt mask. */ + outw(0x0000, ioaddr + IntrMask); + /* Emit info to figure out what went wrong. */ + printk("%s: Tx queue start entry %d dirty entry %d.\n", + dev->name, tp->cur_tx, tp->dirty_tx); + for (i = 0; i < NUM_TX_DESC; i++) + printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n", + dev->name, i, inl(ioaddr + TxStatus0 + i*4), + i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); + printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]); + for (mii_reg = 0; mii_reg < 8; mii_reg++) + printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg)); + printk(".\n"); + + /* Soft reset the chip. */ + outb(CmdReset, ioaddr + ChipCmd); + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--) + if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) + break; + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + MAC0 + i); + + outb(0x00, ioaddr + Cfg9346); + tp->cur_rx = 0; + /* Must enable Tx/Rx before setting transfer thresholds! */ + outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), + ioaddr + RxConfig); + outl((TX_DMA_BURST<<8), ioaddr + TxConfig); + set_rx_mode(dev); + { /* Save the unsent Tx packets. */ + struct sk_buff *saved_skb[NUM_TX_DESC], *skb; + int j; + for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) { + struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC]; + + saved_skb[j] = rp->skb; + if (rp->mapping != 0) { + pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len); + rp->mapping = 0; + } + } + tp->dirty_tx = tp->cur_tx = 0; + + for (i = 0; i < j; i++) { + skb = tp->tx_info[i].skb = saved_skb[i]; + if ((long)skb->data & 3) { /* Must use alignment buffer. */ + memcpy(tp->tx_buf[i], skb->data, skb->len); + outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs), + ioaddr + TxAddr0 + i*4); + } else { + tp->tx_info[i].mapping = + pci_map_single(tp->pdev, skb->data, skb->len); + outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4); + } + /* Note: the chip doesn't have auto-pad! */ + outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), + ioaddr + TxStatus0 + i*4); + } + tp->cur_tx = i; + while (i < NUM_TX_DESC) { + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; + i++; + } + if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ + netif_wake_queue(dev); + tp->tx_full = 0; + } else { + tp->tx_full = 1; + netif_stop_queue(dev); + } + } + + dev->trans_start = jiffies; + tp->stats.tx_errors++; + /* Enable all known interrupts by setting the interrupt mask. */ + outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver + | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void +rtl8129_init_ring(struct net_device *dev) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = 0; + tp->dirty_tx = tp->cur_tx = 0; + + for (i = 0; i < NUM_TX_DESC; i++) { + tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE]; + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; + } +} + +static int +rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + long ioaddr = dev->base_addr; + int entry; + + netif_stop_queue(dev); + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % NUM_TX_DESC; + + tp->tx_info[entry].skb = skb; + if ((long)skb->data & 3) { /* Must use alignment buffer. */ + tp->tx_info[entry].mapping = 0; + memcpy(tp->tx_buf[entry], skb->data, skb->len); + outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs), + ioaddr + TxAddr0 + entry*4); + } else { + tp->tx_info[entry].mapping = + pci_map_single(tp->pdev, skb->data, skb->len); + outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4); + } + /* Note: the chip doesn't have auto-pad! */ + outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), + ioaddr + TxStatus0 + entry*4); + + if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ + netif_start_queue(dev); + } else { + tp->tx_full = 1; + } + + dev->trans_start = jiffies; + if (rtl8129_debug > 4) + printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n", + dev->name, skb->data, (int)skb->len, entry); + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + int boguscnt = max_interrupt_work; + int status, link_changed = 0; + long ioaddr = dev->base_addr; + + do { + status = inw(ioaddr + IntrStatus); + /* Acknowledge all of the current interrupt sources ASAP, but + an first get an additional status bit from CSCR. */ + if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit) + link_changed = 1; + outw(status, ioaddr + IntrStatus); + + if (rtl8129_debug > 4) + printk(KERN_DEBUG"%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", + dev->name, status, inw(ioaddr + IntrStatus)); + + if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver + |TxErr|TxOK|RxErr|RxOK)) == 0) + break; + + if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */ + rtl8129_rx(dev); + + if (status & (TxOK | TxErr)) { + unsigned int dirty_tx = tp->dirty_tx; + + while (tp->cur_tx - dirty_tx > 0) { + int entry = dirty_tx % NUM_TX_DESC; + int txstatus = inl(ioaddr + TxStatus0 + entry*4); + + if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted))) + break; /* It still hasn't been Txed */ + + /* Note: TxCarrierLost is always asserted at 100mbps. */ + if (txstatus & (TxOutOfWindow | TxAborted)) { + /* There was an major error, log it. */ + if (rtl8129_debug > 1) + printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); + tp->stats.tx_errors++; + if (txstatus&TxAborted) { + tp->stats.tx_aborted_errors++; + outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig); + } + if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++; + if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++; +#ifdef ETHER_STATS + if ((txstatus & 0x0f000000) == 0x0f000000) + tp->stats.collisions16++; +#endif + } else { + if (txstatus & TxUnderrun) { + /* Add 64 to the Tx FIFO threshold. */ + if (tp->tx_flag < 0x00300000) + tp->tx_flag += 0x00020000; + tp->stats.tx_fifo_errors++; + } + tp->stats.collisions += (txstatus >> 24) & 15; +#if LINUX_VERSION_CODE > 0x20119 + tp->stats.tx_bytes += txstatus & 0x7ff; +#endif + tp->stats.tx_packets++; + } + + if (tp->tx_info[entry].mapping != 0) { + pci_unmap_single(tp->pdev, + tp->tx_info[entry].mapping, + tp->tx_info[entry].skb->len); + tp->tx_info[entry].mapping = 0; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_info[entry].skb); + tp->tx_info[entry].skb = NULL; + if (tp->tx_full) { + /* The ring is no longer full, wake the queue. */ + tp->tx_full = 0; + netif_wake_queue(dev); + } + dirty_tx++; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { + printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, tp->cur_tx, tp->tx_full); + dirty_tx += NUM_TX_DESC; + } +#endif + tp->dirty_tx = dirty_tx; + } + + /* Check uncommon events with one test. */ + if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver + |TxErr|RxErr)) { + if (rtl8129_debug > 2) + printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); + + if (status == 0xffffffff) + break; + /* Update the error count. */ + tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); + outl(0, ioaddr + RxMissed); + + if ((status & RxUnderrun) && link_changed && + (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) { + /* Really link-change on new chips. */ + int lpar = inw(ioaddr + NWayLPAR); + int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + outb(0xC0, ioaddr + Cfg9346); + outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); + outb(0x00, ioaddr + Cfg9346); + } + status &= ~RxUnderrun; + } + if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) + tp->stats.rx_errors++; + + if (status & (PCSTimeout)) tp->stats.rx_length_errors++; + if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++; + if (status & RxOverflow) { + tp->stats.rx_over_errors++; + tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN; + outw(tp->cur_rx - 16, ioaddr + RxBufPtr); + } + if (status & PCIErr) { + u32 pci_cmd_status; + pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn, + PCI_COMMAND, &pci_cmd_status); + + printk(KERN_ERR "%s: PCI Bus error %4.4x.\n", + dev->name, pci_cmd_status); + } + } + if (--boguscnt < 0) { + printk(KERN_WARNING"%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outw(0xffff, ioaddr + IntrStatus); + break; + } + } while (1); + + if (rtl8129_debug > 3) + printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, inl(ioaddr + IntrStatus)); + return; +} + +/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the + field alignments and semantics. */ +static int rtl8129_rx(struct net_device *dev) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + long ioaddr = dev->base_addr; + unsigned char *rx_ring = tp->rx_ring; + u16 cur_rx = tp->cur_rx; + + if (rtl8129_debug > 4) + printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x," + " free to %4.4x, Cmd %2.2x.\n", + dev->name, cur_rx, inw(ioaddr + RxBufAddr), + inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); + + while ((inb(ioaddr + ChipCmd) & 1) == 0) { + int ring_offset = cur_rx % RX_BUF_LEN; + u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset)); + int rx_size = rx_status >> 16; + + if (rtl8129_debug > 4) { + int i; + printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n", + dev->name, rx_status, rx_size, cur_rx); + printk(KERN_DEBUG"%s: Frame contents ", dev->name); + for (i = 0; i < 70; i++) + printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i])); + printk(".\n"); + } + if (rx_status & RxTooLong) { + if (rtl8129_debug > 0) + printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n", + dev->name, rx_status); + tp->stats.rx_length_errors++; + } else if (rx_status & + (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) { + if (rtl8129_debug > 1) + printk(KERN_DEBUG"%s: Ethernet frame had errors," + " status %4.4x.\n", dev->name, rx_status); + tp->stats.rx_errors++; + if (rx_status & (RxBadSymbol|RxBadAlign)) + tp->stats.rx_frame_errors++; + if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++; + if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; + /* Reset the receiver, based on RealTek recommendation. (Bug?) */ + tp->cur_rx = 0; + outb(CmdTxEnb, ioaddr + ChipCmd); + outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); + outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | + (RX_DMA_BURST<<8), ioaddr + RxConfig); + } else { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + struct sk_buff *skb; + + skb = dev_alloc_skb(rx_size + 2); + if (skb == NULL) { + printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", + dev->name); + /* We should check that some rx space is free. + If not, free one and mark stats->rx_dropped++. */ + tp->stats.rx_dropped++; + break; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP fields. */ + if (ring_offset+rx_size+4 > RX_BUF_LEN) { + int semi_count = RX_BUF_LEN - ring_offset - 4; + memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], + semi_count); + memcpy(skb_put(skb, rx_size-semi_count), rx_ring, + rx_size-semi_count); + if (rtl8129_debug > 4) { + int i; + printk(KERN_DEBUG"%s: Frame wrap @%d", + dev->name, semi_count); + for (i = 0; i < 16; i++) + printk(" %2.2x", le32_to_cpu(rx_ring[i])); + printk(".\n"); + memset(rx_ring, 0xcc, 16); + } + } else { +#if 1 /* USE_IP_COPYSUM */ + eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], + rx_size, 0); + skb_put(skb, rx_size); +#else + memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4], + rx_size); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); +#if LINUX_VERSION_CODE > 0x20119 + tp->stats.rx_bytes += rx_size; +#endif + tp->stats.rx_packets++; + } + + cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; + outw(cur_rx - 16, ioaddr + RxBufPtr); + } + if (rtl8129_debug > 4) + printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x," + " free to %4.4x, Cmd %2.2x.\n", + dev->name, cur_rx, inw(ioaddr + RxBufAddr), + inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); + tp->cur_rx = cur_rx; + return 0; +} + +static int +rtl8129_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (rtl8129_debug > 1) + printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", + dev->name, inw(ioaddr + IntrStatus)); + + /* Disable interrupts by clearing the interrupt mask. */ + outw(0x0000, ioaddr + IntrMask); + + /* Stop the chip's Tx and Rx DMA processes. */ + outb(0x00, ioaddr + ChipCmd); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); + outl(0, ioaddr + RxMissed); + + del_timer(&tp->timer); + + free_irq(dev->irq, dev); + + for (i = 0; i < NUM_TX_DESC; i++) { + struct sk_buff *skb = tp->tx_info[i].skb; + dma_addr_t mapping = tp->tx_info[i].mapping; + + if (skb) { + if (mapping) + pci_unmap_single(tp->pdev, mapping, skb->len); + dev_kfree_skb(skb); + } + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; + } + pci_free_consistent(tp->pdev, RX_BUF_LEN + 16, + tp->rx_ring, tp->rx_ring_dma); + pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, + tp->tx_bufs, tp->tx_bufs_dma); + tp->rx_ring = NULL; + tp->tx_bufs = NULL; + + /* Green! Put the chip in low-power mode. */ + outb(0xC0, ioaddr + Cfg9346); + outb(0x03, ioaddr + Config1); + outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = tp->phys[0] & 0x3f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0], data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static struct enet_statistics * +rtl8129_get_stats(struct net_device *dev) +{ + struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (test_bit(LINK_STATE_START, &dev->state)) { + tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); + outl(0, ioaddr + RxMissed); + } + + return &tp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + This routine is not state sensitive and need not be SMP locked. */ + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while (--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + return crc; +} + +/* Bits in RxConfig. */ +enum rx_mode_bits { + AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, + AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, +}; + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u32 mc_filter[2]; /* Multicast hash filter */ + int i, rx_mode; + + if (rtl8129_debug > 3) + printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", + dev->name, dev->flags, inl(ioaddr + RxConfig)); + + /* Note: do not reorder, GCC is clever about common statements. */ + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else { + struct dev_mc_list *mclist; + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); + } + /* We can safely update without stopping the chip. */ + outb(rx_mode, ioaddr + RxConfig); + outl(mc_filter[0], ioaddr + MAR0 + 0); + outl(mc_filter[1], ioaddr + MAR0 + 4); + return; +} + + +static void __exit rtl8129_cleanup (void) +{ + struct net_device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_rtl8129_dev) { + struct rtl8129_private *tp = + (struct rtl8129_private *)root_rtl8129_dev->priv; + next_dev = tp->next_module; + unregister_netdev(root_rtl8129_dev); + release_region(root_rtl8129_dev->base_addr, + pci_tbl[tp->chip_id].io_size); + kfree(tp); + kfree(root_rtl8129_dev); + root_rtl8129_dev = next_dev; + } +} + +module_init(rtl8129_probe); +module_exit(rtl8129_cleanup); + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.3.44/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c --- v2.3.44/linux/drivers/net/rtl8139.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/rtl8139.c Wed Dec 31 16:00:00 1969 @@ -1,1473 +0,0 @@ -/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */ -/* - Written 1997-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - All other rights reserved. - - This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet - chips. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - Support and updates available at - http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html - - Twister-tuning table provided by Kinston . -*/ - -static const char *version = -"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; - -/* A few user-configurable values. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -#define rtl8129_debug debug -static int rtl8129_debug = 1; - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; - -/* Used to pass the full-duplex flag, etc. */ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE 1536 - -/* PCI Tuning Parameters - Threshold is bytes transferred to chip before transmission starts. */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ -#define TX_DMA_BURST 4 /* Calculate as 16< -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include - -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -#include - -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#else -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -/* Grrrr, the PCI code changed, but did not consider CardBus... */ -#include -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif - -/* The I/O extent. */ -#define RTL8129_TOTAL_SIZE 0x80 - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the RealTek RTL8129, the RealTek Fast -Ethernet controllers for PCI. This chip is used on a few clone boards. - - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. -Note: Kernel versions earlier than 1.3.73 do not support shared PCI -interrupt lines. - -III. Driver operation - -IIIa. Rx Ring buffers - -The receive unit uses a single linear ring buffer rather than the more -common (and more efficient) descriptor-based architecture. Incoming frames -are sequentially stored into the Rx region, and the host copies them into -skbuffs. - -Comment: While it is theoretically possible to process many frames in place, -any delay in Rx processing would cause us to drop frames. More importantly, -the Linux protocol stack is not designed to operate in this manner. - -IIIb. Tx operation - -The RTL8129 uses a fixed set of four Tx descriptors in register space. -In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux -aligns the IP header on word boundaries, and 14 byte ethernet header means -that almost all frames will need to be copied to an alignment buffer. - -IVb. References - -http://www.realtek.com.tw/cn/cn.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - -IVc. Errata - -*/ - - -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. - Note the matching code -- the first table entry matchs all 56** cards but - second only the 1234 card. -*/ -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, -}; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; - -static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); - -static struct pci_id_info pci_tbl[] = -{{ "RealTek RTL8129 Fast Ethernet", - 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "RealTek RTL8139 Fast Ethernet", - 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", - 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "Accton MPX5030 (RealTek RTL8139)", - 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - {0,}, /* 0 terminated list. */ -}; - -/* The capability table matches the chip table above. */ -enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; -static int rtl_cap_tbl[] = { - HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG, -}; - - -/* The rest of these values should never change. */ -#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */ - -/* Symbolic offsets to registers. */ -enum RTL8129_registers { - MAC0=0, /* Ethernet hardware address. */ - MAR0=8, /* Multicast filter. */ - TxStatus0=0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ - RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, - ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, - IntrMask=0x3C, IntrStatus=0x3E, - TxConfig=0x40, RxConfig=0x44, - Timer=0x48, /* A general-purpose counter. */ - RxMissed=0x4C, /* 24 bits valid, write clears. */ - Cfg9346=0x50, Config0=0x51, Config1=0x52, - FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B, - MultiIntr=0x5C, TxSummary=0x60, - MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, - NWayExpansion=0x6A, - /* Undocumented registers, but required for proper operation. */ - FIFOTMS=0x70, /* FIFO Test Mode Select */ - CSCR=0x74, /* Chip Status and Configuration Register. */ - PARA78=0x78, PARA7c=0x7c, /* Magic transceiver parameter register. */ -}; - -enum ChipCmdBits { - CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, }; - -/* Interrupt register bits, using my own meaningful names. */ -enum IntrStatusBits { - PCIErr=0x8000, PCSTimeout=0x4000, - RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10, - TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01, -}; -enum TxStatusBits { - TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000, - TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000, -}; -enum RxStatusBits { - RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000, - RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004, - RxBadAlign=0x0002, RxStatusOK=0x0001, -}; - -/* Twister tuning parameters from RealTek. - Completely undocumented, but required to tune bad links. */ -enum CSCRBits { - CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, - CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, - CSCR_LinkDownCmd=0x0f3c0, -}; -unsigned long param[4][4]={ - {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43}, - {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, - {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, - {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83} -}; - -struct ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - -struct rtl8129_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - struct pci_dev *pdev; - int chip_id; - int chip_revision; - unsigned char pci_bus, pci_devfn; -#if LINUX_VERSION_CODE > 0x20139 - struct net_device_stats stats; -#else - struct enet_statistics stats; -#endif - struct timer_list timer; /* Media selection timer. */ - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int cur_tx, dirty_tx, tx_flag; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct ring_info tx_info[NUM_TX_DESC]; - unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - unsigned char *rx_ring; - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - dma_addr_t rx_ring_dma; - dma_addr_t tx_bufs_dma; - char phys[4]; /* MII device addresses. */ - char twistie, twist_cnt; /* Twister tune state. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int duplex_lock:1; - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ -}; - -#ifdef MODULE -#if LINUX_VERSION_CODE > 0x20115 -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(multicast_filter_limit, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(debug, "i"); -#endif -#endif - -static int rtl8129_open(struct net_device *dev); -static int read_eeprom(long ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int val); -static void rtl8129_timer(unsigned long data); -static void rtl8129_tx_timeout(struct net_device *dev); -static void rtl8129_init_ring(struct net_device *dev); -static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int rtl8129_rx(struct net_device *dev); -static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int rtl8129_close(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct enet_statistics *rtl8129_get_stats(struct net_device *dev); -static inline u32 ether_crc(int length, unsigned char *data); -static void set_rx_mode(struct net_device *dev); - - -/* A list of all installed RTL8129 devices, for removing the driver module. */ -static struct net_device *root_rtl8129_dev = NULL; - -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - Rtl81*9 cards in slot order. */ - -int rtl8139_probe(void) -{ - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - struct net_device *dev; - - if ( ! pcibios_present()) - return -ENODEV; - - for (; pci_index < 0xff; pci_index++) { - struct pci_dev *pdev; - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; - irq = pdev->irq; - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && - check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); - - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printk(KERN_NOTICE " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to 64 clocks.\n", - pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 64); - } - } - dev = 0; - cards_found++; - } - - return cards_found ? 0 : -ENODEV; -} - -static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chip_idx, int found_cnt) -{ - static int did_version = 0; /* Already printed version info. */ - struct rtl8129_private *tp; - int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0; - struct net_device *dev; - - if (rtl8129_debug > 0 && did_version++ == 0) - printk(KERN_INFO "%s", version); - - dev = init_etherdev(NULL, 0); - - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, pci_tbl[chip_idx].name, ioaddr, irq); - - /* Bring the chip out of low-power mode. */ - outb(0x00, ioaddr + Config1); - - if (read_eeprom(ioaddr, 0) != 0xffff) { - for (i = 0; i < 3; i++) { - ((u16 *)(dev->dev_addr))[i] = - le16_to_cpu(read_eeprom(ioaddr, i + 7)); - } - } else { - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb(ioaddr + MAC0 + i); - } - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - - /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); - - dev->base_addr = ioaddr; - dev->irq = irq; - - /* Some data structures must be quadword aligned. */ - tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); - memset(tp, 0, sizeof(*tp)); - dev->priv = tp; - - tp->next_module = root_rtl8129_dev; - root_rtl8129_dev = dev; - - tp->pdev = pdev; - tp->chip_id = chip_idx; - tp->pci_bus = pci_bus; - tp->pci_devfn = pci_devfn; - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ - if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) { - int phy, phy_idx; - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - tp->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver found at address %d.\n", - dev->name, phy); - } - } - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " - "transceiver.\n", - dev->name); - tp->phys[0] = -1; - } - } else - tp->phys[0] = 32; - - /* Put the chip into low-power mode. */ - outb(0xC0, ioaddr + Cfg9346); - outb(0x03, ioaddr + Config1); - outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ - - /* The lower four bits are the media type. */ - if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; - if (tp->default_port) - tp->medialock = 1; - } - - if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) - tp->full_duplex = full_duplex[found_cnt]; - - if (tp->full_duplex) { - printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); - mdio_write(dev, tp->phys[0], 4, 0x141); - tp->duplex_lock = 1; - } - - /* The Rtl8129-specific entries in the device structure. */ - dev->open = &rtl8129_open; - dev->hard_start_xmit = &rtl8129_start_xmit; - dev->tx_timeout = &rtl8129_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = &rtl8129_close; - dev->get_stats = &rtl8129_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; - - return dev; -} - -/* Serial EEPROM section. */ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ -#define EE_CS 0x08 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x00 -#define EE_WRITE_1 0x02 -#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ -#define EE_ENB (0x80 | EE_CS) - -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. - */ - -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) - -static int read_eeprom(long ioaddr, int location) -{ - int i; - unsigned retval = 0; - long ee_addr = ioaddr + Cfg9346; - int read_cmd = location | EE_READ_CMD; - - outb(EE_ENB & ~EE_CS, ee_addr); - outb(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outb(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - } - outb(EE_ENB, ee_addr); - eeprom_delay(); - - for (i = 16; i > 0; i--) { - outb(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); - outb(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outb(~EE_CS, ee_addr); - return retval; -} - -/* MII serial management: mostly bogus for now. */ -/* Read and write the MII management registers using software-generated - serial MDIO protocol. - The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ -#define MDIO_DIR 0x80 -#define MDIO_DATA_OUT 0x04 -#define MDIO_DATA_IN 0x02 -#define MDIO_CLK 0x01 -#define MDIO_WRITE0 (MDIO_DIR) -#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) - -#define mdio_delay() inb(mdio_addr) - -static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert, - NWayLPAR, NWayExpansion, 0 }; - -/* Syncronize the MII management interface by shifting 32 one bits out. */ -static void mdio_sync(long mdio_addr) -{ - int i; - - for (i = 32; i >= 0; i--) { - outb(MDIO_WRITE1, mdio_addr); - mdio_delay(); - outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay(); - } - return; -} -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - long mdio_addr = dev->base_addr + MII_SMI; - int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - int i; - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - return location < 8 && mii_2_8139_map[location] ? - inw(dev->base_addr + mii_2_8139_map[location]) : 0; - } - mdio_sync(mdio_addr); - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; - - outb(MDIO_DIR | dataval, mdio_addr); - mdio_delay(); - outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay(); - } - - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); - outb(MDIO_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - long mdio_addr = dev->base_addr + MII_SMI; - int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - int i; - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) - outw(value, dev->base_addr + mii_2_8139_map[location]); - return; - } - mdio_sync(mdio_addr); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; - outb(dataval, mdio_addr); - mdio_delay(); - outb(dataval | MDIO_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - outb(MDIO_CLK, mdio_addr); - mdio_delay(); - } - return; -} - - -static int -rtl8129_open(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int i; - - /* Soft reset the chip. */ - outb(CmdReset, ioaddr + ChipCmd); - - if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) { - return -EAGAIN; - } - - MOD_INC_USE_COUNT; - - tp->tx_bufs = pci_alloc_consistent(tp->pdev, - TX_BUF_SIZE * NUM_TX_DESC, - &tp->tx_bufs_dma); - tp->rx_ring = pci_alloc_consistent(tp->pdev, - RX_BUF_LEN + 16, - &tp->rx_ring_dma); - if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { - free_irq(dev->irq, dev); - if (tp->tx_bufs) - pci_free_consistent(tp->pdev, - TX_BUF_SIZE * NUM_TX_DESC, - tp->tx_bufs, tp->tx_bufs_dma); - if (tp->rx_ring) - pci_free_consistent(tp->pdev, - RX_BUF_LEN + 16, - tp->rx_ring, tp->rx_ring_dma); - if (rtl8129_debug > 0) - printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", - dev->name, RX_BUF_LEN); - return -ENOMEM; - } - rtl8129_init_ring(dev); - - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; - - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + MAC0 + i); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), - ioaddr + RxConfig); - outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); - tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000; - - tp->full_duplex = tp->duplex_lock; - if (tp->phys[0] >= 0 || (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) { - u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); - if (mii_reg5 == 0xffff) - ; /* Not there */ - else if ((mii_reg5 & 0x0100) == 0x0100 - || (mii_reg5 & 0x00C0) == 0x0040) - tp->full_duplex = 1; - if (rtl8129_debug > 1) - printk(KERN_INFO"%s: Setting %s%s-duplex based on" - " auto-negotiated partner ability %4.4x.\n", dev->name, - mii_reg5 == 0 ? "" : - (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", - tp->full_duplex ? "full" : "half", mii_reg5); - } - - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - - outl(tp->rx_ring_dma, ioaddr + RxBuf); - - /* Start the chip's Tx and Rx process. */ - outl(0, ioaddr + RxMissed); - set_rx_mode(dev); - - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - - /* Enable all known interrupts by setting the interrupt mask. */ - outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); - - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" - " GP Pins %2.2x %s-duplex.\n", - dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData), - tp->full_duplex ? "full" : "half"); - - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - tp->timer.data = (unsigned long)dev; - tp->timer.function = &rtl8129_timer; - add_timer(&tp->timer); - - return 0; -} - -static void rtl8129_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - int mii_reg5 = mdio_read(dev, tp->phys[0], 5); - - if (! tp->duplex_lock && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", dev->name, - tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - } - } - /* Check for bogusness. */ - if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { - int status = inw(ioaddr + IntrStatus); - if (status & (TxOK | RxOK)) { /* Double check */ - printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n", - dev->name, status); - rtl8129_interrupt(dev->irq, dev, 0); - } - } - if (test_bit(LINK_STATE_XOFF, &dev->state) && - (jiffies - dev->trans_start) >= 2*TX_TIMEOUT) - rtl8129_tx_timeout(dev); - -#if 0 - if (tp->twistie) { - unsigned int CSCRval = inw(ioaddr + CSCR); /* Read link status. */ - if (tp->twistie == 1) { - if (CSCRval & CSCR_LinkOKBit) { - outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); - tp->twistie = 2; - next_tick = HZ/10; - } else { - outw(CSCR_LinkDownCmd, ioaddr + CSCR); - outl(FIFOTMS_default,ioaddr + FIFOTMS); - outl(PARA78_default ,ioaddr + PARA78); - outl(PARA7c_default ,ioaddr + PARA7c); - tp->twistie = 0; - } - } else if (tp->twistie == 2) { - int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12; - int row; - if (linkcase >= 0x7000) row = 3; - else if (linkcase >= 0x3000) row = 2; - else if (linkcase >= 0x1000) row = 1; - else row = 0; - tp->twistie == row + 3; - outw(0,ioaddr+FIFOTMS); - outl(param[row][0], ioaddr+PARA7c); - tp->twist_cnt = 1; - } else { - outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c); - if (++tp->twist_cnt < 4) { - next_tick = HZ/10; - } else if (tp->twistie-3 == 3) { - if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) { - outl(PARA7c_xxx, ioaddr+PARA7c); - next_tick = HZ/10; /* 100ms. */ - outl(FIFOTMS_default, ioaddr+FIFOTMS); - outl(PARA78_default, ioaddr+PARA78); - outl(PARA7c_default, ioaddr+PARA7c); - tp->twistie == 3 + 3; - outw(0,ioaddr+FIFOTMS); - outl(param[3][0], ioaddr+PARA7c); - tp->twist_cnt = 1; - } - } - } - } -#endif - - if (rtl8129_debug > 2) { - if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR) - printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n", - dev->name, inb(ioaddr + GPPinData)); - else - printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n", - dev->name, inw(ioaddr + NWayLPAR)); - printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4x.\n", - dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus), - inl(ioaddr + RxEarlyStatus)); - printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n", - dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); - } - - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void rtl8129_tx_timeout(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int mii_reg, i; - - if (rtl8129_debug > 0) - printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x " - "media %2.2x.\n", - dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus), - inb(ioaddr + GPPinData)); - - /* Disable interrupts by clearing the interrupt mask. */ - outw(0x0000, ioaddr + IntrMask); - /* Emit info to figure out what went wrong. */ - printk("%s: Tx queue start entry %d dirty entry %d.\n", - dev->name, tp->cur_tx, tp->dirty_tx); - for (i = 0; i < NUM_TX_DESC; i++) - printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n", - dev->name, i, inl(ioaddr + TxStatus0 + i*4), - i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); - printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]); - for (mii_reg = 0; mii_reg < 8; mii_reg++) - printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg)); - printk(".\n"); - - /* Soft reset the chip. */ - outb(CmdReset, ioaddr + ChipCmd); - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + MAC0 + i); - - outb(0x00, ioaddr + Cfg9346); - tp->cur_rx = 0; - /* Must enable Tx/Rx before setting transfer thresholds! */ - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), - ioaddr + RxConfig); - outl((TX_DMA_BURST<<8), ioaddr + TxConfig); - set_rx_mode(dev); - { /* Save the unsent Tx packets. */ - struct sk_buff *saved_skb[NUM_TX_DESC], *skb; - int j; - for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) { - struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC]; - - saved_skb[j] = rp->skb; - if (rp->mapping != 0) { - pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len); - rp->mapping = 0; - } - } - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < j; i++) { - skb = tp->tx_info[i].skb = saved_skb[i]; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ - memcpy(tp->tx_buf[i], skb->data, skb->len); - outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs), - ioaddr + TxAddr0 + i*4); - } else { - tp->tx_info[i].mapping = - pci_map_single(tp->pdev, skb->data, skb->len); - outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4); - } - /* Note: the chip doesn't have auto-pad! */ - outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), - ioaddr + TxStatus0 + i*4); - } - tp->cur_tx = i; - while (i < NUM_TX_DESC) { - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - i++; - } - if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ - netif_wake_queue(dev); - tp->tx_full = 0; - } else { - tp->tx_full = 1; - } - } - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - /* Enable all known interrupts by setting the interrupt mask. */ - outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); - return; -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -rtl8129_init_ring(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = 0; - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE]; - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - } -} - -static int -rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int entry; - - netif_stop_queue(dev); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % NUM_TX_DESC; - - tp->tx_info[entry].skb = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ - tp->tx_info[entry].mapping = 0; - memcpy(tp->tx_buf[entry], skb->data, skb->len); - outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs), - ioaddr + TxAddr0 + entry*4); - } else { - tp->tx_info[entry].mapping = - pci_map_single(tp->pdev, skb->data, skb->len); - outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4); - } - /* Note: the chip doesn't have auto-pad! */ - outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), - ioaddr + TxStatus0 + entry*4); - - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ - netif_start_queue(dev); - } else { - tp->tx_full = 1; - } - - dev->trans_start = jiffies; - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n", - dev->name, skb->data, (int)skb->len, entry); - - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int boguscnt = max_interrupt_work; - int status, link_changed = 0; - long ioaddr = dev->base_addr; - - do { - status = inw(ioaddr + IntrStatus); - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit) - link_changed = 1; - outw(status, ioaddr + IntrStatus); - - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, inw(ioaddr + IntrStatus)); - - if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver - |TxErr|TxOK|RxErr|RxOK)) == 0) - break; - - if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */ - rtl8129_rx(dev); - - if (status & (TxOK | TxErr)) { - unsigned int dirty_tx = tp->dirty_tx; - - while (tp->cur_tx - dirty_tx > 0) { - int entry = dirty_tx % NUM_TX_DESC; - int txstatus = inl(ioaddr + TxStatus0 + entry*4); - - if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted))) - break; /* It still hasn't been Txed */ - - /* Note: TxCarrierLost is always asserted at 100mbps. */ - if (txstatus & (TxOutOfWindow | TxAborted)) { - /* There was an major error, log it. */ - if (rtl8129_debug > 1) - printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); - tp->stats.tx_errors++; - if (txstatus&TxAborted) { - tp->stats.tx_aborted_errors++; - outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig); - } - if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++; - if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++; -#ifdef ETHER_STATS - if ((txstatus & 0x0f000000) == 0x0f000000) - tp->stats.collisions16++; -#endif - } else { - if (txstatus & TxUnderrun) { - /* Add 64 to the Tx FIFO threshold. */ - if (tp->tx_flag < 0x00300000) - tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; - } - tp->stats.collisions += (txstatus >> 24) & 15; -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.tx_bytes += txstatus & 0x7ff; -#endif - tp->stats.tx_packets++; - } - - if (tp->tx_info[entry].mapping != 0) { - pci_unmap_single(tp->pdev, - tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len); - tp->tx_info[entry].mapping = 0; - } - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_info[entry].skb); - tp->tx_info[entry].skb = NULL; - if (tp->tx_full) { - /* The ring is no longer full, wake the queue. */ - tp->tx_full = 0; - netif_wake_queue(dev); - } - dirty_tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, tp->cur_tx, tp->tx_full); - dirty_tx += NUM_TX_DESC; - } -#endif - tp->dirty_tx = dirty_tx; - } - - /* Check uncommon events with one test. */ - if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver - |TxErr|RxErr)) { - if (rtl8129_debug > 2) - printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); - - if (status == 0xffffffff) - break; - /* Update the error count. */ - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - - if ((status & RxUnderrun) && link_changed && - (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) { - /* Really link-change on new chips. */ - int lpar = inw(ioaddr + NWayLPAR); - int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - } - status &= ~RxUnderrun; - } - if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) - tp->stats.rx_errors++; - - if (status & (PCSTimeout)) tp->stats.rx_length_errors++; - if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++; - if (status & RxOverflow) { - tp->stats.rx_over_errors++; - tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN; - outw(tp->cur_rx - 16, ioaddr + RxBufPtr); - } - if (status & PCIErr) { - u32 pci_cmd_status; - pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn, - PCI_COMMAND, &pci_cmd_status); - - printk(KERN_ERR "%s: PCI Bus error %4.4x.\n", - dev->name, pci_cmd_status); - } - } - if (--boguscnt < 0) { - printk(KERN_WARNING"%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outw(0xffff, ioaddr + IntrStatus); - break; - } - } while (1); - - if (rtl8129_debug > 3) - printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + IntrStatus)); - return; -} - -/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the - field alignments and semantics. */ -static int rtl8129_rx(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - unsigned char *rx_ring = tp->rx_ring; - u16 cur_rx = tp->cur_rx; - - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", - dev->name, cur_rx, inw(ioaddr + RxBufAddr), - inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); - - while ((inb(ioaddr + ChipCmd) & 1) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; - u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset)); - int rx_size = rx_status >> 16; - - if (rtl8129_debug > 4) { - int i; - printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n", - dev->name, rx_status, rx_size, cur_rx); - printk(KERN_DEBUG"%s: Frame contents ", dev->name); - for (i = 0; i < 70; i++) - printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i])); - printk(".\n"); - } - if (rx_status & RxTooLong) { - if (rtl8129_debug > 0) - printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n", - dev->name, rx_status); - tp->stats.rx_length_errors++; - } else if (rx_status & - (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) { - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: Ethernet frame had errors," - " status %4.4x.\n", dev->name, rx_status); - tp->stats.rx_errors++; - if (rx_status & (RxBadSymbol|RxBadAlign)) - tp->stats.rx_frame_errors++; - if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++; - if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; - /* Reset the receiver, based on RealTek recommendation. (Bug?) */ - tp->cur_rx = 0; - outb(CmdTxEnb, ioaddr + ChipCmd); - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | - (RX_DMA_BURST<<8), ioaddr + RxConfig); - } else { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - struct sk_buff *skb; - - skb = dev_alloc_skb(rx_size + 2); - if (skb == NULL) { - printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; - break; - } - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size+4 > RX_BUF_LEN) { - int semi_count = RX_BUF_LEN - ring_offset - 4; - memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], - semi_count); - memcpy(skb_put(skb, rx_size-semi_count), rx_ring, - rx_size-semi_count); - if (rtl8129_debug > 4) { - int i; - printk(KERN_DEBUG"%s: Frame wrap @%d", - dev->name, semi_count); - for (i = 0; i < 16; i++) - printk(" %2.2x", le32_to_cpu(rx_ring[i])); - printk(".\n"); - memset(rx_ring, 0xcc, 16); - } - } else { -#if 1 /* USE_IP_COPYSUM */ - eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - rx_size, 0); - skb_put(skb, rx_size); -#else - memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4], - rx_size); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += rx_size; -#endif - tp->stats.rx_packets++; - } - - cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - outw(cur_rx - 16, ioaddr + RxBufPtr); - } - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", - dev->name, cur_rx, inw(ioaddr + RxBufAddr), - inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); - tp->cur_rx = cur_rx; - return 0; -} - -static int -rtl8129_close(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int i; - - netif_stop_queue(dev); - - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, inw(ioaddr + IntrStatus)); - - /* Disable interrupts by clearing the interrupt mask. */ - outw(0x0000, ioaddr + IntrMask); - - /* Stop the chip's Tx and Rx DMA processes. */ - outb(0x00, ioaddr + ChipCmd); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - - del_timer(&tp->timer); - - free_irq(dev->irq, dev); - - for (i = 0; i < NUM_TX_DESC; i++) { - struct sk_buff *skb = tp->tx_info[i].skb; - dma_addr_t mapping = tp->tx_info[i].mapping; - - if (skb) { - if (mapping) - pci_unmap_single(tp->pdev, mapping, skb->len); - dev_kfree_skb(skb); - } - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - } - pci_free_consistent(tp->pdev, RX_BUF_LEN + 16, - tp->rx_ring, tp->rx_ring_dma); - pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, - tp->tx_bufs, tp->tx_bufs_dma); - tp->rx_ring = NULL; - tp->tx_bufs = NULL; - - /* Green! Put the chip in low-power mode. */ - outb(0xC0, ioaddr + Cfg9346); - outb(0x03, ioaddr + Config1); - outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ - - MOD_DEC_USE_COUNT; - - return 0; -} - -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - u16 *data = (u16 *)&rq->ifr_data; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = tp->phys[0] & 0x3f; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0], data[1] & 0x1f); - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - mdio_write(dev, data[0], data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; - } -} - -static struct enet_statistics * -rtl8129_get_stats(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (test_bit(LINK_STATE_START, &dev->state)) { - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - } - - return &tp->stats; -} - -/* Set or clear the multicast filter for this adaptor. - This routine is not state sensitive and need not be SMP locked. */ - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - -/* Bits in RxConfig. */ -enum rx_mode_bits { - AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, - AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, -}; - -static void set_rx_mode(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - u32 mc_filter[2]; /* Multicast hash filter */ - int i, rx_mode; - - if (rtl8129_debug > 3) - printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", - dev->name, dev->flags, inl(ioaddr + RxConfig)); - - /* Note: do not reorder, GCC is clever about common statements. */ - if (dev->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); - rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter perfectly -- accept all multicasts. */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else { - struct dev_mc_list *mclist; - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); - } - /* We can safely update without stopping the chip. */ - outb(rx_mode, ioaddr + RxConfig); - outl(mc_filter[0], ioaddr + MAR0 + 0); - outl(mc_filter[1], ioaddr + MAR0 + 4); - return; -} - -#ifdef MODULE -int init_module(void) -{ - return rtl8139_probe(); -} - -void -cleanup_module(void) -{ - struct net_device *next_dev; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_rtl8129_dev) { - struct rtl8129_private *tp = - (struct rtl8129_private *)root_rtl8129_dev->priv; - next_dev = tp->next_module; - unregister_netdev(root_rtl8129_dev); - release_region(root_rtl8129_dev->base_addr, - pci_tbl[tp->chip_id].io_size); - kfree(tp); - kfree(root_rtl8129_dev); - root_rtl8129_dev = next_dev; - } -} - -#endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff -u --recursive --new-file v2.3.44/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.3.44/linux/drivers/net/seeq8005.c Thu Nov 11 20:11:42 1999 +++ linux/drivers/net/seeq8005.c Sat Feb 12 15:45:05 2000 @@ -83,6 +83,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr); static int seeq8005_open(struct net_device *dev); +static void seeq8005_timeout(struct net_device *dev); static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void seeq8005_rx(struct net_device *dev); @@ -324,9 +325,11 @@ dev->open = seeq8005_open; dev->stop = seeq8005_close; - dev->hard_start_xmit = seeq8005_send_packet; - dev->get_stats = seeq8005_get_stats; - dev->set_multicast_list = &set_multicast_list; + dev->hard_start_xmit = seeq8005_send_packet; + dev->tx_timeout = seeq8005_timeout; + dev->watchdog_timeo = HZ/20; + dev->get_stats = seeq8005_get_stats; + dev->set_multicast_list = set_multicast_list; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); @@ -344,8 +347,7 @@ registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. */ -static int -seeq8005_open(struct net_device *dev) +static int seeq8005_open(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; @@ -363,46 +365,34 @@ lp->open_time = jiffies; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); return 0; } -static int -seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) +static void seeq8005_timeout(struct net_device *dev) { int ioaddr = dev->base_addr; + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict" : "network cable problem"); + /* Try to restart the adaptor. */ + seeq8005_init(dev, 1); + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) +{ struct net_local *lp = (struct net_local *)dev->priv; + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; - if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk("%s: transmit timed out, %s?\n", dev->name, - tx_done(dev) ? "IRQ conflict" : "network cable problem"); - /* Try to restart the adaptor. */ - seeq8005_init(dev, 1); - dev->tbusy=0; - dev->trans_start = jiffies; - } - - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - - hardware_send_packet(dev, buf, length); - dev->trans_start = jiffies; - lp->stats.tx_bytes += length; - } + /* Block a timer-based transmit from overlapping */ + netif_stop_queue(dev); + + hardware_send_packet(dev, buf, length); + dev->trans_start = jiffies; + lp->stats.tx_bytes += length; dev_kfree_skb (skb); - /* You might need to clean up and record Tx statistics here. */ return 0; @@ -410,22 +400,12 @@ /* The typical workload of the driver: Handle the network interface interrupts. */ -static void -seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; struct net_local *lp; int ioaddr, status, boguscount = 0; - if (dev == NULL) { - printk ("net_interrupt(): irq %d for unknown device.\n", irq); - return; - } - - if (dev->interrupt) - printk ("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; - ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -444,8 +424,7 @@ if (status & SEEQSTAT_TX_INT) { outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); lp->stats.tx_packets++; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue(dev); /* Inform upper layers. */ } if (status & SEEQSTAT_RX_INT) { /* Got a packet(s). */ @@ -457,13 +436,10 @@ if(net_debug>2) { printk("%s: eoi\n",dev->name); } - dev->interrupt = 0; - return; } /* We have a good packet(s), get it/them out of the buffers. */ -static void -seeq8005_rx(struct net_device *dev) +static void seeq8005_rx(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int boguscount = 10; @@ -561,17 +537,15 @@ } /* The inverse routine to net_open(). */ -static int -seeq8005_close(struct net_device *dev) +static int seeq8005_close(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; lp->open_time = 0; - dev->tbusy = 1; - dev->start = 0; - + netif_stop_queue(dev); + /* Flush the Tx and disable Rx here. */ outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD); @@ -598,8 +572,7 @@ num_addrs > 0 Multicast mode, receive normal and MC packets, and do best-effort filtering. */ -static void -set_multicast_list(struct net_device *dev) +static void set_multicast_list(struct net_device *dev) { /* * I _could_ do up to 6 addresses here, but won't (yet?) diff -u --recursive --new-file v2.3.44/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.3.44/linux/drivers/net/sis900.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/sis900.c Sun Feb 13 18:51:08 2000 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.06.03 Dec 23 1999 + Revision: 1.06.04 Feb 11 2000 Modified from the driver which is originally written by Donald Becker. @@ -135,7 +135,7 @@ int LinkOn; }; -MODULE_AUTHOR("Jim Huang "); +MODULE_AUTHOR("Jim Huang , Ollie Lho "); MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver"); MODULE_PARM(multicast_filter_limit, "i"); MODULE_PARM(max_interrupt_work, "i"); @@ -257,7 +257,7 @@ net_dev->irq = irq; sis_priv->pci_dev = pci_dev; sis_priv->mac = mac; - sis_priv->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&sis_priv->lock); /* probe for mii transciver */ if (sis900_mii_probe(net_dev) == 0) { @@ -668,8 +668,8 @@ next_tick = 5*HZ; /* change what cur_phy means */ if (mii_phy->phy_addr != sis_priv->cur_phy) { - printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name, - mii_phy->chip_info->name); + printk(KERN_INFO "%s: Changing transceiver to %s\n", + net_dev->name, mii_phy->chip_info->name); status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status | MII_CNTL_ISOLATE); @@ -798,9 +798,10 @@ /* Disable interrupts by clearing the interrupt mask. */ outl(0x0000, ioaddr + imr); - /* discard unsent packets, should this code section be protected by - cli(), sti() ?? */ + /* use spinlock to prevent interrupt handler accessing buffer ring */ spin_lock_irqsave(&sis_priv->lock, flags); + + /* discard unsent packets */ sis_priv->dirty_tx = sis_priv->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { if (sis_priv->tx_skbuff[i] != NULL) { @@ -811,13 +812,15 @@ sis_priv->stats.tx_dropped++; } } + sis_priv->tx_full = 0; + netif_wake_queue(net_dev); + spin_unlock_irqrestore(&sis_priv->lock, flags); net_dev->trans_start = jiffies; - sis_priv->tx_full = 0; - netif_start_queue(net_dev); /* FIXME: Should we restart the transmission thread here ?? */ + outl(TxENA, ioaddr + cr); /* Enable all known interrupts by setting the interrupt mask. */ outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); @@ -830,6 +833,9 @@ struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; long ioaddr = net_dev->base_addr; unsigned int entry; + unsigned long flags; + + spin_lock_irqsave(&sis_priv->lock, flags); /* Calculate the next Tx descriptor entry. */ entry = sis_priv->cur_tx % NUM_TX_DESC; @@ -841,14 +847,16 @@ outl(TxENA, ioaddr + cr); if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) { - /* Typical path, clear tbusy to indicate more - transmission is possible */ + /* Typical path, tell upper layer that more transmission is possible */ netif_start_queue(net_dev); } else { - /* no more transmit descriptor avaiable, tbusy remain set */ + /* buffer full, tell upper layer no more transmission */ sis_priv->tx_full = 1; + netif_stop_queue(net_dev); } + spin_unlock_irqrestore(&sis_priv->lock, flags); + net_dev->trans_start = jiffies; if (sis900_debug > 3) @@ -922,7 +930,7 @@ if (sis900_debug > 3) printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", - sis_priv->cur_rx, sis_priv->dirty_rx,rx_status); + sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); while (rx_status & OWN) { unsigned int rx_size; @@ -1060,8 +1068,8 @@ if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) && sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { - /* The ring is no longer full, clear tbusy, tx_full and - schedule more transmission by marking NET_BH */ + /* The ring is no longer full, clear tx_full and schedule more transmission + by netif_wake_queue(net_dev) */ sis_priv->tx_full = 0; netif_wake_queue (net_dev); } diff -u --recursive --new-file v2.3.44/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.3.44/linux/drivers/net/sk_g16.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/sk_g16.c Sun Feb 13 18:20:21 2000 @@ -472,6 +472,7 @@ int SK_init(struct net_device *dev); static int SK_probe(struct net_device *dev, short ioaddr); +static void SK_timeout(struct net_device *dev); static int SK_open(struct net_device *dev); static int SK_send_packet(struct sk_buff *skb, struct net_device *dev); static void SK_interrupt(int irq, void *dev_id, struct pt_regs * regs); @@ -778,11 +779,13 @@ /* Assign our Device Driver functions */ - dev->open = &SK_open; - dev->stop = &SK_close; - dev->hard_start_xmit = &SK_send_packet; - dev->get_stats = &SK_get_stats; - dev->set_multicast_list = &set_multicast_list; + dev->open = SK_open; + dev->stop = SK_close; + dev->hard_start_xmit = SK_send_packet; + dev->get_stats = SK_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->tx_timeout = SK_timeout; + dev->watchdog_timeo = HZ/7; /* Set the generic fields of the device structure */ @@ -1169,30 +1172,18 @@ * YY/MM/DD uid Description -*/ -static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) +static int SK_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; - struct tmd *tmdp; - - if (test_bit(LINK_STATE_XOFF, &dev->flags)) - { - /* if Transmitter more than 150ms busy -> time_out */ - - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 15) - { - return 1; /* We have to try transmit later */ - } - - printk("%s: xmitter timed out, try to restart!\n", dev->name); - + printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name); SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ - netif_start_queue(dev); /* Clear Transmitter flag */ - dev->trans_start = jiffies; /* Mark Start of transmission */ +} - } +static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + struct tmd *tmdp; PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", SK_NAME, SK_read_reg(CSR0))); diff -u --recursive --new-file v2.3.44/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c --- v2.3.44/linux/drivers/net/smc-mca.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/net/smc-mca.c Sat Feb 12 15:45:05 2000 @@ -414,9 +414,8 @@ { int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */ - dev->start = 0; - dev->tbusy = 1; - + netif_stop_queue(dev); + if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); diff -u --recursive --new-file v2.3.44/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.3.44/linux/drivers/net/smc9194.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/smc9194.c Sat Feb 12 15:45:05 2000 @@ -50,11 +50,8 @@ static const char *version = "smc9194.c:v0.12 03/06/96 by Erik Stahlman (erik@vt.edu)\n"; -#ifdef MODULE #include #include -#endif - #include #include #include @@ -82,22 +79,6 @@ -------------------------------------------------------------------------*/ /* - . this is for kernels > 1.2.70 -*/ -#define REALLY_NEW_KERNEL -#ifndef REALLY_NEW_KERNEL -#define free_irq( x, y ) free_irq( x ) -#define request_irq( x, y, z, u, v ) request_irq( x, y, z, u ) -#endif - -/* - . Do you want to use this with old kernels. - . WARNING: this is not well tested. -#define SUPPORT_OLD_KERNEL -*/ - - -/* . Do you want to use 32 bit xfers? This should work on all chips, as . the chipset is designed to accommodate them. */ @@ -108,9 +89,10 @@ .for a slightly different card, you can add it to the array. Keep in .mind that the array must end in zero. */ -static unsigned int smc_portlist[] __initdata = - { 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, - 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0}; +static unsigned int smc_portlist[] __initdata = { + 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, + 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 +}; /* . Wait time for memory to be free. This probably shouldn't be @@ -149,12 +131,6 @@ #endif -/* the older versions of the kernel cannot support autoprobing */ -#ifdef SUPPORT_OLD_KERNEL -#define NO_AUTOPROBE -#endif - - /*------------------------------------------------------------------------ . . The internal workings of the driver. If you are changing anything @@ -164,9 +140,6 @@ -------------------------------------------------------------------------*/ #define CARDNAME "SMC9194" -#ifdef SUPPORT_OLD_KERNEL -char kernel_version[] = UTS_RELEASE; -#endif /* store this information for the driver.. */ struct smc_local { @@ -217,6 +190,11 @@ static int smc_open(struct net_device *dev); /* + . Our watchdog timed out. Called by the networking layer +*/ +static void smc_timeout(struct net_device *dev); + +/* . This is called by the kernel to send a packet out into the net. it's . responsible for doing a best-effort send, but if it's simply not possible . to send it, the packet gets dropped. @@ -240,12 +218,12 @@ . Finally, a call to set promiscuous mode ( for TCPDUMP and related . programs ) and multicast modes. */ -#ifdef SUPPORT_OLD_KERNEL -static void smc_set_multicast_list(struct net_device *dev, int num_addrs, - void *addrs); -#else static void smc_set_multicast_list(struct net_device *dev); -#endif + +/* + . CRC compute + */ +static int crc32( char * s, int length ); /*--------------------------------------------------------------- . @@ -256,11 +234,7 @@ /* . Handles the actual interrupt */ -#ifdef REALLY_NEW_KERNEL static void smc_interrupt(int irq, void *, struct pt_regs *regs); -#else -static void smc_interrupt(int irq, struct pt_regs *regs); -#endif /* . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner @@ -321,25 +295,9 @@ /* this puts the device in an inactive state */ static void smc_shutdown( int ioaddr ); -#ifndef NO_AUTOPROBE /* This routine will find the IRQ of the driver if one is not . specified in the input to the device. */ static int smc_findirq( int ioaddr ); -#endif - -/* - this routine will set the hardware multicast table to the specified - values given it by the higher level routines -*/ -#ifndef SUPPORT_OLD_KERNEL -static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * ); -static int crc32( char *, int ); -#endif - -#ifdef SUPPORT_OLD_KERNEL -extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private, - unsigned long *mem_startp ); -#endif /* . Function: smc_reset( int ioaddr ) @@ -442,7 +400,6 @@ } -#ifndef SUPPORT_OLD_KERNEL /* . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) . Purpose: @@ -525,8 +482,6 @@ return crc_value; } -#endif - /* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) @@ -575,6 +530,7 @@ dev_kfree_skb (skb); lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ + netif_wake_queue(dev); return 0; } /* either way, a packet is waiting now */ @@ -616,7 +572,7 @@ } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); - + netif_wake_queue(dev); return 0; } @@ -663,7 +619,7 @@ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); kfree(skb); lp->saved_skb = NULL; - dev->tbusy = 0; + netif_wake_queue(dev); return; } @@ -729,8 +685,7 @@ dev->trans_start = jiffies; /* we can send another packet */ - dev->tbusy = 0; - + netif_wake_queue(dev); return; } @@ -787,7 +742,6 @@ return -ENODEV; } -#ifndef NO_AUTOPROBE /*---------------------------------------------------------------------- . smc_findirq . @@ -860,7 +814,6 @@ /* and return what I found */ return autoirq_report( 0 ); } -#endif /*---------------------------------------------------------------------- . Function: smc_probe( int ioaddr ) @@ -962,14 +915,7 @@ /* see if I need to initialize the ethernet card structure */ if (dev == NULL) { -#ifdef SUPPORT_OLD_KERNEL -#ifndef MODULE -/* note: the old module interface does not support this call */ - dev = init_etherdev( 0, sizeof( struct smc_local ), 0 ); -#endif -#else dev = init_etherdev(0, 0); -#endif if (dev == NULL) return -ENOMEM; } @@ -1043,7 +989,6 @@ . what (s)he is doing. No checking is done!!!! . */ -#ifndef NO_AUTOPROBE if ( dev->irq < 2 ) { int trials; @@ -1060,13 +1005,6 @@ printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n"); return -ENODEV; } -#else - if (dev->irq == 0 ) { - printk(CARDNAME - ": Autoprobing IRQs is not supported for old kernels.\n"); - return -ENODEV; - } -#endif if (dev->irq == 2) { /* Fixup for users that don't know that IRQ 2 is really IRQ 9, * or don't know which one to set. @@ -1114,10 +1052,10 @@ dev->open = smc_open; dev->stop = smc_close; dev->hard_start_xmit = smc_send_packet; + dev->tx_timeout = smc_timeout; + dev->watchdog_timeo = HZ/20; dev->get_stats = smc_query_statistics; -#ifdef HAVE_MULTICAST - dev->set_multicast_list = &smc_set_multicast_list; -#endif + dev->set_multicast_list = smc_set_multicast_list; return 0; } @@ -1174,12 +1112,7 @@ /* clear out all the junk that was put here before... */ memset(dev->priv, 0, sizeof(struct smc_local)); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif /* reset the hardware */ @@ -1211,6 +1144,8 @@ address |= dev->dev_addr[ i ]; outw( address, ioaddr + ADDR0 + i ); } + + netif_start_queue(dev); return 0; } @@ -1220,38 +1155,29 @@ . skeleton.c, from Becker. .-------------------------------------------------------- */ + +static void smc_timeout(struct net_device *dev) +{ + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n", + tx_done(dev) ? "IRQ conflict" : + "network cable problem"); + /* "kick" the adaptor */ + smc_reset( dev->base_addr ); + smc_enable( dev->base_addr ); + dev->trans_start = jiffies; + /* clear anything saved */ + ((struct smc_local *)dev->priv)->saved_skb = NULL; + netif_wake_queue(dev); +} + static int smc_send_packet(struct sk_buff *skb, struct net_device *dev) { - if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n", - tx_done(dev) ? "IRQ conflict" : - "network cable problem"); - /* "kick" the adaptor */ - smc_reset( dev->base_addr ); - smc_enable( dev->base_addr ); - - dev->tbusy = 0; - dev->trans_start = jiffies; - /* clear anything saved */ - ((struct smc_local *)dev->priv)->saved_skb = NULL; - } - - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n"); - dev_kfree_skb (skb); - } else { - /* Well, I want to send the packet.. but I don't know - if I can send it right now... */ - return smc_wait_to_send_packet( skb, dev ); - } - return 0; + netif_stop_queue(dev); + /* Well, I want to send the packet.. but I don't know + if I can send it right now... */ + return smc_wait_to_send_packet( skb, dev ); } /*-------------------------------------------------------------------- @@ -1266,11 +1192,8 @@ . and finally restore state. . ---------------------------------------------------------------------*/ -#ifdef REALLY_NEW_KERNEL + static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) -#else -static void smc_interrupt(int irq, struct pt_regs * regs) -#endif { struct net_device *dev = dev_id; int ioaddr = dev->base_addr; @@ -1288,20 +1211,6 @@ PRINTK3((CARDNAME": SMC interrupt started \n")); - if (dev == NULL) { - printk(KERN_WARNING CARDNAME": irq %d for unknown device.\n", - irq); - return; - } - -/* will Linux let this happen ?? If not, this costs some speed */ - if ( dev->interrupt ) { - printk(KERN_WARNING CARDNAME": interrupt inside interrupt.\n"); - return; - } - - dev->interrupt = 1; - saved_bank = inw( ioaddr + BANK_SELECT ); SMC_SELECT_BANK(2); @@ -1346,12 +1255,7 @@ lp->stats.collisions += card_stats & 0xF; /* these are for when linux supports these statistics */ -#if 0 - card_stats >>= 4; - /* deferred */ - card_stats >>= 4; - /* excess deferred */ -#endif + SMC_SELECT_BANK( 2 ); PRINTK2((KERN_WARNING CARDNAME ": TX_BUFFER_EMPTY handled\n")); @@ -1372,8 +1276,8 @@ mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); /* and let the card send more packets to me */ - mark_bh( NET_BH ); - + netif_wake_queue(dev); + PRINTK2((CARDNAME": Handoff done successfully.\n")); } else if (status & IM_RX_OVRN_INT ) { lp->stats.rx_errors++; @@ -1397,7 +1301,6 @@ SMC_SELECT_BANK( saved_bank ); - dev->interrupt = 0; PRINTK3((CARDNAME ": Interrupt done\n")); return; } @@ -1462,11 +1365,7 @@ if ( status & RS_MULTICAST ) lp->stats.multicast++; -#ifdef SUPPORT_OLD_KERNEL - skb = alloc_skb( packet_length + 5, GFP_ATOMIC ); -#else skb = dev_alloc_skb( packet_length + 5); -#endif if ( skb == NULL ) { printk(KERN_NOTICE CARDNAME @@ -1478,18 +1377,12 @@ ! This should work without alignment, but it could be ! in the worse case */ -#ifndef SUPPORT_OLD_KERNEL - /* TODO: Should I use 32bit alignment here ? */ + skb_reserve( skb, 2 ); /* 16 bit alignment */ -#endif skb->dev = dev; -#ifdef SUPPORT_OLD_KERNEL - skb->len = packet_length; - data = skb->data; -#else data = skb_put( skb, packet_length); -#endif + #ifdef USE_32_BIT /* QUESTION: Like in the TX routine, do I want to send the DWORDs or the bytes first, or some @@ -1516,9 +1409,7 @@ print_packet( data, packet_length ); #endif -#ifndef SUPPORT_OLD_KERNEL skb->protocol = eth_type_trans(skb, dev ); -#endif netif_rx(skb); lp->stats.rx_packets++; } else { @@ -1616,17 +1507,12 @@ -----------------------------------------------------*/ static int smc_close(struct net_device *dev) { - dev->tbusy = 1; - dev->start = 0; - + netif_stop_queue(dev); /* clear everything */ smc_shutdown( dev->base_addr ); /* Update the statistics here. */ -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif - return 0; } @@ -1648,21 +1534,12 @@ . promiscuous mode ( for TCPDUMP and cousins ) or accept . a select set of multicast packets */ -#ifdef SUPPORT_OLD_KERNEL -static void smc_set_multicast_list( struct net_device * dev, - int num_addrs, void * addrs ) -#else static void smc_set_multicast_list(struct net_device *dev) -#endif { short ioaddr = dev->base_addr; SMC_SELECT_BANK(0); -#ifdef SUPPORT_OLD_KERNEL - if ( num_addrs < 0 ) -#else if ( dev->flags & IFF_PROMISC ) -#endif outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR ); /* BUG? I never disable promiscuous mode if multicasting was turned on. @@ -1674,27 +1551,12 @@ I don't need to zero the multicast table, because the flag is checked before the table is */ -#ifdef SUPPORT_OLD_KERNEL - else if ( num_addrs > 20 ) /* arbitrary constant */ -#else else if (dev->flags & IFF_ALLMULTI) -#endif outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR ); /* We just get all multicast packets even if we only want them . from one source. This will be changed at some future . point. */ -#ifdef SUPPORT_OLD_KERNEL - else if (num_addrs > 0 ) { -/* the old kernel support will not have hardware multicast support. It would - involve more kludges, and make the multicast setting code even worse. - Instead, just use the ALMUL method. This is reasonable, considering that - it is seldom used -*/ - outw( inw( ioaddr + RCR ) & ~RCR_PROMISC, ioaddr + RCR ); - outw( inw( ioadddr + RCR ) | RCR_ALMUL, ioadddr + RCR ); - } -#else else if (dev->mc_count ) { /* support hardware multicasting */ @@ -1705,7 +1567,6 @@ last thing called. The bank is set to zero at the top */ smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); } -#endif else { outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), ioaddr + RCR ); diff -u --recursive --new-file v2.3.44/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.3.44/linux/drivers/net/strip.c Tue Nov 23 22:42:21 1999 +++ linux/drivers/net/strip.c Sat Feb 12 15:45:05 2000 @@ -1036,9 +1036,7 @@ */ strip_info->idle_timer.expires = jiffies + 1*HZ; add_timer(&strip_info->idle_timer); - if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy)) - printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", - strip_info->dev.name); + netif_wake_queue(&strip_info->dev); } @@ -1355,7 +1353,8 @@ struct strip *strip_info = (struct strip *) tty->disc_data; /* First make sure we're connected. */ - if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start) + if (!strip_info || strip_info->magic != STRIP_MAGIC || + !test_bit(LINK_STATE_START, &strip_info->dev.state)) return; if (strip_info->tx_left > 0) @@ -1387,7 +1386,6 @@ { tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); strip_unlock(strip_info); - mark_bh(NET_BH); } } @@ -1646,12 +1644,14 @@ { struct strip *strip_info = (struct strip *)(dev->priv); - if (!dev->start) + if (!test_bit(LINK_STATE_START, &dev->state)) { printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); return(1); } - if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); + + netif_stop_queue(dev); + del_timer(&strip_info->idle_timer); /* See if someone has been ifconfigging */ @@ -1687,7 +1687,8 @@ strip_send(strip_info, skb); - if (skb) dev_kfree_skb(skb); + if (skb) + dev_kfree_skb(skb); return(0); } @@ -2336,7 +2337,8 @@ struct strip *strip_info = (struct strip *) tty->disc_data; const unsigned char *end = cp + count; - if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start) + if (!strip_info || strip_info->magic != STRIP_MAGIC + || !test_bit(LINK_STATE_START, &strip_info->dev.state)) return; /* Argh! mtu change time! - costs us the packet part received at the change */ @@ -2507,13 +2509,11 @@ if (in_dev->ifa_list->ifa_address == 0) in_dev->ifa_list->ifa_address = ntohl(0xC0A80001); #endif - dev->tbusy = 0; - dev->start = 1; - printk(KERN_INFO "%s: Initializing Radio.\n", strip_info->dev.name); ResetRadio(strip_info); strip_info->idle_timer.expires = jiffies + 1*HZ; add_timer(&strip_info->idle_timer); + netif_wake_queue(dev); return(0); } @@ -2529,9 +2529,9 @@ if (strip_info->tty == NULL) return -EBUSY; strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); + /* * Free all STRIP frame buffers. */ diff -u --recursive --new-file v2.3.44/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.3.44/linux/drivers/net/tulip.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/net/tulip.c Sun Feb 13 18:24:53 2000 @@ -102,12 +102,6 @@ #define IRQ(irq, dev_id, pt_regs) (irq, pt_regs) #endif -/* This my implementation of shared IRQs, now only used for 1.2.13. */ -#ifdef HAVE_SHARED_IRQ -#define USE_SHARED_IRQ -#include -#endif - /* The total size is unusually large: The 21040 aligns each of its 16 longword-wide registers on a quadword boundary. */ #define TULIP_TOTAL_SIZE 0x80 diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c --- v2.3.44/linux/drivers/net/wan/cycx_x25.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/wan/cycx_x25.c Sun Feb 13 18:20:21 2000 @@ -93,6 +93,9 @@ /* This is an extension of the 'struct net_device' we create for each network interface to keep the rest of X.25 channel-specific data. */ typedef struct x25_channel { + /* This member must be first. */ + struct net_device *slave; /* WAN slave */ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ char *local_addr; /* local media address, ASCIIZ - @@ -502,12 +505,10 @@ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) return -EBUSY; /* only one open is allowed */ - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; + netif_start_queue(dev); cyclomx_mod_inc_use_count(card); return 0; @@ -521,8 +522,8 @@ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; - dev->start = 0; - + netif_stop_queue(dev); + if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING) chan_disconnect(dev); @@ -556,7 +557,7 @@ } /* Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). + * o set busy flag (marks start of the transmission). * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. @@ -575,11 +576,6 @@ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; - if (dev->tbusy) { - ++chan->ifstats.rx_dropped; - return -EBUSY; - } - if (!chan->svc) chan->protocol = skb->protocol; @@ -595,14 +591,14 @@ switch (chan->state) { case WAN_DISCONNECTED: if (chan_connect(dev)) { - dev->tbusy = 1; + netif_stop_queue(dev); return -EBUSY; } /* fall thru */ case WAN_CONNECTED: reset_timer(dev); dev->trans_start = jiffies; - dev->tbusy = 1; + netif_stop_queue(dev); if (chan_send(dev, skb)) return -EBUSY; @@ -632,8 +628,8 @@ skb_pull(skb, 1); /* Remove control byte */ reset_timer(dev); dev->trans_start = jiffies; - dev->tbusy = 1; - + netif_stop_queue(dev); + if (chan_send(dev, skb)) { /* prepare for future retransmissions */ skb_push(skb, 1); @@ -705,9 +701,6 @@ cycx_poke(&card->hw, 0, &z, sizeof(z)); cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z)); card->in_isr = 0; - - if (card->buff_int_mode_unbusy) - mark_bh(NET_BH); } /* Transmit interrupt handler. @@ -724,7 +717,7 @@ /* unbusy device and then dev_tint(); */ if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) { card->buff_int_mode_unbusy = 1; - dev->tbusy = 0; + netif_wake_queue(dev); } else printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n", card->devname, lcn); @@ -1263,11 +1256,13 @@ static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn) { struct net_device *dev = wandev->dev; + x25_channel_t *chan; - for (; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) + while (dev) { + if (chan->lcn == lcn) break; - + dev = chan->slave; + } return dev; } @@ -1275,11 +1270,13 @@ static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte) { struct net_device *dev = wandev->dev; + x25_channel_t *chan; - for (; dev; dev = dev->slave) - if (!strcmp(((x25_channel_t*)dev->priv)->addr, dte)) + while (dev) { + if (!strcmp(chan->addr, dte)) break; - + dev = chan->slave; + } return dev; } @@ -1357,7 +1354,7 @@ case WAN_CONNECTED: string_state = "connected!"; *(u16*)dev->dev_addr = htons(chan->lcn); - dev->tbusy = 0; + netif_wake_queue(dev); reset_timer(dev); if (chan->protocol == ETH_P_X25) @@ -1384,7 +1381,7 @@ if (chan->protocol == ETH_P_X25) chan_x25_send_event(dev, 2); - dev->tbusy = 0; + netif_wake_queue(dev); break; } @@ -1560,15 +1557,16 @@ struct net_device *dev = wandev->dev; printk(KERN_INFO "X.25 dev states\n"); - printk(KERN_INFO "name: addr: tbusy: protocol:\n"); + printk(KERN_INFO "name: addr: txoff: protocol:\n"); printk(KERN_INFO "---------------------------------------\n"); - for (; dev; dev = dev->slave) { + while(dev) { x25_channel_t *chan = dev->priv; - printk(KERN_INFO "%-5.5s %-15.15s %ld ETH_P_%s\n", - chan->name, chan->addr, dev->tbusy, + printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n", + chan->name, chan->addr, test_bit(LINK_STATE_XOFF, &dev->state), chan->protocol == ETH_P_IP ? "IP" : "X25"); + dev = chan->slave; } } diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c --- v2.3.44/linux/drivers/net/wan/lapbether.c Mon Oct 11 15:38:15 1999 +++ linux/drivers/net/wan/lapbether.c Sat Feb 12 15:45:05 2000 @@ -163,7 +163,7 @@ dev = lapbeth_get_x25_dev(dev); - if (dev == NULL || dev->start == 0) { + if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) { kfree_skb(skb); return 0; } @@ -215,7 +215,7 @@ * Just to be *really* sure not to send anything if the interface * is down, the ethernet device may have gone. */ - if (!dev->start) { + if (!test_bit(LINK_STATE_START, &dev->state)) { lapbeth_check_devices(dev); kfree_skb(skb); return -ENODEV; @@ -360,9 +360,6 @@ if (lapbeth_check_devices(dev)) return -ENODEV; /* oops, it's gone */ - dev->tbusy = 0; - dev->start = 1; - lapbeth = (struct lapbethdev *)dev->priv; lapbeth_callbacks.connect_confirmation = lapbeth_connected; @@ -374,12 +371,11 @@ if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err); - dev->tbusy = 1; - dev->start = 0; return -ENODEV; } MOD_INC_USE_COUNT; + netif_start_queue(dev); return 0; } @@ -389,9 +385,8 @@ struct lapbethdev *lapbeth; int err; - dev->tbusy = 1; - dev->start = 0; - + netif_stop_queue(dev); + lapbeth = (struct lapbethdev *)dev->priv; if ((err = lapb_unregister(lapbeth)) != LAPB_OK) diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c --- v2.3.44/linux/drivers/net/wan/sbni.c Fri Oct 15 15:25:13 1999 +++ linux/drivers/net/wan/sbni.c Sat Feb 12 15:45:05 2000 @@ -59,11 +59,6 @@ #include -#if LINUX_VERSION_CODE >=0x020200 -#define v22 -#endif - - #include #include #include @@ -74,6 +69,7 @@ #include #include #include +#include #include #include @@ -88,12 +84,8 @@ #include - - -#ifdef v22 #include #include -#endif #include "sbni.h" @@ -523,6 +515,7 @@ dev->hard_header_cache = sbni_header_cache; dev->header_cache_update = sbni_header_cache_update; + spin_lock_init(&lp->lock); lp->m=dev; lp->me=dev; lp->next_lp=NULL; @@ -538,15 +531,15 @@ { struct net_local* lp = (struct net_local*)dev->priv; struct timer_list* watchdog = &lp->watchdog; - + unsigned long flags; DP( printk("%s: sbni_open\n", dev->name); ) + save_flags(flags); cli(); lp->currframe = NULL; card_start(dev); - dev->start = 1; /* set timer watchdog */ init_timer(watchdog); watchdog->expires = jiffies + SBNI_TIMEOUT; @@ -555,8 +548,9 @@ add_timer(watchdog); DP( printk("%s: sbni timer watchdog initialized\n", dev->name); ); - sti(); - + restore_flags(flags); + + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; } @@ -566,21 +560,18 @@ int ioaddr = dev->base_addr; struct net_local* lp = (struct net_local*) dev->priv; struct timer_list* watchdog = &lp->watchdog; - - + unsigned long flags; + DP( printk("%s: sbni_close\n", dev->name); ) + netif_stop_queue(dev); + + save_flags(flags); cli(); - sbni_drop_tx_queue(dev); - - dev->tbusy = 1; - dev->start = 0; - del_timer(watchdog); - outb(0, ioaddr + CSR0); - sti(); + restore_flags(flags); MOD_DEC_USE_COUNT; return 0; @@ -590,6 +581,7 @@ { struct net_local *lp = (struct net_local*)dev->priv; struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data; + unsigned long flags; #ifdef KATYUSHA struct net_local *nl; @@ -602,13 +594,6 @@ if(lp->me != dev) panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n"); - if(dev->interrupt) - { - DP( printk("sbni_xmit_start: interrupt\n"); ) - /* May be unloading, don't stamp on */ - return 1; /* the packet buffer this time */ - } - hh->number = 1; hh->reserv = 0; @@ -623,6 +608,7 @@ skb->len - sizeof(struct sbni_hard_header), hh->crc); + spin_lock_irqsave(&lp->lock, flags); #ifdef KATYUSHA /* looking for first idle device */ for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp) @@ -657,6 +643,7 @@ /* set request for transmit */ outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0); #endif + spin_unlock_irqrestore(&lp->lock, flags); return 0; } @@ -677,9 +664,6 @@ lp->waitack=0; skb_queue_head_init(&lp->queue); sbni_drop_tx_queue(dev); - dev->tbusy = 0; - - dev->interrupt = 0; /* Reset the card and set start parameters */ outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1); outb(EN_INT, dev->base_addr + CSR0); @@ -776,8 +760,7 @@ /* * reset output active flags */ - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); /*} if */ } case PACKET_RESEND: @@ -920,17 +903,12 @@ return; } - if(dev->interrupt) - { - printk("%s: Reentering the interrupt driver!\n", dev->name); - return; - } - dev->interrupt = 1; - csr0 = inb(dev->base_addr + CSR0); DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); ) lp=dev->priv; + + spin_lock(&lp->lock); if(!lp->carrier) lp->carrier=1; @@ -971,7 +949,7 @@ */ outb(csr0 | EN_INT, dev->base_addr + CSR0); - dev->interrupt = 0; + spin_unlock(&lp->lock); } static struct enet_statistics *sbni_get_stats(struct net_device *dev) @@ -1103,7 +1081,7 @@ } sti(); outb(csr0 | RC_CHK, dev->base_addr + CSR0); - if(dev->start) + if(test_bit(LINK_STATE_START, &dev->state)) { struct timer_list* watchdog = &lp->watchdog; init_timer(watchdog); @@ -1167,9 +1145,8 @@ } } lp->waitack=0; - dev->tbusy = 0; - - mark_bh(NET_BH); + netif_wake_queue(dev); + DP( printk("%s: queue dropping stoped\n",dev->name); ); } @@ -1194,7 +1171,7 @@ /* struct net_local *lp = (struct net_local *)dev->priv; */ struct sockaddr *saddr = addr; - if(dev->start) + if(test_bit(LINK_STATE_START, &dev->state)) { /* Only possible while card isn't started */ return -EBUSY; @@ -1400,13 +1377,11 @@ static int baud[SBNI_MAX_NUM_CARDS] = { 0 }; static long mac[SBNI_MAX_NUM_CARDS] = { 0 }; -#ifdef v22 MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i"); -#endif static int sbniautodetect = -1; diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sbni.h linux/drivers/net/wan/sbni.h --- v2.3.44/linux/drivers/net/wan/sbni.h Mon Oct 11 15:38:15 1999 +++ linux/drivers/net/wan/sbni.h Sat Feb 12 15:45:05 2000 @@ -146,7 +146,7 @@ int carrier; - + spinlock_t lock; }; diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c --- v2.3.44/linux/drivers/net/wan/sdla_chdlc.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/wan/sdla_chdlc.c Sun Feb 13 18:20:21 2000 @@ -74,6 +74,9 @@ typedef struct chdlc_private_area { + /* This member must be first. */ + struct net_device *slave; /* WAN slave */ + sdla_t *card; int TracingEnabled; /* For enabling Tracing */ unsigned long curr_trace_addr; /* Used for Tracing */ diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c --- v2.3.44/linux/drivers/net/wan/sdla_fr.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/wan/sdla_fr.c Sun Feb 13 18:20:21 2000 @@ -167,6 +167,9 @@ */ typedef struct fr_channel { + /* This member must be first. */ + struct net_device *slave; /* WAN slave */ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ unsigned dlci_configured ; /* check whether configured or not */ unsigned cir_status; /* check whether CIR enabled or not */ @@ -1960,7 +1963,9 @@ // Used to send inarp request at given interval if (card->wandev.state == WAN_CONNECTED) { int num_remaining = 0; - for (dev=card->wandev.dev;dev;dev=dev->slave) { + + dev = card->wandev.dev; + while (dev) { fr_channel_t *chan = dev->priv; if (chan->inarp == INARP_REQUEST && @@ -1972,6 +1977,7 @@ chan->inarp_tick = jiffies; } } + dev = chan->slave; } if (!num_remaining) { // no more to process flags->imask &= ~FR_INTR_TIMER; @@ -2135,65 +2141,68 @@ /* Dynamic Route adding/removing */ - for (dev = card->wandev.dev; dev ; dev = dev->slave) { - if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE || - ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) { - fs = get_fs(); + dev = card->wandev.dev; + while (dev) { + fr_channel_t *chan = dev->priv; + + if (chan->route_flag == ADD_ROUTE || + chan->route_flag == REMOVE_ROUTE ) { + fs = get_fs(); - in_dev = dev->ip_ptr; + in_dev = dev->ip_ptr; - if( in_dev != NULL && in_dev->ifa_list != NULL) { - memset(&route, 0, sizeof(route)); - route.rt_dev = dev->name; - route.rt_flags = 0; - - ((struct sockaddr_in *) &(route.rt_dst)) -> - sin_addr.s_addr=in_dev->ifa_list->ifa_address; - ((struct sockaddr_in *) &(route.rt_dst)) -> - sin_family = AF_INET; - ((struct sockaddr_in *) &(route.rt_genmask)) -> - sin_addr.s_addr = 0xFFFFFFFF; - ((struct sockaddr_in *) &(route.rt_genmask)) -> - sin_family = AF_INET; - - switch(((fr_channel_t*)dev->priv)->route_flag) { - - case ADD_ROUTE: - set_fs(get_ds()); /* get user space block */ - err = ip_rt_ioctl( SIOCADDRT, &route); - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); - printk(KERN_INFO "%s: Address: %s\n", - ((fr_channel_t*)dev->priv)->name, - in_ntoa(in_dev->ifa_list->ifa_address) ); - } - else { - ((fr_channel_t*)dev->priv)-> - route_flag = ROUTE_ADDED; - } - break; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=in_dev->ifa_list->ifa_address; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + + switch(chan->route_flag) { + + case ADD_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCADDRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + chan->name, + in_ntoa(in_dev->ifa_list->ifa_address) ); + } else { + chan->route_flag = ROUTE_ADDED; + } + break; - case REMOVE_ROUTE: - set_fs(get_ds()); /* get user space block */ - err = ip_rt_ioctl( SIOCDELRT, &route); - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); - printk(KERN_INFO "%s: Address: %s\n", - dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); - } else { - printk(KERN_INFO "%s: Removed route.\n", - ((fr_channel_t*)dev->priv)->name); - ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE; - } - break; - } /* Case Statement */ - } - } /* If ADD/DELETE ROUTE */ - } /* Device 'For' Loop */ + case REMOVE_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCDELRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); + } else { + printk(KERN_INFO "%s: Removed route.\n", + chan->name); + chan->route_flag = NO_ROUTE; + } + break; + } /* Case Statement */ + } + } /* If ADD/DELETE ROUTE */ + + dev = chan->slave; + } /* Device 'While' Loop */ card->poll = NULL; } @@ -2568,7 +2577,8 @@ struct net_device *dev; /* Remove all routes from associated DLCI's */ - for (dev = card->wandev.dev; dev; dev = dev->slave) { + dev = card->wandev.dev; + while (dev) { fr_channel_t *chan = dev->priv; if (chan->route_flag == ROUTE_ADDED) { chan->route_flag = REMOVE_ROUTE; @@ -2578,6 +2588,8 @@ if (chan->inarp == INARP_CONFIGURED) { chan->inarp = INARP_REQUEST; } + + dev = chan->slave; } wanpipe_set_state(card, WAN_DISCONNECTED); @@ -2590,12 +2602,14 @@ int num_requests = 0; /* Remove all routes from associated DLCI's */ - for (dev = card->wandev.dev; dev; dev = dev->slave) { + dev = card->wandev.dev; + while (dev) { fr_channel_t *chan = dev->priv; if( chan->inarp == INARP_REQUEST ){ num_requests++; chan->inarp_tick = jiffies; } + dev = chan->slave; } /* Allow timer interrupts */ @@ -2731,8 +2745,8 @@ } } - for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){ - + dev2 = card->wandev.dev; + while (dev2) { chan = dev2->priv; if (chan->dlci_configured == DLCI_CONFIG_PENDING) { @@ -2741,6 +2755,7 @@ } } + dev2 = chan->slave; } return 1; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c --- v2.3.44/linux/drivers/net/wan/sdla_ppp.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/wan/sdla_ppp.c Sun Feb 13 18:20:21 2000 @@ -155,6 +155,9 @@ typedef struct ppp_private_area { + /* This member must be first. */ + struct net_device *slave; /* WAN slave */ + sdla_t* card; unsigned long router_start_time; /*router start time in sec */ unsigned long tick_counter; /*used for 5 second counter*/ diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c --- v2.3.44/linux/drivers/net/wan/sdla_x25.c Mon Oct 11 15:38:15 1999 +++ linux/drivers/net/wan/sdla_x25.c Sun Feb 13 18:20:21 2000 @@ -75,6 +75,9 @@ */ typedef struct x25_channel { + /* This member must be first. */ + struct net_device *slave; /* WAN slave */ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ unsigned lcn; /* logical channel number */ @@ -708,11 +711,13 @@ return dev->tbusy; } printk(KERN_INFO "%s: Transmit time out %s!\n", - card->devname, dev->name) - ; - for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { + card->devname, dev->name); + + dev2 = card->wandev.dev; + while (dev2) { + x25_channel_t *chan2 = dev2->priv; dev2->tbusy = 0; + dev2 = chan2->slave; } } chan->tick_counter = jiffies; @@ -898,13 +903,17 @@ if(card->buff_int_mode_unbusy) { - for(dev = card->wandev.dev; dev; dev = dev->slave) - { - if(((x25_channel_t*)dev->priv)->devtint) - { + x25_channel_t *chan; + + dev = card->wandev.dev; + while (dev) { + chan = dev->priv; + if(chan->devtint) { mark_bh(NET_BH); return; } + + dev = chan->slave; } } } @@ -1042,12 +1051,15 @@ static void tx_intr (sdla_t* card) { struct net_device *dev; + x25_channel_t *chan; /* unbusy all devices and then dev_tint(); */ - for(dev = card->wandev.dev; dev; dev = dev->slave) - { - ((x25_channel_t*)dev->priv)->devtint = dev->tbusy; + dev = card->wandev.dev; + while (dev) { + chan->devtint = dev->tbusy; dev->tbusy = 0; + + dev = chan->slave; } } @@ -1170,8 +1182,8 @@ /* Fetch X.25 asynchronous events */ x25_fetch_events(card); - for (dev = card->wandev.dev; dev; dev = dev->slave) - { + dev = card->wandev.dev; + while (dev) { x25_channel_t* chan = dev->priv; struct sk_buff* skb = chan->tx_skb; @@ -1199,6 +1211,8 @@ chan_disc(dev); } } + + dev = chan->slave; } } @@ -1785,8 +1799,8 @@ card->devname, new_lcn, mb->data); /* Find available channel */ - for (dev = wandev->dev; dev; dev = dev->slave) - { + dev = wandev->dev; + while (dev) { chan = dev->priv; if (!chan->svc || (chan->state != WAN_DISCONNECTED)) @@ -1796,6 +1810,8 @@ /* If just an '@' is specified, accept all incoming calls */ if (strcmp(chan->addr, "") == 0) break; + + dev = chan->slave; } if (dev == NULL) @@ -1912,8 +1928,14 @@ card->devname, mb->cmd.cause, mb->cmd.diagn); /* down all logical channels */ - for (dev = wandev->dev; dev; dev = dev->slave) + dev = wandev->dev; + while (dev) { + x25_channel_t *chan = dev->priv; + set_chan_state(dev, WAN_DISCONNECTED); + dev = chan->slave; + } + return (cmd == X25_WRITE) ? 0 : 1; } @@ -1979,10 +2001,14 @@ static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn) { struct net_device* dev; + x25_channel_t *chan; - for (dev = wandev->dev; dev; dev = dev->slave) - if (((x25_channel_t*)dev->priv)->lcn == lcn) + dev = wandev->dev; + while (dev) { + if (chan->lcn == lcn) break; + dev = chan->slave; + } return dev; } diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c --- v2.3.44/linux/drivers/net/wan/x25_asy.c Thu Nov 11 20:11:42 1999 +++ linux/drivers/net/wan/x25_asy.c Sat Feb 12 15:45:05 2000 @@ -205,8 +205,7 @@ static inline void x25_asy_lock(struct x25_asy *sl) { - if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) - printk("%s: trying to lock already locked device!\n", sl->dev->name); + netif_stop_queue(sl->dev); } @@ -214,8 +213,7 @@ static inline void x25_asy_unlock(struct x25_asy *sl) { - if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) - printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); + netif_wake_queue(sl->dev); } /* Send one completely decapsulated IP datagram to the IP layer. */ @@ -303,7 +301,7 @@ struct x25_asy *sl = (struct x25_asy *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start) + if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) return; if (sl->xleft <= 0) @@ -313,7 +311,6 @@ sl->tx_packets++; tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); x25_asy_unlock(sl); - mark_bh(NET_BH); return; } @@ -322,6 +319,20 @@ sl->xhead += actual; } +static void x25_asy_timeout(struct net_device *dev) +{ + struct x25_asy *sl = (struct x25_asy*)(dev->priv); + /* May be we must check transmitter timeout here ? + * 14 Oct 1994 Dmitry Gorodchanin. + */ + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? + "bad line quality" : "driver error"); + sl->xleft = 0; + sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + x25_asy_unlock(sl); +} + /* Encapsulate an IP datagram and kick it into a TTY queue. */ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) @@ -329,7 +340,7 @@ struct x25_asy *sl = (struct x25_asy*)(dev->priv); int err; - if (!dev->start) + if (!test_bit(LINK_STATE_START, &sl->dev->state)) { printk("%s: xmit call when iface is down\n", dev->name); return 1; @@ -361,25 +372,6 @@ * So, no queues ! * 14 Oct 1994 Dmitry Gorodchanin. */ - if (dev->tbusy) { - /* May be we must check transmitter timeout here ? - * 14 Oct 1994 Dmitry Gorodchanin. - */ -#ifdef SL_CHECK_TRANSMIT - if (jiffies - dev->trans_start < 20 * HZ) { - /* 20 sec timeout not reached */ - return 1; - } - printk("%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? - "bad line quality" : "driver error"); - sl->xleft = 0; - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - x25_asy_unlock(sl); -#else - return 1; -#endif - } if((err=lapb_data_request(sl,skb))!=LAPB_OK) { @@ -414,7 +406,7 @@ static void x25_asy_data_transmit(void *token, struct sk_buff *skb) { struct x25_asy *sl=token; - if(sl->dev->tbusy) + if(test_bit(LINK_STATE_XOFF, &sl->dev->state)) { printk(KERN_ERR "x25_asy: tbusy drop\n"); kfree_skb(skb); @@ -514,10 +506,8 @@ sl->xleft = 0; sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ - dev->tbusy = 0; -/* dev->flags |= IFF_UP; */ - dev->start = 1; - + netif_start_queue(dev); + /* * Now attach LAPB */ @@ -551,12 +541,9 @@ return -EBUSY; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); if((err=lapb_unregister(sl))!=LAPB_OK) printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err); - -/* dev->flags &= ~IFF_UP; */ return 0; } @@ -576,7 +563,7 @@ { struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start) + if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) return; /* @@ -876,6 +863,8 @@ dev->mtu = SL_MTU; dev->hard_start_xmit = x25_asy_xmit; + dev->tx_timeout = x25_asy_timeout; + dev->watchdog_timeo = HZ*20; dev->open = x25_asy_open_dev; dev->stop = x25_asy_close; dev->get_stats = x25_asy_get_stats; @@ -914,7 +903,7 @@ * VSV = if dev->start==0, then device * unregistered while close proc. */ - if (x25_asy_ctrls[i]->dev.start) + if (test_bit(LINK_STATE_START, &x25_asy_ctrls[i]->dev.state)) unregister_netdev(&(x25_asy_ctrls[i]->dev)); kfree(x25_asy_ctrls[i]); diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c --- v2.3.44/linux/drivers/net/wan/z85230.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/net/wan/z85230.c Sat Feb 12 15:45:05 2000 @@ -54,12 +54,23 @@ static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; -/* +/** + * z8530_read_port: + * @p: port to read + * * Provided port access methods. The Comtrol SV11 requires no delays * between accesses and uses PC I/O. Some drivers may need a 5uS delay + * + * In the longer term this should become an architecture specific + * section so that this can become a generic driver interface for all + * platforms. For now we only handle PC I/O ports with or without the + * dread 5uS sanity delay. + * + * The caller must hold sufficient locks to avoid violating the horrible + * 5uS delay rule. */ -extern __inline__ int z8530_read_port(int p) +extern __inline__ int z8530_read_port(unsigned long p) { u8 r=inb(Z8530_PORT_OF(p)); if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */ @@ -67,7 +78,23 @@ return r; } -extern __inline__ void z8530_write_port(int p, u8 d) +/** + * z8530_write_port: + * @p: port to write + * @d: value to write + * + * Write a value to a port with delays if need be. Note that the + * caller must hold locks to avoid read/writes from other contexts + * violating the 5uS rule + * + * In the longer term this should become an architecture specific + * section so that this can become a generic driver interface for all + * platforms. For now we only handle PC I/O ports with or without the + * dread 5uS sanity delay. + */ + + +extern __inline__ void z8530_write_port(unsigned long p, u8 d) { outb(d,Z8530_PORT_OF(p)); if(p&Z8530_PORT_SLEEP) @@ -80,8 +107,16 @@ static void z8530_tx_done(struct z8530_channel *c); -/* - * Port accesses +/** + * read_zsreg: + * @c: Z8530 channel to read from (2 per chip) + * @reg: Register to read + * FIXME: Use a spinlock. + * + * Most of the Z8530 registers are indexed off the control registers. + * A read is done by writing to the control register and reading the + * register back. We do the locking needed to protect this + * operation. */ extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg) @@ -97,6 +132,14 @@ return r; } +/** + * read_zsdata: + * @c: The Z8530 channel to read the data port from + * + * The data port provides fast access to some things. We still + * have all the 5uS delays to worry about. + */ + extern inline u8 read_zsdata(struct z8530_channel *c) { u8 r; @@ -104,6 +147,17 @@ return r; } +/** + * write_zsreg: + * @c: The Z8530 channel + * @reg: Register number + * @val: Value to write + * + * Write a value to an indexed register. Perform the locking needed + * to honour the irritating delay rules. We know about register 0 + * being fast to access. + */ + extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) { unsigned long flags; @@ -194,8 +248,16 @@ EXPORT_SYMBOL(z8530_hdlc_kilostream_85230); -/* - * Flush the FIFO +/** + * z8530_flush_fifo: + * @c: Channel to flush + * + * Flush the receive FIFO. There is no specific option for this, we + * blindly read bytes and discard them. Reading when there is no data + * is harmless. The 8530 has a 4 byte FIFO, the 85230 has 8 bytes. + * + * All locking is handled for the caller. On return data may still be + * present if it arrived during the flush. */ static void z8530_flush_fifo(struct z8530_channel *c) @@ -213,7 +275,16 @@ } } -/* Sets or clears DTR/RTS on the requested line */ +/** + * z8530_rtsdtr: + * @c: The Z8530 channel to contro; + * @set: 1 to set, 0 to clear + * + * Sets or clears DTR/RTS on the requested line. All locking is handled + * for the caller. For now we assume all boards use the actual RTS/DTR + * on the chip. Apparently one or two don't. We'll scream about them + * later. + */ static void z8530_rtsdtr(struct z8530_channel *c, int set) { @@ -224,9 +295,12 @@ write_zsreg(c, R5, c->regs[5]); } -/* - * Receive handler. This is much like the async one but not quite the - * same or as complex +/** + * z8530_rx: + * @c: Z8530 channel to process + * + * Receive handler for receiving in PIO mode. This is much like the + * async one but not quite the same or as complex * * Note: Its intended that this handler can easily be separated from * the main code to run realtime. That'll be needed for some machines @@ -238,9 +312,9 @@ * other code - this is true in the RT case too. * * We only cover the sync cases for this. If you want 2Mbit async - * do it yourself but consider medical assistance first. - * - * This non DMA synchronous mode is portable code. + * do it yourself but consider medical assistance first. This non DMA + * synchronous mode is portable code. The DMA mode assumes PCI like + * ISA DMA */ static void z8530_rx(struct z8530_channel *c) @@ -303,8 +377,14 @@ } -/* - * Z8530 transmit interrupt handler +/** + * z8530_tx: + * @c: Z8530 channel to process + * + * Z8530 transmit interrupt handler for the PIO mode. The basic + * idea is to attempt to keep the FIFO fed. We fill as many bytes + * in as possible, its quite possible that we won't keep up with the + * data rate otherwise. */ static void z8530_tx(struct z8530_channel *c) @@ -340,6 +420,17 @@ write_zsctrl(c, RES_H_IUS); } +/** + * z8530_status: + * @chan: Z8530 channel to process + * + * A status event occured in PIO synchronous mode. There are several + * reasons the chip will bother us here. A transmit underrun means we + * failed to feed the chip fast enough and just broke a packet. A DCD + * change is a line up or down. We communicate that back to the protocol + * layer for synchronous PPP to renegotiate. + */ + static void z8530_status(struct z8530_channel *chan) { u8 status=read_zsreg(chan, R0); @@ -387,9 +478,14 @@ EXPORT_SYMBOL(z8530_sync); -/* +/** + * z8530_dma_rx: + * @chan: Channel to handle + * * Non bus mastering DMA interfaces for the Z8x30 devices. This - * is really pretty PC specific. + * is really pretty PC specific. The DMA mode means that most receive + * events are handled by the DMA hardware. We get a kick here only if + * a frame ended. */ static void z8530_dma_rx(struct z8530_channel *chan) @@ -417,6 +513,14 @@ } } +/** + * z8530_dma_tx: + * @chan: The Z8530 channel to handle + * + * We have received an interrupt while doing DMA transmissions. It + * shouldn't happen. Scream loudly if it does. + */ + static void z8530_dma_tx(struct z8530_channel *chan) { if(!chan->dma_tx) @@ -430,6 +534,17 @@ z8530_tx(chan); } +/** + * z8530_dma_status: + * @chan: Z8530 channel to process + * + * A status event occured on the Z8530. We receive these for two reasons + * when in DMA mode. Firstly if we finished a packet transfer we get one + * and kick the next packet out. Secondly we may see a DCD change and + * have to poke the protocol layer. + * + */ + static void z8530_dma_status(struct z8530_channel *chan) { unsigned long flags; @@ -490,8 +605,11 @@ EXPORT_SYMBOL(z8530_txdma_sync); -/* - * Interrupt vectors for a Z8530 that is in 'parked' mode. +/** + * z8530_rx_clear: + * @c: Z8530 channel to shut up + * + * Receive interrupt vectors for a Z8530 that is in 'parked' mode. * For machines with PCI Z85x30 cards, or level triggered interrupts * (eg the MacII) we must clear the interrupt cause or die. */ @@ -516,12 +634,30 @@ write_zsctrl(c, RES_H_IUS); } +/** + * z8530_tx_clear: + * @c: Z8530 channel to shut up + * + * Transmit interrupt vectors for a Z8530 that is in 'parked' mode. + * For machines with PCI Z85x30 cards, or level triggered interrupts + * (eg the MacII) we must clear the interrupt cause or die. + */ + static void z8530_tx_clear(struct z8530_channel *c) { write_zsctrl(c, RES_Tx_P); write_zsctrl(c, RES_H_IUS); } +/** + * z8530_status_clear: + * @chan: Z8530 channel to shut up + * + * Status interrupt vectors for a Z8530 that is in 'parked' mode. + * For machines with PCI Z85x30 cards, or level triggered interrupts + * (eg the MacII) we must clear the interrupt cause or die. + */ + static void z8530_status_clear(struct z8530_channel *chan) { u8 status=read_zsreg(chan, R0); @@ -541,8 +677,17 @@ EXPORT_SYMBOL(z8530_nop); -/* - * A Z85[2]30 device has stuck its hand in the air for attention +/** + * z8530_interrupt: + * @irq: Interrupt number + * @dev_id: The Z8530 device that is interrupting. + * @regs: unused + * + * A Z85[2]30 device has stuck its hand in the air for attention. + * We scan both the channels on the chip for events and then call + * the channel specific call backs for each channel that has events. + * We have to use callback functions because the two channels can be + * in different modes. */ void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -612,6 +757,15 @@ }; +/** + * z8530_sync_open: + * @dev: The network interface we are using + * @c: The Z8530 channel to open in synchronous PIO mode + * + * Switch a Z8530 into synchronous mode without DMA assist. We + * raise the RTS/DTR and commence network operation. + */ + int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) { c->sync = 1; @@ -634,6 +788,15 @@ EXPORT_SYMBOL(z8530_sync_open); +/** + * z8530_sync_close: + * @dev: Network device to close + * @c: Z8530 channel to disassociate and move to idle + * + * Close down a Z8530 interface and switch its interrupt handlers + * to discard future events. + */ + int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) { u8 chk; @@ -650,6 +813,16 @@ EXPORT_SYMBOL(z8530_sync_close); +/** + * z8530_sync_dma_open: + * @dev: The network device to attach + * @c: The Z8530 channel to configure in sync DMA mode. + * + * Set up a Z85x30 device for synchronous DMA in both directions. Two + * ISA DMA channels must be available for this to work. We assume ISA + * DMA driven I/O and PC limits on access. + */ + int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c) { unsigned long flags; @@ -760,6 +933,15 @@ EXPORT_SYMBOL(z8530_sync_dma_open); +/** + * z8530_sync_dma_close: + * @dev: Network device to detach + * @c: Z8530 channel to move into discard mode + * + * Shut down a DMA mode synchronous interface. Halt the DMA, and + * free the buffers. + */ + int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c) { u8 chk; @@ -816,6 +998,16 @@ EXPORT_SYMBOL(z8530_sync_dma_close); +/** + * z8530_sync_txdma_open: + * @dev: The network device to attach + * @c: The Z8530 channel to configure in sync DMA mode. + * + * Set up a Z85x30 device for synchronous DMA tranmission. One + * ISA DMA channel must be available for this to work. The receive + * side is run in PIO mode, but then it has the bigger FIFO. + */ + int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c) { unsigned long flags; @@ -905,7 +1097,16 @@ } EXPORT_SYMBOL(z8530_sync_txdma_open); - + +/** + * z8530_sync_txdma_close: + * @dev: Network device to detach + * @c: Z8530 channel to move into discard mode + * + * Shut down a DMA/PIO split mode synchronous interface. Halt the DMA, + * and free the buffers. + */ + int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c) { unsigned long flags; @@ -954,21 +1155,32 @@ EXPORT_SYMBOL(z8530_sync_txdma_close); + /* - * Describe a Z8530 in a standard format. We must pass the I/O as - * the port offset isnt predictable. The main reason for this function - * is to try and get a common format of report. + * Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny + * it exists... */ - + static char *z8530_type_name[]={ "Z8530", "Z85C30", "Z85230" }; -void z8530_describe(struct z8530_dev *dev, char *mapping, int io) +/** + * z8530_describe: + * @dev: Z8530 device to describe + * @mapping: string holding mapping type (eg "I/O" or "Mem") + * @io: the port value in question + * + * Describe a Z8530 in a standard format. We must pass the I/O as + * the port offset isnt predictable. The main reason for this function + * is to try and get a common format of report. + */ + +void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io) { - printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n", + printk(KERN_INFO "%s: %s found at %s 0x%lX, IRQ %d.\n", dev->name, z8530_type_name[dev->type], mapping, @@ -978,8 +1190,21 @@ EXPORT_SYMBOL(z8530_describe); -/* - * Configure up a Z8530 +/** + * z8530_init: + * @dev: Z8530 device to initialise. + * + * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device + * is present, identify the type and then program it to hopefully + * keep quite and behave. This matters a lot, a Z8530 in the wrong + * state will sometimes get into stupid modes generating 10Khz + * interrupt streams and the like. + * + * We set the interrupt handler up to discard any events, in case + * we get them during reset or setp. + * + * Return 0 for success, or a negative value indicating the problem + * in errno form. */ @@ -1047,6 +1272,15 @@ EXPORT_SYMBOL(z8530_init); +/** + * z8530_shutdown: + * @dev: The Z8530 chip to shutdown + * + * We set the interrupt handlers to silence any interrupts. We then + * reset the chip and wait 100uS to be sure the reset completed. Just + * in case the caller then tries to do stuff. + */ + int z8530_shutdown(struct z8530_dev *dev) { /* Reset the chip */ @@ -1059,9 +1293,15 @@ EXPORT_SYMBOL(z8530_shutdown); -/* - * Load a Z8530 channel up from the system data - * We use +16 to indicate the 'prime' registers +/** + * z8530_channel_load: + * @c: Z8530 channel to configure + * @rtable: Table of register, value pairs + * FIXME: ioctl to allow user uploaded tables + * + * Load a Z8530 channel up from the system data> We use +16 to + * indicate the 'prime' registers. The value 255 terminates the + * table */ int z8530_channel_load(struct z8530_channel *c, u8 *rtable) @@ -1092,8 +1332,16 @@ EXPORT_SYMBOL(z8530_channel_load); -/* - * Higher level shovelling - transmit chains +/** + * z8530_tx_begin: + * @c: The Z8530 channel to kick + * + * This is the speed sensitive side of transmission. If we are called + * and no buffer is being transmitted we commence the next buffer. If + * nothing is queued we idle the sync. + * + * Note: We are handling this code path in the interrupt path, keep it + * fast or bad things will happen. */ static void z8530_tx_begin(struct z8530_channel *c) @@ -1180,7 +1428,15 @@ } } } - + +/** + * z8530_tx_done: + * @c: The channel that completed a transmit. + * + * This is called when we complete a packet send. We wake the queue, + * start the next packet going and then free the buffer of the existing + * packet. This code is fairly timing sensitive. + */ static void z8530_tx_done(struct z8530_channel *c) { @@ -1201,11 +1457,16 @@ spin_unlock_irqrestore(&z8530_buffer_lock, flags); c->stats.tx_packets++; c->stats.tx_bytes+=skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); } -/* - * Higher level shovelling - receive chains +/** + * z8530_null_rx: + * @c: The channel the packet arrived on + * @skb: The buffer + * + * We point the receive handler at this function when idle. Instead + * of syncppp processing the frames we get to throw them away. */ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) @@ -1215,6 +1476,17 @@ EXPORT_SYMBOL(z8530_null_rx); +/** + * z8530_rx_done: + * @c: The channel that completed a receive + * + * A new packet is complete. Our goal here is to get back into receive + * mode as fast as possible. On the Z85230 we could change to using + * ESCC mode, but on the older chips we have no choice. We flip to the + * new buffer immediately in DMA mode so that the DMA of the next + * frame can occur while we are copying the previous buffer to an sk_buff + */ + static void z8530_rx_done(struct z8530_channel *c) { struct sk_buff *skb; @@ -1269,7 +1541,7 @@ else /* Can't occur as we dont reenable the DMA irq until after the flip is done */ - printk("DMA flip overrun!\n"); + printk(KERN_WARNING "%s: DMA flip overrun!\n", c->netdevice->name); release_dma_lock(flags); @@ -1357,8 +1629,12 @@ } } -/* - * Cannot DMA over a 64K boundary on a PC +/** + * spans_boundary: + * @skb: The buffer to check + * + * Returns true if the buffer cross a DMA boundary on a PC. The poor + * thing can only DMA within a 64K block not across the edges of it. */ extern inline int spans_boundary(struct sk_buff *skb) @@ -1373,7 +1649,11 @@ return 0; } -/* +/** + * z8530_queue_xmit: + * @c: The channel to use + * @skb: The packet to kick down the channel + * * Queue a packet for transmission. Because we have rather * hard to hit interrupt latencies for the Z85230 per packet * even in DMA mode we do the flip to DMA buffer if needed here @@ -1426,6 +1706,14 @@ EXPORT_SYMBOL(z8530_queue_xmit); +/** + * z8530_get_stats: + * @c: The channel to use + * + * Get the statistics block. We keep the statistics in software as + * the chip doesn't do it for us. + */ + struct net_device_stats *z8530_get_stats(struct z8530_channel *c) { return &c->stats; diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/z85230.h linux/drivers/net/wan/z85230.h --- v2.3.44/linux/drivers/net/wan/z85230.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/wan/z85230.h Sat Feb 12 15:45:05 2000 @@ -304,8 +304,8 @@ */ struct z8530_dev *dev; /* Z85230 chip instance we are from */ - int ctrlio; /* I/O ports */ - int dataio; + unsigned long ctrlio; /* I/O ports */ + unsigned long dataio; /* * For PC we encode this way. @@ -395,7 +395,7 @@ extern u8 z8530_hdlc_kilostream_85230[]; extern u8 z8530_hdlc_kilostream[]; extern void z8530_interrupt(int, void *, struct pt_regs *); -extern void z8530_describe(struct z8530_dev *, char *mapping,int io); +extern void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io); extern int z8530_init(struct z8530_dev *); extern int z8530_shutdown(struct z8530_dev *); extern int z8530_sync_open(struct net_device *, struct z8530_channel *); diff -u --recursive --new-file v2.3.44/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.3.44/linux/drivers/net/wavelan.c Tue Dec 7 09:32:44 1999 +++ linux/drivers/net/wavelan.c Sat Feb 12 15:45:05 2000 @@ -6,9 +6,9 @@ * Reorganisation and extension of the driver. * Original copyright follows (also see the end of this file). * See wavelan.p.h for details. - */ - -/* + * + * + * * AT&T GIS (nee NCR) WaveLAN card: * An Ethernet-like radio transceiver * controlled by an Intel 82586 coprocessor. @@ -26,54 +26,49 @@ /* * Wrapper for disabling interrupts. */ -static inline unsigned long -wv_splhi(void) -{ - unsigned long flags; - - save_flags(flags); - cli(); - return(flags); +static inline unsigned long wv_splhi(void) +{ + unsigned long flags; + save_flags(flags); + cli(); + return (flags); } /*------------------------------------------------------------------*/ /* * Wrapper for re-enabling interrupts. */ -static inline void -wv_splx(unsigned long flags) +static inline void wv_splx(unsigned long flags) { - restore_flags(flags); + restore_flags(flags); } /*------------------------------------------------------------------*/ /* * Translate irq number to PSA irq parameter */ -static u_char -wv_irq_to_psa(int irq) +static u8 wv_irq_to_psa(int irq) { - if(irq < 0 || irq >= NELS(irqvals)) - return 0; + if (irq < 0 || irq >= NELS(irqvals)) + return 0; - return irqvals[irq]; + return irqvals[irq]; } /*------------------------------------------------------------------*/ /* * Translate PSA irq parameter to irq number */ -static int __init -wv_psa_to_irq(u_char irqval) +static int __init wv_psa_to_irq(u8 irqval) { - int irq; + int irq; - for(irq = 0; irq < NELS(irqvals); irq++) - if(irqvals[irq] == irqval) - return irq; + for (irq = 0; irq < NELS(irqvals); irq++) + if (irqvals[irq] == irqval) + return irq; - return -1; + return -1; } #ifdef STRUCT_CHECK @@ -82,21 +77,20 @@ * Sanity routine to verify the sizes of the various WaveLAN interface * structures. */ -static char * -wv_struct_check(void) +static char *wv_struct_check(void) { #define SC(t,s,n) if (sizeof(t) != s) return(n); - SC(psa_t, PSA_SIZE, "psa_t"); - SC(mmw_t, MMW_SIZE, "mmw_t"); - SC(mmr_t, MMR_SIZE, "mmr_t"); - SC(ha_t, HA_SIZE, "ha_t"); + SC(psa_t, PSA_SIZE, "psa_t"); + SC(mmw_t, MMW_SIZE, "mmw_t"); + SC(mmr_t, MMR_SIZE, "mmr_t"); + SC(ha_t, HA_SIZE, "ha_t"); #undef SC - return((char *) NULL); -} /* wv_struct_check */ -#endif /* STRUCT_CHECK */ + return ((char *) NULL); +} /* wv_struct_check */ +#endif /* STRUCT_CHECK */ /********************* HOST ADAPTER SUBROUTINES *********************/ /* @@ -111,120 +105,106 @@ /* * Read from card's Host Adaptor Status Register. */ -static inline u_short -hasr_read(u_long ioaddr) +static inline u16 hasr_read(unsigned long ioaddr) { - return(inw(HASR(ioaddr))); -} /* hasr_read */ + return (inw(HASR(ioaddr))); +} /* hasr_read */ /*------------------------------------------------------------------*/ /* * Write to card's Host Adapter Command Register. */ -static inline void -hacr_write(u_long ioaddr, - u_short hacr) +static inline void hacr_write(unsigned long ioaddr, u16 hacr) { - outw(hacr, HACR(ioaddr)); -} /* hacr_write */ + outw(hacr, HACR(ioaddr)); +} /* hacr_write */ /*------------------------------------------------------------------*/ /* * Write to card's Host Adapter Command Register. Include a delay for * those times when it is needed. */ -static inline void -hacr_write_slow(u_long ioaddr, - u_short hacr) +static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr) { - hacr_write(ioaddr, hacr); - /* delay might only be needed sometimes */ - mdelay(1); -} /* hacr_write_slow */ + hacr_write(ioaddr, hacr); + /* delay might only be needed sometimes */ + mdelay(1); +} /* hacr_write_slow */ /*------------------------------------------------------------------*/ /* * Set the channel attention bit. */ -static inline void -set_chan_attn(u_long ioaddr, - u_short hacr) +static inline void set_chan_attn(unsigned long ioaddr, u16 hacr) { - hacr_write(ioaddr, hacr | HACR_CA); -} /* set_chan_attn */ + hacr_write(ioaddr, hacr | HACR_CA); +} /* set_chan_attn */ /*------------------------------------------------------------------*/ /* * Reset, and then set host adaptor into default mode. */ -static inline void -wv_hacr_reset(u_long ioaddr) +static inline void wv_hacr_reset(unsigned long ioaddr) { - hacr_write_slow(ioaddr, HACR_RESET); - hacr_write(ioaddr, HACR_DEFAULT); -} /* wv_hacr_reset */ + hacr_write_slow(ioaddr, HACR_RESET); + hacr_write(ioaddr, HACR_DEFAULT); +} /* wv_hacr_reset */ /*------------------------------------------------------------------*/ /* * Set the I/O transfer over the ISA bus to 8-bit mode */ -static inline void -wv_16_off(u_long ioaddr, - u_short hacr) +static inline void wv_16_off(unsigned long ioaddr, u16 hacr) { - hacr &= ~HACR_16BITS; - hacr_write(ioaddr, hacr); -} /* wv_16_off */ + hacr &= ~HACR_16BITS; + hacr_write(ioaddr, hacr); +} /* wv_16_off */ /*------------------------------------------------------------------*/ /* * Set the I/O transfer over the ISA bus to 8-bit mode */ -static inline void -wv_16_on(u_long ioaddr, - u_short hacr) +static inline void wv_16_on(unsigned long ioaddr, u16 hacr) { - hacr |= HACR_16BITS; - hacr_write(ioaddr, hacr); -} /* wv_16_on */ + hacr |= HACR_16BITS; + hacr_write(ioaddr, hacr); +} /* wv_16_on */ /*------------------------------------------------------------------*/ /* * Disable interrupts on the WaveLAN hardware. */ -static inline void -wv_ints_off(device * dev) +static inline void wv_ints_off(device * dev) { - net_local * lp = (net_local *)dev->priv; - u_long ioaddr = dev->base_addr; - u_long x; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + unsigned long flags; + + save_flags(flags); + cli(); + + lp->hacr &= ~HACR_INTRON; + hacr_write(ioaddr, lp->hacr); - x = wv_splhi(); - - lp->hacr &= ~HACR_INTRON; - hacr_write(ioaddr, lp->hacr); - - wv_splx(x); -} /* wv_ints_off */ + restore_flags(flags); +} /* wv_ints_off */ /*------------------------------------------------------------------*/ /* * Enable interrupts on the WaveLAN hardware. */ -static inline void -wv_ints_on(device * dev) +static inline void wv_ints_on(device * dev) { - net_local * lp = (net_local *)dev->priv; - u_long ioaddr = dev->base_addr; - u_long x; - - x = wv_splhi(); - - lp->hacr |= HACR_INTRON; - hacr_write(ioaddr, lp->hacr); - - wv_splx(x); -} /* wv_ints_on */ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + unsigned long flags; + + save_flags(flags); + cli(); + lp->hacr |= HACR_INTRON; + hacr_write(ioaddr, lp->hacr); + restore_flags(flags); +} /* wv_ints_on */ /******************* MODEM MANAGEMENT SUBROUTINES *******************/ /* @@ -238,57 +218,48 @@ /* * Read bytes from the PSA. */ -static void -psa_read(u_long ioaddr, - u_short hacr, - int o, /* offset in PSA */ - u_char * b, /* buffer to fill */ - int n) /* size to read */ -{ - wv_16_off(ioaddr, hacr); - - while(n-- > 0) - { - outw(o, PIOR2(ioaddr)); - o++; - *b++ = inb(PIOP2(ioaddr)); - } +static void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ + u8 * b, /* buffer to fill */ + int n) +{ /* size to read */ + wv_16_off(ioaddr, hacr); + + while (n-- > 0) { + outw(o, PIOR2(ioaddr)); + o++; + *b++ = inb(PIOP2(ioaddr)); + } - wv_16_on(ioaddr, hacr); -} /* psa_read */ + wv_16_on(ioaddr, hacr); +} /* psa_read */ /*------------------------------------------------------------------*/ /* * Write the Parameter Storage Area to the WaveLAN card's memory. */ -static void -psa_write(u_long ioaddr, - u_short hacr, - int o, /* Offset in PSA */ - u_char * b, /* Buffer in memory */ - int n) /* Length of buffer */ -{ - int count = 0; - - wv_16_off(ioaddr, hacr); - - while(n-- > 0) - { - outw(o, PIOR2(ioaddr)); - o++; - - outb(*b, PIOP2(ioaddr)); - b++; - - /* Wait for the memory to finish its write cycle */ - count = 0; - while((count++ < 100) && - (hasr_read(ioaddr) & HASR_PSA_BUSY)) - mdelay(1); - } +static void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ + u8 * b, /* Buffer in memory */ + int n) +{ /* Length of buffer */ + int count = 0; + + wv_16_off(ioaddr, hacr); + + while (n-- > 0) { + outw(o, PIOR2(ioaddr)); + o++; + + outb(*b, PIOP2(ioaddr)); + b++; + + /* Wait for the memory to finish its write cycle */ + count = 0; + while ((count++ < 100) && + (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); + } - wv_16_on(ioaddr, hacr); -} /* psa_write */ + wv_16_on(ioaddr, hacr); +} /* psa_write */ #ifdef SET_PSA_CRC /*------------------------------------------------------------------*/ @@ -301,88 +272,80 @@ * The Windows drivers don't use the CRC, but the AP and the PtP tool * depend on it. */ -static inline u_short -psa_crc(u_char * psa, /* The PSA */ - int size) /* Number of short for CRC */ -{ - int byte_cnt; /* Loop on the PSA */ - u_short crc_bytes = 0; /* Data in the PSA */ - int bit_cnt; /* Loop on the bits of the short */ - - for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) - { - crc_bytes ^= psa[byte_cnt]; /* Its an xor */ +static inline u16 psa_crc(u8 * psa, /* The PSA */ + int size) +{ /* Number of short for CRC */ + int byte_cnt; /* Loop on the PSA */ + u16 crc_bytes = 0; /* Data in the PSA */ + int bit_cnt; /* Loop on the bits of the short */ + + for (byte_cnt = 0; byte_cnt < size; byte_cnt++) { + crc_bytes ^= psa[byte_cnt]; /* Its an xor */ + + for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) { + if (crc_bytes & 0x0001) + crc_bytes = (crc_bytes >> 1) ^ 0xA001; + else + crc_bytes >>= 1; + } + } - for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) - { - if(crc_bytes & 0x0001) - crc_bytes = (crc_bytes >> 1) ^ 0xA001; - else - crc_bytes >>= 1 ; - } - } - - return crc_bytes; -} /* psa_crc */ -#endif /* SET_PSA_CRC */ + return crc_bytes; +} /* psa_crc */ +#endif /* SET_PSA_CRC */ /*------------------------------------------------------------------*/ /* * update the checksum field in the Wavelan's PSA */ -static void -update_psa_checksum(device * dev, - u_long ioaddr, - u_short hacr) +static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr) { #ifdef SET_PSA_CRC - psa_t psa; - u_short crc; + psa_t psa; + u16 crc; - /* read the parameter storage area */ - psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); + /* read the parameter storage area */ + psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); - /* update the checksum */ - crc = psa_crc((unsigned char *) &psa, - sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) - - sizeof(psa.psa_crc_status)); - - psa.psa_crc[0] = crc & 0xFF; - psa.psa_crc[1] = (crc & 0xFF00) >> 8; - - /* Write it ! */ - psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa, - (unsigned char *)&psa.psa_crc, 2); + /* update the checksum */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc[0]) - + sizeof(psa.psa_crc[1]) + - sizeof(psa.psa_crc_status)); + + psa.psa_crc[0] = crc & 0xFF; + psa.psa_crc[1] = (crc & 0xFF00) >> 8; + + /* Write it ! */ + psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa, + (unsigned char *) &psa.psa_crc, 2); #ifdef DEBUG_IOCTL_INFO - printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", - dev->name, psa.psa_crc[0], psa.psa_crc[1]); + printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", + dev->name, psa.psa_crc[0], psa.psa_crc[1]); - /* Check again (luxury !) */ - crc = psa_crc ((unsigned char *) &psa, - sizeof(psa) - sizeof(psa.psa_crc_status)); - - if(crc != 0) - printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name); -#endif /* DEBUG_IOCTL_INFO */ -#endif /* SET_PSA_CRC */ -} /* update_psa_checksum */ + /* Check again (luxury !) */ + crc = psa_crc((unsigned char *) &psa, + sizeof(psa) - sizeof(psa.psa_crc_status)); + + if (crc != 0) + printk(KERN_WARNING + "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", + dev->name); +#endif /* DEBUG_IOCTL_INFO */ +#endif /* SET_PSA_CRC */ +} /* update_psa_checksum */ /*------------------------------------------------------------------*/ /* * Write 1 byte to the MMC. */ -static inline void -mmc_out(u_long ioaddr, - u_short o, - u_char d) -{ - /* Wait for MMC to go idle */ - while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) - ; +static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d) +{ + /* Wait for MMC to go idle */ + while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); - outw((u_short) (((u_short) d << 8) | (o << 1) | 1), - MMCR(ioaddr)); + outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr)); } /*------------------------------------------------------------------*/ @@ -390,35 +353,27 @@ * Routine to write bytes to the Modem Management Controller. * We start at the end because it is the way it should be! */ -static inline void -mmc_write(u_long ioaddr, - u_char o, - u_char * b, - int n) -{ - o += n; - b += n; - - while(n-- > 0 ) - mmc_out(ioaddr, --o, *(--b)); -} /* mmc_write */ +static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n) +{ + o += n; + b += n; + + while (n-- > 0) + mmc_out(ioaddr, --o, *(--b)); +} /* mmc_write */ /*------------------------------------------------------------------*/ /* * Read a byte from the MMC. * Optimised version for 1 byte, avoid using memory. */ -static inline u_char -mmc_in(u_long ioaddr, - u_short o) -{ - while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) - ; - outw(o << 1, MMCR(ioaddr)); - - while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) - ; - return (u_char) (inw(MMCR(ioaddr)) >> 8); +static inline u8 mmc_in(unsigned long ioaddr, u16 o) +{ + while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + outw(o << 1, MMCR(ioaddr)); + + while (inw(HASR(ioaddr)) & HASR_MMC_BUSY); + return (u8) (inw(MMCR(ioaddr)) >> 8); } /*------------------------------------------------------------------*/ @@ -429,33 +384,28 @@ * (code has just been moved in the above function) * We start at the end because it is the way it should be! */ -static inline void -mmc_read(u_long ioaddr, - u_char o, - u_char * b, - int n) -{ - o += n; - b += n; - - while(n-- > 0) - *(--b) = mmc_in(ioaddr, --o); -} /* mmc_read */ +static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n) +{ + o += n; + b += n; + + while (n-- > 0) + *(--b) = mmc_in(ioaddr, --o); +} /* mmc_read */ /*------------------------------------------------------------------*/ /* * Get the type of encryption available. */ -static inline int -mmc_encr(u_long ioaddr) /* I/O port of the card */ -{ - int temp; - - temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); - if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) - return 0; - else - return temp; +static inline int mmc_encr(unsigned long ioaddr) +{ /* I/O port of the card */ + int temp; + + temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); + if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) + return 0; + else + return temp; } /*------------------------------------------------------------------*/ @@ -463,49 +413,47 @@ * Wait for the frequency EEPROM to complete a command. * I hope this one will be optimally inlined. */ -static inline void -fee_wait(u_long ioaddr, /* I/O port of the card */ - int delay, /* Base delay to wait for */ - int number) /* Number of time to wait */ -{ - int count = 0; /* Wait only a limited time */ - - while((count++ < number) && - (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) - udelay(delay); +static inline void fee_wait(unsigned long ioaddr, /* I/O port of the card */ + int delay, /* Base delay to wait for */ + int number) +{ /* Number of time to wait */ + int count = 0; /* Wait only a limited time */ + + while ((count++ < number) && + (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + MMR_FEE_STATUS_BUSY)) udelay(delay); } /*------------------------------------------------------------------*/ /* * Read bytes from the Frequency EEPROM (frequency select cards). */ -static void -fee_read(u_long ioaddr, /* I/O port of the card */ - u_short o, /* destination offset */ - u_short * b, /* data buffer */ - int n) /* number of registers */ -{ - b += n; /* Position at the end of the area */ - - /* Write the address */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); - - /* Loop on all buffer */ - while(n-- > 0) - { - /* Write the read command */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); - - /* Wait until EEPROM is ready (should be quick). */ - fee_wait(ioaddr, 10, 100); - - /* Read the value. */ - *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | - mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); - } +static void fee_read(unsigned long ioaddr, /* I/O port of the card */ + u16 o, /* destination offset */ + u16 * b, /* data buffer */ + int n) +{ /* number of registers */ + b += n; /* Position at the end of the area */ + + /* Write the address */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while (n-- > 0) { + /* Write the read command */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ); + + /* Wait until EEPROM is ready (should be quick). */ + fee_wait(ioaddr, 10, 100); + + /* Read the value. */ + *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | + mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); + } } -#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ +#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel */ /*------------------------------------------------------------------*/ /* @@ -514,83 +462,82 @@ * be unprotected and the write enabled. * Jean II */ -static void -fee_write(u_long ioaddr, /* I/O port of the card */ - u_short o, /* destination offset */ - u_short * b, /* data buffer */ - int n) /* number of registers */ -{ - b += n; /* Position at the end of the area. */ +static void fee_write(unsigned long ioaddr, /* I/O port of the card */ + u16 o, /* destination offset */ + u16 * b, /* data buffer */ + int n) +{ /* number of registers */ + b += n; /* Position at the end of the area. */ #ifdef EEPROM_IS_PROTECTED /* disabled */ #ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* Ask to read the protected register */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); + /* Ask to read the protected register */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); - fee_wait(ioaddr, 10, 100); + fee_wait(ioaddr, 10, 100); - /* Read the protected register. */ - printk("Protected 2: %02X-%02X\n", - mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), - mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); -#endif /* DOESNT_SEEM_TO_WORK */ - - /* Enable protected register. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); - - fee_wait(ioaddr, 10, 100); - - /* Unprotect area. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + /* Read the protected register. */ + printk("Protected 2: %02X-%02X\n", + mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), + mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); +#endif /* DOESNT_SEEM_TO_WORK */ + + /* Enable protected register. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); + + fee_wait(ioaddr, 10, 100); + + /* Unprotect area. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); #ifdef DOESNT_SEEM_TO_WORK /* disabled */ - /* or use: */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); -#endif /* DOESNT_SEEM_TO_WORK */ - - fee_wait(ioaddr, 10, 100); -#endif /* EEPROM_IS_PROTECTED */ - - /* Write enable. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); - - fee_wait(ioaddr, 10, 100); - - /* Write the EEPROM address. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); - - /* Loop on all buffer */ - while(n-- > 0) - { - /* Write the value. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); - mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); - - /* Write the write command. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); - - /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ - mdelay(10); - fee_wait(ioaddr, 10, 100); - } - - /* Write disable. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); + /* or use: */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); +#endif /* DOESNT_SEEM_TO_WORK */ + + fee_wait(ioaddr, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ + + /* Write enable. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); + + fee_wait(ioaddr, 10, 100); + + /* Write the EEPROM address. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); + + /* Loop on all buffer */ + while (n-- > 0) { + /* Write the value. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); + mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); + + /* Write the write command. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_WRITE); + + /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ + mdelay(10); + fee_wait(ioaddr, 10, 100); + } + + /* Write disable. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); - fee_wait(ioaddr, 10, 100); + fee_wait(ioaddr, 10, 100); #ifdef EEPROM_IS_PROTECTED /* disabled */ - /* Reprotect EEPROM. */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); + /* Reprotect EEPROM. */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); - fee_wait(ioaddr, 10, 100); -#endif /* EEPROM_IS_PROTECTED */ + fee_wait(ioaddr, 10, 100); +#endif /* EEPROM_IS_PROTECTED */ } -#endif /* WIRELESS_EXT */ +#endif /* WIRELESS_EXT */ /************************ I82586 SUBROUTINES *************************/ /* @@ -602,68 +549,61 @@ * Read bytes from the on-board RAM. * Why does inlining this function make it fail? */ -static /*inline*/ void -obram_read(u_long ioaddr, - u_short o, - u_char * b, - int n) +static /*inline */ void obram_read(unsigned long ioaddr, + u16 o, u8 * b, int n) { - outw(o, PIOR1(ioaddr)); - insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); + outw(o, PIOR1(ioaddr)); + insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); } /*------------------------------------------------------------------*/ /* * Write bytes to the on-board RAM. */ -static inline void -obram_write(u_long ioaddr, - u_short o, - u_char * b, - int n) +static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) { - outw(o, PIOR1(ioaddr)); - outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); + outw(o, PIOR1(ioaddr)); + outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); } /*------------------------------------------------------------------*/ /* * Acknowledge the reading of the status issued by the i82586. */ -static void -wv_ack(device * dev) +static void wv_ack(device * dev) { - net_local * lp = (net_local *)dev->priv; - u_long ioaddr = dev->base_addr; - u_short scb_cs; - int i; - - obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - scb_cs &= SCB_ST_INT; - - if(scb_cs == 0) - return; - - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - - set_chan_attn(ioaddr, lp->hacr); - - for(i = 1000; i > 0; i--) - { - obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs)); - if(scb_cs == 0) - break; - - udelay(10); - } - udelay(100); + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cs; + int i; + + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + scb_cs &= SCB_ST_INT; + + if (scb_cs == 0) + return; + + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; + + udelay(10); + } + udelay(100); #ifdef DEBUG_CONFIG_ERROR - if(i <= 0) - printk(KERN_INFO "%s: wv_ack(): board not accepting command.\n", - dev->name); + if (i <= 0) + printk(KERN_INFO + "%s: wv_ack(): board not accepting command.\n", + dev->name); #endif } @@ -672,48 +612,45 @@ * Set channel attention bit and busy wait until command has * completed, then acknowledge completion of the command. */ -static inline int -wv_synchronous_cmd(device * dev, - const char * str) +static inline int wv_synchronous_cmd(device * dev, const char *str) { - net_local * lp = (net_local *)dev->priv; - u_long ioaddr = dev->base_addr; - u_short scb_cmd; - ach_t cb; - int i; - - scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cmd, sizeof(scb_cmd)); - - set_chan_attn(ioaddr, lp->hacr); - - for (i = 1000; i > 0; i--) - { - obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); - if (cb.ac_status & AC_SFLD_C) - break; - - udelay(10); - } - udelay(100); + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cmd; + ach_t cb; + int i; + + scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cmd, sizeof(scb_cmd)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, + sizeof(cb)); + if (cb.ac_status & AC_SFLD_C) + break; - if(i <= 0 || !(cb.ac_status & AC_SFLD_OK)) - { + udelay(10); + } + udelay(100); + + if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: %s failed; status = 0x%x\n", - dev->name, str, cb.ac_status); + printk(KERN_INFO "%s: %s failed; status = 0x%x\n", + dev->name, str, cb.ac_status); #endif #ifdef DEBUG_I82586_SHOW - wv_scb_show(ioaddr); + wv_scb_show(ioaddr); #endif - return -1; - } + return -1; + } - /* Ack the status */ - wv_ack(dev); + /* Ack the status */ + wv_ack(dev); - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -722,60 +659,64 @@ * Check if done, and if OK. */ static inline int -wv_config_complete(device * dev, - u_long ioaddr, - net_local * lp) -{ - unsigned short mcs_addr; - unsigned short status; - int ret; +wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp) +{ + unsigned short mcs_addr; + unsigned short status; + int ret; #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); #endif - mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) - + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); + mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) + + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); - /* Read the status of the last command (set mc list). */ - obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status)); + /* Read the status of the last command (set mc list). */ + obram_read(ioaddr, acoff(mcs_addr, ac_status), + (unsigned char *) &status, sizeof(status)); - /* If not completed -> exit */ - if((status & AC_SFLD_C) == 0) - ret = 0; /* Not ready to be scrapped */ - else - { + /* If not completed -> exit */ + if ((status & AC_SFLD_C) == 0) + ret = 0; /* Not ready to be scrapped */ + else { #ifdef DEBUG_CONFIG_ERROR - unsigned short cfg_addr; - unsigned short ias_addr; - - /* Check mc_config command */ - if((status & AC_SFLD_OK) != AC_SFLD_OK) - printk(KERN_INFO "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", - dev->name, status); + unsigned short cfg_addr; + unsigned short ias_addr; - /* check ia-config command */ - ias_addr = mcs_addr - sizeof(ac_ias_t); - obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status)); - if((status & AC_SFLD_OK) != AC_SFLD_OK) - printk(KERN_INFO "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", - dev->name, status); - - /* Check config command. */ - cfg_addr = ias_addr - sizeof(ac_cfg_t); - obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status)); - if((status & AC_SFLD_OK) != AC_SFLD_OK) - printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n", - dev->name, status); -#endif /* DEBUG_CONFIG_ERROR */ + /* Check mc_config command */ + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", + dev->name, status); + + /* check ia-config command */ + ias_addr = mcs_addr - sizeof(ac_ias_t); + obram_read(ioaddr, acoff(ias_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", + dev->name, status); + + /* Check config command. */ + cfg_addr = ias_addr - sizeof(ac_cfg_t); + obram_read(ioaddr, acoff(cfg_addr, ac_status), + (unsigned char *) &status, sizeof(status)); + if ((status & AC_SFLD_OK) != AC_SFLD_OK) + printk(KERN_INFO + "%s: wv_config_complete(): configure failed; status = 0x%x\n", + dev->name, status); +#endif /* DEBUG_CONFIG_ERROR */ - ret = 1; /* Ready to be scrapped */ - } + ret = 1; /* Ready to be scrapped */ + } #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, ret); + printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, + ret); #endif - return ret; + return ret; } /*------------------------------------------------------------------*/ @@ -783,141 +724,137 @@ * Command completion interrupt. * Reclaim as many freed tx buffers as we can. */ -static int -wv_complete(device * dev, - u_long ioaddr, - net_local * lp) +static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) { - int nreaped = 0; + int nreaped = 0; #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); #endif - /* Loop on all the transmit buffers */ - while(lp->tx_first_in_use != I82586NULL) - { - unsigned short tx_status; - - /* Read the first transmit buffer */ - obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status)); - - /* If not completed -> exit */ - if((tx_status & AC_SFLD_C) == 0) - break; - - /* Hack for reconfiguration */ - if(tx_status == 0xFFFF) - if(!wv_config_complete(dev, ioaddr, lp)) - break; /* Not completed */ - - /* We now remove this buffer */ - nreaped++; - --lp->tx_n_in_use; + /* Loop on all the transmit buffers */ + while (lp->tx_first_in_use != I82586NULL) { + unsigned short tx_status; + + /* Read the first transmit buffer */ + obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), + (unsigned char *) &tx_status, + sizeof(tx_status)); + + /* If not completed -> exit */ + if ((tx_status & AC_SFLD_C) == 0) + break; + + /* Hack for reconfiguration */ + if (tx_status == 0xFFFF) + if (!wv_config_complete(dev, ioaddr, lp)) + break; /* Not completed */ + + /* We now remove this buffer */ + nreaped++; + --lp->tx_n_in_use; /* if (lp->tx_n_in_use > 0) printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); */ - /* Was it the last one? */ - if(lp->tx_n_in_use <= 0) - lp->tx_first_in_use = I82586NULL; - else - { - /* Next one in the chain */ - lp->tx_first_in_use += TXBLOCKZ; - if(lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ; - } - - /* Hack for reconfiguration */ - if(tx_status == 0xFFFF) - continue; - - /* Now, check status of the finished command */ - if(tx_status & AC_SFLD_OK) - { - int ncollisions; - - lp->stats.tx_packets++; - ncollisions = tx_status & AC_SFLD_MAXCOL; - lp->stats.collisions += ncollisions; + /* Was it the last one? */ + if (lp->tx_n_in_use <= 0) + lp->tx_first_in_use = I82586NULL; + else { + /* Next one in the chain */ + lp->tx_first_in_use += TXBLOCKZ; + if (lp->tx_first_in_use >= + OFFSET_CU + + NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= + NTXBLOCKS * TXBLOCKZ; + } + + /* Hack for reconfiguration */ + if (tx_status == 0xFFFF) + continue; + + /* Now, check status of the finished command */ + if (tx_status & AC_SFLD_OK) { + int ncollisions; + + lp->stats.tx_packets++; + ncollisions = tx_status & AC_SFLD_MAXCOL; + lp->stats.collisions += ncollisions; #ifdef DEBUG_TX_INFO - if(ncollisions > 0) - printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n", - dev->name, ncollisions); -#endif - } - else - { - lp->stats.tx_errors++; - if(tx_status & AC_SFLD_S10) - { - lp->stats.tx_carrier_errors++; + if (ncollisions > 0) + printk(KERN_DEBUG + "%s: wv_complete(): tx completed after %d collisions.\n", + dev->name, ncollisions); +#endif + } else { + lp->stats.tx_errors++; + if (tx_status & AC_SFLD_S10) { + lp->stats.tx_carrier_errors++; #ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n", - dev->name); -#endif - } - if(tx_status & AC_SFLD_S9) - { - lp->stats.tx_carrier_errors++; + printk(KERN_DEBUG + "%s: wv_complete(): tx error: no CS.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S9) { + lp->stats.tx_carrier_errors++; #ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n", - dev->name); -#endif - } - if(tx_status & AC_SFLD_S8) - { - lp->stats.tx_fifo_errors++; + printk(KERN_DEBUG + "%s: wv_complete(): tx error: lost CTS.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S8) { + lp->stats.tx_fifo_errors++; #ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n", - dev->name); -#endif - } - if(tx_status & AC_SFLD_S6) - { - lp->stats.tx_heartbeat_errors++; + printk(KERN_DEBUG + "%s: wv_complete(): tx error: slow DMA.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S6) { + lp->stats.tx_heartbeat_errors++; #ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n", - dev->name); -#endif - } - if(tx_status & AC_SFLD_S5) - { - lp->stats.tx_aborted_errors++; + printk(KERN_DEBUG + "%s: wv_complete(): tx error: heart beat.\n", + dev->name); +#endif + } + if (tx_status & AC_SFLD_S5) { + lp->stats.tx_aborted_errors++; #ifdef DEBUG_TX_FAIL - printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n", - dev->name); + printk(KERN_DEBUG + "%s: wv_complete(): tx error: too many collisions.\n", + dev->name); #endif - } - } + } + } #ifdef DEBUG_TX_INFO - printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n", - dev->name, tx_status); + printk(KERN_DEBUG + "%s: wv_complete(): tx completed, tx_status 0x%04x\n", + dev->name, tx_status); #endif - } + } #ifdef DEBUG_INTERRUPT_INFO - if(nreaped > 1) - printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", dev->name, nreaped); + if (nreaped > 1) + printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", + dev->name, nreaped); #endif - /* - * Inform upper layers. - */ - if(lp->tx_n_in_use < NTXBLOCKS - 1) - { - dev->tbusy = 0; - mark_bh(NET_BH); - } - + /* + * Inform upper layers. + */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) { + netif_wake_queue(dev); + } #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); #endif - return nreaped; + return nreaped; } /*------------------------------------------------------------------*/ @@ -929,22 +866,21 @@ * wavelan_interrupt is not an option), so you may experience * delays sometimes. */ -static inline void -wv_82586_reconfig(device * dev) +static inline void wv_82586_reconfig(device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = (net_local *) dev->priv; - /* Check if we can do it now ! */ - if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0)) - { - lp->reconfig_82586 = 1; + /* Check if we can do it now ! */ + if (!test_bit(LINK_STATE_START, &dev->state) && + test_bit(LINK_STATE_XOFF, &dev->state)) { + lp->reconfig_82586 = 1; #ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (busy = %ld, start = %d)\n", - dev->name, dev->tbusy, dev->start); + printk(KERN_DEBUG + "%s: wv_82586_reconfig(): delayed (state = %lX)\n", + dev->name, dev->state); #endif - } - else - wv_82586_config(dev); + } else + wv_82586_config(dev); } /********************* DEBUG & INFO SUBROUTINES *********************/ @@ -958,89 +894,73 @@ /* * Print the formatted contents of the Parameter Storage Area. */ -static void -wv_psa_show(psa_t * p) +static void wv_psa_show(psa_t * p) { - printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); - printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", - p->psa_io_base_addr_1, - p->psa_io_base_addr_2, - p->psa_io_base_addr_3, - p->psa_io_base_addr_4); - printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", - p->psa_rem_boot_addr_1, - p->psa_rem_boot_addr_2, - p->psa_rem_boot_addr_3); - printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); - printk("psa_int_req_no: %d\n", p->psa_int_req_no); + printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); + printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", + p->psa_io_base_addr_1, + p->psa_io_base_addr_2, + p->psa_io_base_addr_3, p->psa_io_base_addr_4); + printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", + p->psa_rem_boot_addr_1, + p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); + printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); + printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_unused0[0], - p->psa_unused0[1], - p->psa_unused0[2], - p->psa_unused0[3], - p->psa_unused0[4], - p->psa_unused0[5], - p->psa_unused0[6]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_univ_mac_addr[0], - p->psa_univ_mac_addr[1], - p->psa_univ_mac_addr[2], - p->psa_univ_mac_addr[3], - p->psa_univ_mac_addr[4], - p->psa_univ_mac_addr[5]); - printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_local_mac_addr[0], - p->psa_local_mac_addr[1], - p->psa_local_mac_addr[2], - p->psa_local_mac_addr[3], - p->psa_local_mac_addr[4], - p->psa_local_mac_addr[5]); - printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); - printk("psa_comp_number: %d, ", p->psa_comp_number); - printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); - printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", - p->psa_feature_select); - printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); - printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); - printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); - printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); - printk("psa_nwid_select: %d\n", p->psa_nwid_select); - printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); - printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - p->psa_encryption_key[0], - p->psa_encryption_key[1], - p->psa_encryption_key[2], - p->psa_encryption_key[3], - p->psa_encryption_key[4], - p->psa_encryption_key[5], - p->psa_encryption_key[6], - p->psa_encryption_key[7]); - printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); - printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", - p->psa_call_code[0]); - printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - p->psa_call_code[0], - p->psa_call_code[1], - p->psa_call_code[2], - p->psa_call_code[3], - p->psa_call_code[4], - p->psa_call_code[5], - p->psa_call_code[6], - p->psa_call_code[7]); + printk(KERN_DEBUG + "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], + p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], + p->psa_unused0[6]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG + "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], + p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3], + p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]); + printk(KERN_DEBUG + "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_local_mac_addr[0], p->psa_local_mac_addr[1], + p->psa_local_mac_addr[2], p->psa_local_mac_addr[3], + p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]); + printk(KERN_DEBUG "psa_univ_local_sel: %d, ", + p->psa_univ_local_sel); + printk("psa_comp_number: %d, ", p->psa_comp_number); + printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); + printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", + p->psa_feature_select); + printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); + printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); + printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); + printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], + p->psa_nwid[1]); + printk("psa_nwid_select: %d\n", p->psa_nwid_select); + printk(KERN_DEBUG "psa_encryption_select: %d, ", + p->psa_encryption_select); + printk + ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + p->psa_encryption_key[0], p->psa_encryption_key[1], + p->psa_encryption_key[2], p->psa_encryption_key[3], + p->psa_encryption_key[4], p->psa_encryption_key[5], + p->psa_encryption_key[6], p->psa_encryption_key[7]); + printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); + printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", + p->psa_call_code[0]); + printk + ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2], + p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5], + p->psa_call_code[6], p->psa_call_code[7]); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", - p->psa_reserved[0], - p->psa_reserved[1], - p->psa_reserved[2], - p->psa_reserved[3]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); - printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); - printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); -} /* wv_psa_show */ -#endif /* DEBUG_PSA_SHOW */ + printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", + p->psa_reserved[0], + p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); + printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); + printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); +} /* wv_psa_show */ +#endif /* DEBUG_PSA_SHOW */ #ifdef DEBUG_MMC_SHOW /*------------------------------------------------------------------*/ @@ -1048,411 +968,432 @@ * Print the formatted status of the Modem Management Controller. * This function needs to be completed. */ -static void -wv_mmc_show(device * dev) +static void wv_mmc_show(device * dev) { - u_long ioaddr = dev->base_addr; - net_local * lp = (net_local *)dev->priv; - mmr_t m; - - /* Basic check */ - if(hasr_read(ioaddr) & HASR_NO_CLK) - { - printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", - dev->name); - return; - } - - /* Read the mmc */ - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m)); - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); - -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ - /* Don't forget to update statistics */ - lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; -#endif /* WIRELESS_EXT */ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + mmr_t m; + + /* Basic check */ + if (hasr_read(ioaddr) & HASR_NO_CLK) { + printk(KERN_WARNING + "%s: wv_mmc_show: modem not connected\n", + dev->name); + return; + } + + /* Read the mmc */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m)); + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + +#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ + /* Don't forget to update statistics */ + lp->wstats.discard.nwid += + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; +#endif /* WIRELESS_EXT */ - printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); + printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - m.mmr_unused0[0], - m.mmr_unused0[1], - m.mmr_unused0[2], - m.mmr_unused0[3], - m.mmr_unused0[4], - m.mmr_unused0[5], - m.mmr_unused0[6], - m.mmr_unused0[7]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", - m.mmr_des_avail, m.mmr_des_status); + printk(KERN_DEBUG + "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2], + m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5], + m.mmr_unused0[6], m.mmr_unused0[7]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n", + m.mmr_des_avail, m.mmr_des_status); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", - m.mmr_unused1[0], - m.mmr_unused1[1], - m.mmr_unused1[2], - m.mmr_unused1[3], - m.mmr_unused1[4]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", - m.mmr_dce_status, - (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", - (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? - "loop test indicated," : "", - (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", - (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? - "jabber timer expired," : ""); - printk(KERN_DEBUG "Dsp ID: %02X\n", - m.mmr_dsp_id); + printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", + m.mmr_unused1[0], + m.mmr_unused1[1], + m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", + m.mmr_dce_status, + (m. + mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? + "energy detected," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? + "loop test indicated," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? + "transmitter on," : "", + (m. + mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? + "jabber timer expired," : ""); + printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", - m.mmr_unused2[0], - m.mmr_unused2[1]); -#endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", - (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, - (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); - printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", - m.mmr_thr_pre_set & MMR_THR_PRE_SET, - (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); - printk(KERN_DEBUG "signal_lvl: %d [%s], ", - m.mmr_signal_lvl & MMR_SIGNAL_LVL, - (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); - printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, - (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); - printk("sgnl_qual: 0x%x [%s]\n", - m.mmr_sgnl_qual & MMR_SGNL_QUAL, - (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); + printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", + m.mmr_unused2[0], m.mmr_unused2[1]); +#endif /* DEBUG_SHOW_UNUSED */ + printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", + (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, + (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); + printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", + m.mmr_thr_pre_set & MMR_THR_PRE_SET, + (m. + mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : + "below"); + printk(KERN_DEBUG "signal_lvl: %d [%s], ", + m.mmr_signal_lvl & MMR_SIGNAL_LVL, + (m. + mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : + "no new msg"); + printk("silence_lvl: %d [%s], ", + m.mmr_silence_lvl & MMR_SILENCE_LVL, + (m. + mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : + "no new update"); + printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL, + (m. + mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : + "Antenna 0"); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); -#endif /* DEBUG_SHOW_UNUSED */ -} /* wv_mmc_show */ -#endif /* DEBUG_MMC_SHOW */ + printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); +#endif /* DEBUG_SHOW_UNUSED */ +} /* wv_mmc_show */ +#endif /* DEBUG_MMC_SHOW */ #ifdef DEBUG_I82586_SHOW /*------------------------------------------------------------------*/ /* * Print the last block of the i82586 memory. */ -static void -wv_scb_show(u_long ioaddr) +static void wv_scb_show(unsigned long ioaddr) { - scb_t scb; + scb_t scb; - obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb)); + obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); - printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); + printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); - printk(KERN_DEBUG "status: "); - printk("stat 0x%x[%s%s%s%s] ", - (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12, - (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "", - (scb.scb_status & SCB_ST_FR) ? "frame received," : "", - (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "", - (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : ""); - printk("cus 0x%x[%s%s%s] ", - (scb.scb_status & SCB_ST_CUS) >> 8, - ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "", - ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_SUSP) ? "suspended" : "", - ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_ACTV) ? "active" : ""); - printk("rus 0x%x[%s%s%s%s]\n", - (scb.scb_status & SCB_ST_RUS) >> 4, - ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_IDLE) ? "idle" : "", - ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_SUSP) ? "suspended" : "", - ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_NRES) ? "no resources" : "", - ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_RDY) ? "ready" : ""); - - printk(KERN_DEBUG "command: "); - printk("ack 0x%x[%s%s%s%s] ", - (scb.scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, - (scb.scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", - (scb.scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", - (scb.scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", - (scb.scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); - printk("cuc 0x%x[%s%s%s%s%s] ", - (scb.scb_command & SCB_CMD_CUC) >> 8, - ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_NOP) ? "nop" : "", - ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_GO) ? "start cbl_offset" : "", - ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_RES) ? "resume execution" : "", - ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_SUS) ? "suspend execution" : "", - ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_ABT) ? "abort execution" : ""); - printk("ruc 0x%x[%s%s%s%s%s]\n", - (scb.scb_command & SCB_CMD_RUC) >> 4, - ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_NOP) ? "nop" : "", - ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_GO) ? "start rfa_offset" : "", - ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_RES) ? "resume reception" : "", - ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_SUS) ? "suspend reception" : "", - ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_ABT) ? "abort reception" : ""); - - printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); - printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); - - printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); - printk("alnerrs %d ", scb.scb_alnerrs); - printk("rscerrs %d ", scb.scb_rscerrs); - printk("ovrnerrs %d\n", scb.scb_ovrnerrs); + printk(KERN_DEBUG "status: "); + printk("stat 0x%x[%s%s%s%s] ", + (scb. + scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | + SCB_ST_RNR)) >> 12, + (scb. + scb_status & SCB_ST_CX) ? "command completion interrupt," : + "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "", + (scb. + scb_status & SCB_ST_CNA) ? "command unit not active," : "", + (scb. + scb_status & SCB_ST_RNR) ? "receiving unit not ready," : + ""); + printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8, + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_IDLE) ? "idle" : "", + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_SUSP) ? "suspended" : "", + ((scb.scb_status & SCB_ST_CUS) == + SCB_ST_CUS_ACTV) ? "active" : ""); + printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4, + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_IDLE) ? "idle" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_SUSP) ? "suspended" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_NRES) ? "no resources" : "", + ((scb.scb_status & SCB_ST_RUS) == + SCB_ST_RUS_RDY) ? "ready" : ""); + + printk(KERN_DEBUG "command: "); + printk("ack 0x%x[%s%s%s%s] ", + (scb. + scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | + SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, + (scb. + scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", + (scb. + scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", + (scb. + scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", + (scb. + scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); + printk("cuc 0x%x[%s%s%s%s%s] ", + (scb.scb_command & SCB_CMD_CUC) >> 8, + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_NOP) ? "nop" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_GO) ? "start cbl_offset" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_RES) ? "resume execution" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_SUS) ? "suspend execution" : "", + ((scb.scb_command & SCB_CMD_CUC) == + SCB_CMD_CUC_ABT) ? "abort execution" : ""); + printk("ruc 0x%x[%s%s%s%s%s]\n", + (scb.scb_command & SCB_CMD_RUC) >> 4, + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_NOP) ? "nop" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_GO) ? "start rfa_offset" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_RES) ? "resume reception" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_SUS) ? "suspend reception" : "", + ((scb.scb_command & SCB_CMD_RUC) == + SCB_CMD_RUC_ABT) ? "abort reception" : ""); + + printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); + printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); + + printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); + printk("alnerrs %d ", scb.scb_alnerrs); + printk("rscerrs %d ", scb.scb_rscerrs); + printk("ovrnerrs %d\n", scb.scb_ovrnerrs); } /*------------------------------------------------------------------*/ /* * Print the formatted status of the i82586's receive unit. */ -static void -wv_ru_show(device * dev) +static void wv_ru_show(device * dev) { - /* net_local *lp = (net_local *) dev->priv; */ + /* net_local *lp = (net_local *) dev->priv; */ - printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n"); - printk(KERN_DEBUG "ru:"); - /* - * Not implemented yet - */ - printk("\n"); -} /* wv_ru_show */ + printk(KERN_DEBUG + "##### WaveLAN i82586 receiver unit status: #####\n"); + printk(KERN_DEBUG "ru:"); + /* + * Not implemented yet + */ + printk("\n"); +} /* wv_ru_show */ /*------------------------------------------------------------------*/ /* * Display info about one control block of the i82586 memory. */ -static void -wv_cu_show_one(device * dev, - net_local * lp, - int i, - u_short p) +static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p) { - u_long ioaddr; - ac_tx_t actx; + unsigned long ioaddr; + ac_tx_t actx; - ioaddr = dev->base_addr; + ioaddr = dev->base_addr; - printk("%d: 0x%x:", i, p); + printk("%d: 0x%x:", i, p); - obram_read(ioaddr, p, (unsigned char *)&actx, sizeof(actx)); - printk(" status=0x%x,", actx.tx_h.ac_status); - printk(" command=0x%x,", actx.tx_h.ac_command); + obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx)); + printk(" status=0x%x,", actx.tx_h.ac_status); + printk(" command=0x%x,", actx.tx_h.ac_command); - /* - { - tbd_t tbd; + /* + { + tbd_t tbd; - obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); - printk(" tbd_status=0x%x,", tbd.tbd_status); - } - */ + obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); + printk(" tbd_status=0x%x,", tbd.tbd_status); + } + */ - printk("|"); + printk("|"); } /*------------------------------------------------------------------*/ /* * Print status of the command unit of the i82586. */ -static void -wv_cu_show(device * dev) +static void wv_cu_show(device * dev) { - net_local * lp = (net_local *)dev->priv; - unsigned int i; - u_short p; - - printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n"); - - printk(KERN_DEBUG); - for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) - { - wv_cu_show_one(dev, lp, i, p); - - p += TXBLOCKZ; - if(p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - p -= NTXBLOCKS * TXBLOCKZ; - } - printk("\n"); + net_local *lp = (net_local *) dev->priv; + unsigned int i; + u16 p; + + printk(KERN_DEBUG + "##### WaveLAN i82586 command unit status: #####\n"); + + printk(KERN_DEBUG); + for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) { + wv_cu_show_one(dev, lp, i, p); + + p += TXBLOCKZ; + if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + p -= NTXBLOCKS * TXBLOCKZ; + } + printk("\n"); } -#endif /* DEBUG_I82586_SHOW */ +#endif /* DEBUG_I82586_SHOW */ #ifdef DEBUG_DEVICE_SHOW /*------------------------------------------------------------------*/ /* * Print the formatted status of the WaveLAN PCMCIA device driver. */ -static void -wv_dev_show(device * dev) +static void wv_dev_show(device * dev) { - printk(KERN_DEBUG "dev:"); - printk(" start=%d,", dev->start); - printk(" tbusy=%ld,", dev->tbusy); - printk(" interrupt=%d,", dev->interrupt); - printk(" trans_start=%ld,", dev->trans_start); - printk(" flags=0x%x,", dev->flags); - printk("\n"); -} /* wv_dev_show */ + printk(KERN_DEBUG "dev:"); + printk(" state=%lX,", dev->state); + printk(" trans_start=%ld,", dev->trans_start); + printk(" flags=0x%x,", dev->flags); + printk("\n"); +} /* wv_dev_show */ /*------------------------------------------------------------------*/ /* * Print the formatted status of the WaveLAN PCMCIA device driver's * private information. */ -static void -wv_local_show(device * dev) +static void wv_local_show(device * dev) { - net_local *lp; + net_local *lp; - lp = (net_local *)dev->priv; + lp = (net_local *) dev->priv; - printk(KERN_DEBUG "local:"); - printk(" tx_n_in_use=%d,", lp->tx_n_in_use); - printk(" hacr=0x%x,", lp->hacr); - printk(" rx_head=0x%x,", lp->rx_head); - printk(" rx_last=0x%x,", lp->rx_last); - printk(" tx_first_free=0x%x,", lp->tx_first_free); - printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); - printk("\n"); -} /* wv_local_show */ -#endif /* DEBUG_DEVICE_SHOW */ + printk(KERN_DEBUG "local:"); + printk(" tx_n_in_use=%d,", lp->tx_n_in_use); + printk(" hacr=0x%x,", lp->hacr); + printk(" rx_head=0x%x,", lp->rx_head); + printk(" rx_last=0x%x,", lp->rx_last); + printk(" tx_first_free=0x%x,", lp->tx_first_free); + printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); + printk("\n"); +} /* wv_local_show */ +#endif /* DEBUG_DEVICE_SHOW */ #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) /*------------------------------------------------------------------*/ /* * Dump packet header (and content if necessary) on the screen */ -static inline void -wv_packet_info(u_char * p, /* Packet to dump */ - int length, /* Length of the packet */ - char * msg1, /* Name of the device */ - char * msg2) /* Name of the function */ -{ - int i; - int maxi; - - printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", - msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); - printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", - msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); +static inline void wv_packet_info(u8 * p, /* Packet to dump */ + int length, /* Length of the packet */ + char *msg1, /* Name of the device */ + char *msg2) +{ /* Name of the function */ + int i; + int maxi; + + printk(KERN_DEBUG + "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", + msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); + printk(KERN_DEBUG + "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", + msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], + p[13]); #ifdef DEBUG_PACKET_DUMP - printk(KERN_DEBUG "data=\""); + printk(KERN_DEBUG "data=\""); - if((maxi = length) > DEBUG_PACKET_DUMP) - maxi = DEBUG_PACKET_DUMP; - for(i = 14; i < maxi; i++) - if(p[i] >= ' ' && p[i] <= '~') - printk(" %c", p[i]); - else - printk("%02X", p[i]); - if(maxi < length) - printk(".."); - printk("\"\n"); - printk(KERN_DEBUG "\n"); -#endif /* DEBUG_PACKET_DUMP */ + if ((maxi = length) > DEBUG_PACKET_DUMP) + maxi = DEBUG_PACKET_DUMP; + for (i = 14; i < maxi; i++) + if (p[i] >= ' ' && p[i] <= '~') + printk(" %c", p[i]); + else + printk("%02X", p[i]); + if (maxi < length) + printk(".."); + printk("\"\n"); + printk(KERN_DEBUG "\n"); +#endif /* DEBUG_PACKET_DUMP */ } -#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ +#endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ /*------------------------------------------------------------------*/ /* * This is the information which is displayed by the driver at startup. * There are lots of flags for configuring it to your liking. */ -static inline void -wv_init_info(device * dev) +static inline void wv_init_info(device * dev) { - short ioaddr = dev->base_addr; - net_local * lp = (net_local *)dev->priv; - psa_t psa; - int i; + short ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + psa_t psa; + int i; - /* Read the parameter storage area */ - psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); + /* Read the parameter storage area */ + psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); #ifdef DEBUG_PSA_SHOW - wv_psa_show(&psa); + wv_psa_show(&psa); #endif #ifdef DEBUG_MMC_SHOW - wv_mmc_show(dev); + wv_mmc_show(dev); #endif #ifdef DEBUG_I82586_SHOW - wv_cu_show(dev); + wv_cu_show(dev); #endif #ifdef DEBUG_BASIC_SHOW - /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); - for(i = 0; i < WAVELAN_ADDR_SIZE; i++) - printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); - printk(", IRQ %d", dev->irq); - - /* Print current network ID. */ - if(psa.psa_nwid_select) - printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); - else - printk(", nwid off"); - - /* If 2.00 card */ - if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - - /* Print frequency */ - printk(", 2.00, %ld", (freq >> 6) + 2400L); - - /* Hack! */ - if(freq & 0x20) - printk(".5"); - } - else - { - printk(", PC"); - switch(psa.psa_comp_number) - { - case PSA_COMP_PC_AT_915: - case PSA_COMP_PC_AT_2400: - printk("-AT"); - break; - case PSA_COMP_PC_MC_915: - case PSA_COMP_PC_MC_2400: - printk("-MC"); - break; - case PSA_COMP_PCMCIA_915: - printk("MCIA"); - break; - default: - printk("?"); - } - printk(", "); - switch (psa.psa_subband) - { - case PSA_SUBBAND_915: - printk("915"); - break; - case PSA_SUBBAND_2425: - printk("2425"); - break; - case PSA_SUBBAND_2460: - printk("2460"); - break; - case PSA_SUBBAND_2484: - printk("2484"); - break; - case PSA_SUBBAND_2430_5: - printk("2430.5"); - break; - default: - printk("?"); + /* Now, let's go for the basic stuff. */ + printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); + for (i = 0; i < WAVELAN_ADDR_SIZE; i++) + printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); + printk(", IRQ %d", dev->irq); + + /* Print current network ID. */ + if (psa.psa_nwid_select) + printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], + psa.psa_nwid[1]); + else + printk(", nwid off"); + + /* If 2.00 card */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + + /* Print frequency */ + printk(", 2.00, %ld", (freq >> 6) + 2400L); + + /* Hack! */ + if (freq & 0x20) + printk(".5"); + } else { + printk(", PC"); + switch (psa.psa_comp_number) { + case PSA_COMP_PC_AT_915: + case PSA_COMP_PC_AT_2400: + printk("-AT"); + break; + case PSA_COMP_PC_MC_915: + case PSA_COMP_PC_MC_2400: + printk("-MC"); + break; + case PSA_COMP_PCMCIA_915: + printk("MCIA"); + break; + default: + printk("?"); + } + printk(", "); + switch (psa.psa_subband) { + case PSA_SUBBAND_915: + printk("915"); + break; + case PSA_SUBBAND_2425: + printk("2425"); + break; + case PSA_SUBBAND_2460: + printk("2460"); + break; + case PSA_SUBBAND_2484: + printk("2484"); + break; + case PSA_SUBBAND_2430_5: + printk("2430.5"); + break; + default: + printk("?"); + } } - } - printk(" MHz\n"); -#endif /* DEBUG_BASIC_SHOW */ + printk(" MHz\n"); +#endif /* DEBUG_BASIC_SHOW */ #ifdef DEBUG_VERSION_SHOW - /* Print version information */ - printk(KERN_NOTICE "%s", version); + /* Print version information */ + printk(KERN_NOTICE "%s", version); #endif -} /* wv_init_info */ +} /* wv_init_info */ /********************* IOCTL, STATS & RECONFIG *********************/ /* @@ -1468,14 +1409,13 @@ * card open or closed. * Used when the user read /proc/net/dev */ -static en_stats * -wavelan_get_stats(device * dev) +static en_stats *wavelan_get_stats(device * dev) { #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); + printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); #endif - return(&((net_local *) dev->priv)->stats); + return (&((net_local *) dev->priv)->stats); } /*------------------------------------------------------------------*/ @@ -1486,76 +1426,70 @@ * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */ -static void -wavelan_set_multicast_list(device * dev) +static void wavelan_set_multicast_list(device * dev) { - net_local * lp = (net_local *) dev->priv; + net_local *lp = (net_local *) dev->priv; #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); + printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", + dev->name); #endif #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", - dev->name, dev->flags, dev->mc_count); + printk(KERN_DEBUG + "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", + dev->name, dev->flags, dev->mc_count); +#endif + + /* Are we asking for promiscuous mode, + * or all multicast addresses (we don't have that!) + * or too many multicast addresses for the hardware filter? */ + if ((dev->flags & IFF_PROMISC) || + (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) { + /* + * Enable promiscuous mode: receive all packets. + */ + if (!lp->promiscuous) { + lp->promiscuous = 1; + lp->mc_count = 0; + + wv_82586_reconfig(dev); + + /* Tell the kernel that we are doing a really bad job. */ + dev->flags |= IFF_PROMISC; + } + } else + /* Are there multicast addresses to send? */ + if (dev->mc_list != (struct dev_mc_list *) NULL) { + /* + * Disable promiscuous mode, but receive all packets + * in multicast list + */ +#ifdef MULTICAST_AVOID + if (lp->promiscuous || (dev->mc_count != lp->mc_count)) #endif + { + lp->promiscuous = 0; + lp->mc_count = dev->mc_count; + + wv_82586_reconfig(dev); + } + } else { + /* + * Switch to normal mode: disable promiscuous mode and + * clear the multicast list. + */ + if (lp->promiscuous || lp->mc_count == 0) { + lp->promiscuous = 0; + lp->mc_count = 0; - /* Are we asking for promiscuous mode, - * or all multicast addresses (we don't have that!) - * or too many multicast addresses for the hardware filter? */ - if((dev->flags & IFF_PROMISC) || - (dev->flags & IFF_ALLMULTI) || - (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) - { - /* - * Enable promiscuous mode: receive all packets. - */ - if(!lp->promiscuous) - { - lp->promiscuous = 1; - lp->mc_count = 0; - - wv_82586_reconfig(dev); - - /* Tell the kernel that we are doing a really bad job. */ - dev->flags |= IFF_PROMISC; + wv_82586_reconfig(dev); + } } - } - else - /* Are there multicast addresses to send? */ - if(dev->mc_list != (struct dev_mc_list *) NULL) - { - /* - * Disable promiscuous mode, but receive all packets - * in multicast list - */ -#ifdef MULTICAST_AVOID - if(lp->promiscuous || - (dev->mc_count != lp->mc_count)) -#endif - { - lp->promiscuous = 0; - lp->mc_count = dev->mc_count; - - wv_82586_reconfig(dev); - } - } - else - { - /* - * Switch to normal mode: disable promiscuous mode and - * clear the multicast list. - */ - if(lp->promiscuous || lp->mc_count == 0) - { - lp->promiscuous = 0; - lp->mc_count = 0; - - wv_82586_reconfig(dev); - } - } #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", + dev->name); #endif } @@ -1565,23 +1499,21 @@ * (Note : it was a nice way to test the reconfigure stuff...) */ #ifdef SET_MAC_ADDRESS -static int -wavelan_set_mac_address(device * dev, - void * addr) +static int wavelan_set_mac_address(device * dev, void *addr) { - struct sockaddr * mac = addr; + struct sockaddr *mac = addr; - /* Copy the address. */ - memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); + /* Copy the address. */ + memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); - /* Reconfigure the beast. */ - wv_82586_reconfig(dev); + /* Reconfigure the beast. */ + wv_82586_reconfig(dev); - return 0; + return 0; } -#endif /* SET_MAC_ADDRESS */ +#endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ +#ifdef WIRELESS_EXT /* if wireless extensions exist in the kernel */ /*------------------------------------------------------------------*/ /* @@ -1589,232 +1521,215 @@ * It's a bit complicated and you don't really want to look into it. * (called in wavelan_ioctl) */ -static inline int -wv_set_frequency(u_long ioaddr, /* I/O port of the card */ - iw_freq * frequency) +static inline int wv_set_frequency(unsigned long ioaddr, /* I/O port of the card */ + iw_freq * frequency) { - const int BAND_NUM = 10; /* Number of bands */ - long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ + const int BAND_NUM = 10; /* Number of bands */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ #ifdef DEBUG_IOCTL_INFO - int i; + int i; #endif - /* Setting by frequency */ - /* Theoretically, you may set any frequency between - * the two limits with a 0.5 MHz precision. In practice, - * I don't want you to have trouble with local regulations. - */ - if((frequency->e == 1) && - (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) - { - freq = ((frequency->m / 10000) - 24000L) / 5; - } - - /* Setting by channel (same as wfreqsel) */ - /* Warning: each channel is 22 MHz wide, so some of the channels - * will interfere. */ - if((frequency->e == 0) && - (frequency->m >= 0) && (frequency->m < BAND_NUM)) - { - /* Get frequency offset. */ - freq = channel_bands[frequency->m] >> 1; - } - - /* Verify that the frequency is allowed. */ - if(freq != 0L) - { - u_short table[10]; /* Authorized frequency table */ - - /* Read the frequency table. */ - fee_read(ioaddr, 0x71, table, 10); + /* Setting by frequency */ + /* Theoretically, you may set any frequency between + * the two limits with a 0.5 MHz precision. In practice, + * I don't want you to have trouble with local regulations. + */ + if ((frequency->e == 1) && + (frequency->m >= (int) 2.412e8) + && (frequency->m <= (int) 2.487e8)) { + freq = ((frequency->m / 10000) - 24000L) / 5; + } -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Frequency table: "); - for(i = 0; i < 10; i++) - { - printk(" %04X", - table[i]); + /* Setting by channel (same as wfreqsel) */ + /* Warning: each channel is 22 MHz wide, so some of the channels + * will interfere. */ + if ((frequency->e == 0) && + (frequency->m >= 0) && (frequency->m < BAND_NUM)) { + /* Get frequency offset. */ + freq = channel_bands[frequency->m] >> 1; } - printk("\n"); -#endif - /* Look in the table to see whether the frequency is allowed. */ - if(!(table[9 - ((freq - 24) / 16)] & - (1 << ((freq - 24) % 16)))) - return -EINVAL; /* not allowed */ - } - else - return -EINVAL; - - /* if we get a usable frequency */ - if(freq != 0L) - { - unsigned short area[16]; - unsigned short dac[2]; - unsigned short area_verify[16]; - unsigned short dac_verify[2]; - /* Corresponding gain (in the power adjust value table) - * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 - * and WCIN062D.DOC, page 6.2.9. */ - unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; - int power_band = 0; /* Selected band */ - unsigned short power_adjust; /* Correct value */ - - /* Search for the gain. */ - power_band = 0; - while((freq > power_limit[power_band]) && - (power_limit[++power_band] != 0)) - ; - - /* Read the first area. */ - fee_read(ioaddr, 0x00, area, 16); - - /* Read the DAC. */ - fee_read(ioaddr, 0x60, dac, 2); - - /* Read the new power adjust value. */ - fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1); - if(power_band & 0x1) - power_adjust >>= 8; - else - power_adjust &= 0xFF; + /* Verify that the frequency is allowed. */ + if (freq != 0L) { + u16 table[10]; /* Authorized frequency table */ + + /* Read the frequency table. */ + fee_read(ioaddr, 0x71, table, 10); #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); - for(i = 0; i < 16; i++) - { - printk(" %04X", - area[i]); - } - printk("\n"); + printk(KERN_DEBUG "Frequency table: "); + for (i = 0; i < 10; i++) { + printk(" %04X", table[i]); + } + printk("\n"); +#endif + + /* Look in the table to see whether the frequency is allowed. */ + if (!(table[9 - ((freq - 24) / 16)] & + (1 << ((freq - 24) % 16)))) return -EINVAL; /* not allowed */ + } else + return -EINVAL; + + /* if we get a usable frequency */ + if (freq != 0L) { + unsigned short area[16]; + unsigned short dac[2]; + unsigned short area_verify[16]; + unsigned short dac_verify[2]; + /* Corresponding gain (in the power adjust value table) + * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 + * and WCIN062D.DOC, page 6.2.9. */ + unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; + int power_band = 0; /* Selected band */ + unsigned short power_adjust; /* Correct value */ + + /* Search for the gain. */ + power_band = 0; + while ((freq > power_limit[power_band]) && + (power_limit[++power_band] != 0)); + + /* Read the first area. */ + fee_read(ioaddr, 0x00, area, 16); + + /* Read the DAC. */ + fee_read(ioaddr, 0x60, dac, 2); + + /* Read the new power adjust value. */ + fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, + 1); + if (power_band & 0x1) + power_adjust >>= 8; + else + power_adjust &= 0xFF; + +#ifdef DEBUG_IOCTL_INFO + printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); + for (i = 0; i < 16; i++) { + printk(" %04X", area[i]); + } + printk("\n"); - printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", - dac[0], dac[1]); + printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", + dac[0], dac[1]); #endif - /* Frequency offset (for info only) */ - area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); + /* Frequency offset (for info only) */ + area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); - /* Receiver Principle main divider coefficient */ - area[3] = (freq >> 1) + 2400L - 352L; - area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + /* Receiver Principle main divider coefficient */ + area[3] = (freq >> 1) + 2400L - 352L; + area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); - /* Transmitter Main divider coefficient */ - area[13] = (freq >> 1) + 2400L; - area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); + /* Transmitter Main divider coefficient */ + area[13] = (freq >> 1) + 2400L; + area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); - /* Other parts of the area are flags, bit streams or unused. */ + /* Other parts of the area are flags, bit streams or unused. */ - /* Set the value in the DAC. */ - dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); - dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); + /* Set the value in the DAC. */ + dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); + dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); - /* Write the first area. */ - fee_write(ioaddr, 0x00, - area, 16); + /* Write the first area. */ + fee_write(ioaddr, 0x00, area, 16); - /* Write the DAC. */ - fee_write(ioaddr, 0x60, - dac, 2); + /* Write the DAC. */ + fee_write(ioaddr, 0x60, dac, 2); - /* We now should verify here that the writing of the EEPROM went OK. */ + /* We now should verify here that the writing of the EEPROM went OK. */ - /* Reread the first area. */ - fee_read(ioaddr, 0x00, area_verify, 16); + /* Reread the first area. */ + fee_read(ioaddr, 0x00, area_verify, 16); - /* Reread the DAC. */ - fee_read(ioaddr, 0x60, dac_verify, 2); + /* Reread the DAC. */ + fee_read(ioaddr, 0x60, dac_verify, 2); - /* Compare. */ - if(memcmp(area, area_verify, 16 * 2) || - memcmp(dac, dac_verify, 2 * 2)) - { + /* Compare. */ + if (memcmp(area, area_verify, 16 * 2) || + memcmp(dac, dac_verify, 2 * 2)) { #ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); + printk(KERN_INFO + "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); #endif - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; + } - /* We must download the frequency parameters to the - * synthesizers (from the EEPROM - area 1) - * Note: as the EEPROM is automatically decremented, we set the end - * if the area... */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - - /* Wait until the download is finished. */ - fee_wait(ioaddr, 100, 100); - - /* We must now download the power adjust value (gain) to - * the synthesizers (from the EEPROM - area 7 - DAC). */ - mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); - mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), - MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + /* We must download the frequency parameters to the + * synthesizers (from the EEPROM - area 1) + * Note: as the EEPROM is automatically decremented, we set the end + * if the area... */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); + + /* Wait until the download is finished. */ + fee_wait(ioaddr, 100, 100); + + /* We must now download the power adjust value (gain) to + * the synthesizers (from the EEPROM - area 7 - DAC). */ + mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); + mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), + MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); - /* Wait for the download to finish. */ - fee_wait(ioaddr, 100, 100); + /* Wait for the download to finish. */ + fee_wait(ioaddr, 100, 100); #ifdef DEBUG_IOCTL_INFO - /* Verification of what we have done */ + /* Verification of what we have done */ - printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); - for(i = 0; i < 16; i++) - { - printk(" %04X", - area_verify[i]); - } - printk("\n"); + printk(KERN_DEBUG "WaveLAN EEPROM Area 1: "); + for (i = 0; i < 16; i++) { + printk(" %04X", area_verify[i]); + } + printk("\n"); - printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", - dac_verify[0], dac_verify[1]); + printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", + dac_verify[0], dac_verify[1]); #endif - return 0; - } - else - return -EINVAL; /* Bah, never get there... */ + return 0; + } else + return -EINVAL; /* Bah, never get there... */ } /*------------------------------------------------------------------*/ /* * Give the list of available frequencies. */ -static inline int -wv_frequency_list(u_long ioaddr, /* I/O port of the card */ - iw_freq * list, /* List of frequencies to fill */ - int max) /* Maximum number of frequencies */ -{ - u_short table[10]; /* Authorized frequency table */ - long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ - int i; /* index in the table */ - int c = 0; /* Channel number */ - - /* Read the frequency table. */ - fee_read(ioaddr, 0x71 /* frequency table */, table, 10); - - /* Check all frequencies. */ - i = 0; - for(freq = 0; freq < 150; freq++) - /* Look in the table if the frequency is allowed */ - if(table[9 - (freq / 16)] & (1 << (freq % 16))) - { - /* Compute approximate channel number */ - while((((channel_bands[c] >> 1) - 24) < freq) && - (c < NELS(channel_bands))) - c++; - list[i].i = c; /* Set the list index */ - - /* put in the list */ - list[i].m = (((freq + 24) * 5) + 24000L) * 10000; - list[i++].e = 1; - - /* Check number. */ - if(i >= max) - return(i); - } +static inline int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ + iw_freq * list, /* List of frequencies to fill */ + int max) +{ /* Maximum number of frequencies */ + u16 table[10]; /* Authorized frequency table */ + long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ + int i; /* index in the table */ + int c = 0; /* Channel number */ + + /* Read the frequency table. */ + fee_read(ioaddr, 0x71 /* frequency table */ , table, 10); + + /* Check all frequencies. */ + i = 0; + for (freq = 0; freq < 150; freq++) + /* Look in the table if the frequency is allowed */ + if (table[9 - (freq / 16)] & (1 << (freq % 16))) { + /* Compute approximate channel number */ + while ((((channel_bands[c] >> 1) - 24) < freq) && + (c < NELS(channel_bands))) + c++; + list[i].i = c; /* Set the list index */ + + /* put in the list */ + list[i].m = (((freq + 24) * 5) + 24000L) * 10000; + list[i++].e = 1; + + /* Check number. */ + if (i >= max) + return (i); + } - return(i); + return (i); } #ifdef WIRELESS_SPY @@ -1824,27 +1739,24 @@ * address with our list, and if they match, get the statistics. * Sorry, but this function really needs the wireless extensions. */ -static inline void -wl_spy_gather(device * dev, - u_char * mac, /* MAC address */ - u_char * stats) /* Statistics to gather */ -{ - net_local * lp = (net_local *) dev->priv; - int i; - - /* Check all addresses. */ - for(i = 0; i < lp->spy_number; i++) - /* If match */ - if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) - { - /* Update statistics */ - lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; - lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; - lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; - lp->spy_stat[i].updated = 0x7; - } +static inline void wl_spy_gather(device * dev, u8 * mac, /* MAC address */ + u8 * stats) +{ /* Statistics to gather */ + net_local *lp = (net_local *) dev->priv; + int i; + + /* Check all addresses. */ + for (i = 0; i < lp->spy_number; i++) + /* If match */ + if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) { + /* Update statistics */ + lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; + lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; + lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; + lp->spy_stat[i].updated = 0x7; + } } -#endif /* WIRELESS_SPY */ +#endif /* WIRELESS_SPY */ #ifdef HISTOGRAM /*------------------------------------------------------------------*/ @@ -1856,494 +1768,516 @@ * With this histogram you may detect if one WaveLAN is really weak, * or you may also calculate the mean and standard deviation of the level. */ -static inline void -wl_his_gather(device * dev, - u_char * stats) /* Statistics to gather */ -{ - net_local * lp = (net_local *) dev->priv; - u_char level = stats[0] & MMR_SIGNAL_LVL; - int i; - - /* Find the correct interval. */ - i = 0; - while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) - ; +static inline void wl_his_gather(device * dev, u8 * stats) +{ /* Statistics to gather */ + net_local *lp = (net_local *) dev->priv; + u8 level = stats[0] & MMR_SIGNAL_LVL; + int i; + + /* Find the correct interval. */ + i = 0; + while ((i < (lp->his_number - 1)) + && (level >= lp->his_range[i++])); - /* Increment interval counter. */ - (lp->his_sum[i])++; + /* Increment interval counter. */ + (lp->his_sum[i])++; } -#endif /* HISTOGRAM */ +#endif /* HISTOGRAM */ /*------------------------------------------------------------------*/ /* * Perform ioctl for configuration and information. * It is here that the wireless extensions are treated (iwconfig). */ -static int -wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied */ - struct ifreq * rq, /* data passed */ - int cmd) /* ioctl number */ -{ - u_long ioaddr = dev->base_addr; - net_local * lp = (net_local *)dev->priv; /* lp is not unused */ - struct iwreq * wrq = (struct iwreq *) rq; - psa_t psa; - mm_t m; - unsigned long x; - int ret = 0; +static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ + struct ifreq *rq, /* data passed */ + int cmd) +{ /* ioctl number */ + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + struct iwreq *wrq = (struct iwreq *) rq; + psa_t psa; + mm_t m; + unsigned long flags; + int ret = 0; #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); + printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, + cmd); #endif - /* Disable interrupts and save flags. */ - x = wv_splhi(); - - /* Look what is the request */ - switch(cmd) - { - /* --------------- WIRELESS EXTENSIONS --------------- */ - - case SIOCGIWNAME: - strcpy(wrq->u.name, "WaveLAN"); - break; - - case SIOCSIWNWID: - /* Set NWID in WaveLAN. */ - if(!wrq->u.nwid.disabled) - { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; - psa.psa_nwid_select = 0x01; - psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 3); - - /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = psa.psa_nwid[1]; - m.w.mmw_netw_id_h = psa.psa_nwid[0]; - mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m, - (unsigned char *)&m.w.mmw_netw_id_l, 2); - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); - } - else - { - /* Disable NWID in the psa. */ - psa.psa_nwid_select = 0x00; - psa_write(ioaddr, lp->hacr, - (char *)&psa.psa_nwid_select - (char *)&psa, - (unsigned char *)&psa.psa_nwid_select, 1); - - /* Disable NWID in the mmc (no filtering). */ - mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - break; - - case SIOCGIWNWID: - /* Read the NWID. */ - psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 3); - wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.disabled = !(psa.psa_nwid_select); - wrq->u.nwid.fixed = 1; /* Superfluous */ - break; - - case SIOCSIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); - else - ret = -EOPNOTSUPP; - break; - - case SIOCGIWFREQ: - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). - * Does it work for everybody, especially old cards? */ - if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - unsigned short freq; - - /* Ask the EEPROM to read the frequency from the first area. */ - fee_read(ioaddr, 0x00, &freq, 1); - wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; - wrq->u.freq.e = 1; - } - else - { - psa_read(ioaddr, lp->hacr, (char *)&psa.psa_subband - (char *)&psa, - (unsigned char *)&psa.psa_subband, 1); - - if(psa.psa_subband <= 4) - { - wrq->u.freq.m = fixed_bands[psa.psa_subband]; - wrq->u.freq.e = (psa.psa_subband != 0); - } - else - ret = -EOPNOTSUPP; - } - break; - - case SIOCSIWSENS: - /* Set the level threshold. */ - /* We should complain loudly if wrq->u.sens.fixed = 0, because we - * can't set auto mode... */ - psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; - psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); - break; - - case SIOCGIWSENS: - /* Read the level threshold. */ - psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *) &psa.psa_thr_pre_set, 1); - wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; - wrq->u.sens.fixed = 1; - break; - - case SIOCSIWENCODE: - /* Set encryption key */ - if(!mmc_encr(ioaddr)) - { - ret = -EOPNOTSUPP; - break; - } - - /* Basic checking... */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - /* Check the size of the key */ - if(wrq->u.encoding.length != 8) - { - ret = -EINVAL; - break; - } - - /* Copy the key in the driver */ - if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, - wrq->u.encoding.length)) - { - ret = -EFAULT; - break; - } - - psa.psa_encryption_select = 1; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 8+1); - - mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); - mmc_write(ioaddr, mmwoff(0, mmw_encr_key), - (unsigned char *) &psa.psa_encryption_key, 8); - } - - if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) - { /* disable encryption */ - psa.psa_encryption_select = 0; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1); - - mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - break; - - case SIOCGIWENCODE: - /* Read the encryption key */ - if(!mmc_encr(ioaddr)) - { - ret = -EOPNOTSUPP; - break; - } - - /* only super-user can see encryption key */ - if(!suser()) - { - ret = -EPERM; - break; - } - - /* Basic checking... */ - if(wrq->u.encoding.pointer != (caddr_t) 0) - { - /* Verify the user buffer */ - ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8); - if(ret) - break; - - psa_read(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1+8); - - /* encryption is enabled ? */ - if(psa.psa_encryption_select) - wrq->u.encoding.flags = IW_ENCODE_ENABLED; - else - wrq->u.encoding.flags = IW_ENCODE_DISABLED; - wrq->u.encoding.flags |= mmc_encr(ioaddr); - - /* Copy the key to the user buffer */ - wrq->u.encoding.length = 8; - if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) - ret = -EFAULT; - } - break; - - case SIOCGIWRANGE: - /* basic checking */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - struct iw_range range; - - /* Set the length (useless: it's constant). */ - wrq->u.data.length = sizeof(struct iw_range); - - /* Set information in the range struct. */ - range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ - range.min_nwid = 0x0000; - range.max_nwid = 0xFFFF; - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ - if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - range.num_channels = 10; - range.num_frequency = wv_frequency_list(ioaddr, range.freq, + /* Disable interrupts and save flags. */ + save_flags(flags); + cli(); + /* FIXME: can't copy*user when cli this is broken! */ + + /* Look what is the request */ + switch (cmd) { + /* --------------- WIRELESS EXTENSIONS --------------- */ + + case SIOCGIWNAME: + strcpy(wrq->u.name, "WaveLAN"); + break; + + case SIOCSIWNWID: + /* Set NWID in WaveLAN. */ + if (!wrq->u.nwid.disabled) { + /* Set NWID in psa */ + psa.psa_nwid[0] = + (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; + psa.psa_nwid_select = 0x01; + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + + /* Set NWID in mmc. */ + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; + mmc_write(ioaddr, + (char *) &m.w.mmw_netw_id_l - + (char *) &m, + (unsigned char *) &m.w.mmw_netw_id_l, 2); + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); + } else { + /* Disable NWID in the psa. */ + psa.psa_nwid_select = 0x00; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_nwid_select - + (char *) &psa, + (unsigned char *) &psa.psa_nwid_select, + 1); + + /* Disable NWID in the mmc (no filtering). */ + mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), + MMW_LOOPT_SEL_DIS_NWID); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + break; + + case SIOCGIWNWID: + /* Read the NWID. */ + psa_read(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 3); + wrq->u.nwid.value = + (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ + break; + + case SIOCSIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) + ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); + else + ret = -EOPNOTSUPP; + break; + + case SIOCGIWFREQ: + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). + * Does it work for everybody, especially old cards? */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + unsigned short freq; + + /* Ask the EEPROM to read the frequency from the first area. */ + fee_read(ioaddr, 0x00, &freq, 1); + wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; + wrq->u.freq.e = 1; + } else { + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_subband - (char *) &psa, + (unsigned char *) &psa.psa_subband, 1); + + if (psa.psa_subband <= 4) { + wrq->u.freq.m = + fixed_bands[psa.psa_subband]; + wrq->u.freq.e = (psa.psa_subband != 0); + } else + ret = -EOPNOTSUPP; + } + break; + + case SIOCSIWSENS: + /* Set the level threshold. */ + /* We should complain loudly if wrq->u.sens.fixed = 0, because we + * can't set auto mode... */ + psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), + psa.psa_thr_pre_set); + break; + + case SIOCGIWSENS: + /* Read the level threshold. */ + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; + wrq->u.sens.fixed = 1; + break; + + case SIOCSIWENCODE: + /* Set encryption key */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + break; + } + + /* Basic checking... */ + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Check the size of the key */ + if (wrq->u.encoding.length != 8) { + ret = -EINVAL; + break; + } + + /* Copy the key in the driver */ + if (copy_from_user + (psa.psa_encryption_key, + wrq->u.encoding.pointer, + wrq->u.encoding.length)) { + ret = -EFAULT; + break; + } + + psa.psa_encryption_select = 1; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 8 + 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(ioaddr, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa. + psa_encryption_key, 8); + } + + if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ + psa.psa_encryption_select = 0; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + break; + + case SIOCGIWENCODE: + /* Read the encryption key */ + if (!mmc_encr(ioaddr)) { + ret = -EOPNOTSUPP; + break; + } + + /* only super-user can see encryption key */ + if (!suser()) { + ret = -EPERM; + break; + } + + /* Basic checking... */ + if (wrq->u.encoding.pointer != (caddr_t) 0) { + /* Verify the user buffer */ + ret = + verify_area(VERIFY_WRITE, + wrq->u.encoding.pointer, 8); + if (ret) + break; + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - + (char *) &psa, + (unsigned char *) &psa. + psa_encryption_select, 1 + 8); + + /* encryption is enabled ? */ + if (psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(ioaddr); + + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + if (copy_to_user + (wrq->u.encoding.pointer, + psa.psa_encryption_key, 8)) ret = -EFAULT; + } + break; + + case SIOCGIWRANGE: + /* basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) { + struct iw_range range; + + /* Set the length (useless: it's constant). */ + wrq->u.data.length = sizeof(struct iw_range); + + /* Set information in the range struct. */ + range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ + range.min_nwid = 0x0000; + range.max_nwid = 0xFFFF; + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + range.num_channels = 10; + range.num_frequency = + wv_frequency_list(ioaddr, range.freq, IW_MAX_FREQUENCIES); - } - else - range.num_channels = range.num_frequency = 0; - - range.sensitivity = 0x3F; - range.max_qual.qual = MMR_SGNL_QUAL; - range.max_qual.level = MMR_SIGNAL_LVL; - range.max_qual.noise = MMR_SILENCE_LVL; - - range.num_bitrates = 1; - range.bitrate[0] = 2000000; /* 2 Mb/s */ - - /* Encryption supported ? */ - if(mmc_encr(ioaddr)) - { - range.encoding_size[0] = 8; /* DES = 64 bits key */ - range.num_encoding_sizes = 1; - range.max_encoding_tokens = 1; /* Only one key possible */ - } - else - { - range.num_encoding_sizes = 0; - range.max_encoding_tokens = 0; - } - - /* Copy structure to the user buffer. */ - if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) - ret = -EFAULT; - } - break; - - case SIOCGIWPRIV: - /* Basic checking */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - struct iw_priv_args priv[] = - { /* cmd, set_args, get_args, name */ - { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, - { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, - - { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, - { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, - }; - - /* Set the number of available ioctls. */ - wrq->u.data.length = 4; - - /* Copy structure to the user buffer. */ - if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv))) - ret = -EFAULT; - } - break; + } else + range.num_channels = range.num_frequency = + 0; + + range.sensitivity = 0x3F; + range.max_qual.qual = MMR_SGNL_QUAL; + range.max_qual.level = MMR_SIGNAL_LVL; + range.max_qual.noise = MMR_SILENCE_LVL; + + range.num_bitrates = 1; + range.bitrate[0] = 2000000; /* 2 Mb/s */ + + /* Encryption supported ? */ + if (mmc_encr(ioaddr)) { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + + /* Copy structure to the user buffer. */ + if (copy_to_user + (wrq->u.data.pointer, &range, + sizeof(struct iw_range))) ret = -EFAULT; + } + break; + + case SIOCGIWPRIV: + /* Basic checking */ + if (wrq->u.data.pointer != (caddr_t) 0) { + struct iw_priv_args priv[] = { /* cmd, set_args, get_args, name */ + + {SIOCSIPQTHR, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | + 1, 0, "setqualthr"}, + {SIOCGIPQTHR, 0, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | + 1, "getqualthr"}, + + + {SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, + 0, "sethisto"}, + {SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, + "gethisto"}, + }; + + /* Set the number of available ioctls. */ + wrq->u.data.length = 4; + + /* Copy structure to the user buffer. */ + if (copy_to_user + (wrq->u.data.pointer, (u8 *) priv, + sizeof(priv))) ret = -EFAULT; + } + break; #ifdef WIRELESS_SPY - case SIOCSIWSPY: - /* Set the spy list */ - - /* Check the number of addresses. */ - if(wrq->u.data.length > IW_MAX_SPY) - { - ret = -E2BIG; - break; - } - lp->spy_number = wrq->u.data.length; - - /* Are there are addresses to copy? */ - if(lp->spy_number > 0) - { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses to the driver. */ - if (copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number)) { - ret = -EFAULT; - break; - } - - /* Copy addresses to the lp structure. */ - for(i = 0; i < lp->spy_number; i++) - { - memcpy(lp->spy_address[i], address[i].sa_data, - WAVELAN_ADDR_SIZE); - } + case SIOCSIWSPY: + /* Set the spy list */ - /* Reset structure. */ - memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); + /* Check the number of addresses. */ + if (wrq->u.data.length > IW_MAX_SPY) { + ret = -E2BIG; + break; + } + lp->spy_number = wrq->u.data.length; + + /* Are there are addresses to copy? */ + if (lp->spy_number > 0) { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses to the driver. */ + if (copy_from_user + (address, wrq->u.data.pointer, + sizeof(struct sockaddr) * lp->spy_number)) { + ret = -EFAULT; + break; + } + + /* Copy addresses to the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(lp->spy_address[i], + address[i].sa_data, + WAVELAN_ADDR_SIZE); + } + + /* Reset structure. */ + memset(lp->spy_stat, 0x00, + sizeof(iw_qual) * IW_MAX_SPY); #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "SetSpy: set of new addresses is: \n"); - for(i = 0; i < wrq->u.data.length; i++) - printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } - - break; - - case SIOCGIWSPY: - /* Get the spy list and spy stats. */ - - /* Set the number of addresses */ - wrq->u.data.length = lp->spy_number; - - /* Does the user want to have the addresses back? */ - if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) - { - struct sockaddr address[IW_MAX_SPY]; - int i; - - /* Copy addresses from the lp structure. */ - for(i = 0; i < lp->spy_number; i++) - { - memcpy(address[i].sa_data, lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = AF_UNIX; - } - - /* Copy addresses to the user buffer. */ - if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number)) { - ret = -EFAULT; - break; - } - - /* Copy stats to the user buffer (just after). */ - if (copy_to_user(wrq->u.data.pointer + - (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) { - ret = -EFAULT; - break; - } - - /* Reset updated flags. */ - for(i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - } /* if(pointer != NULL) */ - - break; -#endif /* WIRELESS_SPY */ - - /* ------------------ PRIVATE IOCTL ------------------ */ - - case SIOCSIPQTHR: - if(!suser()) - { - ret = -EPERM; - break; - } - psa.psa_quality_thr = *(wrq->u.name) & 0x0F; - psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); - break; - - case SIOCGIPQTHR: - psa_read(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - *(wrq->u.name) = psa.psa_quality_thr & 0x0F; - break; + printk(KERN_DEBUG + "SetSpy: set of new addresses is: \n"); + for (i = 0; i < wrq->u.data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + lp->spy_address[i][0], + lp->spy_address[i][1], + lp->spy_address[i][2], + lp->spy_address[i][3], + lp->spy_address[i][4], + lp->spy_address[i][5]); +#endif /* DEBUG_IOCTL_INFO */ + } + + break; + + case SIOCGIWSPY: + /* Get the spy list and spy stats. */ + + /* Set the number of addresses */ + wrq->u.data.length = lp->spy_number; + + /* Does the user want to have the addresses back? */ + if ((lp->spy_number > 0) + && (wrq->u.data.pointer != (caddr_t) 0)) { + struct sockaddr address[IW_MAX_SPY]; + int i; + + /* Copy addresses from the lp structure. */ + for (i = 0; i < lp->spy_number; i++) { + memcpy(address[i].sa_data, + lp->spy_address[i], + WAVELAN_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } + + /* Copy addresses to the user buffer. */ + if (copy_to_user + (wrq->u.data.pointer, address, + sizeof(struct sockaddr) * lp->spy_number)) { + ret = -EFAULT; + break; + } + + /* Copy stats to the user buffer (just after). */ + if (copy_to_user(wrq->u.data.pointer + + (sizeof(struct sockaddr) * + lp->spy_number), lp->spy_stat, + sizeof(iw_qual) * lp->spy_number)) { + ret = -EFAULT; + break; + } + + /* Reset updated flags. */ + for (i = 0; i < lp->spy_number; i++) + lp->spy_stat[i].updated = 0x0; + } + /* if(pointer != NULL) */ + break; +#endif /* WIRELESS_SPY */ + + /* ------------------ PRIVATE IOCTL ------------------ */ + + case SIOCSIPQTHR: + if (!suser()) { + ret = -EPERM; + break; + } + psa.psa_quality_thr = *(wrq->u.name) & 0x0F; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), + psa.psa_quality_thr); + break; + + case SIOCGIPQTHR: + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + *(wrq->u.name) = psa.psa_quality_thr & 0x0F; + break; #ifdef HISTOGRAM - case SIOCSIPHISTO: - /* Verify that the user is root. */ - if(!suser()) - { - ret = -EPERM; - break; - } - - /* Check the number of intervals. */ - if(wrq->u.data.length > 16) - { - ret = -E2BIG; - break; - } - lp->his_number = wrq->u.data.length; + case SIOCSIPHISTO: + /* Verify that the user is root. */ + if (!suser()) { + ret = -EPERM; + break; + } + + /* Check the number of intervals. */ + if (wrq->u.data.length > 16) { + ret = -E2BIG; + break; + } + lp->his_number = wrq->u.data.length; + + /* Are there addresses to copy? */ + if (lp->his_number > 0) { + /* Copy interval ranges to the driver */ + if (copy_from_user + (lp->his_range, wrq->u.data.pointer, + sizeof(char) * lp->his_number)) { + ret = -EFAULT; + break; + } + + /* Reset structure. */ + memset(lp->his_sum, 0x00, sizeof(long) * 16); + } + break; + + case SIOCGIPHISTO: + /* Set the number of intervals. */ + wrq->u.data.length = lp->his_number; + + /* Give back the distribution statistics */ + if ((lp->his_number > 0) + && (wrq->u.data.pointer != (caddr_t) 0)) { + /* Copy data to the user buffer. */ + if (copy_to_user + (wrq->u.data.pointer, lp->his_sum, + sizeof(long) * lp->his_number)) + ret = -EFAULT; + + } /* if(pointer != NULL) */ + break; +#endif /* HISTOGRAM */ - /* Are there addresses to copy? */ - if(lp->his_number > 0) - { - /* Copy interval ranges to the driver */ - if (copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number)) { - ret = -EFAULT; - break; - } - - /* Reset structure. */ - memset(lp->his_sum, 0x00, sizeof(long) * 16); - } - break; - - case SIOCGIPHISTO: - /* Set the number of intervals. */ - wrq->u.data.length = lp->his_number; + /* ------------------- OTHER IOCTL ------------------- */ - /* Give back the distribution statistics */ - if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) - { - /* Copy data to the user buffer. */ - if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number)) - ret = -EFAULT; - - } /* if(pointer != NULL) */ - break; -#endif /* HISTOGRAM */ - - /* ------------------- OTHER IOCTL ------------------- */ - - default: - ret = -EOPNOTSUPP; - } + default: + ret = -EOPNOTSUPP; + } - /* Enable interrupts and restore flags. */ - wv_splx(x); + /* Enable interrupts and restore flags. */ + restore_flags(flags); #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); #endif - return ret; + return ret; } /*------------------------------------------------------------------*/ @@ -2351,56 +2285,64 @@ * Get wireless statistics. * Called by /proc/net/wireless */ -static iw_stats * -wavelan_get_wireless_stats(device * dev) +static iw_stats *wavelan_get_wireless_stats(device * dev) { - u_long ioaddr = dev->base_addr; - net_local * lp = (net_local *) dev->priv; - mmr_t m; - iw_stats * wstats; - unsigned long x; + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + mmr_t m; + iw_stats *wstats; + unsigned long flags; #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); + printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", + dev->name); #endif - /* Disable interrupts and save flags. */ - x = wv_splhi(); + /* Disable interrupts and save flags. */ + save_flags(flags); + cli(); + + if (lp == (net_local *) NULL) + { + restore_flags(flags); + return (iw_stats *) NULL; + } + + wstats = &lp->wstats; + + /* Get data from the mmc. */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - if(lp == (net_local *) NULL) - return (iw_stats *) NULL; - wstats = &lp->wstats; - - /* Get data from the mmc. */ - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - - mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); - mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); - mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); - - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); - - /* Copy data to wireless stuff. */ - wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; - wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; - wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; - wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; - wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | - ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | - ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); - wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; - wstats->discard.code = 0L; - wstats->discard.misc = 0L; + mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); + mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, + 2); + mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, + 4); + + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + + /* Copy data to wireless stuff. */ + wstats->status = m.mmr_dce_status & MMR_DCE_STATUS; + wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; + wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; + wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; + wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) + | ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) + | ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); + wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; + wstats->discard.code = 0L; + wstats->discard.misc = 0L; - /* Enable interrupts and restore flags. */ - wv_splx(x); + /* Enable interrupts and restore flags. */ + restore_flags(flags); #ifdef DEBUG_IOCTL_TRACE - printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", + dev->name); #endif - return &lp->wstats; + return &lp->wstats; } -#endif /* WIRELESS_EXT */ +#endif /* WIRELESS_EXT */ /************************* PACKET RECEPTION *************************/ /* @@ -2423,90 +2365,90 @@ * (called by wv_packet_rcv()) */ static inline void -wv_packet_read(device * dev, - u_short buf_off, - int sksize) -{ - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - struct sk_buff * skb; +wv_packet_read(device * dev, u16 buf_off, int sksize) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + struct sk_buff *skb; #ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", - dev->name, buf_off, sksize); + printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", + dev->name, buf_off, sksize); #endif - /* Allocate buffer for the data */ - if((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) - { + /* Allocate buffer for the data */ + if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) { #ifdef DEBUG_RX_ERROR - printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", - dev->name, sksize); + printk(KERN_INFO + "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", + dev->name, sksize); #endif - lp->stats.rx_dropped++; - return; - } - - skb->dev = dev; - - /* Copy the packet to the buffer. */ - obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); - skb->protocol=eth_type_trans(skb, dev); + lp->stats.rx_dropped++; + return; + } + + skb->dev = dev; + + /* Copy the packet to the buffer. */ + obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); + skb->protocol = eth_type_trans(skb, dev); #ifdef DEBUG_RX_INFO - wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); -#endif /* DEBUG_RX_INFO */ + wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); +#endif /* DEBUG_RX_INFO */ - /* Statistics-gathering and associated stuff. - * It seem a bit messy with all the define, but it's really simple... */ + /* Statistics-gathering and associated stuff. + * It seem a bit messy with all the define, but it's really simple... */ #if defined(WIRELESS_SPY) || defined(HISTOGRAM) - if( + if ( #ifdef WIRELESS_SPY - (lp->spy_number > 0) || -#endif /* WIRELESS_SPY */ + (lp->spy_number > 0) || +#endif /* WIRELESS_SPY */ #ifdef HISTOGRAM - (lp->his_number > 0) || -#endif /* HISTOGRAM */ - 0) - { - u_char stats[3]; /* signal level, noise level, signal quality */ - - /* Read signal level, silence level and signal quality bytes. */ - /* Note: in the PCMCIA hardware, these are part of the frame. It seems - * that for the ISA hardware, it's nowhere to be found in the frame, - * so I'm obliged to do this (it has a side effect on /proc/net/wireless). - * Any ideas? - */ - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); - mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); - mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); + (lp->his_number > 0) || +#endif /* HISTOGRAM */ + 0) { + u8 stats[3]; /* signal level, noise level, signal quality */ + + /* Read signal level, silence level and signal quality bytes. */ + /* Note: in the PCMCIA hardware, these are part of the frame. It seems + * that for the ISA hardware, it's nowhere to be found in the frame, + * so I'm obliged to do this (it has a side effect on /proc/net/wireless). + * Any ideas? + */ + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); + mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); + mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); #ifdef DEBUG_RX_INFO - printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", - dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); + printk(KERN_DEBUG + "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", + dev->name, stats[0] & 0x3F, stats[1] & 0x3F, + stats[2] & 0x0F); #endif - /* Spying stuff */ + /* Spying stuff */ #ifdef WIRELESS_SPY - wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); -#endif /* WIRELESS_SPY */ + wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, + stats); +#endif /* WIRELESS_SPY */ #ifdef HISTOGRAM - wl_his_gather(dev, stats); -#endif /* HISTOGRAM */ - } -#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */ - - /* - * Hand the packet to the network module. - */ - netif_rx(skb); - - /* Keep statistics up to date */ - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + wl_his_gather(dev, stats); +#endif /* HISTOGRAM */ + } +#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */ + + /* + * Hand the packet to the network module. + */ + netif_rx(skb); + + /* Keep statistics up to date */ + lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; #ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); #endif } @@ -2516,150 +2458,160 @@ * from the device RAM. * Called by the interrupt handler. */ -static inline void -wv_receive(device * dev) +static inline void wv_receive(device * dev) { - u_long ioaddr = dev->base_addr; - net_local * lp = (net_local *)dev->priv; - fd_t fd; - rbd_t rbd; - int nreaped = 0; + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + fd_t fd; + rbd_t rbd; + int nreaped = 0; #ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); #endif - /* Loop on each received packet. */ - for(;;) - { - obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd)); - - /* Note about the status : - * It start up to be 0 (the value we set). Then, when the RU - * grab the buffer to prepare for reception, it sets the - * FD_STATUS_B flag. When the RU has finished receiving the - * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate - * completion and set the other flags to indicate the eventual - * errors. FD_STATUS_OK indicates that the reception was OK. - */ - - /* If the current frame is not complete, we have reached the end. */ - if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) - break; /* This is how we exit the loop. */ - - nreaped++; - - /* Check whether frame was correctly received. */ - if((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) - { - /* Does the frame contain a pointer to the data? Let's check. */ - if(fd.fd_rbd_offset != I82586NULL) - { - /* Read the receive buffer descriptor */ - obram_read(ioaddr, fd.fd_rbd_offset, - (unsigned char *) &rbd, sizeof(rbd)); + /* Loop on each received packet. */ + for (;;) { + obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, + sizeof(fd)); + + /* Note about the status : + * It start up to be 0 (the value we set). Then, when the RU + * grab the buffer to prepare for reception, it sets the + * FD_STATUS_B flag. When the RU has finished receiving the + * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate + * completion and set the other flags to indicate the eventual + * errors. FD_STATUS_OK indicates that the reception was OK. + */ + + /* If the current frame is not complete, we have reached the end. */ + if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) + break; /* This is how we exit the loop. */ + + nreaped++; + + /* Check whether frame was correctly received. */ + if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) { + /* Does the frame contain a pointer to the data? Let's check. */ + if (fd.fd_rbd_offset != I82586NULL) { + /* Read the receive buffer descriptor */ + obram_read(ioaddr, fd.fd_rbd_offset, + (unsigned char *) &rbd, + sizeof(rbd)); #ifdef DEBUG_RX_ERROR - if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF) - printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n", - dev->name); - - if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F) - printk(KERN_INFO "%s: wv_receive(): missing F flag.\n", - dev->name); -#endif /* DEBUG_RX_ERROR */ - - /* Read the packet and transmit to Linux */ - wv_packet_read(dev, rbd.rbd_bufl, - rbd.rbd_status & RBD_STATUS_ACNT); - } + if ((rbd.rbd_status & RBD_STATUS_EOF) != + RBD_STATUS_EOF) printk(KERN_INFO + "%s: wv_receive(): missing EOF flag.\n", + dev->name); + + if ((rbd.rbd_status & RBD_STATUS_F) != + RBD_STATUS_F) printk(KERN_INFO + "%s: wv_receive(): missing F flag.\n", + dev->name); +#endif /* DEBUG_RX_ERROR */ + + /* Read the packet and transmit to Linux */ + wv_packet_read(dev, rbd.rbd_bufl, + rbd. + rbd_status & + RBD_STATUS_ACNT); + } #ifdef DEBUG_RX_ERROR - else /* if frame has no data */ - printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", - dev->name); + else /* if frame has no data */ + printk(KERN_INFO + "%s: wv_receive(): frame has no data.\n", + dev->name); #endif - } - else /* If reception was no successful */ - { - lp->stats.rx_errors++; + } else { /* If reception was no successful */ + + lp->stats.rx_errors++; #ifdef DEBUG_RX_INFO - printk(KERN_DEBUG "%s: wv_receive(): frame not received successfully (%X).\n", - dev->name, fd.fd_status); + printk(KERN_DEBUG + "%s: wv_receive(): frame not received successfully (%X).\n", + dev->name, fd.fd_status); #endif #ifdef DEBUG_RX_ERROR - if((fd.fd_status & FD_STATUS_S6) != 0) - printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name); + if ((fd.fd_status & FD_STATUS_S6) != 0) + printk(KERN_INFO + "%s: wv_receive(): no EOF flag.\n", + dev->name); #endif - if((fd.fd_status & FD_STATUS_S7) != 0) - { - lp->stats.rx_length_errors++; + if ((fd.fd_status & FD_STATUS_S7) != 0) { + lp->stats.rx_length_errors++; #ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG "%s: wv_receive(): frame too short.\n", - dev->name); + printk(KERN_DEBUG + "%s: wv_receive(): frame too short.\n", + dev->name); #endif - } + } - if((fd.fd_status & FD_STATUS_S8) != 0) - { - lp->stats.rx_over_errors++; + if ((fd.fd_status & FD_STATUS_S8) != 0) { + lp->stats.rx_over_errors++; #ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG "%s: wv_receive(): rx DMA overrun.\n", - dev->name); + printk(KERN_DEBUG + "%s: wv_receive(): rx DMA overrun.\n", + dev->name); #endif - } + } - if((fd.fd_status & FD_STATUS_S9) != 0) - { - lp->stats.rx_fifo_errors++; + if ((fd.fd_status & FD_STATUS_S9) != 0) { + lp->stats.rx_fifo_errors++; #ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG "%s: wv_receive(): ran out of resources.\n", - dev->name); + printk(KERN_DEBUG + "%s: wv_receive(): ran out of resources.\n", + dev->name); #endif - } + } - if((fd.fd_status & FD_STATUS_S10) != 0) - { - lp->stats.rx_frame_errors++; + if ((fd.fd_status & FD_STATUS_S10) != 0) { + lp->stats.rx_frame_errors++; #ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG "%s: wv_receive(): alignment error.\n", - dev->name); + printk(KERN_DEBUG + "%s: wv_receive(): alignment error.\n", + dev->name); #endif - } + } - if((fd.fd_status & FD_STATUS_S11) != 0) - { - lp->stats.rx_crc_errors++; + if ((fd.fd_status & FD_STATUS_S11) != 0) { + lp->stats.rx_crc_errors++; #ifdef DEBUG_RX_FAIL - printk(KERN_DEBUG "%s: wv_receive(): CRC error.\n", dev->name); -#endif - } - } - - fd.fd_status = 0; - obram_write(ioaddr, fdoff(lp->rx_head, fd_status), - (unsigned char *) &fd.fd_status, sizeof(fd.fd_status)); - - fd.fd_command = FD_COMMAND_EL; - obram_write(ioaddr, fdoff(lp->rx_head, fd_command), - (unsigned char *) &fd.fd_command, sizeof(fd.fd_command)); - - fd.fd_command = 0; - obram_write(ioaddr, fdoff(lp->rx_last, fd_command), - (unsigned char *) &fd.fd_command, sizeof(fd.fd_command)); - - lp->rx_last = lp->rx_head; - lp->rx_head = fd.fd_link_offset; - } /* for(;;) -> loop on all frames */ + printk(KERN_DEBUG + "%s: wv_receive(): CRC error.\n", + dev->name); +#endif + } + } + + fd.fd_status = 0; + obram_write(ioaddr, fdoff(lp->rx_head, fd_status), + (unsigned char *) &fd.fd_status, + sizeof(fd.fd_status)); + + fd.fd_command = FD_COMMAND_EL; + obram_write(ioaddr, fdoff(lp->rx_head, fd_command), + (unsigned char *) &fd.fd_command, + sizeof(fd.fd_command)); + + fd.fd_command = 0; + obram_write(ioaddr, fdoff(lp->rx_last, fd_command), + (unsigned char *) &fd.fd_command, + sizeof(fd.fd_command)); + + lp->rx_last = lp->rx_head; + lp->rx_head = fd.fd_link_offset; + } /* for(;;) -> loop on all frames */ #ifdef DEBUG_RX_INFO - if(nreaped > 1) - printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", dev->name, nreaped); + if (nreaped > 1) + printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", + dev->name, nreaped); #endif #ifdef DEBUG_RX_TRACE - printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); #endif } @@ -2689,130 +2641,124 @@ * * (called in wavelan_packet_xmit()) */ -static inline void -wv_packet_write(device * dev, - void * buf, - short length) -{ - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - unsigned short txblock; - unsigned short txpred; - unsigned short tx_addr; - unsigned short nop_addr; - unsigned short tbd_addr; - unsigned short buf_addr; - ac_tx_t tx; - ac_nop_t nop; - tbd_t tbd; - int clen = length; - unsigned long x; +static inline void wv_packet_write(device * dev, void *buf, short length) +{ + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + unsigned short txblock; + unsigned short txpred; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short buf_addr; + ac_tx_t tx; + ac_nop_t nop; + tbd_t tbd; + int clen = length; + unsigned long flags; #ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); + printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, + length); #endif - /* Do we need some padding? */ - if(clen < ETH_ZLEN) - clen = ETH_ZLEN; - - x = wv_splhi(); - - /* Calculate addresses of next block and previous block. */ - txblock = lp->tx_first_free; - txpred = txblock - TXBLOCKZ; - if(txpred < OFFSET_CU) - txpred += NTXBLOCKS * TXBLOCKZ; - lp->tx_first_free += TXBLOCKZ; - if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + /* Do we need some padding? */ + if (clen < ETH_ZLEN) + clen = ETH_ZLEN; + + save_flags(flags); + cli(); + + /* Calculate addresses of next block and previous block. */ + txblock = lp->tx_first_free; + txpred = txblock - TXBLOCKZ; + if (txpred < OFFSET_CU) + txpred += NTXBLOCKS * TXBLOCKZ; + lp->tx_first_free += TXBLOCKZ; + if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + + lp->tx_n_in_use++; + + /* Calculate addresses of the different parts of the block. */ + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + buf_addr = tbd_addr + sizeof(tbd); -/* -if (lp->tx_n_in_use > 0) - printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); -*/ + /* + * Transmit command + */ + tx.tx_h.ac_status = 0; + obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), + (unsigned char *) &tx.tx_h.ac_status, + sizeof(tx.tx_h.ac_status)); + + /* + * NOP command + */ + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); - lp->tx_n_in_use++; + /* + * Transmit buffer descriptor + */ + tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); + tbd.tbd_next_bd_offset = I82586NULL; + tbd.tbd_bufl = buf_addr; + tbd.tbd_bufh = 0; + obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); - /* Calculate addresses of the different parts of the block. */ - tx_addr = txblock; - nop_addr = tx_addr + sizeof(tx); - tbd_addr = nop_addr + sizeof(nop); - buf_addr = tbd_addr + sizeof(tbd); - - /* - * Transmit command - */ - tx.tx_h.ac_status = 0; - obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), - (unsigned char *) &tx.tx_h.ac_status, - sizeof(tx.tx_h.ac_status)); - - /* - * NOP command - */ - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *) &nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = nop_addr; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* - * Transmit buffer descriptor - */ - tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); - tbd.tbd_next_bd_offset = I82586NULL; - tbd.tbd_bufl = buf_addr; - tbd.tbd_bufh = 0; - obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd)); - - /* - * Data - */ - obram_write(ioaddr, buf_addr, buf, length); - - /* - * Overwrite the predecessor NOP link - * so that it points to this txblock. - */ - nop_addr = txpred + sizeof(tx); - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *)&nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = txblock; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* Keep stats up to date. */ - lp->stats.tx_bytes += length; - - /* If watchdog not already active, activate it... */ - if(lp->watchdog.prev == (timer_list *) NULL) - { - /* Set timer to expire in WATCHDOG_JIFFIES. */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } + /* + * Data + */ + obram_write(ioaddr, buf_addr, buf, length); - if(lp->tx_first_in_use == I82586NULL) - lp->tx_first_in_use = txblock; + /* + * Overwrite the predecessor NOP link + * so that it points to this txblock. + */ + nop_addr = txpred + sizeof(tx); + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = txblock; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Keep stats up to date. */ + lp->stats.tx_bytes += length; + + /* If watchdog not already active, activate it... */ + if (lp->watchdog.prev == (timer_list *) NULL) { + /* Set timer to expire in WATCHDOG_JIFFIES. */ + lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; + add_timer(&lp->watchdog); + } - if(lp->tx_n_in_use < NTXBLOCKS - 1) - dev->tbusy = 0; + if (lp->tx_first_in_use == I82586NULL) + lp->tx_first_in_use = txblock; - wv_splx(x); + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + restore_flags(flags); + #ifdef DEBUG_TX_INFO - wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); -#endif /* DEBUG_TX_INFO */ + wv_packet_info((u8 *) buf, length, dev->name, + "wv_packet_write"); +#endif /* DEBUG_TX_INFO */ #ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif } @@ -2823,59 +2769,41 @@ * the packet. We also prevent reentrance. Then we call the function * to send the packet. */ -static int -wavelan_packet_xmit(struct sk_buff * skb, - device * dev) +static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = (net_local *) dev->priv; #ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, - (unsigned) skb); + printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, + (unsigned) skb); #endif - /* This flag indicate that the hardware can't perform a transmission. - * Theoretically, NET3 checks it before sending a packet to the driver, - * but in fact it never does that and pools continuously. - * As the watchdog will abort overly long transmissions, we are quite safe. - */ - if(dev->tbusy) - return 1; - - /* - * Block a timer-based transmit from overlapping. - * In other words, prevent reentering this routine. - */ - if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) -#ifdef DEBUG_TX_ERROR - printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name); -#endif - else - { - /* If somebody has asked to reconfigure the controller, - * we can do it now. - */ - if(lp->reconfig_82586) - { - wv_82586_config(dev); - if(dev->tbusy) - return 1; - } + /* + * Block a timer-based transmit from overlapping. + * In other words, prevent reentering this routine. + */ + + netif_stop_queue(dev); + /* If somebody has asked to reconfigure the controller, + * we can do it now. + */ + if (lp->reconfig_82586) { + wv_82586_config(dev); + } #ifdef DEBUG_TX_ERROR - if(skb->next) - printk(KERN_INFO "skb has next\n"); + if (skb->next) + printk(KERN_INFO "skb has next\n"); #endif - wv_packet_write(dev, skb->data, skb->len); - } + wv_packet_write(dev, skb->data, skb->len); - dev_kfree_skb(skb); + dev_kfree_skb(skb); #ifdef DEBUG_TX_TRACE - printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); #endif - return 0; + return 0; } /*********************** HARDWARE CONFIGURATION ***********************/ @@ -2888,166 +2816,170 @@ * Routine to initialize the Modem Management Controller. * (called by wv_hw_reset()) */ -static inline int -wv_mmc_init(device * dev) +static inline int wv_mmc_init(device * dev) { - u_long ioaddr = dev->base_addr; - net_local * lp = (net_local *)dev->priv; - psa_t psa; - mmw_t m; - int configured; + unsigned long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + psa_t psa; + mmw_t m; + int configured; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); #endif - /* Read the parameter storage area. */ - psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); + /* Read the parameter storage area. */ + psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); #ifdef USE_PSA_CONFIG - configured = psa.psa_conf_status & 1; + configured = psa.psa_conf_status & 1; #else - configured = 0; + configured = 0; #endif - /* Is the PSA is not configured */ - if(!configured) - { - /* User will be able to configure NWID later (with iwconfig). */ - psa.psa_nwid[0] = 0; - psa.psa_nwid[1] = 0; - - /* no NWID checking since NWID is not set */ - psa.psa_nwid_select = 0; - - /* Disable encryption */ - psa.psa_encryption_select = 0; - - /* Set to standard values: - * 0x04 for AT, - * 0x01 for MCA, - * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) - */ - if (psa.psa_comp_number & 1) - psa.psa_thr_pre_set = 0x01; - else - psa.psa_thr_pre_set = 0x04; - psa.psa_quality_thr = 0x03; + /* Is the PSA is not configured */ + if (!configured) { + /* User will be able to configure NWID later (with iwconfig). */ + psa.psa_nwid[0] = 0; + psa.psa_nwid[1] = 0; + + /* no NWID checking since NWID is not set */ + psa.psa_nwid_select = 0; + + /* Disable encryption */ + psa.psa_encryption_select = 0; + + /* Set to standard values: + * 0x04 for AT, + * 0x01 for MCA, + * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) + */ + if (psa.psa_comp_number & 1) + psa.psa_thr_pre_set = 0x01; + else + psa.psa_thr_pre_set = 0x04; + psa.psa_quality_thr = 0x03; - /* It is configured */ - psa.psa_conf_status |= 1; + /* It is configured */ + psa.psa_conf_status |= 1; #ifdef USE_PSA_CONFIG - /* Write the psa. */ - psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, - (unsigned char *)psa.psa_nwid, 4); - psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, - (unsigned char *)&psa.psa_thr_pre_set, 1); - psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, - (unsigned char *)&psa.psa_quality_thr, 1); - psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa, - (unsigned char *)&psa.psa_conf_status, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); -#endif - } - - /* Zero the mmc structure. */ - memset(&m, 0x00, sizeof(m)); - - /* Copy PSA info to the mmc. */ - m.mmw_netw_id_l = psa.psa_nwid[1]; - m.mmw_netw_id_h = psa.psa_nwid[0]; - - if(psa.psa_nwid_select & 1) - m.mmw_loopt_sel = 0x00; - else - m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; - - memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, - sizeof(m.mmw_encr_key)); - - if(psa.psa_encryption_select) - m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; - else - m.mmw_encr_enable = 0; - - m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; - m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; - - /* - * Set default modem control parameters. - * See NCR document 407-0024326 Rev. A. - */ - m.mmw_jabber_enable = 0x01; - m.mmw_freeze = 0; - m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; - m.mmw_ifs = 0x20; - m.mmw_mod_delay = 0x04; - m.mmw_jam_time = 0x38; - - m.mmw_des_io_invert = 0; - m.mmw_decay_prm = 0; - m.mmw_decay_updat_prm = 0; - - /* Write all info to MMC. */ - mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m)); - - /* The following code starts the modem of the 2.00 frequency - * selectable cards at power on. It's not strictly needed for the - * following boots. - * The original patch was by Joe Finney for the PCMCIA driver, but - * I've cleaned it up a bit and added documentation. - * Thanks to Loeke Brederveld from Lucent for the info. - */ - - /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * Does it work for everybody, especially old cards? */ - /* Note: WFREQSEL verifies that it is able to read a sensible - * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID - * is 0xA (Xilinx version) or 0xB (Ariadne version). - * My test is more crude but does work. */ - if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & - (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) - { - /* We must download the frequency parameters to the - * synthesizers (from the EEPROM - area 1) - * Note: as the EEPROM is automatically decremented, we set the end - * if the area... */ - m.mmw_fee_addr = 0x0F; - m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; - mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m, - (unsigned char *)&m.mmw_fee_ctrl, 2); + /* Write the psa. */ + psa_write(ioaddr, lp->hacr, + (char *) psa.psa_nwid - (char *) &psa, + (unsigned char *) psa.psa_nwid, 4); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_thr_pre_set - (char *) &psa, + (unsigned char *) &psa.psa_thr_pre_set, 1); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_quality_thr - (char *) &psa, + (unsigned char *) &psa.psa_quality_thr, 1); + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_conf_status - (char *) &psa, + (unsigned char *) &psa.psa_conf_status, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); +#endif + } - /* Wait until the download is finished. */ - fee_wait(ioaddr, 100, 100); + /* Zero the mmc structure. */ + memset(&m, 0x00, sizeof(m)); -#ifdef DEBUG_CONFIG_INFO - /* The frequency was in the last word downloaded. */ - mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m, - (unsigned char *)&m.mmw_fee_data_l, 2); - - /* Print some info for the user. */ - printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", - dev->name, - ((m.mmw_fee_data_h << 4) | - (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); -#endif - - /* We must now download the power adjust value (gain) to - * the synthesizers (from the EEPROM - area 7 - DAC). */ - m.mmw_fee_addr = 0x61; - m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; - mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m, - (unsigned char *)&m.mmw_fee_ctrl, 2); + /* Copy PSA info to the mmc. */ + m.mmw_netw_id_l = psa.psa_nwid[1]; + m.mmw_netw_id_h = psa.psa_nwid[0]; + + if (psa.psa_nwid_select & 1) + m.mmw_loopt_sel = 0x00; + else + m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; + + memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, + sizeof(m.mmw_encr_key)); + + if (psa.psa_encryption_select) + m.mmw_encr_enable = + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; + else + m.mmw_encr_enable = 0; + + m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; + m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; + + /* + * Set default modem control parameters. + * See NCR document 407-0024326 Rev. A. + */ + m.mmw_jabber_enable = 0x01; + m.mmw_freeze = 0; + m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; + m.mmw_ifs = 0x20; + m.mmw_mod_delay = 0x04; + m.mmw_jam_time = 0x38; + + m.mmw_des_io_invert = 0; + m.mmw_decay_prm = 0; + m.mmw_decay_updat_prm = 0; + + /* Write all info to MMC. */ + mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m)); + + /* The following code starts the modem of the 2.00 frequency + * selectable cards at power on. It's not strictly needed for the + * following boots. + * The original patch was by Joe Finney for the PCMCIA driver, but + * I've cleaned it up a bit and added documentation. + * Thanks to Loeke Brederveld from Lucent for the info. + */ + + /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) + * Does it work for everybody, especially old cards? */ + /* Note: WFREQSEL verifies that it is able to read a sensible + * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID + * is 0xA (Xilinx version) or 0xB (Ariadne version). + * My test is more crude but does work. */ + if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & + (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { + /* We must download the frequency parameters to the + * synthesizers (from the EEPROM - area 1) + * Note: as the EEPROM is automatically decremented, we set the end + * if the area... */ + m.mmw_fee_addr = 0x0F; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, + (unsigned char *) &m.mmw_fee_ctrl, 2); - /* Wait until the download is finished. */ - } /* if 2.00 card */ + /* Wait until the download is finished. */ + fee_wait(ioaddr, 100, 100); +#ifdef DEBUG_CONFIG_INFO + /* The frequency was in the last word downloaded. */ + mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m, + (unsigned char *) &m.mmw_fee_data_l, 2); + + /* Print some info for the user. */ + printk(KERN_DEBUG + "%s: WaveLAN 2.00 recognised (frequency select). Current frequency = %ld\n", + dev->name, + ((m. + mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) * + 5 / 2 + 24000L); +#endif + + /* We must now download the power adjust value (gain) to + * the synthesizers (from the EEPROM - area 7 - DAC). */ + m.mmw_fee_addr = 0x61; + m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; + mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m, + (unsigned char *) &m.mmw_fee_ctrl, 2); + + /* Wait until the download is finished. */ + } + /* if 2.00 card */ #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -3056,81 +2988,79 @@ * Start the receive unit. * (called by wv_hw_reset()) */ -static inline int -wv_ru_start(device * dev) +static inline int wv_ru_start(device * dev) { - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - u_short scb_cs; - fd_t fd; - rbd_t rbd; - u_short rx; - u_short rx_next; - int i; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cs; + fd_t fd; + rbd_t rbd; + u16 rx; + u16 rx_next; + int i; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); #endif - obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&scb_cs, sizeof(scb_cs)); - if((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) - return 0; - - lp->rx_head = OFFSET_RU; - - for(i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) - { - rx_next = (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; - - fd.fd_status = 0; - fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; - fd.fd_link_offset = rx_next; - fd.fd_rbd_offset = rx + sizeof(fd); - obram_write(ioaddr, rx, (unsigned char *)&fd, sizeof(fd)); - - rbd.rbd_status = 0; - rbd.rbd_next_rbd_offset = I82586NULL; - rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); - rbd.rbd_bufh = 0; - rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); - obram_write(ioaddr, rx + sizeof(fd), - (unsigned char *) &rbd, sizeof(rbd)); - - lp->rx_last = rx; - } + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) + return 0; + + lp->rx_head = OFFSET_RU; + + for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) { + rx_next = + (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; + + fd.fd_status = 0; + fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; + fd.fd_link_offset = rx_next; + fd.fd_rbd_offset = rx + sizeof(fd); + obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd)); + + rbd.rbd_status = 0; + rbd.rbd_next_rbd_offset = I82586NULL; + rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); + rbd.rbd_bufh = 0; + rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); + obram_write(ioaddr, rx + sizeof(fd), + (unsigned char *) &rbd, sizeof(rbd)); - obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), - (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); - - scb_cs = SCB_CMD_RUC_GO; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); + lp->rx_last = rx; + } - set_chan_attn(ioaddr, lp->hacr); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), + (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); - for(i = 1000; i > 0; i--) - { - obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - if (scb_cs == 0) - break; + scb_cs = SCB_CMD_RUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; - udelay(10); - } + udelay(10); + } - if(i <= 0) - { + if (i <= 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_ru_start(): board not accepting command.\n", + dev->name); #endif - return -1; - } - + return -1; + } #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -3150,94 +3080,93 @@ * * (called by wv_hw_reset()) */ -static inline int -wv_cu_start(device * dev) +static inline int wv_cu_start(device * dev) { - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - int i; - u_short txblock; - u_short first_nop; - u_short scb_cs; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + int i; + u16 txblock; + u16 first_nop; + u16 scb_cs; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); #endif - lp->tx_first_free = OFFSET_CU; - lp->tx_first_in_use = I82586NULL; + lp->tx_first_free = OFFSET_CU; + lp->tx_first_in_use = I82586NULL; + + for (i = 0, txblock = OFFSET_CU; + i < NTXBLOCKS; i++, txblock += TXBLOCKZ) { + ac_tx_t tx; + ac_nop_t nop; + tbd_t tbd; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short buf_addr; + + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + buf_addr = tbd_addr + sizeof(tbd); + + tx.tx_h.ac_status = 0; + tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; + tx.tx_h.ac_link = nop_addr; + tx.tx_tbd_offset = tbd_addr; + obram_write(ioaddr, tx_addr, (unsigned char *) &tx, + sizeof(tx)); + + nop.nop_h.ac_status = 0; + nop.nop_h.ac_command = acmd_nop; + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, nop_addr, (unsigned char *) &nop, + sizeof(nop)); + + tbd.tbd_status = TBD_STATUS_EOF; + tbd.tbd_next_bd_offset = I82586NULL; + tbd.tbd_bufl = buf_addr; + tbd.tbd_bufh = 0; + obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, + sizeof(tbd)); + } - for(i = 0, txblock = OFFSET_CU; - i < NTXBLOCKS; - i++, txblock += TXBLOCKZ) - { - ac_tx_t tx; - ac_nop_t nop; - tbd_t tbd; - unsigned short tx_addr; - unsigned short nop_addr; - unsigned short tbd_addr; - unsigned short buf_addr; - - tx_addr = txblock; - nop_addr = tx_addr + sizeof(tx); - tbd_addr = nop_addr + sizeof(nop); - buf_addr = tbd_addr + sizeof(tbd); - - tx.tx_h.ac_status = 0; - tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; - tx.tx_h.ac_link = nop_addr; - tx.tx_tbd_offset = tbd_addr; - obram_write(ioaddr, tx_addr, (unsigned char *) &tx, sizeof(tx)); - - nop.nop_h.ac_status = 0; - nop.nop_h.ac_command = acmd_nop; - nop.nop_h.ac_link = nop_addr; - obram_write(ioaddr, nop_addr, (unsigned char *) &nop, sizeof(nop)); - - tbd.tbd_status = TBD_STATUS_EOF; - tbd.tbd_next_bd_offset = I82586NULL; - tbd.tbd_bufl = buf_addr; - tbd.tbd_bufh = 0; - obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); - } - - first_nop = OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); - obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), - (unsigned char *) &first_nop, sizeof(first_nop)); - - scb_cs = SCB_CMD_CUC_GO; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - - set_chan_attn(ioaddr, lp->hacr); - - for(i = 1000; i > 0; i--) - { - obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &scb_cs, sizeof(scb_cs)); - if (scb_cs == 0) - break; + first_nop = + OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), + (unsigned char *) &first_nop, sizeof(first_nop)); + + scb_cs = SCB_CMD_CUC_GO; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + + set_chan_attn(ioaddr, lp->hacr); + + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cs, sizeof(scb_cs)); + if (scb_cs == 0) + break; - udelay(10); - } + udelay(10); + } - if(i <= 0) - { + if (i <= 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_cu_start(): board not accepting command.\n", + dev->name); #endif - return -1; - } - - lp->tx_n_in_use = 0; - dev->tbusy = 0; + return -1; + } + lp->tx_n_in_use = 0; + netif_wake_queue(dev); #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -3252,121 +3181,122 @@ * * (called by wv_hw_reset()) */ -static inline int -wv_82586_start(device * dev) +static inline int wv_82586_start(device * dev) { - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - scp_t scp; /* system configuration pointer */ - iscp_t iscp; /* intermediate scp */ - scb_t scb; /* system control block */ - ach_t cb; /* Action command header */ - u_char zeroes[512]; - int i; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + scp_t scp; /* system configuration pointer */ + iscp_t iscp; /* intermediate scp */ + scb_t scb; /* system control block */ + ach_t cb; /* Action command header */ + u8 zeroes[512]; + int i; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); #endif - /* - * Clear the onboard RAM. - */ - memset(&zeroes[0], 0x00, sizeof(zeroes)); - for(i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) - obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); - - /* - * Construct the command unit structures: - * scp, iscp, scb, cb. - */ - memset(&scp, 0x00, sizeof(scp)); - scp.scp_sysbus = SCP_SY_16BBUS; - scp.scp_iscpl = OFFSET_ISCP; - obram_write(ioaddr, OFFSET_SCP, (unsigned char *)&scp, sizeof(scp)); - - memset(&iscp, 0x00, sizeof(iscp)); - iscp.iscp_busy = 1; - iscp.iscp_offset = OFFSET_SCB; - obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp)); - - /* Our first command is to reset the i82586. */ - memset(&scb, 0x00, sizeof(scb)); - scb.scb_command = SCB_CMD_RESET; - scb.scb_cbl_offset = OFFSET_CU; - scb.scb_rfa_offset = OFFSET_RU; - obram_write(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb)); - - set_chan_attn(ioaddr, lp->hacr); - - /* Wait for command to finish. */ - for(i = 1000; i > 0; i--) - { - obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp)); + /* + * Clear the onboard RAM. + */ + memset(&zeroes[0], 0x00, sizeof(zeroes)); + for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) + obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); + + /* + * Construct the command unit structures: + * scp, iscp, scb, cb. + */ + memset(&scp, 0x00, sizeof(scp)); + scp.scp_sysbus = SCP_SY_16BBUS; + scp.scp_iscpl = OFFSET_ISCP; + obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp, + sizeof(scp)); + + memset(&iscp, 0x00, sizeof(iscp)); + iscp.iscp_busy = 1; + iscp.iscp_offset = OFFSET_SCB; + obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, + sizeof(iscp)); + + /* Our first command is to reset the i82586. */ + memset(&scb, 0x00, sizeof(scb)); + scb.scb_command = SCB_CMD_RESET; + scb.scb_cbl_offset = OFFSET_CU; + scb.scb_rfa_offset = OFFSET_RU; + obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); + + set_chan_attn(ioaddr, lp->hacr); + + /* Wait for command to finish. */ + for (i = 1000; i > 0; i--) { + obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, + sizeof(iscp)); - if(iscp.iscp_busy == (unsigned short) 0) - break; + if (iscp.iscp_busy == (unsigned short) 0) + break; - udelay(10); - } + udelay(10); + } - if(i <= 0) - { + if (i <= 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n", - dev->name); + printk(KERN_INFO + "%s: wv_82586_start(): iscp_busy timeout.\n", + dev->name); #endif - return -1; - } + return -1; + } - /* Check command completion. */ - for(i = 15; i > 0; i--) - { - obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb)); + /* Check command completion. */ + for (i = 15; i > 0; i--) { + obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, + sizeof(scb)); - if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) - break; + if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) + break; - udelay(10); - } + udelay(10); + } - if (i <= 0) - { + if (i <= 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", - dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); + printk(KERN_INFO + "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", + dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); #endif - return -1; - } + return -1; + } + + wv_ack(dev); + + /* Set the action command header. */ + memset(&cb, 0x00, sizeof(cb)); + cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); + cb.ac_link = OFFSET_CU; + obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); - wv_ack(dev); + if (wv_synchronous_cmd(dev, "diag()") == -1) + return -1; - /* Set the action command header. */ - memset(&cb, 0x00, sizeof(cb)); - cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); - cb.ac_link = OFFSET_CU; - obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); - - if(wv_synchronous_cmd(dev, "diag()") == -1) - return -1; - - obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); - if(cb.ac_status & AC_SFLD_FAIL) - { + obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); + if (cb.ac_status & AC_SFLD_FAIL) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n", - dev->name); + printk(KERN_INFO + "%s: wv_82586_start(): i82586 Self Test failed.\n", + dev->name); #endif - return -1; - } - + return -1; + } #ifdef DEBUG_I82586_SHOW - wv_scb_show(ioaddr); + wv_scb_show(ioaddr); #endif #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -3383,184 +3313,179 @@ * * (called by wv_hw_reset(), wv_82586_reconfig()) */ -static void -wv_82586_config(device * dev) +static void wv_82586_config(device * dev) { - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - unsigned short txblock; - unsigned short txpred; - unsigned short tx_addr; - unsigned short nop_addr; - unsigned short tbd_addr; - unsigned short cfg_addr; - unsigned short ias_addr; - unsigned short mcs_addr; - ac_tx_t tx; - ac_nop_t nop; - ac_cfg_t cfg; /* Configure action */ - ac_ias_t ias; /* IA-setup action */ - ac_mcs_t mcs; /* Multicast setup */ - struct dev_mc_list * dmi; - unsigned long x; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + unsigned short txblock; + unsigned short txpred; + unsigned short tx_addr; + unsigned short nop_addr; + unsigned short tbd_addr; + unsigned short cfg_addr; + unsigned short ias_addr; + unsigned short mcs_addr; + ac_tx_t tx; + ac_nop_t nop; + ac_cfg_t cfg; /* Configure action */ + ac_ias_t ias; /* IA-setup action */ + ac_mcs_t mcs; /* Multicast setup */ + struct dev_mc_list *dmi; + unsigned long flags; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); #endif - x = wv_splhi(); + save_flags(flags); + cli(); + + /* Calculate addresses of next block and previous block. */ + txblock = lp->tx_first_free; + txpred = txblock - TXBLOCKZ; + if (txpred < OFFSET_CU) + txpred += NTXBLOCKS * TXBLOCKZ; + lp->tx_first_free += TXBLOCKZ; + if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) + lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; + + lp->tx_n_in_use++; + + /* Calculate addresses of the different parts of the block. */ + tx_addr = txblock; + nop_addr = tx_addr + sizeof(tx); + tbd_addr = nop_addr + sizeof(nop); + cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ + ias_addr = cfg_addr + sizeof(cfg); + mcs_addr = ias_addr + sizeof(ias); + + /* + * Transmit command + */ + tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ + obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), + (unsigned char *) &tx.tx_h.ac_status, + sizeof(tx.tx_h.ac_status)); + + /* + * NOP command + */ + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = nop_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* Create a configure action. */ + memset(&cfg, 0x00, sizeof(cfg)); - /* Calculate addresses of next block and previous block. */ - txblock = lp->tx_first_free; - txpred = txblock - TXBLOCKZ; - if(txpred < OFFSET_CU) - txpred += NTXBLOCKS * TXBLOCKZ; - lp->tx_first_free += TXBLOCKZ; - if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) - lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; - - lp->tx_n_in_use++; - - /* Calculate addresses of the different parts of the block. */ - tx_addr = txblock; - nop_addr = tx_addr + sizeof(tx); - tbd_addr = nop_addr + sizeof(nop); - cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ - ias_addr = cfg_addr + sizeof(cfg); - mcs_addr = ias_addr + sizeof(ias); - - /* - * Transmit command - */ - tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ - obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), - (unsigned char *) &tx.tx_h.ac_status, - sizeof(tx.tx_h.ac_status)); - - /* - * NOP command - */ - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *) &nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = nop_addr; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* Create a configure action. */ - memset(&cfg, 0x00, sizeof(cfg)); - - /* - * For Linux we invert AC_CFG_ALOC() so as to conform - * to the way that net packets reach us from above. - * (See also ac_tx_t.) - * - * Updated from Wavelan Manual WCIN085B - */ - cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); - cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); - cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | - AC_CFG_SRDY(0); - cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | - AC_CFG_ILPBCK(0) | - AC_CFG_PRELEN(AC_CFG_PLEN_2) | - AC_CFG_ALOC(1) | - AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); - cfg.cfg_byte10 = AC_CFG_BOFMET(1) | - AC_CFG_ACR(6) | - AC_CFG_LINPRIO(0); - cfg.cfg_ifs = 0x20; - cfg.cfg_slotl = 0x0C; - cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | - AC_CFG_SLTTMHI(0); - cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | - AC_CFG_BTSTF(0) | - AC_CFG_CRC16(0) | - AC_CFG_NCRC(0) | - AC_CFG_TNCRS(1) | - AC_CFG_MANCH(0) | - AC_CFG_BCDIS(0) | - AC_CFG_PRM(lp->promiscuous); - cfg.cfg_byte15 = AC_CFG_ICDS(0) | - AC_CFG_CDTF(0) | - AC_CFG_ICSS(0) | - AC_CFG_CSTF(0); + /* + * For Linux we invert AC_CFG_ALOC() so as to conform + * to the way that net packets reach us from above. + * (See also ac_tx_t.) + * + * Updated from Wavelan Manual WCIN085B + */ + cfg.cfg_byte_cnt = + AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); + cfg.cfg_fifolim = AC_CFG_FIFOLIM(4); + cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0); + cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | + AC_CFG_ILPBCK(0) | + AC_CFG_PRELEN(AC_CFG_PLEN_2) | + AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); + cfg.cfg_byte10 = AC_CFG_BOFMET(1) | + AC_CFG_ACR(6) | AC_CFG_LINPRIO(0); + cfg.cfg_ifs = 0x20; + cfg.cfg_slotl = 0x0C; + cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0); + cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | + AC_CFG_BTSTF(0) | + AC_CFG_CRC16(0) | + AC_CFG_NCRC(0) | + AC_CFG_TNCRS(1) | + AC_CFG_MANCH(0) | + AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous); + cfg.cfg_byte15 = AC_CFG_ICDS(0) | + AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0); /* cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); */ - cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); + cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); - cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); - cfg.cfg_h.ac_link = ias_addr; - obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg)); - - /* Set up the MAC address */ - memset(&ias, 0x00, sizeof(ias)); - ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); - ias.ias_h.ac_link = mcs_addr; - memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr)); - obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias)); - - /* Initialize adapter's Ethernet multicast addresses */ - memset(&mcs, 0x00, sizeof(mcs)); - mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); - mcs.mcs_h.ac_link = nop_addr; - mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; - obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs)); - - /* Any address to set? */ - if(lp->mc_count) - { - for(dmi=dev->mc_list; dmi; dmi=dmi->next) - outsw(PIOP1(ioaddr), (u_short *) dmi->dmi_addr, - WAVELAN_ADDR_SIZE >> 1); + cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); + cfg.cfg_h.ac_link = ias_addr; + obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg)); + + /* Set up the MAC address */ + memset(&ias, 0x00, sizeof(ias)); + ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); + ias.ias_h.ac_link = mcs_addr; + memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0], + sizeof(ias.ias_addr)); + obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias)); + + /* Initialize adapter's Ethernet multicast addresses */ + memset(&mcs, 0x00, sizeof(mcs)); + mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); + mcs.mcs_h.ac_link = nop_addr; + mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; + obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs)); + + /* Any address to set? */ + if (lp->mc_count) { + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr, + WAVELAN_ADDR_SIZE >> 1); #ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", - dev->name, lp->mc_count); - for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); -#endif - } - - /* - * Overwrite the predecessor NOP link - * so that it points to the configure action. - */ - nop_addr = txpred + sizeof(tx); - nop.nop_h.ac_status = 0; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), - (unsigned char *)&nop.nop_h.ac_status, - sizeof(nop.nop_h.ac_status)); - nop.nop_h.ac_link = cfg_addr; - obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), - (unsigned char *) &nop.nop_h.ac_link, - sizeof(nop.nop_h.ac_link)); - - /* If watchdog not already active, activate it... */ - if(lp->watchdog.prev == (timer_list *) NULL) - { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - - lp->reconfig_82586 = 0; + printk(KERN_DEBUG + "%s: wv_82586_config(): set %d multicast addresses:\n", + dev->name, lp->mc_count); + for (dmi = dev->mc_list; dmi; dmi = dmi->next) + printk(KERN_DEBUG + " %02x:%02x:%02x:%02x:%02x:%02x\n", + dmi->dmi_addr[0], dmi->dmi_addr[1], + dmi->dmi_addr[2], dmi->dmi_addr[3], + dmi->dmi_addr[4], dmi->dmi_addr[5]); +#endif + } + + /* + * Overwrite the predecessor NOP link + * so that it points to the configure action. + */ + nop_addr = txpred + sizeof(tx); + nop.nop_h.ac_status = 0; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), + (unsigned char *) &nop.nop_h.ac_status, + sizeof(nop.nop_h.ac_status)); + nop.nop_h.ac_link = cfg_addr; + obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), + (unsigned char *) &nop.nop_h.ac_link, + sizeof(nop.nop_h.ac_link)); + + /* If watchdog not already active, activate it... */ + if (lp->watchdog.prev == (timer_list *) NULL) { + /* set timer to expire in WATCHDOG_JIFFIES */ + lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; + add_timer(&lp->watchdog); + } - if(lp->tx_first_in_use == I82586NULL) - lp->tx_first_in_use = txblock; + lp->reconfig_82586 = 0; - if(lp->tx_n_in_use < NTXBLOCKS - 1) - dev->tbusy = 0; + if (lp->tx_first_in_use == I82586NULL) + lp->tx_first_in_use = txblock; - wv_splx(x); + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + restore_flags(flags); #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); #endif } @@ -3569,28 +3494,29 @@ * This routine, called by wavelan_close(), gracefully stops the * WaveLAN controller (i82586). */ -static inline void -wv_82586_stop(device * dev) +static inline void wv_82586_stop(device * dev) { - net_local * lp = (net_local *) dev->priv; - u_long ioaddr = dev->base_addr; - u_short scb_cmd; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 scb_cmd; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); + printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); #endif - /* Suspend both command unit and receive unit. */ - scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS); - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *)&scb_cmd, sizeof(scb_cmd)); - set_chan_attn(ioaddr, lp->hacr); + /* Suspend both command unit and receive unit. */ + scb_cmd = + (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & + SCB_CMD_RUC_SUS); + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &scb_cmd, sizeof(scb_cmd)); + set_chan_attn(ioaddr, lp->hacr); - /* No more interrupts */ - wv_ints_off(dev); + /* No more interrupts */ + wv_ints_off(dev); #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); #endif } @@ -3604,49 +3530,47 @@ * 4. Start the LAN controller's command unit * 5. Start the LAN controller's receive unit */ -static int -wv_hw_reset(device * dev) +static int wv_hw_reset(device * dev) { - net_local * lp = (net_local *)dev->priv; - u_long ioaddr = dev->base_addr; + net_local *lp = (net_local *) dev->priv; + unsigned long ioaddr = dev->base_addr; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, - (unsigned int)dev); + printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, + (unsigned int) dev); #endif - /* If watchdog was activated, kill it! */ - if(lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); + /* If watchdog was activated, kill it! */ + if (lp->watchdog.prev != (timer_list *) NULL) + del_timer(&lp->watchdog); - /* Increase the number of resets done. */ - lp->nresets++; + /* Increase the number of resets done. */ + lp->nresets++; - wv_hacr_reset(ioaddr); - lp->hacr = HACR_DEFAULT; + wv_hacr_reset(ioaddr); + lp->hacr = HACR_DEFAULT; - if((wv_mmc_init(dev) < 0) || - (wv_82586_start(dev) < 0)) - return -1; + if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0)) + return -1; - /* Enable the card to send interrupts. */ - wv_ints_on(dev); + /* Enable the card to send interrupts. */ + wv_ints_on(dev); - /* Start card functions */ - if(wv_cu_start(dev) < 0) - return -1; + /* Start card functions */ + if (wv_cu_start(dev) < 0) + return -1; - /* Setup the controller and parameters */ - wv_82586_config(dev); + /* Setup the controller and parameters */ + wv_82586_config(dev); - /* Finish configuration with the receive unit */ - if(wv_ru_start(dev) < 0) - return -1; + /* Finish configuration with the receive unit */ + if (wv_ru_start(dev) < 0) + return -1; #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); + printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -3655,40 +3579,39 @@ * As a side effect, this reads the MAC address. * (called in wavelan_probe() and init_module()) */ -static int -wv_check_ioaddr(u_long ioaddr, - u_char * mac) -{ - int i; /* Loop counter */ - - /* Check if the base address if available. */ - if(check_region(ioaddr, sizeof(ha_t))) - return EADDRINUSE; /* ioaddr already used */ - - /* Reset host interface */ - wv_hacr_reset(ioaddr); - - /* Read the MAC address from the parameter storage area. */ - psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), - mac, 6); - - /* - * Check the first three octets of the address for the manufacturer's code. - * Note: if this can't find your WaveLAN card, you've got a - * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on - * how to configure your card. - */ - for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) - if((mac[0] == MAC_ADDRESSES[i][0]) && - (mac[1] == MAC_ADDRESSES[i][1]) && - (mac[2] == MAC_ADDRESSES[i][2])) - return 0; +static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) +{ + int i; /* Loop counter */ + + /* Check if the base address if available. */ + if (check_region(ioaddr, sizeof(ha_t))) + return EADDRINUSE; /* ioaddr already used */ + + /* Reset host interface */ + wv_hacr_reset(ioaddr); + + /* Read the MAC address from the parameter storage area. */ + psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), + mac, 6); + + /* + * Check the first three octets of the address for the manufacturer's code. + * Note: if this can't find your WaveLAN card, you've got a + * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on + * how to configure your card. + */ + for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) + if ((mac[0] == MAC_ADDRESSES[i][0]) && + (mac[1] == MAC_ADDRESSES[i][1]) && + (mac[2] == MAC_ADDRESSES[i][2])) + return 0; #ifdef DEBUG_CONFIG_INFO - printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", - ioaddr, mac[0], mac[1], mac[2]); + printk(KERN_WARNING + "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n", + ioaddr, mac[0], mac[1], mac[2]); #endif - return ENODEV; + return ENODEV; } /************************ INTERRUPT HANDLING ************************/ @@ -3697,133 +3620,121 @@ * This function is the interrupt handler for the WaveLAN card. This * routine will be called whenever: */ -static void -wavelan_interrupt(int irq, - void * dev_id, - struct pt_regs * regs) -{ - device * dev; - u_long ioaddr; - net_local * lp; - u_short hasr; - u_short status; - u_short ack_cmd; +static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + device *dev; + unsigned long ioaddr; + net_local *lp; + u16 hasr; + u16 status; + u16 ack_cmd; - dev = dev_id; + dev = dev_id; #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); + printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); #endif - lp = (net_local *) dev->priv; - ioaddr = dev->base_addr; + lp = (net_local *) dev->priv; + ioaddr = dev->base_addr; - /* Prevent reentrance. What should we do here? */ -#ifdef DEBUG_INTERRUPT_ERROR - if(dev->interrupt) - printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n", - dev->name); -#endif - dev->interrupt = 1; - - if((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) - { - u_char dce_status; - - /* - * Interrupt from the modem management controller. - * This will clear it -- ignored for now. - */ - mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status)); + /* Prevent reentrance. What should we do here? */ + + if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { + u8 dce_status; + + /* + * Interrupt from the modem management controller. + * This will clear it -- ignored for now. + */ + mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, + sizeof(dce_status)); #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", - dev->name, dce_status); + printk(KERN_INFO + "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", + dev->name, dce_status); #endif - } + } - if((hasr & HASR_82586_INTR) == 0) - { - dev->interrupt = 0; + if ((hasr & HASR_82586_INTR) == 0) { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_interrupt(): interrupt not coming from i82586\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_interrupt(): interrupt not coming from i82586\n", + dev->name); #endif - return; - } + return; + } - /* Read interrupt data. */ - obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), - (unsigned char *) &status, sizeof(status)); - - /* - * Acknowledge the interrupt(s). - */ - ack_cmd = status & SCB_ST_INT; - obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), - (unsigned char *) &ack_cmd, sizeof(ack_cmd)); - set_chan_attn(ioaddr, lp->hacr); + /* Read interrupt data. */ + obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), + (unsigned char *) &status, sizeof(status)); + + /* + * Acknowledge the interrupt(s). + */ + ack_cmd = status & SCB_ST_INT; + obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), + (unsigned char *) &ack_cmd, sizeof(ack_cmd)); + set_chan_attn(ioaddr, lp->hacr); #ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", - dev->name, status); + printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", + dev->name, status); #endif - /* Command completed. */ - if((status & SCB_ST_CX) == SCB_ST_CX) - { + /* Command completed. */ + if ((status & SCB_ST_CX) == SCB_ST_CX) { #ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wavelan_interrupt(): command completed.\n", - dev->name); + printk(KERN_DEBUG + "%s: wavelan_interrupt(): command completed.\n", + dev->name); #endif - wv_complete(dev, ioaddr, lp); + wv_complete(dev, ioaddr, lp); - /* If watchdog was activated, kill it ! */ - if(lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - if(lp->tx_n_in_use > 0) - { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - } - - /* Frame received. */ - if((status & SCB_ST_FR) == SCB_ST_FR) - { + /* If watchdog was activated, kill it ! */ + if (lp->watchdog.prev != (timer_list *) NULL) + del_timer(&lp->watchdog); + if (lp->tx_n_in_use > 0) { + /* set timer to expire in WATCHDOG_JIFFIES */ + lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; + add_timer(&lp->watchdog); + } + } + + /* Frame received. */ + if ((status & SCB_ST_FR) == SCB_ST_FR) { #ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wavelan_interrupt(): received packet.\n", - dev->name); + printk(KERN_DEBUG + "%s: wavelan_interrupt(): received packet.\n", + dev->name); #endif - wv_receive(dev); - } + wv_receive(dev); + } - /* Check the state of the command unit. */ - if(((status & SCB_ST_CNA) == SCB_ST_CNA) || - (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start)) - { + /* Check the state of the command unit. */ + if (((status & SCB_ST_CNA) == SCB_ST_CNA) || + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && test_bit(LINK_STATE_START, &dev->state))) { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_interrupt(): CU inactive -- restarting\n", + dev->name); #endif - wv_hw_reset(dev); - } + wv_hw_reset(dev); + } - /* Check the state of the command unit. */ - if(((status & SCB_ST_RNR) == SCB_ST_RNR) || - (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start)) - { + /* Check the state of the command unit. */ + if (((status & SCB_ST_RNR) == SCB_ST_RNR) || + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && test_bit(LINK_STATE_START, &dev->state))) { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_interrupt(): RU not ready -- restarting\n", + dev->name); #endif - wv_hw_reset(dev); - } - - dev->interrupt = 0; + wv_hw_reset(dev); + } #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); #endif } @@ -3838,83 +3749,81 @@ * way because the overhead of add_timer() and del_timer() is nothing * and because it avoids calling the watchdog, saving some CPU. */ -static void -wavelan_watchdog(u_long a) +static void wavelan_watchdog(unsigned long a) { - device * dev; - net_local * lp; - u_long ioaddr; - unsigned long x; - unsigned int nreaped; - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + device *dev; + net_local *lp; + unsigned long ioaddr; + unsigned long flags; + unsigned int nreaped; + + dev = (device *) a; + ioaddr = dev->base_addr; + lp = (net_local *) dev->priv; #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); + printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); #endif #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", - dev->name); + printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", + dev->name); #endif - x = wv_splhi(); - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; - - if(lp->tx_n_in_use <= 0) - { - wv_splx(x); - return; - } + save_flags(flags); + cli(); + + dev = (device *) a; + ioaddr = dev->base_addr; + lp = (net_local *) dev->priv; + + if (lp->tx_n_in_use <= 0) { + restore_flags(flags); + return; + } - nreaped = wv_complete(dev, ioaddr, lp); + nreaped = wv_complete(dev, ioaddr, lp); #ifdef DEBUG_INTERRUPT_INFO - printk(KERN_DEBUG "%s: wavelan_watchdog(): %d reaped, %d remain.\n", - dev->name, nreaped, lp->tx_n_in_use); + printk(KERN_DEBUG + "%s: wavelan_watchdog(): %d reaped, %d remain.\n", + dev->name, nreaped, lp->tx_n_in_use); #endif #ifdef DEBUG_PSA_SHOW - { - psa_t psa; - psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); - wv_psa_show(&psa); - } + { + psa_t psa; + psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); + wv_psa_show(&psa); + } #endif #ifdef DEBUG_MMC_SHOW - wv_mmc_show(dev); + wv_mmc_show(dev); #endif #ifdef DEBUG_I82586_SHOW - wv_cu_show(dev); + wv_cu_show(dev); #endif - /* If no buffer has been freed */ - if(nreaped == 0) - { + /* If no buffer has been freed */ + if (nreaped == 0) { #ifdef DEBUG_INTERRUPT_ERROR - printk(KERN_INFO "%s: wavelan_watchdog(): cleanup failed, trying reset\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_watchdog(): cleanup failed, trying reset\n", + dev->name); #endif - wv_hw_reset(dev); - } - else - /* Reset watchdog for next transmission. */ - if(lp->tx_n_in_use > 0) - { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - - wv_splx(x); + wv_hw_reset(dev); + } else + /* Reset watchdog for next transmission. */ + if (lp->tx_n_in_use > 0) { + /* set timer to expire in WATCHDOG_JIFFIES */ + lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; + add_timer(&lp->watchdog); + } + restore_flags(flags); + #ifdef DEBUG_INTERRUPT_TRACE - printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); #endif } @@ -3930,56 +3839,55 @@ * Configure and start up the WaveLAN PCMCIA adaptor. * Called by NET3 when it "opens" the device. */ -static int -wavelan_open(device * dev) +static int wavelan_open(device * dev) { - u_long x; + unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, - (unsigned int) dev); + printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, + (unsigned int) dev); #endif - /* Check irq */ - if(dev->irq == 0) - { + /* Check irq */ + if (dev->irq == 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name); + printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", + dev->name); #endif - return -ENXIO; - } + return -ENXIO; + } - if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) - { + if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) + { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name); + printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", + dev->name); #endif - return -EAGAIN; - } + return -EAGAIN; + } - x = wv_splhi(); - if(wv_hw_reset(dev) != -1) - { - dev->interrupt = 0; - dev->start = 1; - } - else - { - free_irq(dev->irq, dev); + save_flags(flags); + cli(); + + if (wv_hw_reset(dev) != -1) { + netif_start_queue(dev); + } else { + free_irq(dev->irq, dev); #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n", - dev->name); + printk(KERN_INFO + "%s: wavelan_open(): impossible to start the card\n", + dev->name); #endif - return -EAGAIN; - } - wv_splx(x); - - MOD_INC_USE_COUNT; + return -EAGAIN; + } + restore_flags(flags); + + MOD_INC_USE_COUNT; #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -3987,40 +3895,34 @@ * Shut down the WaveLAN ISA card. * Called by NET3 when it "closes" the device. */ -static int -wavelan_close(device * dev) +static int wavelan_close(device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = (net_local *) dev->priv; #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, - (unsigned int) dev); + printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, + (unsigned int) dev); #endif - /* Don't do the job twice. */ - if(dev->start == 0) - return 0; - - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); - /* If watchdog was activated, kill it! */ - if(lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); + /* If watchdog was activated, kill it! */ + if (lp->watchdog.prev != (timer_list *) NULL) + del_timer(&lp->watchdog); - /* - * Flush the Tx and disable Rx. - */ - wv_82586_stop(dev); + /* + * Flush the Tx and disable Rx. + */ + wv_82586_stop(dev); - free_irq(dev->irq, dev); + free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -4029,113 +3931,111 @@ * device structure * (called by wavelan_probe() and via init_module()). */ -static int __init -wavelan_config(device * dev) +static int __init wavelan_config(device * dev) { - u_long ioaddr = dev->base_addr; - u_char irq_mask; - int irq; - net_local * lp; + unsigned long ioaddr = dev->base_addr; + u8 irq_mask; + int irq; + net_local *lp; #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n", dev->name, - (unsigned int)dev, ioaddr); + printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n", + dev->name, (unsigned int) dev, ioaddr); #endif - /* Check IRQ argument on command line. */ - if(dev->irq != 0) - { - irq_mask = wv_irq_to_psa(dev->irq); + /* Check IRQ argument on command line. */ + if (dev->irq != 0) { + irq_mask = wv_irq_to_psa(dev->irq); - if(irq_mask == 0) - { + if (irq_mask == 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n", - dev->name, dev->irq); + printk(KERN_WARNING + "%s: wavelan_config(): invalid IRQ %d ignored.\n", + dev->name, dev->irq); #endif - dev->irq = 0; - } - else - { + dev->irq = 0; + } else { #ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n", - dev->name, dev->irq); -#endif - psa_write(ioaddr, HACR_DEFAULT, - psaoff(0, psa_int_req_no), &irq_mask, 1); - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, HACR_DEFAULT); - wv_hacr_reset(ioaddr); - } - } - - psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), &irq_mask, 1); - if((irq = wv_psa_to_irq(irq_mask)) == -1) - { + printk(KERN_DEBUG + "%s: wavelan_config(): changing IRQ to %d\n", + dev->name, dev->irq); +#endif + psa_write(ioaddr, HACR_DEFAULT, + psaoff(0, psa_int_req_no), &irq_mask, 1); + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, HACR_DEFAULT); + wv_hacr_reset(ioaddr); + } + } + + psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), + &irq_mask, 1); + if ((irq = wv_psa_to_irq(irq_mask)) == -1) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_INFO "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", - dev->name, irq_mask); + printk(KERN_INFO + "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", + dev->name, irq_mask); #endif - return EAGAIN; - } + return EAGAIN; + } + + dev->irq = irq; - dev->irq = irq; + request_region(ioaddr, sizeof(ha_t), "wavelan"); - request_region(ioaddr, sizeof(ha_t), "wavelan"); - - dev->mem_start = 0x0000; - dev->mem_end = 0x0000; - dev->if_port = 0; - - /* Initialize device structures */ - dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); - if(dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0x00, sizeof(net_local)); - lp = (net_local *)dev->priv; - - /* Back link to the device structure. */ - lp->dev = dev; - /* Add the device at the beginning of the linked list. */ - lp->next = wavelan_list; - wavelan_list = lp; - - lp->hacr = HACR_DEFAULT; - - lp->watchdog.function = wavelan_watchdog; - lp->watchdog.data = (unsigned long) dev; - lp->promiscuous = 0; - lp->mc_count = 0; - - /* - * Fill in the fields of the device structure - * with generic Ethernet values. - */ - ether_setup(dev); - - dev->open = wavelan_open; - dev->stop = wavelan_close; - dev->hard_start_xmit = wavelan_packet_xmit; - dev->get_stats = wavelan_get_stats; - dev->set_multicast_list = &wavelan_set_multicast_list; + dev->mem_start = 0x0000; + dev->mem_end = 0x0000; + dev->if_port = 0; + + /* Initialize device structures */ + dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0x00, sizeof(net_local)); + lp = (net_local *) dev->priv; + + /* Back link to the device structure. */ + lp->dev = dev; + /* Add the device at the beginning of the linked list. */ + lp->next = wavelan_list; + wavelan_list = lp; + + lp->hacr = HACR_DEFAULT; + + lp->watchdog.function = wavelan_watchdog; + lp->watchdog.data = (unsigned long) dev; + lp->promiscuous = 0; + lp->mc_count = 0; + + /* + * Fill in the fields of the device structure + * with generic Ethernet values. + */ + ether_setup(dev); + + dev->open = wavelan_open; + dev->stop = wavelan_close; + dev->hard_start_xmit = wavelan_packet_xmit; + dev->get_stats = wavelan_get_stats; + dev->set_multicast_list = &wavelan_set_multicast_list; #ifdef SET_MAC_ADDRESS - dev->set_mac_address = &wavelan_set_mac_address; -#endif /* SET_MAC_ADDRESS */ + dev->set_mac_address = &wavelan_set_mac_address; +#endif /* SET_MAC_ADDRESS */ -#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ - dev->do_ioctl = wavelan_ioctl; - dev->get_wireless_stats = wavelan_get_wireless_stats; +#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ + dev->do_ioctl = wavelan_ioctl; + dev->get_wireless_stats = wavelan_get_wireless_stats; #endif - dev->mtu = WAVELAN_MTU; + dev->mtu = WAVELAN_MTU; - /* Display nice information. */ - wv_init_info(dev); + /* Display nice information. */ + wv_init_info(dev); #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); #endif - return 0; + return 0; } /*------------------------------------------------------------------*/ @@ -4146,90 +4046,88 @@ * We follow the example in drivers/net/ne.c. * (called in "Space.c") */ -int __init -wavelan_probe(device * dev) +int __init wavelan_probe(device * dev) { - short base_addr; - mac_addr mac; /* MAC address (check existence of WaveLAN) */ - int i; - int r; + short base_addr; + mac_addr mac; /* MAC address (check existence of WaveLAN) */ + int i; + int r; #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", - dev->name, (unsigned int)dev, (unsigned int)dev->base_addr); + printk(KERN_DEBUG + "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", + dev->name, (unsigned int) dev, + (unsigned int) dev->base_addr); #endif #ifdef STRUCT_CHECK - if (wv_struct_check() != (char *) NULL) - { - printk(KERN_WARNING "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", - dev->name, wv_struct_check()); - return ENODEV; - } -#endif /* STRUCT_CHECK */ - - /* Check the value of the command line parameter for base address. */ - base_addr = dev->base_addr; - - /* Don't probe at all. */ - if(base_addr < 0) - { + if (wv_struct_check() != (char *) NULL) { + printk(KERN_WARNING + "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", + dev->name, wv_struct_check()); + return ENODEV; + } +#endif /* STRUCT_CHECK */ + + /* Check the value of the command line parameter for base address. */ + base_addr = dev->base_addr; + + /* Don't probe at all. */ + if (base_addr < 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n", - dev->name); + printk(KERN_WARNING + "%s: wavelan_probe(): invalid base address\n", + dev->name); #endif - return ENXIO; - } - - /* Check a single specified location. */ - if(base_addr > 0x100) - { - /* Check if there is something at this base address */ - if((r = wv_check_ioaddr(base_addr, mac)) == 0) - { - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - r = wavelan_config(dev); + return ENXIO; } + /* Check a single specified location. */ + if (base_addr > 0x100) { + /* Check if there is something at this base address */ + if ((r = wv_check_ioaddr(base_addr, mac)) == 0) { + memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + r = wavelan_config(dev); + } #ifdef DEBUG_CONFIG_INFO - if(r != 0) - printk(KERN_DEBUG "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", - dev->name, base_addr); + if (r != 0) + printk(KERN_DEBUG + "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", + dev->name, base_addr); #endif #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); + printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); #endif - return r; - } + return r; + } - /* Scan all possible addresses of the WaveLAN hardware. */ - for(i = 0; i < NELS(iobase); i++) - { - /* Check whether there is something at this base address. */ - if(wv_check_ioaddr(iobase[i], mac) == 0) - { - dev->base_addr = iobase[i]; /* Copy base address. */ - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - if(wavelan_config(dev) == 0) - { + /* Scan all possible addresses of the WaveLAN hardware. */ + for (i = 0; i < NELS(iobase); i++) { + /* Check whether there is something at this base address. */ + if (wv_check_ioaddr(iobase[i], mac) == 0) { + dev->base_addr = iobase[i]; /* Copy base address. */ + memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + if (wavelan_config(dev) == 0) { #ifdef DEBUG_CALLBACK_TRACE - printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); -#endif - return 0; - } + printk(KERN_DEBUG + "%s: <-wavelan_probe()\n", + dev->name); +#endif + return 0; + } + } } - } - /* We may have touched base_addr. Another driver may not like it. */ - dev->base_addr = base_addr; + /* We may have touched base_addr. Another driver may not like it. */ + dev->base_addr = base_addr; #ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", - dev->name); + printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", + dev->name); #endif - return ENODEV; + return ENODEV; } /****************************** MODULE ******************************/ @@ -4243,120 +4141,115 @@ * Insertion of the module * I'm now quite proud of the multi-device support. */ -int -init_module(void) +int init_module(void) { - mac_addr mac; /* MAC address (check WaveLAN existence) */ - int ret = -EIO; /* Return error if no cards found */ - int i; + mac_addr mac; /* MAC address (check WaveLAN existence) */ + int ret = -EIO; /* Return error if no cards found */ + int i; #ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "-> init_module()\n"); + printk(KERN_DEBUG "-> init_module()\n"); #endif - /* If probing is asked */ - if(io[0] == 0) - { + /* If probing is asked */ + if (io[0] == 0) { #ifdef DEBUG_CONFIG_ERROR - printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n"); - printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n"); + printk(KERN_WARNING + "WaveLAN init_module(): doing device probing (bad !)\n"); + printk(KERN_WARNING + "Specify base addresses while loading module to correct the problem\n"); #endif - /* Copy the basic set of address to be probed. */ - for(i = 0; i < NELS(iobase); i++) - io[i] = iobase[i]; - } - - - /* Loop on all possible base addresses. */ - i = -1; - while((io[++i] != 0) && (i < NELS(io))) - { - /* Check if there is something at this base address. */ - if(wv_check_ioaddr(io[i], mac) == 0) - { - device * dev; + /* Copy the basic set of address to be probed. */ + for (i = 0; i < NELS(iobase); i++) + io[i] = iobase[i]; + } - /* Create device and set basic arguments. */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - if(dev==NULL) - { - ret = -ENOMEM; - break; - } - memset(dev, 0x00, sizeof(struct net_device)); - dev->name = name[i]; - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->init = &wavelan_config; - memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ - - /* Try to create the device. */ - if(register_netdev(dev) != 0) - { - /* Deallocate everything. */ - /* Note: if dev->priv is mallocated, there is no way to fail. */ - kfree_s(dev, sizeof(struct net_device)); - } - else - { - /* If at least one device OK, we do not fail */ - ret = 0; - } - } /* if there is something at the address */ - } /* Loop on all addresses. */ + + /* Loop on all possible base addresses. */ + i = -1; + while ((io[++i] != 0) && (i < NELS(io))) { + /* Check if there is something at this base address. */ + if (wv_check_ioaddr(io[i], mac) == 0) { + device *dev; + + /* Create device and set basic arguments. */ + dev = + kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + break; + } + memset(dev, 0x00, sizeof(struct net_device)); + dev->name = name[i]; + dev->base_addr = io[i]; + dev->irq = irq[i]; + dev->init = &wavelan_config; + memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ + + /* Try to create the device. */ + if (register_netdev(dev) != 0) { + /* Deallocate everything. */ + /* Note: if dev->priv is mallocated, there is no way to fail. */ + kfree_s(dev, sizeof(struct net_device)); + } else { + /* If at least one device OK, we do not fail */ + ret = 0; + } + } /* if there is something at the address */ + } /* Loop on all addresses. */ #ifdef DEBUG_CONFIG_ERROR - if(wavelan_list == (net_local *) NULL) - printk(KERN_WARNING "WaveLAN init_module(): no device found\n"); + if (wavelan_list == (net_local *) NULL) + printk(KERN_WARNING + "WaveLAN init_module(): no device found\n"); #endif #ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "<- init_module()\n"); + printk(KERN_DEBUG "<- init_module()\n"); #endif - return ret; + return ret; } /*------------------------------------------------------------------*/ /* * Removal of the module */ -void -cleanup_module(void) +void cleanup_module(void) { #ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "-> cleanup_module()\n"); + printk(KERN_DEBUG "-> cleanup_module()\n"); #endif - /* Loop on all devices and release them. */ - while(wavelan_list != (net_local *) NULL) - { - device * dev = wavelan_list->dev; + /* Loop on all devices and release them. */ + while (wavelan_list != (net_local *) NULL) { + device *dev = wavelan_list->dev; #ifdef DEBUG_CONFIG_INFO - printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n", - dev->name, (unsigned int) dev); + printk(KERN_DEBUG + "%s: cleanup_module(): removing device at 0x%x\n", + dev->name, (unsigned int) dev); #endif - /* Release the ioport region. */ - release_region(dev->base_addr, sizeof(ha_t)); + /* Release the ioport region. */ + release_region(dev->base_addr, sizeof(ha_t)); - /* Definitely remove the device. */ - unregister_netdev(dev); + /* Definitely remove the device. */ + unregister_netdev(dev); - /* Unlink the device. */ - wavelan_list = wavelan_list->next; + /* Unlink the device. */ + wavelan_list = wavelan_list->next; - /* Free pieces. */ - kfree_s(dev->priv, sizeof(struct net_local)); - kfree_s(dev, sizeof(struct net_device)); - } + /* Free pieces. */ + kfree_s(dev->priv, sizeof(struct net_local)); + kfree_s(dev, sizeof(struct net_device)); + } #ifdef DEBUG_MODULE_TRACE - printk(KERN_DEBUG "<- cleanup_module()\n"); + printk(KERN_DEBUG "<- cleanup_module()\n"); #endif } -#endif /* MODULE */ +#endif /* MODULE */ /* * This software may only be used and distributed @@ -4379,7 +4272,7 @@ * * Thanks go also to: * James Ashton (jaa101@syseng.anu.edu.au), - * Alan Cox (iialan@iiit.swan.ac.uk), + * Alan Cox (alan@redhat.com), * Allan Creighton (allanc@cs.usyd.edu.au), * Matthew Geier (matthew@cs.usyd.edu.au), * Remo di Giovanni (remo@cs.usyd.edu.au), diff -u --recursive --new-file v2.3.44/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.3.44/linux/drivers/net/znet.c Wed Aug 18 11:36:43 1999 +++ linux/drivers/net/znet.c Sun Feb 13 10:25:33 2000 @@ -119,10 +119,13 @@ #define CMD0_STAT2 (2 << 5) #define CMD0_STAT3 (3 << 5) +#define TX_TIMEOUT 10 + #define net_local znet_private struct znet_private { int rx_dma, tx_dma; struct net_device_stats stats; + spinlock_t lock; /* The starting, current, and end pointers for the packet buffers. */ ushort *rx_start, *rx_cur, *rx_end; ushort *tx_start, *tx_cur, *tx_end; @@ -190,6 +193,7 @@ static void set_multicast_list(struct net_device *dev); static void hardware_init(struct net_device *dev); static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); +static void znet_tx_timeout (struct net_device *dev); #ifdef notdef static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, }; @@ -245,6 +249,7 @@ dev->priv = (void *) &zn; zn.rx_dma = netinfo->dma1; zn.tx_dma = netinfo->dma2; + zn.lock = SPIN_LOCK_UNLOCKED; /* These should never fail. You can't add devices to a sealed box! */ if (request_irq(dev->irq, &znet_interrupt, 0, "ZNet", dev) @@ -275,6 +280,8 @@ dev->stop = &znet_close; dev->get_stats = net_get_stats; dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = znet_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; /* Fill in the 'dev' with ethernet-generic values. */ ether_setup(dev); @@ -306,41 +313,47 @@ printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n", dev->name); - dev->tbusy = 0; - dev->interrupt = 0; hardware_init(dev); - dev->start = 1; + netif_start_queue (dev); return 0; } + +static void znet_tx_timeout (struct net_device *dev) +{ + int ioaddr = dev->base_addr; + ushort event, tx_status, rx_offset, state; + + outb (CMD0_STAT0, ioaddr); + event = inb (ioaddr); + outb (CMD0_STAT1, ioaddr); + tx_status = inw (ioaddr); + outb (CMD0_STAT2, ioaddr); + rx_offset = inw (ioaddr); + outb (CMD0_STAT3, ioaddr); + state = inb (ioaddr); + printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x," + " resetting.\n", dev->name, event, tx_status, rx_offset, state); + if (tx_status == 0x0400) + printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n", + dev->name); + outb (CMD0_RESET, ioaddr); + hardware_init (dev); + netif_start_queue (dev); +} + static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) { int ioaddr = dev->base_addr; struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; if (znet_debug > 4) - printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy); - - /* Transmitter timeout, likely just recovery after suspending the machine. */ - if (dev->tbusy) { - ushort event, tx_status, rx_offset, state; - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 10) - return 1; - outb(CMD0_STAT0, ioaddr); event = inb(ioaddr); - outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr); - outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr); - outb(CMD0_STAT3, ioaddr); state = inb(ioaddr); - printk(KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x," - " resetting.\n", dev->name, event, tx_status, rx_offset, state); - if (tx_status == 0x0400) - printk(KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n", - dev->name); - outb(CMD0_RESET, ioaddr); - hardware_init(dev); - } + printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name); + netif_stop_queue (dev); + /* Check that the part hasn't reset itself, probably from suspend. */ outb(CMD0_STAT0, ioaddr); if (inw(ioaddr) == 0x0010 @@ -348,11 +361,7 @@ && inw(ioaddr) == 0x0010) hardware_init(dev); - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - else { + if (1) { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = (void *)skb->data; ushort *tx_link = zn.tx_cur - 1; @@ -385,13 +394,18 @@ zn.tx_cur += rnd_len; } *zn.tx_cur++ = 0; - cli(); { + + spin_lock_irqsave(&lp->lock, flags); + { *tx_link = CMD0_TRANSMIT + CMD0_CHNL_1; /* Is this always safe to do? */ outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr); - } sti(); + } + spin_unlock_irqrestore (&lp->lock, flags); dev->trans_start = jiffies; + netif_start_queue (dev); + if (znet_debug > 4) printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); } @@ -403,6 +417,7 @@ static void znet_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; + struct net_local *lp = (struct net_local *)dev->priv; int ioaddr; int boguscnt = 20; @@ -411,7 +426,8 @@ return; } - dev->interrupt = 1; + spin_lock (&lp->lock); + ioaddr = dev->base_addr; outb(CMD0_STAT0, ioaddr); @@ -432,7 +448,6 @@ break; if ((status & 0x0F) == 4) { /* Transmit done. */ - struct net_local *lp = (struct net_local *)dev->priv; int tx_status; outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr); @@ -449,8 +464,7 @@ if ((tx_status | 0x0760) != 0x0760) lp->stats.tx_errors++; } - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue (dev); } if ((status & 0x40) @@ -461,7 +475,8 @@ outb(CMD0_ACK,ioaddr); } while (boguscnt--); - dev->interrupt = 0; + spin_unlock (&lp->lock); + return; } @@ -594,8 +609,7 @@ unsigned long flags; int ioaddr = dev->base_addr; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue (dev); outb(CMD0_RESET, ioaddr); /* CMD0_RESET */ @@ -728,7 +742,7 @@ update_stop_hit(ioaddr, 8192); if (znet_debug > 1) printk("enabling Rx.\n"); outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr); - dev->tbusy = 0; + netif_start_queue (dev); } static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset) diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.3.44/linux/drivers/scsi/eata.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/eata.c Sun Feb 13 18:20:21 2000 @@ -910,7 +910,7 @@ if (info.sign != EATA_SIGNATURE) return FALSE; if (DEV2H(info.data_len) < EATA_2_0A_SIZE) { - printk("%s: config structure size (%ld bytes) too short, detaching.\n", + printk("%s: config structure size (%d bytes) too short, detaching.\n", name, DEV2H(info.data_len)); return FALSE; } diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.3.44/linux/drivers/scsi/hosts.h Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/hosts.h Sun Feb 13 19:05:39 2000 @@ -504,6 +504,15 @@ * tackle the character devices first, as there aren't any locking implications * in the block device layer. The block devices will require more work. */ +#ifndef CONFIG_SD_EXTRA_DEVS +#define CONFIG_SD_EXTRA_DEVS 2 +#endif +#ifndef CONFIG_ST_EXTRA_DEVS +#define CONFIG_ST_EXTRA_DEVS 2 +#endif +#ifndef CONFIG_SR_EXTRA_DEVS +#define CONFIG_SR_EXTRA_DEVS 2 +#endif #define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS #define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS #define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/mac_esp.c linux/drivers/scsi/mac_esp.c --- v2.3.44/linux/drivers/scsi/mac_esp.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/mac_esp.c Sun Feb 13 11:21:42 2000 @@ -417,7 +417,9 @@ esp->irq = IRQ_MAC_SCSI; request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp); +#if 0 /* conflicts with IOP ADB */ request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp); +#endif if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) { esp->cfreq = 16500000; @@ -429,8 +431,9 @@ } else { /* chipnum == 1 */ esp->irq = IRQ_MAC_SCSIDRQ; - +#if 0 /* conflicts with IOP ADB */ request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp); +#endif esp->cfreq = 25000000; diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/mac_scsi.c linux/drivers/scsi/mac_scsi.c --- v2.3.44/linux/drivers/scsi/mac_scsi.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/mac_scsi.c Sun Feb 13 11:21:42 2000 @@ -78,7 +78,6 @@ #define NDEBUG (NDEBUG_ABORT) #endif -#define USE_WRAPPER #define RESET_BOOT #define DRIVER_SETUP @@ -90,30 +89,9 @@ #undef DRIVER_SETUP #endif -/* - * Need to define this to make SCSI work on RBV machines; leave undefined - * to enable interrupts a bit more on other machines - * Changes method of SCSI interrupt disable from software mask to VIA IER! - * (don't know if that's essential) - * - * 990502 (jmt) - not needed (and won't work) on new irq architecture - */ -/* #define RBV_HACK */ - -#ifdef RBV_HACK -#define ENABLE_IRQ() mac_turnon_irq( IRQ_MAC_SCSI ); -#define DISABLE_IRQ() mac_turnoff_irq( IRQ_MAC_SCSI ); -#else #define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI ); #define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI ); -#endif - -#define mac_turnon_irq(x) mac_enable_irq(x) -#define mac_turnoff_irq(x) mac_disable_irq(x) -extern void via_scsi_clear(void); - -static void scsi_mac_intr(int irq, void *dummy, struct pt_regs *fp); #ifdef RESET_BOOT static void mac_scsi_reset_boot(struct Scsi_Host *instance); #endif @@ -253,7 +231,7 @@ if (macintosh_config->scsi_type != MAC_SCSI_OLD) return( 0 ); - tpnt->proc_name = "Mac 5380 SCSI"; + tpnt->proc_name = "mac5380"; /* setup variables */ tpnt->can_queue = @@ -306,11 +284,7 @@ ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; if (instance->irq != IRQ_NONE) -#ifdef USE_WRAPPER - if (request_irq(instance->irq, scsi_mac_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) { -#else - if (request_irq(instance->irq, macscsi_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) { -#endif + if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = IRQ_NONE; @@ -337,7 +311,7 @@ int macscsi_release (struct Scsi_Host *shpnt) { if (shpnt->irq != IRQ_NONE) - free_irq (shpnt->irq, NULL); + free_irq (shpnt->irq, NCR5380_intr); return 0; } @@ -362,7 +336,7 @@ printk( "Macintosh SCSI: resetting the SCSI bus..." ); /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ - mac_turnoff_irq( IRQ_MAC_SCSI ); + mac_disable_irq(IRQ_MAC_SCSI); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, @@ -380,7 +354,7 @@ barrier(); /* switch on SCSI IRQ again */ - mac_turnon_irq( IRQ_MAC_SCSI ); + mac_enable_irq(IRQ_MAC_SCSI); printk( " done\n" ); } @@ -399,49 +373,6 @@ restore_flags(flags); } -#ifdef USE_WRAPPER -/* - * SCSI interrupt wrapper - just to make sure it's the proper irq, and - * that we leave the handler in a clean state - */ - -static void scsi_mac_intr (int irq, void *dev_id, struct pt_regs *fp) -{ -#ifndef RBV_HACK - unsigned long flags; -#endif - -#ifdef RBV_HACK - mac_turnoff_irq( IRQ_MAC_SCSI ); -#else - mac_disable_irq( IRQ_MAC_SCSI ); -#endif - - if ( irq == IRQ_MAC_SCSI ) { -#ifndef RBV_HACK - save_flags(flags); - restore_irq(fp); -#endif - NCR5380_intr (irq, dev_id, fp); -#ifndef RBV_HACK - restore_flags(flags); -#endif - } - - /* To be sure the int is not masked */ -#ifdef RBV_HACK - mac_turnon_irq( IRQ_MAC_SCSI ); -#else - mac_enable_irq( IRQ_MAC_SCSI ); -#endif - -#if 1 /* ??? 0 worked */ - /* Clear the IRQ */ - via_scsi_clear(); -#endif -} -#endif - /* * pseudo-DMA transfer functions, copied and modified from Russel King's * ARM 5380 driver (cumana_1) @@ -720,11 +651,7 @@ printk("SCSI poll\n"); save_flags(flags); cli(); -#ifdef USE_WRAPPER - scsi_mac_intr(IRQ_MAC_SCSI, instance, NULL); -#else - macscsi_intr(IRQ_MAC_SCSI, instance, NULL); -#endif + NCR5380_intr(IRQ_MAC_SCSI, instance, NULL); restore_flags(flags); } #if 0 diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c --- v2.3.44/linux/drivers/scsi/mvme16x.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/mvme16x.c Sun Feb 13 11:21:42 2000 @@ -40,7 +40,7 @@ if (called) return 0; - tpnt->proc_name = "MVME16x" + tpnt->proc_name = "MVME16x"; options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c --- v2.3.44/linux/drivers/scsi/qla1280.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/qla1280.c Sun Feb 13 10:30:38 2000 @@ -182,6 +182,7 @@ - Initial Beta Release. *****************************************************************************/ + #ifdef MODULE #include #endif @@ -2789,7 +2790,7 @@ DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);) DEBUG(qla1280_print(debug_buff)); - printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address); + DEBUG(printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address)); BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1)); mb[0] = MBC_LOAD_RAM; /* mb[0] = MBC_LOAD_RAM_A64; */ @@ -2799,7 +2800,7 @@ mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff; mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff); mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff; - printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]); + DEBUG(printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3])); if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, &mb[0])) ) { diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.3.44/linux/drivers/scsi/qlogicisp.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/qlogicisp.c Sun Feb 13 10:14:58 2000 @@ -811,6 +811,7 @@ ds = cmd->dataseg; sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg); + Cmnd->use_sg = sg_count; cmd->segment_cnt = cpu_to_le16(sg_count); diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/sun3_NCR5380.c linux/drivers/scsi/sun3_NCR5380.c --- v2.3.44/linux/drivers/scsi/sun3_NCR5380.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/sun3_NCR5380.c Sun Feb 13 11:21:42 2000 @@ -0,0 +1,3012 @@ +/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by + Sam Creasey. */ +/* + * NCR 5380 generic driver routines. These should make it *trivial* + * to implement 5380 SCSI drivers under Linux with a non-trantor + * architecture. + * + * Note that these routines also work with NR53c400 family chips. + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 + * + * DISTRIBUTION RELEASE 6. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * ++roman: To port the 5380 driver to the Atari, I had to do some changes in + * this file, too: + * + * - Some of the debug statements were incorrect (undefined variables and the + * like). I fixed that. + * + * - In information_transfer(), I think a #ifdef was wrong. Looking at the + * possible DMA transfer size should also happen for REAL_DMA. I added this + * in the #if statement. + * + * - When using real DMA, information_transfer() should return in a DATAOUT + * phase after starting the DMA. It has nothing more to do. + * + * - The interrupt service routine should run main after end of DMA, too (not + * only after RESELECTION interrupts). Additionally, it should _not_ test + * for more interrupts after running main, since a DMA process may have + * been started and interrupts are turned on now. The new int could happen + * inside the execution of NCR5380_intr(), leading to recursive + * calls. + * + * - I've added a function merge_contiguous_buffers() that tries to + * merge scatter-gather buffers that are located at contiguous + * physical addresses and can be processed with the same DMA setup. + * Since most scatter-gather operations work on a page (4K) of + * 4 buffers (1K), in more than 90% of all cases three interrupts and + * DMA setup actions are saved. + * + * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA + * and USLEEP, because these were messing up readability and will never be + * needed for Atari SCSI. + * + * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' + * stuff), and 'main' is executed in a bottom half if awoken by an + * interrupt. + * + * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..." + * constructs. In my eyes, this made the source rather unreadable, so I + * finally replaced that by the *_PRINTK() macros. + * + */ + +/* + * Further development / testing that should be done : + * 1. Test linked command handling code after Eric is ready with + * the high level code. + */ + +#if (NDEBUG & NDEBUG_LISTS) +#define LIST(x,y) \ + { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \ + if ((x)==(y)) udelay(5); } +#define REMOVE(w,x,y,z) \ + { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \ + (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \ + if ((x)==(y)) udelay(5); } +#else +#define LIST(x,y) +#define REMOVE(w,x,y,z) +#endif + +#ifndef notyet +#undef LINKED +#endif + +/* + * Design + * Issues : + * + * The other Linux SCSI drivers were written when Linux was Intel PC-only, + * and specifically for each board rather than each chip. This makes their + * adaptation to platforms like the Mac (Some of which use NCR5380's) + * more difficult than it has to be. + * + * Also, many of the SCSI drivers were written before the command queuing + * routines were implemented, meaning their implementations of queued + * commands were hacked on rather than designed in from the start. + * + * When I designed the Linux SCSI drivers I figured that + * while having two different SCSI boards in a system might be useful + * for debugging things, two of the same type wouldn't be used. + * Well, I was wrong and a number of users have mailed me about running + * multiple high-performance SCSI boards in a server. + * + * Finally, when I get questions from users, I have no idea what + * revision of my driver they are running. + * + * This driver attempts to address these problems : + * This is a generic 5380 driver. To use it on a different platform, + * one simply writes appropriate system specific macros (ie, data + * transfer - some PC's will use the I/O bus, 68K's must use + * memory mapped) and drops this file in their 'C' wrapper. + * + * As far as command queueing, two queues are maintained for + * each 5380 in the system - commands that haven't been issued yet, + * and commands that are currently executing. This means that an + * unlimited number of commands may be queued, letting + * more commands propagate from the higher driver levels giving higher + * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, + * allowing multiple commands to propagate all the way to a SCSI-II device + * while a command is already executing. + * + * To solve the multiple-boards-in-the-same-system problem, + * there is a separate instance structure for each instance + * of a 5380 in the system. So, multiple NCR5380 drivers will + * be able to coexist with appropriate changes to the high level + * SCSI code. + * + * A NCR5380_PUBLIC_REVISION macro is provided, with the release + * number (updated for each public release) printed by the + * NCR5380_print_options command, which should be called from the + * wrapper detect function, so that I know what release of the driver + * users are using. + * + * Issues specific to the NCR5380 : + * + * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead + * piece of hardware that requires you to sit in a loop polling for + * the REQ signal as long as you are connected. Some devices are + * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect + * while doing long seek operations. + * + * The workaround for this is to keep track of devices that have + * disconnected. If the device hasn't disconnected, for commands that + * should disconnect, we do something like + * + * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } + * + * Some tweaking of N and M needs to be done. An algorithm based + * on "time to data" would give the best results as long as short time + * to datas (ie, on the same track) were considered, however these + * broken devices are the exception rather than the rule and I'd rather + * spend my time optimizing for the normal case. + * + * Architecture : + * + * At the heart of the design is a coroutine, NCR5380_main, + * which is started when not running by the interrupt handler, + * timer, and queue command function. It attempts to establish + * I_T_L or I_T_L_Q nexuses by removing the commands from the + * issue queue and calling NCR5380_select() if a nexus + * is not established. + * + * Once a nexus is established, the NCR5380_information_transfer() + * phase goes through the various phases as instructed by the target. + * if the target goes into MSG IN and sends a DISCONNECT message, + * the command structure is placed into the per instance disconnected + * queue, and NCR5380_main tries to find more work. If USLEEP + * was defined, and the target is idle for too long, the system + * will try to sleep. + * + * If a command has disconnected, eventually an interrupt will trigger, + * calling NCR5380_intr() which will in turn call NCR5380_reselect + * to reestablish a nexus. This will run main if necessary. + * + * On command termination, the done function will be called as + * appropriate. + * + * SCSI pointers are maintained in the SCp field of SCSI command + * structures, being initialized after the command is connected + * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. + * Note that in violation of the standard, an implicit SAVE POINTERS operation + * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. + */ + +/* + * Using this file : + * This file a skeleton Linux SCSI driver for the NCR 5380 series + * of chips. To use it, you write an architecture specific functions + * and macros and include this file in your driver. + * + * These macros control options : + * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically + * for commands that return with a CHECK CONDITION status. + * + * LINKED - if defined, linked commands are supported. + * + * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. + * + * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible + * + * These macros MUST be defined : + * + * NCR5380_read(register) - read from the specified register + * + * NCR5380_write(register, value) - write to the specific register + * + * Either real DMA *or* pseudo DMA may be implemented + * REAL functions : + * NCR5380_REAL_DMA should be defined if real DMA is to be used. + * Note that the DMA setup functions should return the number of bytes + * that they were able to program the controller for. + * + * Also note that generic i386/PC versions of these macros are + * available as NCR5380_i386_dma_write_setup, + * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. + * + * NCR5380_dma_write_setup(instance, src, count) - initialize + * NCR5380_dma_read_setup(instance, dst, count) - initialize + * NCR5380_dma_residual(instance); - residual count + * + * PSEUDO functions : + * NCR5380_pwrite(instance, src, count) + * NCR5380_pread(instance, dst, count); + * + * If nothing specific to this implementation needs doing (ie, with external + * hardware), you must also define + * + * NCR5380_queue_command + * NCR5380_reset + * NCR5380_abort + * NCR5380_proc_info + * + * to be the global entry points into the specific driver, ie + * #define NCR5380_queue_command t128_queue_command. + * + * If this is not done, the routines will be defined as static functions + * with the NCR5380* names and the user must provide a globally + * accessible wrapper function. + * + * The generic driver is initialized by calling NCR5380_init(instance), + * after setting the appropriate host specific fields and ID. If the + * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, + * possible) function may be used. Before the specific driver initialization + * code finishes, NCR5380_print_options should be called. + */ + +static struct Scsi_Host *first_instance = NULL; +static Scsi_Host_Template *the_template = NULL; + +/* Macros ease life... :-) */ +#define SETUP_HOSTDATA(in) \ + struct NCR5380_hostdata *hostdata = \ + (struct NCR5380_hostdata *)(in)->hostdata +#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) + +#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble)) +#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) + +#define HOSTNO instance->host_no +#define H_NO(cmd) (cmd)->host->host_no + +#ifdef SUPPORT_TAGS + +/* + * Functions for handling tagged queuing + * ===================================== + * + * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes: + * + * Using consecutive numbers for the tags is no good idea in my eyes. There + * could be wrong re-usings if the counter (8 bit!) wraps and some early + * command has been preempted for a long time. My solution: a bitfield for + * remembering used tags. + * + * There's also the problem that each target has a certain queue size, but we + * cannot know it in advance :-( We just see a QUEUE_FULL status being + * returned. So, in this case, the driver internal queue size assumption is + * reduced to the number of active tags if QUEUE_FULL is returned by the + * target. The command is returned to the mid-level, but with status changed + * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL + * correctly. + * + * We're also not allowed running tagged commands as long as an untagged + * command is active. And REQUEST SENSE commands after a contingent allegiance + * condition _must_ be untagged. To keep track whether an untagged command has + * been issued, the host->busy array is still employed, as it is without + * support for tagged queuing. + * + * One could suspect that there are possible race conditions between + * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the + * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(), + * which already guaranteed to be running at most once. It is also the only + * place where tags/LUNs are allocated. So no other allocation can slip + * between that pair, there could only happen a reselection, which can free a + * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes + * important: the tag bit must be cleared before 'nr_allocated' is decreased. + */ + +/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */ +#undef TAG_NONE +#define TAG_NONE 0xff + +/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */ +#if (MAX_TAGS % 32) != 0 +#error "MAX_TAGS must be a multiple of 32!" +#endif + +typedef struct { + char allocated[MAX_TAGS/8]; + int nr_allocated; + int queue_size; +} TAG_ALLOC; + +static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ + + +static void __init init_tags( void ) +{ + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for( target = 0; target < 8; ++target ) { + for( lun = 0; lun < 8; ++lun ) { + ta = &TagAlloc[target][lun]; + memset( &ta->allocated, 0, MAX_TAGS/8 ); + ta->nr_allocated = 0; + /* At the beginning, assume the maximum queue size we could + * support (MAX_TAGS). This value will be decreased if the target + * returns QUEUE_FULL status. + */ + ta->queue_size = MAX_TAGS; + } + } +} + + +/* Check if we can issue a command to this LUN: First see if the LUN is marked + * busy by an untagged command. If the command should use tagged queuing, also + * check that there is a free tag and the target's queue won't overflow. This + * function should be called with interrupts disabled to avoid race + * conditions. + */ + +static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) +{ + SETUP_HOSTDATA(cmd->host); + + if (hostdata->busy[cmd->target] & (1 << cmd->lun)) + return( 1 ); + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) + return( 0 ); + if (TagAlloc[cmd->target][cmd->lun].nr_allocated >= + TagAlloc[cmd->target][cmd->lun].queue_size ) { + TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", + H_NO(cmd), cmd->target, cmd->lun ); + return( 1 ); + } + return( 0 ); +} + + +/* Allocate a tag for a command (there are no checks anymore, check_lun_busy() + * must be called before!), or reserve the LUN in 'busy' if the command is + * untagged. + */ + +static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) +{ + SETUP_HOSTDATA(cmd->host); + + /* If we or the target don't support tagged queuing, allocate the LUN for + * an untagged command. + */ + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) { + cmd->tag = TAG_NONE; + hostdata->busy[cmd->target] |= (1 << cmd->lun); + TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " + "command\n", H_NO(cmd), cmd->target, cmd->lun ); + } + else { + TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + + cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS ); + set_bit( cmd->tag, &ta->allocated ); + ta->nr_allocated++; + TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " + "(now %d tags in use)\n", + H_NO(cmd), cmd->tag, cmd->target, cmd->lun, + ta->nr_allocated ); + } +} + + +/* Mark the tag of command 'cmd' as free, or in case of an untagged command, + * unlock the LUN. + */ + +static void cmd_free_tag( Scsi_Cmnd *cmd ) +{ + SETUP_HOSTDATA(cmd->host); + + if (cmd->tag == TAG_NONE) { + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", + H_NO(cmd), cmd->target, cmd->lun ); + } + else if (cmd->tag >= MAX_TAGS) { + printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", + H_NO(cmd), cmd->tag ); + } + else { + TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + clear_bit( cmd->tag, &ta->allocated ); + ta->nr_allocated--; + TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", + H_NO(cmd), cmd->tag, cmd->target, cmd->lun ); + } +} + + +static void free_all_tags( void ) +{ + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for( target = 0; target < 8; ++target ) { + for( lun = 0; lun < 8; ++lun ) { + ta = &TagAlloc[target][lun]; + memset( &ta->allocated, 0, MAX_TAGS/8 ); + ta->nr_allocated = 0; + } + } +} + +#endif /* SUPPORT_TAGS */ + + +/* + * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd ) + * + * Purpose: Try to merge several scatter-gather requests into one DMA + * transfer. This is possible if the scatter buffers lie on + * physical contiguous addresses. + * + * Parameters: Scsi_Cmnd *cmd + * The command to work on. The first scatter buffer's data are + * assumed to be already transfered into ptr/this_residual. + */ + +static void merge_contiguous_buffers( Scsi_Cmnd *cmd ) +{ + unsigned long endaddr; +#if (NDEBUG & NDEBUG_MERGING) + unsigned long oldlen = cmd->SCp.this_residual; + int cnt = 1; +#endif + + for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; + cmd->SCp.buffers_residual && + virt_to_phys(cmd->SCp.buffer[1].address) == endaddr; ) { + + MER_PRINTK("VTOP(%p) == %08lx -> merging\n", + cmd->SCp.buffer[1].address, endaddr); +#if (NDEBUG & NDEBUG_MERGING) + ++cnt; +#endif + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual += cmd->SCp.buffer->length; + endaddr += cmd->SCp.buffer->length; + } +#if (NDEBUG & NDEBUG_MERGING) + if (oldlen != cmd->SCp.this_residual) + MER_PRINTK("merged %d buffers from %p, new length %08x\n", + cnt, cmd->SCp.ptr, cmd->SCp.this_residual); +#endif +} + +/* + * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * + * Purpose : initialize the saved data pointers for cmd to point to the + * start of the buffer. + * + * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + */ + +static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) +{ + /* + * Initialize the Scsi Pointer field so that all of the commands in the + * various queues are valid. + */ + + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + /* ++roman: Try to merge some scatter-buffers if they are at + * contiguous physical addresses. + */ + merge_contiguous_buffers( cmd ); + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } + +} + +#include +#include + +#if 1 +static struct { + unsigned char mask; + const char * name;} +signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, + { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, + { SR_SEL, "SEL" }, {0, NULL}}, +basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, +icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL}}, +mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, + "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL}}; + +/* + * Function : void NCR5380_print(struct Scsi_Host *instance) + * + * Purpose : print the SCSI bus signals for debugging purposes + * + * Input : instance - which NCR5380 + */ + +static void NCR5380_print(struct Scsi_Host *instance) { + unsigned char status, data, basr, mr, icr, i; + unsigned long flags; + + save_flags(flags); + cli(); + data = NCR5380_read(CURRENT_SCSI_DATA_REG); + status = NCR5380_read(STATUS_REG); + mr = NCR5380_read(MODE_REG); + icr = NCR5380_read(INITIATOR_COMMAND_REG); + basr = NCR5380_read(BUS_AND_STATUS_REG); + restore_flags(flags); + printk("STATUS_REG: %02x ", status); + for (i = 0; signals[i].mask ; ++i) + if (status & signals[i].mask) + printk(",%s", signals[i].name); + printk("\nBASR: %02x ", basr); + for (i = 0; basrs[i].mask ; ++i) + if (basr & basrs[i].mask) + printk(",%s", basrs[i].name); + printk("\nICR: %02x ", icr); + for (i = 0; icrs[i].mask; ++i) + if (icr & icrs[i].mask) + printk(",%s", icrs[i].name); + printk("\nMODE: %02x ", mr); + for (i = 0; mrs[i].mask; ++i) + if (mr & mrs[i].mask) + printk(",%s", mrs[i].name); + printk("\n"); +} + +static struct { + unsigned char value; + const char *name; +} phases[] = { + {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"}}; + +/* + * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * + * Purpose : print the current SCSI phase for debugging purposes + * + * Input : instance - which NCR5380 + */ + +static void NCR5380_print_phase(struct Scsi_Host *instance) +{ + unsigned char status; + int i; + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && + (phases[i].value != (status & PHASE_MASK)); ++i); + printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); + } +} + +#else /* !NDEBUG */ + +/* dummies... */ +__inline__ void NCR5380_print(struct Scsi_Host *instance) { }; +__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; + +#endif + +/* + * ++roman: New scheme of calling NCR5380_main() + * + * If we're not in an interrupt, we can call our main directly, it cannot be + * already running. Else, we queue it on a task queue, if not 'main_running' + * tells us that a lower level is already executing it. This way, + * 'main_running' needs not be protected in a special way. + * + * queue_main() is a utility function for putting our main onto the task + * queue, if main_running is false. It should be called only from a + * interrupt or bottom half. + */ + +#include +#include + +static volatile int main_running = 0; +static struct tq_struct NCR5380_tqueue = { + NULL, /* next */ + 0, /* sync */ + (void (*)(void*))NCR5380_main, /* routine, must have (void *) arg... */ + NULL /* data */ +}; + +static __inline__ void queue_main(void) +{ + if (!main_running) { + /* If in interrupt and NCR5380_main() not already running, + queue it on the 'immediate' task queue, to be processed + immediately after the current interrupt processing has + finished. */ + queue_task(&NCR5380_tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + /* else: nothing to do: the running NCR5380_main() will pick up + any newly queued command. */ +} + + +static inline void NCR5380_all_init (void) +{ + static int done = 0; + if (!done) { + INI_PRINTK("scsi : NCR5380_all_init()\n"); + done = 1; + } +} + + +/* + * Function : void NCR58380_print_options (struct Scsi_Host *instance) + * + * Purpose : called by probe code indicating the NCR5380 driver + * options that were selected. + * + * Inputs : instance, pointer to this instance. Unused. + */ + +static void __init NCR5380_print_options (struct Scsi_Host *instance) +{ + printk(" generic options" +#ifdef AUTOSENSE + " AUTOSENSE" +#endif +#ifdef REAL_DMA + " REAL DMA" +#endif +#ifdef PARITY + " PARITY" +#endif +#ifdef SUPPORT_TAGS + " SCSI-2 TAGGED QUEUING" +#endif + ); + printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); +} + +/* + * Function : void NCR5380_print_status (struct Scsi_Host *instance) + * + * Purpose : print commands in the various queues, called from + * NCR5380_abort and NCR5380_debug to aid debugging. + * + * Inputs : instance, pointer to this instance. + */ + +static void NCR5380_print_status (struct Scsi_Host *instance) +{ + char *pr_bfr; + char *start; + int len; + + NCR_PRINT(NDEBUG_ANY); + NCR_PRINT_PHASE(NDEBUG_ANY); + + pr_bfr = (char *) __get_free_page(GFP_ATOMIC); + if (!pr_bfr) { + printk("NCR5380_print_status: no memory for print buffer\n"); + return; + } + len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0); + pr_bfr[len] = 0; + printk("\n%s\n", pr_bfr); + free_page((unsigned long) pr_bfr); +} + + +/******************************************/ +/* + * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] + * + * *buffer: I/O buffer + * **start: if inout == FALSE pointer into buffer where user read should start + * offset: current offset + * length: length of buffer + * hostno: Scsi_Host host_no + * inout: TRUE - user is writing; FALSE - user is reading + * + * Return the number of bytes read from or written +*/ + +#undef SPRINTF +#define SPRINTF(fmt,args...) \ + do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ + pos += sprintf(pos, fmt , ## args); } while(0) +static +char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); + +#ifndef NCR5380_proc_info +static +#endif +int NCR5380_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + char *pos = buffer; + struct Scsi_Host *instance; + struct NCR5380_hostdata *hostdata; + Scsi_Cmnd *ptr; + unsigned long flags; + off_t begin = 0; +#define check_offset() \ + do { \ + if (pos - buffer < offset - begin) { \ + begin += pos - buffer; \ + pos = buffer; \ + } \ + } while (0) + + for (instance = first_instance; instance && HOSTNO != hostno; + instance = instance->next) + ; + if (!instance) + return(-ESRCH); + hostdata = (struct NCR5380_hostdata *)instance->hostdata; + + if (inout) { /* Has data been written to the file ? */ + return(-ENOSYS); /* Currently this is a no-op */ + } + SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); + check_offset(); + save_flags(flags); + cli(); + SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); + check_offset(); + if (!hostdata->connected) + SPRINTF("scsi%d: no currently connected command\n", HOSTNO); + else + pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, + pos, buffer, length); + SPRINTF("scsi%d: issue_queue\n", HOSTNO); + check_offset(); + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { + pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); + check_offset(); + } + + SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); + check_offset(); + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; + ptr = NEXT(ptr)) { + pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); + check_offset(); + } + + restore_flags(flags); + *start = buffer + (offset - begin); + if (pos - buffer < offset - begin) + return 0; + else if (pos - buffer - (offset - begin) < length) + return pos - buffer - (offset - begin); + return length; +} + +static char * +lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) +{ + int i, s; + unsigned char *command; + SPRINTF("scsi%d: destination target %d, lun %d\n", + H_NO(cmd), cmd->target, cmd->lun); + SPRINTF(" command = "); + command = cmd->cmnd; + SPRINTF("%2d (0x%02x)", command[0], command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + SPRINTF(" %02x", command[i]); + SPRINTF("\n"); + return pos; +} + + +/* + * Function : void NCR5380_init (struct Scsi_Host *instance) + * + * Purpose : initializes *instance and corresponding 5380 chip. + * + * Inputs : instance - instantiation of the 5380 driver. + * + * Notes : I assume that the host, hostno, and id bits have been + * set correctly. I don't care about the irq and other fields. + * + */ + +static void __init NCR5380_init (struct Scsi_Host *instance, int flags) +{ + int i; + SETUP_HOSTDATA(instance); + + NCR5380_all_init(); + + hostdata->aborted = 0; + hostdata->id_mask = 1 << instance->this_id; + hostdata->id_higher_mask = 0; + for (i = hostdata->id_mask; i <= 0x80; i <<= 1) + if (i > hostdata->id_mask) + hostdata->id_higher_mask |= i; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; +#ifdef SUPPORT_TAGS + init_tags(); +#endif +#if defined (REAL_DMA) + hostdata->dma_len = 0; +#endif + hostdata->targets_present = 0; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; + hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; + + if (!the_template) { + the_template = instance->hostt; + first_instance = instance; + } + + +#ifndef AUTOSENSE + if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) + printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" + " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", HOSTNO); +#endif /* def AUTOSENSE */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, 0); +} + +/* + * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, + * void (*done)(Scsi_Cmnd *)) + * + * Purpose : enqueues a SCSI command + * + * Inputs : cmd - SCSI command, done - function called on completion, with + * a pointer to the command descriptor. + * + * Returns : 0 + * + * Side effects : + * cmd is added to the per instance issue_queue, with minor + * twiddling done to the host specific fields of cmd. If the + * main coroutine is not running, it is restarted. + * + */ + +/* Only make static if a wrapper function is used */ +#ifndef NCR5380_queue_command +static +#endif +int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +{ + SETUP_HOSTDATA(cmd->host); + Scsi_Cmnd *tmp; + unsigned long flags; + extern int update_timeout(Scsi_Cmnd * SCset, int timeout); + +#if (NDEBUG & NDEBUG_NO_WRITE) + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", + H_NO(cmd)); + cmd->result = (DID_ERROR << 16); + done(cmd); + return 0; + } +#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ + + +#ifdef NCR5380_STATS +# if 0 + if (!hostdata->connected && !hostdata->issue_queue && + !hostdata->disconnected_queue) { + hostdata->timebase = jiffies; + } +# endif +# ifdef NCR5380_STAT_LIMIT + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) +# endif + switch (cmd->cmnd[0]) + { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->target] += cmd->request_bufflen; + hostdata->pendingw++; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->target] += cmd->request_bufflen; + hostdata->pendingr++; + break; + } +#endif + + /* + * We use the host_scribble field as a pointer to the next command + * in a queue + */ + + NEXT(cmd) = NULL; + cmd->scsi_done = done; + + cmd->result = 0; + + + /* + * Insert the cmd into the issue queue. Note that REQUEST SENSE + * commands are added to the head of the queue since any command will + * clear the contingent allegiance condition that exists and the + * sense data is only guaranteed to be valid while the condition exists. + */ + + save_flags(flags); + cli(); + /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. + * Otherwise a running NCR5380_main may steal the lock. + * Lock before actually inserting due to fairness reasons explained in + * atari_scsi.c. If we insert first, then it's impossible for this driver + * to release the lock. + * Stop timer for this command while waiting for the lock, or timeouts + * may happen (and they really do), and it's no good if the command doesn't + * appear in any of the queues. + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which would + * alter queues and touch the lock. + */ + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; + NEXT(tmp); tmp = NEXT(tmp)) + ; + LIST(cmd, tmp); + NEXT(tmp) = cmd; + } + + restore_flags(flags); + + QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), + (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); + + /* If queue_command() is called from an interrupt (real one or bottom + * half), we let queue_main() do the job of taking care about main. If it + * is already running, this is a no-op, else main will be queued. + * + * If we're not in an interrupt, we can call NCR5380_main() + * unconditionally, because it cannot be already running. + */ + if (in_interrupt() || ((flags >> 8) & 7) >= 6) + queue_main(); + else + NCR5380_main(); + return 0; +} + +/* + * Function : NCR5380_main (void) + * + * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * be done on the NCR5380 host adapters in a system. Both + * NCR5380_queue_command() and NCR5380_intr() will try to start it + * in case it is not running. + * + * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should + * reenable them. This prevents reentrancy and kernel stack overflow. + */ + +static void NCR5380_main (void) +{ + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance = first_instance; + struct NCR5380_hostdata *hostdata = HOSTDATA(instance); + int done; + unsigned long flags; + + /* + * We run (with interrupts disabled) until we're sure that none of + * the host adapters have anything that can be done, at which point + * we set main_running to 0 and exit. + * + * Interrupts are enabled before doing various other internal + * instructions, after we've decided that we need to run through + * the loop again. + * + * this should prevent any race conditions. + * + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which can + * alter queues and touch the Falcon lock. + */ + + /* Tell int handlers main() is now already executing. Note that + no races are possible here. If an int comes in before + 'main_running' is set here, and queues/executes main via the + task queue, it doesn't do any harm, just this instance of main + won't find any work left to do. */ + if (main_running) + return; + main_running = 1; + + save_flags(flags); + do { + cli(); /* Freeze request queues */ + done = 1; + + if (!hostdata->connected) { + MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO ); + /* + * Search through the issue_queue for a command destined + * for a target that's not busy. + */ +#if (NDEBUG & NDEBUG_LISTS) + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; + tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) + ; + if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ +#endif + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, + prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { + +#if (NDEBUG & NDEBUG_LISTS) + if (prev != tmp) + printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", + tmp, tmp->target, hostdata->busy[tmp->target], + tmp->lun); +#endif + /* When we find one, remove it from the issue queue. */ + /* ++guenther: possible race with Falcon locking */ + if ( +#ifdef SUPPORT_TAGS + !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) +#else + !(hostdata->busy[tmp->target] & (1 << tmp->lun)) +#endif + ) { + cli(); /* ++guenther: just to be sure, this must be atomic */ + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); + } else { + REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); + hostdata->issue_queue = NEXT(tmp); + } + NEXT(tmp) = NULL; + + /* reenable interrupts after finding one */ + restore_flags(flags); + + /* + * Attempt to establish an I_T_L nexus here. + * On success, instance->hostdata->connected is set. + * On failure, we must add the command back to the + * issue queue so we can keep trying. + */ + MAIN_PRINTK("scsi%d: main(): command for target %d " + "lun %d removed from issue_queue\n", + HOSTNO, tmp->target, tmp->lun); + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + /* ++roman: ...and the standard also requires that + * REQUEST SENSE command are untagged. + */ + +#ifdef SUPPORT_TAGS + cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE ); +#endif + if (!NCR5380_select(instance, tmp, + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : + TAG_NEXT)) { + break; + } else { + cli(); + LIST(tmp, hostdata->issue_queue); + NEXT(tmp) = hostdata->issue_queue; + hostdata->issue_queue = tmp; +#ifdef SUPPORT_TAGS + cmd_free_tag( tmp ); +#endif + restore_flags(flags); + MAIN_PRINTK("scsi%d: main(): select() failed, " + "returned to issue_queue\n", HOSTNO); + if (hostdata->connected) + break; + } + } /* if target/lun/target queue is not busy */ + } /* for issue_queue */ + } /* if (!hostdata->connected) */ + if (hostdata->connected +#ifdef REAL_DMA + && !hostdata->dma_len +#endif + ) { + restore_flags(flags); + MAIN_PRINTK("scsi%d: main: performing information transfer\n", + HOSTNO); + NCR5380_information_transfer(instance); + MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); + done = 0; + } + } while (!done); + + /* Better allow ints _after_ 'main_running' has been cleared, else + an interrupt could believe we'll pick up the work it left for + us, but we won't see it anymore here... */ + main_running = 0; + restore_flags(flags); +} + + +#ifdef REAL_DMA +/* + * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) + * + * Purpose : Called by interrupt handler when DMA finishes or a phase + * mismatch occurs (which would finish the DMA transfer). + * + * Inputs : instance - this instance of the NCR5380. + * + */ + +static void NCR5380_dma_complete( struct Scsi_Host *instance ) +{ + SETUP_HOSTDATA(instance); + int transfered; + unsigned char **data; + volatile int *count; + + if (!hostdata->connected) { + printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " + "no connected cmd\n", HOSTNO); + return; + } + + DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", + HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); + + if((sun3scsi_dma_finish())) { + printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO); + printk("please e-mail sammy@oh.verio.com with a description of how this\n"); + printk("error was produced.\n"); + machine_halt(); + } + + /* make sure we're not stuck in a data phase */ + if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | + BASR_ACK)) == + (BASR_PHASE_MATCH | BASR_ACK)) { + printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG)); + printk("scsi%d: bus stuck in data phase -- probably a + single byte overrun!\n", HOSTNO); + printk("not prepared for this error!\n"); + printk("please e-mail sammy@oh.verio.com with a description of how this\n"); + printk("error was produced.\n"); + machine_halt(); + } + + + + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + transfered = hostdata->dma_len - NCR5380_dma_residual(instance); + hostdata->dma_len = 0; + + data = (unsigned char **) &(hostdata->connected->SCp.ptr); + count = &(hostdata->connected->SCp.this_residual); + *data += transfered; + *count -= transfered; + +} +#endif /* REAL_DMA */ + + +/* + * Function : void NCR5380_intr (int irq) + * + * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses + * from the disconnected queue, and restarting NCR5380_main() + * as required. + * + * Inputs : int irq, irq that caused this interrupt. + * + */ + +static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *instance = first_instance; + int done = 1; + unsigned char basr; + + INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); + + /* Look for pending interrupts */ + basr = NCR5380_read(BUS_AND_STATUS_REG); + INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); + /* dispatch to appropriate routine if found and done=0 */ + if (basr & BASR_IRQ) { + NCR_PRINT(NDEBUG_INTR); + if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { + done = 0; + ENABLE_IRQ(); + INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); + NCR5380_reselect(instance); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else if (basr & BASR_PARITY_ERROR) { + INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { + INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + else { + /* + * The rest of the interrupt conditions can occur only during a + * DMA transfer + */ + +#if defined(REAL_DMA) + /* + * We should only get PHASE MISMATCH and EOP interrupts if we have + * DMA enabled, so do a sanity check based on the current setting + * of the MODE register. + */ + + if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && + ((basr & BASR_END_DMA_TRANSFER) || + !(basr & BASR_PHASE_MATCH))) { + + INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); + NCR5380_dma_complete( instance ); + done = 0; + ENABLE_IRQ(); + } else +#endif /* REAL_DMA */ + { +/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ + if (basr & BASR_PHASE_MATCH) + printk(KERN_NOTICE "scsi%d: unknown interrupt, " + "BASR 0x%x, MR 0x%x, SR 0x%x\n", + HOSTNO, basr, NCR5380_read(MODE_REG), + NCR5380_read(STATUS_REG)); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + } /* if !(SELECTION || PARITY) */ + } /* BASR & IRQ */ + else { + + printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " + "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, + NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + + if (!done) { + INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); + /* Put a call to NCR5380_main() on the queue... */ + queue_main(); + } +} + +#ifdef NCR5380_STATS +static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) +{ +# ifdef NCR5380_STAT_LIMIT + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) +# endif + switch (cmd->cmnd[0]) + { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/ + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/ + hostdata->pendingr--; + break; + } +} +#endif + +/* + * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, + * int tag); + * + * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, + * including ARBITRATION, SELECTION, and initial message out for + * IDENTIFY and queue messages. + * + * Inputs : instance - instantiation of the 5380 driver on which this + * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for + * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for + * the command that is presently connected. + * + * Returns : -1 if selection could not execute for some reason, + * 0 if selection succeeded or failed because the target + * did not respond. + * + * Side effects : + * If bus busy, arbitration failed, etc, NCR5380_select() will exit + * with registers as they should have been on entry - ie + * SELECT_ENABLE will be set appropriately, the NCR5380 + * will cease to drive any SCSI bus signals. + * + * If successful : I_T_L or I_T_L_Q nexus will be established, + * instance->connected will be set to cmd. + * SELECT interrupt will be disabled. + * + * If failed (no target) : cmd->scsi_done() will be called, and the + * cmd->result host byte set to DID_BAD_TARGET. + */ + +static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) +{ + SETUP_HOSTDATA(instance); + unsigned char tmp[3], phase; + unsigned char *data; + int len; + unsigned long timeout; + unsigned long flags; + + hostdata->restart_select = 0; + NCR_PRINT(NDEBUG_ARBITRATION); + ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, + instance->this_id); + + /* + * Set the phase bits to 0, otherwise the NCR5380 won't drive the + * data bus during SELECTION. + */ + + save_flags(flags); + cli(); + if (hostdata->connected) { + restore_flags(flags); + return -1; + } + NCR5380_write(TARGET_COMMAND_REG, 0); + + + /* + * Start arbitration. + */ + + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); + + restore_flags(flags); + + /* Wait for arbitration logic to complete */ +#if NCR_TIMEOUT + { + unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && time_before(jiffies, timeout) && !hostdata->connected) + ; + if (time_after_eq(jiffies, timeout)) + { + printk("scsi : arbitration timeout at %d\n", __LINE__); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + } +#else /* NCR_TIMEOUT */ + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && !hostdata->connected); +#endif + + ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); + + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + return -1; + } + /* + * The arbitration delay is 2.2us, but this is a minimum and there is + * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate + * the integral nature of udelay(). + * + */ + + udelay(3); + + /* Check for lost arbitration */ + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", + HOSTNO); + return -1; + } + + /* after/during arbitration, BSY should be asserted. + IBM DPES-31080 Version S31Q works now */ + /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL | + ICR_ASSERT_BSY ) ; + + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", + HOSTNO); + return -1; + } + + /* + * Again, bus clear + bus settle time is 1.2us, however, this is + * a minimum so we'll udelay ceil(1.2) + */ + +#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY + /* ++roman: But some targets (see above :-) seem to need a bit more... */ + udelay(15); +#else + udelay(2); +#endif + + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } + + ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); + + /* + * Now that we have won arbitration, start Selection process, asserting + * the host and target ID's on the SCSI bus. + */ + + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after selection. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); + NCR5380_write(MODE_REG, MR_BASE); + + /* + * Reselect interrupts must be turned off prior to the dropping of BSY, + * otherwise we will trigger an interrupt. + */ + + if (hostdata->connected) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } + + NCR5380_write(SELECT_ENABLE_REG, 0); + + /* + * The initiator shall then wait at least two deskew delays and release + * the BSY signal. + */ + udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ + + /* Reset BSY */ + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | + ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + + /* + * Something weird happens when we cease to drive BSY - looks + * like the board/chip is letting us do another read before the + * appropriate propagation delay has expired, and we're confusing + * a BSY signal from ourselves as the target's response to SELECTION. + * + * A small delay (the 'C++' frontend breaks the pipeline with an + * unnecessary jump, making it work on my 386-33/Trantor T128, the + * tighter 'C' code breaks and requires this) solves the problem - + * the 1 us delay is arbitrary, and only used because this delay will + * be the same on other platforms and since it works here, it should + * work there. + * + * wingel suggests that this could be due to failing to wait + * one deskew delay. + */ + + udelay(1); + + SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target); + + /* + * The SCSI specification calls for a 250 ms timeout for the actual + * selection. + */ + + timeout = jiffies + 25; + + /* + * XXX very interesting - we're seeing a bounce where the BSY we + * asserted is being reflected / still asserted (propagation delay?) + * and it's detecting as true. Sigh. + */ + +#if 0 + /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert + * IO while SEL is true. But again, there are some disks out the in the + * world that do that nevertheless. (Somebody claimed that this announces + * reselection capability of the target.) So we better skip that test and + * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) + */ + + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & + (SR_BSY | SR_IO))); + + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == + (SR_SEL | SR_IO)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_reselect(instance); + printk (KERN_ERR "scsi%d: reselection after won arbitration?\n", + HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } +#else + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); +#endif + + /* + * No less than two deskew delays after the initiator detects the + * BSY signal is true, it shall release the SEL signal and may + * change the DATA BUS. -wingel + */ + + udelay(1); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + + if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + if (hostdata->targets_present & (1 << cmd->target)) { + printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); + if (hostdata->restart_select) + printk(KERN_NOTICE "\trestart select\n"); + NCR_PRINT(NDEBUG_ANY); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + cmd->result = DID_BAD_TARGET << 16; +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); +#endif + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return 0; + } + + hostdata->targets_present |= (1 << cmd->target); + + /* + * Since we followed the SCSI spec, and raised ATN while SEL + * was true but before BSY was false during selection, the information + * transfer phase should be a MESSAGE OUT phase so that we can send the + * IDENTIFY message. + * + * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG + * message (2 bytes) with a tag ID that we increment with every command + * until it wraps back to 0. + * + * XXX - it turns out that there are some broken SCSI-II devices, + * which claim to support tagged queuing but fail when more than + * some number of commands are issued at once. + */ + + /* Wait for start of REQ/ACK handshake */ + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + + SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", + HOSTNO, cmd->target); + tmp[0] = IDENTIFY(1, cmd->lun); + +#ifdef SUPPORT_TAGS + if (cmd->tag != TAG_NONE) { + tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; + tmp[2] = cmd->tag; + len = 3; + } else + len = 1; +#else + len = 1; + cmd->tag=0; +#endif /* SUPPORT_TAGS */ + + /* Send message(s) */ + data = tmp; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(instance, &phase, &len, &data); + SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); + /* XXX need to handle errors here */ + hostdata->connected = cmd; +#ifndef SUPPORT_TAGS + hostdata->busy[cmd->target] |= (1 << cmd->lun); +#endif + + initialize_SCp(cmd); + + + return 0; +} + +/* + * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, + * unsigned char *phase, int *count, unsigned char **data) + * + * Purpose : transfers data in given phase using polled I/O + * + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. + * + * Returns : -1 when different phase is entered without transferring + * maximum number of bytes, 0 if all bytes are transfered or exit + * is in same phase. + * + * Also, *phase, *count, *data are modified in place. + * + * XXX Note : handling for bus free may be useful. + */ + +/* + * Note : this code is not as quick as it could be, however it + * IS 100% reliable, and for the actual data transfer where speed + * counts, we will always do a pseudo DMA or DMA transfer. + */ + +static int NCR5380_transfer_pio( struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) +{ + register unsigned char p = *phase, tmp; + register int c = *count; + register unsigned char *d = *data; + + /* + * The NCR5380 chip will only drive the SCSI bus when the + * phase specified in the appropriate bits of the TARGET COMMAND + * REGISTER match the STATUS REGISTER + */ + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + + do { + /* + * Wait for assertion of REQ, after which the phase bits will be + * valid + */ + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); + + HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); + + /* Check for phase mismatch */ + if ((tmp & PHASE_MASK) != p) { + PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); + NCR_PRINT_PHASE(NDEBUG_PIO); + break; + } + + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); + else + *d = NCR5380_read(CURRENT_SCSI_DATA_REG); + + ++d; + + /* + * The SCSI standard suggests that in MSGOUT phase, the initiator + * should drop ATN on the last byte of the message phase + * after REQ has been asserted for the handshake but before + * the initiator raises ACK. + */ + + if (!(p & SR_IO)) { + if (!((p & SR_MSG) && c > 1)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA); + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ACK); + } else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + } + } else { + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); + } + + while (NCR5380_read(STATUS_REG) & SR_REQ); + + HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); + +/* + * We have several special cases to consider during REQ/ACK handshaking : + * 1. We were in MSGOUT phase, and we are on the last byte of the + * message. ATN must be dropped as ACK is dropped. + * + * 2. We are in a MSGIN phase, and we are on the last byte of the + * message. We must exit with ACK asserted, so that the calling + * code may raise ATN before dropping ACK to reject the message. + * + * 3. ACK and ATN are clear and the target may proceed as normal. + */ + if (!(p == PHASE_MSGIN && c == 1)) { + if (p == PHASE_MSGOUT && c > 1) + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + else + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } + } while (--c); + + PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); + + *count = c; + *data = d; + tmp = NCR5380_read(STATUS_REG); + /* The phase read from the bus is valid if either REQ is (already) + * asserted or if ACK hasn't been released yet. The latter is the case if + * we're in MSGIN and all wanted bytes have been received. */ + if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) + *phase = tmp & PHASE_MASK; + else + *phase = PHASE_UNKNOWN; + + if (!c || (*phase == p)) + return 0; + else + return -1; +} + +/* + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + */ + +static int do_abort (struct Scsi_Host *host) +{ + unsigned char tmp, *msgptr, phase; + int len; + + /* Request message out phase */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + + /* + * Wait for the target to indicate a valid phase by asserting + * REQ. Once this happens, we'll have either a MSGOUT phase + * and can immediately send the ABORT message, or we'll have some + * other phase and will have to source/sink data. + * + * We really don't care what value was on the bus or what value + * the target sees, so we just handshake. + */ + + while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + } + + tmp = ABORT; + msgptr = &tmp; + len = 1; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio (host, &phase, &len, &msgptr); + + /* + * If we got here, and the command completed successfully, + * we're about to go into bus free state. + */ + + return len ? -1 : 0; +} + +#if defined(REAL_DMA) +/* + * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, + * unsigned char *phase, int *count, unsigned char **data) + * + * Purpose : transfers data in given phase using either real + * or pseudo DMA. + * + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. + * + * Returns : -1 when different phase is entered without transferring + * maximum number of bytes, 0 if all bytes or transfered or exit + * is in same phase. + * + * Also, *phase, *count, *data are modified in place. + * + */ + + +static int NCR5380_transfer_dma( struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) +{ + SETUP_HOSTDATA(instance); + register int c = *count; + register unsigned char p = *phase; + unsigned long flags; + + /* sanity check */ + if(!sun3_dma_setup_done) { + printk("scsi%d: transfer_dma without setup!\n", HOSTNO); + machine_halt(); + } + + hostdata->dma_len = c; + + DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", + HOSTNO, (p & SR_IO) ? "reading" : "writing", + c, (p & SR_IO) ? "to" : "from", d); + + /* netbsd turns off ints here, why not be safe and do it too */ + save_flags(flags); + cli(); + + /* send start chain */ + sun3_udc_write(UDC_CHN_START, UDC_CSR); + + if (p & SR_IO) { + NCR5380_write(TARGET_COMMAND_REG, 1); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(INITIATOR_COMMAND_REG, 0); + NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR)); + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + } else { + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA); + NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR)); + NCR5380_write(START_DMA_SEND_REG, 0); + } + + restore_flags(flags); + + sun3_dma_active = 1; + return 0; +} +#endif /* defined(REAL_DMA) */ + +/* + * Function : NCR5380_information_transfer (struct Scsi_Host *instance) + * + * Purpose : run through the various SCSI phases and do as the target + * directs us to. Operates on the currently connected command, + * instance->connected. + * + * Inputs : instance, instance for which we are doing commands + * + * Side effects : SCSI things happen, the disconnected queue will be + * modified if a command disconnects, *instance->connected will + * change. + * + * XXX Note : we need to watch for bus free or a reset condition here + * to recover from an unexpected bus free condition. + */ + +static void NCR5380_information_transfer (struct Scsi_Host *instance) +{ + SETUP_HOSTDATA(instance); + unsigned long flags; + unsigned char msgout = NOP; + int sink = 0; + int len; +#if defined(REAL_DMA) + int transfersize; +#endif + unsigned char *data; + unsigned char phase, tmp, extended_msg[10], old_phase=0xff; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + + while (1) { + tmp = NCR5380_read(STATUS_REG); + /* We only have a valid SCSI phase when REQ is asserted */ + if (tmp & SR_REQ) { + phase = (tmp & PHASE_MASK); + if (phase != old_phase) { + old_phase = phase; + NCR_PRINT_PHASE(NDEBUG_INFORMATION); + } + + if(phase == PHASE_CMDOUT) { + void *d; + unsigned long count; + + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + count = cmd->SCp.buffer->length; + d = cmd->SCp.buffer->address; + } else { + count = cmd->SCp.this_residual; + d = cmd->SCp.ptr; + } +#ifdef REAL_DMA + /* this command setup for dma yet? */ + if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done + != cmd)) + { + sun3scsi_dma_setup(d, count, + cmd->request.cmd); + sun3_dma_setup_done = cmd; + } +#endif + } + + + if (sink && (phase != PHASE_MSGOUT)) { + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 0; + continue; + } + + switch (phase) { + case PHASE_DATAOUT: +#if (NDEBUG & NDEBUG_NO_DATAOUT) + printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " + "aborted\n", HOSTNO); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + return; +#endif + case PHASE_DATAIN: + /* + * If there is no room left in the current buffer in the + * scatter-gather list, move onto the next one. + */ + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + + /* ++roman: Try to merge some scatter-buffers if + * they are at contiguous physical addresses. + */ +// merge_contiguous_buffers( cmd ); + INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", + HOSTNO, cmd->SCp.this_residual, + cmd->SCp.buffers_residual); + } + + /* + * The preferred transfer method is going to be + * PSEUDO-DMA for systems that are strictly PIO, + * since we can let the hardware do the handshaking. + * + * For this to work, we need to know the transfersize + * ahead of time, since the pseudo-DMA code will sit + * in an unconditional loop. + */ + +/* ++roman: I suggest, this should be + * #if def(REAL_DMA) + * instead of leaving REAL_DMA out. + */ + +#if defined(REAL_DMA) +// if (!cmd->device->borken && + if((transfersize = + NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) { + len = transfersize; + cmd->SCp.phase = phase; + + if (NCR5380_transfer_dma(instance, &phase, + &len, (unsigned char **) &cmd->SCp.ptr)) { + /* + * If the watchdog timer fires, all future + * accesses to this device will use the + * polled-IO. */ + printk(KERN_NOTICE "scsi%d: switching target %d " + "lun %d to slow handshake\n", HOSTNO, + cmd->target, cmd->lun); + cmd->device->borken = 1; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + /* XXX - need to source or sink data here, as appropriate */ + } else { +#ifdef REAL_DMA + /* ++roman: When using real DMA, + * information_transfer() should return after + * starting DMA since it has nothing more to + * do. + */ + return; +#else + cmd->SCp.this_residual -= transfersize - len; +#endif + } + } else +#endif /* defined(REAL_DMA) */ + NCR5380_transfer_pio(instance, &phase, + (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); +#ifdef REAL_DMA + /* if we had intended to dma that command clear it */ + if(sun3_dma_setup_done == cmd) + sun3_dma_setup_done = NULL; +#endif + + break; + case PHASE_MSGIN: + len = 1; + data = &tmp; + NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Message = tmp; + + switch (tmp) { + /* + * Linking lets us reduce the time required to get the + * next command out to the device, hopefully this will + * mean we don't waste another revolution due to the delays + * required by ARBITRATION and another SELECTION. + * + * In the current implementation proposal, low level drivers + * merely have to start the next command, pointed to by + * next_link, done() is called as with unlinked commands. + */ +#ifdef LINKED + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + LNK_PRINTK("scsi%d: target %d lun %d linked command " + "complete.\n", HOSTNO, cmd->target, cmd->lun); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Sanity check : A linked command should only terminate + * with one of these messages if there are more linked + * commands available. + */ + + if (!cmd->next_link) { + printk(KERN_NOTICE "scsi%d: target %d lun %d " + "linked command complete, no next_link\n", + HOSTNO, cmd->target, cmd->lun); + sink = 1; + do_abort (instance); + return; + } + + initialize_SCp(cmd->next_link); + /* The next command is still part of this process; copy it + * and don't free it! */ + cmd->next_link->tag = cmd->tag; + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + LNK_PRINTK("scsi%d: target %d lun %d linked request " + "done, calling scsi_done().\n", + HOSTNO, cmd->target, cmd->lun); +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif + cmd->scsi_done(cmd); + cmd = hostdata->connected; + break; +#endif /* def LINKED */ + case ABORT: + case COMMAND_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + hostdata->connected = NULL; + QU_PRINTK("scsi%d: command for target %d, lun %d " + "completed\n", HOSTNO, cmd->target, cmd->lun); +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); + if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { + /* Turn a QUEUE FULL status into BUSY, I think the + * mid level cannot handle QUEUE FULL :-( (The + * command is retried after BUSY). Also update our + * queue size to the number of currently issued + * commands now. + */ + /* ++Andreas: the mid level code knows about + QUEUE_FULL now. */ + TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun]; + TAG_PRINTK("scsi%d: target %d lun %d returned " + "QUEUE_FULL after %d commands\n", + HOSTNO, cmd->target, cmd->lun, + ta->nr_allocated); + if (ta->queue_size > ta->nr_allocated) + ta->nr_allocated = ta->queue_size; + } +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + + /* + * I'm not sure what the correct thing to do here is : + * + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * + * If it was a REQUEST SENSE command, we need some way to + * differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the + * result code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed + */ + + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (status_byte(cmd->SCp.Status) != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + +#ifdef AUTOSENSE + if ((cmd->cmnd[0] != REQUEST_SENSE) && + (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { + ASEN_PRINTK("scsi%d: performing request sense\n", + HOSTNO); + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); + + cmd->use_sg = 0; + /* this is initialized from initialize_SCp + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + */ + cmd->request_buffer = (char *) cmd->sense_buffer; + cmd->request_bufflen = sizeof(cmd->sense_buffer); + + save_flags(flags); + cli(); + LIST(cmd,hostdata->issue_queue); + NEXT(cmd) = hostdata->issue_queue; + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + restore_flags(flags); + QU_PRINTK("scsi%d: REQUEST SENSE added to head of " + "issue queue\n", H_NO(cmd)); + } else +#endif /* def AUTOSENSE */ + { +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif + cmd->scsi_done(cmd); + } + + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + + return; + case MESSAGE_REJECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + switch (hostdata->last_message) { + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + /* The target obviously doesn't support tagged + * queuing, even though it announced this ability in + * its INQUIRY data ?!? (maybe only this LUN?) Ok, + * clear 'tagged_supported' and lock the LUN, since + * the command is treated as untagged further on. + */ + cmd->device->tagged_supported = 0; + hostdata->busy[cmd->target] |= (1 << cmd->lun); + cmd->tag = TAG_NONE; + TAG_PRINTK("scsi%d: target %d lun %d rejected " + "QUEUE_TAG message; tagged queuing " + "disabled\n", + HOSTNO, cmd->target, cmd->lun); + break; + } + break; + case DISCONNECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + save_flags(flags); + cli(); + cmd->device->disconnect = 1; + LIST(cmd,hostdata->disconnected_queue); + NEXT(cmd) = hostdata->disconnected_queue; + hostdata->connected = NULL; + hostdata->disconnected_queue = cmd; + restore_flags(flags); + QU_PRINTK("scsi%d: command for target %d lun %d was " + "moved from connected to the " + "disconnected_queue\n", HOSTNO, + cmd->target, cmd->lun); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* Wait for bus free to avoid nasty timeouts */ + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + return; + /* + * The SCSI data pointer is *IMPLICITLY* saved on a disconnect + * operation, in violation of the SCSI spec so we can safely + * ignore SAVE/RESTORE pointers calls. + * + * Unfortunately, some disks violate the SCSI spec and + * don't issue the required SAVE_POINTERS message before + * disconnecting, and we have to break spec to remain + * compatible. + */ + case SAVE_POINTERS: + case RESTORE_POINTERS: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + break; + case EXTENDED_MESSAGE: +/* + * Extended messages are sent in the following format : + * Byte + * 0 EXTENDED_MESSAGE == 1 + * 1 length (includes one byte for code, doesn't + * include first two bytes) + * 2 code + * 3..length+1 arguments + * + * Start the extended message buffer with the EXTENDED_MESSAGE + * byte, since print_msg() wants the whole thing. + */ + extended_msg[0] = EXTENDED_MESSAGE; + /* Accept first byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); + + len = 2; + data = extended_msg + 1; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, + (int)extended_msg[1], (int)extended_msg[2]); + + if (!len && extended_msg[1] <= + (sizeof (extended_msg) - 1)) { + /* Accept third byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = extended_msg[1] - 1; + data = extended_msg + 3; + phase = PHASE_MSGIN; + + NCR5380_transfer_pio(instance, &phase, &len, &data); + EXT_PRINTK("scsi%d: message received, residual %d\n", + HOSTNO, len); + + switch (extended_msg[2]) { + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; + } + } else if (len) { + printk(KERN_NOTICE "scsi%d: error receiving " + "extended message\n", HOSTNO); + tmp = 0; + } else { + printk(KERN_NOTICE "scsi%d: extended message " + "code %02x length %d is too long\n", + HOSTNO, extended_msg[2], extended_msg[1]); + tmp = 0; + } + /* Fall through to reject message */ + + /* + * If we get something weird that we aren't expecting, + * reject it. + */ + default: + if (!tmp) { + printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); + print_msg (extended_msg); + printk("\n"); + } else if (tmp != EXTENDED_MESSAGE) + printk(KERN_DEBUG "scsi%d: rejecting unknown " + "message %02x from target %d, lun %d\n", + HOSTNO, tmp, cmd->target, cmd->lun); + else + printk(KERN_DEBUG "scsi%d: rejecting unknown " + "extended message " + "code %02x, length %d from target %d, lun %d\n", + HOSTNO, extended_msg[1], extended_msg[0], + cmd->target, cmd->lun); + + + msgout = MESSAGE_REJECT; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + break; + } /* switch (tmp) */ + break; + case PHASE_MSGOUT: + len = 1; + data = &msgout; + hostdata->last_message = msgout; + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (msgout == ABORT) { +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + hostdata->connected = NULL; + cmd->result = DID_ERROR << 16; +#ifdef NCR5380_STATS + collect_stats(hostdata, cmd); +#endif + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return; + } + msgout = NOP; + break; + case PHASE_CMDOUT: + len = cmd->cmd_len; + data = cmd->cmnd; + /* + * XXX for performance reasons, on machines with a + * PSEUDO-DMA architecture we should probably + * use the dma transfer function. + */ + NCR5380_transfer_pio(instance, &phase, &len, + &data); + break; + case PHASE_STATIN: + len = 1; + data = &tmp; + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Status = tmp; + break; + default: + printk("scsi%d: unknown phase\n", HOSTNO); + NCR_PRINT(NDEBUG_ANY); + } /* switch(phase) */ + } /* if (tmp * SR_REQ) */ + } /* while (1) */ +} + +/* + * Function : void NCR5380_reselect (struct Scsi_Host *instance) + * + * Purpose : does reselection, initializing the instance->connected + * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * nexus has been reestablished, + * + * Inputs : instance - this instance of the NCR5380. + * + */ + +/* it might eventually prove necessary to do a dma setup on + reselection, but it doesn't seem to be needed now -- sam */ + +static void NCR5380_reselect (struct Scsi_Host *instance) +{ + SETUP_HOSTDATA(instance); + unsigned char target_mask; + unsigned char lun; +#ifdef SUPPORT_TAGS + unsigned char tag; +#endif + unsigned char msg[3]; + Scsi_Cmnd *tmp = NULL, *prev; +/* unsigned long flags; */ + + /* + * Disable arbitration, etc. since the host adapter obviously + * lost, and tell an interrupted NCR5380_select() to restart. + */ + + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; + + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + + RSL_PRINTK("scsi%d: reselect\n", HOSTNO); + + /* + * At this point, we have detected that our SCSI ID is on the bus, + * SEL is true and BSY was false for at least one bus settle delay + * (400 ns). + * + * We must assert BSY ourselves, until the target drops the SEL + * signal. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + + while (NCR5380_read(STATUS_REG) & SR_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + /* + * Wait for target to go into MSGIN. + */ + + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + +#if 1 + // acknowledge toggle to MSGIN + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN)); + + // peek at the byte without really hitting the bus + msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG); +#endif + + if (!msg[0] & 0x80) { + printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); + print_msg(msg); + do_abort(instance); + return; + } + lun = (msg[0] & 0x07); + + /* + * Find the command corresponding to the I_T_L or I_T_L_Q nexus we + * just reestablished, and remove it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + tmp; prev = tmp, tmp = NEXT(tmp) ) { + if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) +#ifdef SUPPORT_TAGS + && (tag == tmp->tag) +#endif + ) { + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + NEXT(prev) = NEXT(tmp); + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); + hostdata->disconnected_queue = NEXT(tmp); + } + NEXT(tmp) = NULL; + break; + } + } + + if (!tmp) { + printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " +#ifdef SUPPORT_TAGS + "tag %d " +#endif + "not in disconnected_queue.\n", + HOSTNO, target_mask, lun +#ifdef SUPPORT_TAGS + , tag +#endif + ); + /* + * Since we have an established nexus that we can't do anything + * with, we must abort it. + */ + do_abort(instance); + return; + } +#if 1 + /* engage dma setup for the command we just saw */ + { + void *d; + unsigned long count; + + if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { + count = tmp->SCp.buffer->length; + d = tmp->SCp.buffer->address; + } else { + count = tmp->SCp.this_residual; + d = tmp->SCp.ptr; + } +#ifdef REAL_DMA + /* setup this command for dma if not already */ + if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done + != tmp)) + { + sun3scsi_dma_setup(d, count, + tmp->request.cmd); + sun3_dma_setup_done = tmp; + } +#endif + } +#endif + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + +#ifdef SUPPORT_TAGS + /* If the phase is still MSGIN, the target wants to send some more + * messages. In case it supports tagged queuing, this is probably a + * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. + */ + tag = TAG_NONE; + if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { + /* Accept previous IDENTIFY message by clearing ACK */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + len = 2; + data = msg+1; + if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && + msg[1] == SIMPLE_QUEUE_TAG) + tag = msg[2]; + TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " + "reselection\n", HOSTNO, target_mask, lun, tag); + } +#endif + + hostdata->connected = tmp; + RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", + HOSTNO, tmp->target, tmp->lun, tmp->tag); +} + + +/* + * Function : int NCR5380_abort (Scsi_Cmnd *cmd) + * + * Purpose : abort a command + * + * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the + * host byte of the result field to, if zero DID_ABORTED is + * used. + * + * Returns : 0 - success, -1 on failure. + * + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). + */ + +#ifndef NCR5380_abort +static +#endif +int NCR5380_abort (Scsi_Cmnd *cmd) +{ + struct Scsi_Host *instance = cmd->host; + SETUP_HOSTDATA(instance); + Scsi_Cmnd *tmp, **prev; + unsigned long flags; + + printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); + print_Scsi_Cmnd (cmd); + + NCR5380_print_status (instance); + + save_flags(flags); + cli(); + + ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, + NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); + +#if 1 +/* + * Case 1 : If the command is the currently executing command, + * we'll set the aborted flag and return control so that + * information transfer routine can exit cleanly. + */ + + if (hostdata->connected == cmd) { + + ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); +/* + * We should perform BSY checking, and make sure we haven't slipped + * into BUS FREE. + */ + +/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ +/* + * Since we can't change phases until we've completed the current + * handshake, we have to source or sink a byte of data if the current + * phase is not MSGOUT. + */ + +/* + * Return control to the executing NCR drive so we can clear the + * aborted flag and get back into our main loop. + */ + + if (do_abort(instance) == 0) { + hostdata->aborted = 1; + hostdata->connected = NULL; + cmd->result = DID_ABORT << 16; +#ifdef SUPPORT_TAGS + cmd_free_tag( cmd ); +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + restore_flags(flags); + cmd->scsi_done(cmd); + return SCSI_ABORT_SUCCESS; + } else { +/* restore_flags(flags); */ + printk("scsi%d: abort of connected command failed!\n", HOSTNO); + return SCSI_ABORT_ERROR; + } + } +#endif + +/* + * Case 2 : If the command hasn't been issued yet, we simply remove it + * from the issue queue. + */ + for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), + tmp = (Scsi_Cmnd *) hostdata->issue_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + (*prev) = NEXT(tmp); + NEXT(tmp) = NULL; + tmp->result = DID_ABORT << 16; + restore_flags(flags); + ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", + HOSTNO); + /* Tagged queuing note: no tag to free here, hasn't been assigned + * yet... */ + tmp->scsi_done(tmp); + return SCSI_ABORT_SUCCESS; + } + +/* + * Case 3 : If any commands are connected, we're going to fail the abort + * and let the high level SCSI driver retry at a later time or + * issue a reset. + * + * Timeouts, and therefore aborted commands, will be highly unlikely + * and handling them cleanly in this situation would make the common + * case of noresets less efficient, and would pollute our code. So, + * we fail. + */ + + if (hostdata->connected) { + restore_flags(flags); + ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); + return SCSI_ABORT_SNOOZE; + } + +/* + * Case 4: If the command is currently disconnected from the bus, and + * there are no connected commands, we reconnect the I_T_L or + * I_T_L_Q nexus associated with it, go into message out, and send + * an abort message. + * + * This case is especially ugly. In order to reestablish the nexus, we + * need to call NCR5380_select(). The easiest way to implement this + * function was to abort if the bus was busy, and let the interrupt + * handler triggered on the SEL for reselect take care of lost arbitrations + * where necessary, meaning interrupts need to be enabled. + * + * When interrupts are enabled, the queues may change - so we + * can't remove it from the disconnected queue before selecting it + * because that could cause a failure in hashing the nexus if that + * device reselected. + * + * Since the queues may change, we can't use the pointers from when we + * first locate it. + * + * So, we must first locate the command, and if NCR5380_select() + * succeeds, then issue the abort, relocate the command and remove + * it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + tmp = NEXT(tmp)) + if (cmd == tmp) { + restore_flags(flags); + ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); + + if (NCR5380_select (instance, cmd, (int) cmd->tag)) + return SCSI_ABORT_BUSY; + + ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); + + do_abort (instance); + + save_flags(flags); + cli(); + for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), + tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + *prev = NEXT(tmp); + NEXT(tmp) = NULL; + tmp->result = DID_ABORT << 16; + /* We must unlock the tag/LUN immediately here, since the + * target goes to BUS FREE and doesn't send us another + * message (COMMAND_COMPLETE or the like) + */ +#ifdef SUPPORT_TAGS + cmd_free_tag( tmp ); +#else + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); +#endif + restore_flags(flags); + tmp->scsi_done(tmp); + return SCSI_ABORT_SUCCESS; + } + } + +/* + * Case 5 : If we reached this point, the command was not found in any of + * the queues. + * + * We probably reached this point because of an unlikely race condition + * between the command completing successfully and the abortion code, + * so we won't panic, but we will notify the user in case something really + * broke. + */ + + restore_flags(flags); + printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" + KERN_INFO " before abortion\n", HOSTNO); + + return SCSI_ABORT_NOT_RUNNING; +} + + +/* + * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) + * + * Purpose : reset the SCSI bus. + * + * Returns : SCSI_RESET_WAKEUP + * + */ + +int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) +{ + SETUP_HOSTDATA(cmd->host); + int i; + unsigned long flags; +#if 1 + Scsi_Cmnd *connected, *disconnected_queue; +#endif + + + NCR5380_print_status (cmd->host); + + /* get in phase */ + NCR5380_write( TARGET_COMMAND_REG, + PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); + /* assert RST */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); + udelay (40); + /* reset NCR registers */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + NCR5380_write( MODE_REG, MR_BASE ); + NCR5380_write( TARGET_COMMAND_REG, 0 ); + NCR5380_write( SELECT_ENABLE_REG, 0 ); + /* ++roman: reset interrupt condition! otherwise no interrupts don't get + * through anymore ... */ + (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + +#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ + /* XXX see below XXX */ + + /* MSch: old-style reset: actually abort all command processing here */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; to avoid problems with re-inserting the commands + * into the issue_queue (via scsi_done()), the aborted commands are + * remembered in local variables first. + */ + save_flags(flags); + cli(); + connected = (Scsi_Cmnd *)hostdata->connected; + hostdata->connected = NULL; + disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; + hostdata->disconnected_queue = NULL; +#ifdef SUPPORT_TAGS + free_all_tags(); +#endif + for( i = 0; i < 8; ++i ) + hostdata->busy[i] = 0; +#ifdef REAL_DMA + hostdata->dma_len = 0; +#endif + restore_flags(flags); + + /* In order to tell the mid-level code which commands were aborted, + * set the command status to DID_RESET and call scsi_done() !!! + * This ultimately aborts processing of these commands in the mid-level. + */ + + if ((cmd = connected)) { + ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done( cmd ); + } + + for (i = 0; (cmd = disconnected_queue); ++i) { + disconnected_queue = NEXT(cmd); + NEXT(cmd) = NULL; + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done( cmd ); + } + if (i > 0) + ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); + + + /* since all commands have been explicitly terminated, we need to tell + * the midlevel code that the reset was SUCCESSFUL, and there is no + * need to 'wake up' the commands by a request_sense + */ + return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; +#else /* 1 */ + + /* MSch: new-style reset handling: let the mid-level do what it can */ + + /* ++guenther: MID-LEVEL IS STILL BROKEN. + * Mid-level is supposed to requeue all commands that were active on the + * various low-level queues. In fact it does this, but that's not enough + * because all these commands are subject to timeout. And if a timeout + * happens for any removed command, *_abort() is called but all queues + * are now empty. Abort then gives up the falcon lock, which is fatal, + * since the mid-level will queue more commands and must have the lock + * (it's all happening inside timer interrupt handler!!). + * Even worse, abort will return NOT_RUNNING for all those commands not + * on any queue, so they won't be retried ... + * + * Conclusion: either scsi.c disables timeout for all resetted commands + * immediately, or we loose! As of linux-2.0.20 it doesn't. + */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; so clear the low-level status here to avoid + * conflicts when the mid-level code tries to wake up the affected + * commands! + */ + + if (hostdata->issue_queue) + ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); + if (hostdata->connected) + ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); + if (hostdata->disconnected_queue) + ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); + + save_flags(flags); + cli(); + hostdata->issue_queue = NULL; + hostdata->connected = NULL; + hostdata->disconnected_queue = NULL; +#ifdef SUPPORT_TAGS + free_all_tags(); +#endif + for( i = 0; i < 8; ++i ) + hostdata->busy[i] = 0; +#ifdef REAL_DMA + hostdata->dma_len = 0; +#endif + restore_flags(flags); + + /* we did no complete reset of all commands, so a wakeup is required */ + return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; +#endif /* 1 */ +} + +/* Local Variables: */ +/* tab-width: 8 */ +/* End: */ diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/sun3_scsi.c linux/drivers/scsi/sun3_scsi.c --- v2.3.44/linux/drivers/scsi/sun3_scsi.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/sun3_scsi.c Sun Feb 13 11:21:42 2000 @@ -1,6 +1,8 @@ /* * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) * + * Sun3 DMA routines added by Sam Creasey (sammy@oh.verio.com) + * * Adapted from mac_scsinew.c: */ /* @@ -44,13 +46,10 @@ */ /* - * $Log: mac_NCR5380.c,v $ + * $Log: sun3_NCR5380.c,v $ */ #define AUTOSENSE -#if 0 -#define PSEUDO_DMA -#endif #include #include @@ -68,6 +67,9 @@ #include #include +#include +/* dma on! */ +#define REAL_DMA #include "scsi.h" #include "hosts.h" @@ -75,17 +77,12 @@ #include "NCR5380.h" #include "constants.h" -#if 0 -#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION) -#define NCR_TIMEOUT 100 -#else -#define NDEBUG (NDEBUG_ABORT) -#endif - #define USE_WRAPPER #define RESET_BOOT #define DRIVER_SETUP +#define NDEBUG 0 + /* * BUG can be used to trigger a strange code-size related hang on 2.1 kernels */ @@ -94,14 +91,14 @@ #undef DRIVER_SETUP #endif -#define ENABLE_IRQ() sun3_enable_irq( IRQ_SUN3_SCSI ); -#define DISABLE_IRQ() sun3_enable_irq( IRQ_SUN3_SCSI ); +#undef SUPPORT_TAGS + +#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); -/* extern void via_scsi_clear(void); */ static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp); -static char sun3scsi_read(struct Scsi_Host *instance, int reg); -static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value); +static inline unsigned char sun3scsi_read(int reg); +static inline void sun3scsi_write(int reg, int value); static int setup_can_queue = -1; static int setup_cmd_per_lun = -1; @@ -111,38 +108,65 @@ #endif static int setup_hostid = -1; -static int polled_scsi_on = 0; +static Scsi_Cmnd *sun3_dma_setup_done = NULL; #define AFTER_RESET_DELAY (HZ/2) -static volatile unsigned char *sun3_scsi_regp = IOBASE_SUN3_SCSI; -/* -static volatile unsigned char *sun3_scsi_drq = NULL; -static volatile unsigned char *sun3_scsi_nodrq = NULL; -*/ +/* ms to wait after hitting dma regs */ +#define SUN3_DMA_DELAY 5 + +/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ +#define SUN3_DVMA_BUFSIZE 0xe000 + +/* minimum number of bytes to to dma on */ +#define SUN3_DMA_MINSIZE 128 + +static struct proc_dir_entry proc_scsi_sun3_5380 = { + PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2 +}; + +static volatile unsigned char *sun3_scsi_regp; +static volatile struct sun3_dma_regs *dregs; +static unsigned char *dmabuf = NULL; /* dma memory buffer */ +static struct sun3_udc_regs *udc_regs = NULL; +static void *sun3_dma_orig_addr = NULL; +static unsigned long sun3_dma_orig_count = 0; +static int sun3_dma_active = 0; /* - * Function : sun3_scsi_setup(char *str, int *ints) - * - * Purpose : booter command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. - * - * TODO: make it actually work! - * + * NCR 5380 register access functions */ -void sun3_scsi_setup(char *str, int *ints) { - printk("sun3_scsi_setup() called\n"); - setup_can_queue = -1; - setup_cmd_per_lun = -1; - setup_sg_tablesize = -1; - setup_hostid = -1; -#ifdef SUPPORT_TAGS - setup_use_tagged_queuing = -1; -#endif - printk("sun3_scsi_setup() done\n"); +static inline unsigned char sun3scsi_read(int reg) +{ + return( sun3_scsi_regp[reg] ); +} + +static inline void sun3scsi_write(int reg, int value) +{ + sun3_scsi_regp[reg] = value; +} + +/* dma controller register access functions */ + +static inline unsigned short sun3_udc_read(unsigned char reg) +{ + unsigned short ret; + + dregs->udc_addr = UDC_CSR; + udelay(SUN3_DMA_DELAY); + ret = dregs->udc_data; + udelay(SUN3_DMA_DELAY); + + return ret; +} + +static inline void sun3_udc_write(unsigned short val, unsigned char reg) +{ + dregs->udc_addr = reg; + udelay(SUN3_DMA_DELAY); + dregs->udc_data = val; + udelay(SUN3_DMA_DELAY); } /* @@ -165,7 +189,6 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt) { unsigned long ioaddr, iopte; - unsigned short *ioptr; int count = 0; static int called = 0; struct Scsi_Host *instance; @@ -173,9 +196,7 @@ if(called) return 0; -printk("sun3scsi_detect(0x%p)\n",tpnt); - - tpnt->proc_name = "Sun3 5380 SCSI"; /* Could you spell "ewww..."? */ + tpnt->proc_dir = &proc_scsi_sun3_5380; /* setup variables */ tpnt->can_queue = @@ -204,7 +225,6 @@ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == IOBASE_SUN3_SCSI) { count = 1; -printk("Found ioaddr in pmeg\n"); break; } } @@ -214,22 +234,19 @@ return 0; } - sun3_scsi_regp = ioaddr; + sun3_scsi_regp = (unsigned char *)ioaddr; + dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8); + + if((dmabuf = sun3_dvma_malloc(SUN3_DVMA_BUFSIZE)) == NULL) { + printk("SUN3 Scsi couldn't allocate DVMA memory!\n"); + return 0; + } - /* doing some stuff like resetting DVMA: */ - ioptr = ioaddr; - *(ioptr+8) = 0; - udelay(10); - *(ioptr+9) = 0; - udelay(10); - *(ioptr+12) = 0; - udelay(10); - *(ioptr+12) = 0x7; - udelay(10); - printk("SCSI status reg = %x\n", *(ioptr+12)); - udelay(10); - *(ioptr+13) = 0; - udelay(10); + if((udc_regs = sun3_dvma_malloc(sizeof(struct sun3_udc_regs))) + == NULL) { + printk("SUN3 Scsi couldn't allocate DVMA memory!\n"); + return 0; + } #ifdef SUPPORT_TAGS if (setup_use_tagged_queuing < 0) @@ -239,18 +256,6 @@ instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); default_instance = instance; -/* - if (macintosh_config->ident == MAC_MODEL_IIFX) { - mac_scsi_regp = via1_regp+0x8000; - mac_scsi_drq = via1_regp+0x6000; - mac_scsi_nodrq = via1_regp+0x12000; - } else { - mac_scsi_regp = via1_regp+0x10000; - mac_scsi_drq = via1_regp+0x6000; - mac_scsi_nodrq = via1_regp+0x12000; - } -*/ - instance->io_port = (unsigned long) ioaddr; instance->irq = IRQ_SUN3_SCSI; @@ -260,15 +265,20 @@ ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; - if (instance->irq != IRQ_NONE) - if (sun3_request_irq(instance->irq, sun3scsi_intr, - 0, "Sun3SCSI-5380", NULL)) { - printk("scsi%d: IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = IRQ_NONE; - } - - printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port); + if (request_irq(instance->irq, scsi_sun3_intr, + 0, "Sun3SCSI-5380", NULL)) { +#ifndef REAL_DMA + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; +#else + printk("scsi%d: IRQ%d not free, bailing out\n", + instance->host_no, instance->irq); + return 0; +#endif + } + + printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port); if (instance->irq == IRQ_NONE) printk ("s disabled"); else @@ -280,6 +290,12 @@ NCR5380_print_options(instance); printk("\n"); + dregs->csr = 0; + udelay(SUN3_DMA_DELAY); + dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; + udelay(SUN3_DMA_DELAY); + dregs->fifo_count = 0; + called = 1; return 1; } @@ -342,34 +358,34 @@ return ""; } +// safe bits for the CSR +#define CSR_GOOD 0x060f -/* - * NCR 5380 register access functions - */ - -static char sun3scsi_read(struct Scsi_Host *instance, int reg) +static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) { -/* -printk("sun3scsi_read(instance=0x%p, reg=0x%x): @0x%p= %d\n",instance,reg,sun3_scsi_regp,sun3_scsi_regp[reg]); -*/ - return( sun3_scsi_regp[reg] ); -} + unsigned short csr = dregs->csr; -static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value) -{ -/* - printk("sun3scsi_write(instance=0x%p, reg=0x%x, value=0x%x)\n", instance, reg, value); -*/ - sun3_scsi_regp[reg] = value; -} + if(csr & ~CSR_GOOD) { + if(csr & CSR_DMA_BUSERR) { + printk("scsi%d: bus error in dma\n", default_instance->host_no); + } + + if(csr & CSR_DMA_CONFLICT) { + printk("scsi%d: dma conflict\n", default_instance->host_no); + } + } -#include "NCR5380.c" + if(csr & (CSR_SDB_INT | CSR_DMA_INT)) + NCR5380_intr(irq, dummy, fp); +} /* * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; * reentering NCR5380_print_status seems to have ugly side effects */ +/* this doesn't seem to get used at all -- sam */ +#if 0 void sun3_sun3_debug (void) { unsigned long flags; @@ -381,32 +397,141 @@ NCR5380_print_status(default_instance); restore_flags(flags); } -#if 0 - polled_scsi_on = 1; -#endif } -/* - * Helper function for interrupt trouble. More ugly side effects here. - */ +#endif -void scsi_sun3_polled (void) + +/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ +static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag) { - unsigned long flags; - NCR5380_local_declare(); - struct Scsi_Host *instance; + if(write_flag) + memcpy(dmabuf, data, count); + else { + sun3_dma_orig_addr = data; + sun3_dma_orig_count = count; + } + + dregs->fifo_count = 0; + sun3_udc_write(UDC_RESET, UDC_CSR); - instance = default_instance; - NCR5380_setup(instance); - if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ) - { - printk("SCSI poll\n"); - save_flags(flags); - cli(); - sun3scsi_intr(IRQ_SUN3_SCSI, instance, NULL); - restore_flags(flags); + /* reset fifo */ + dregs->csr &= ~CSR_FIFO; + dregs->csr |= CSR_FIFO; + + /* set direction */ + if(write_flag) + dregs->csr |= CSR_SEND; + else + dregs->csr &= ~CSR_SEND; + + /* byte count for fifo */ + dregs->fifo_count = count; + + sun3_udc_write(UDC_RESET, UDC_CSR); + + /* reset fifo */ + dregs->csr &= ~CSR_FIFO; + dregs->csr |= CSR_FIFO; + + + if(dregs->fifo_count != count) { + printk("scsi%d: fifo_mismatch %04x not %04x\n", + default_instance->host_no, dregs->fifo_count, + (unsigned int) count); + NCR5380_print(default_instance); + } + + /* setup udc */ + udc_regs->addr_hi = ((sun3_dvma_vtop(dmabuf) & 0xff0000) >> 8); + udc_regs->addr_lo = (sun3_dvma_vtop(dmabuf) & 0xffff); + udc_regs->count = count/2; /* count in words */ + udc_regs->mode_hi = UDC_MODE_HIWORD; + if(write_flag) { + if(count & 1) + udc_regs->count++; + udc_regs->mode_lo = UDC_MODE_LSEND; + udc_regs->rsel = UDC_RSEL_SEND; + } else { + udc_regs->mode_lo = UDC_MODE_LRECV; + udc_regs->rsel = UDC_RSEL_RECV; } + + /* announce location of regs block */ + sun3_udc_write(((sun3_dvma_vtop(udc_regs) & 0xff0000) >> 8), + UDC_CHN_HI); + + sun3_udc_write((sun3_dvma_vtop(udc_regs) & 0xffff), UDC_CHN_LO); + + /* set dma master on */ + sun3_udc_write(0xd, UDC_MODE); + + /* interrupt enable */ + sun3_udc_write(UDC_INT_ENABLE, UDC_CSR); + + return count; + } +static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) +{ + unsigned short resid; + + dregs->udc_addr = 0x32; + udelay(SUN3_DMA_DELAY); + resid = dregs->udc_data; + udelay(SUN3_DMA_DELAY); + resid *= 2; + + return (unsigned long) resid; +} + +static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, + int write_flag) +{ + return wanted; +} + +/* clean up after our dma is done */ +static int sun3scsi_dma_finish(void) +{ + unsigned short count; + int ret = 0; + + count = sun3scsi_dma_residual(default_instance); + + sun3_dma_active = 0; + + /* if we've finished a read, copy out the data we read */ + if(sun3_dma_orig_addr) { + /* check for residual bytes after dma end */ + if(count && (NCR5380_read(BUS_AND_STATUS_REG) & + (BASR_PHASE_MATCH | BASR_ACK))) { + printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no); + printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG)); + ret = count; + } + + /* copy in what we dma'd no matter what */ + memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count); + sun3_dma_orig_addr = NULL; + + } + + sun3_udc_write(UDC_RESET, UDC_CSR); + + dregs->csr &= ~CSR_SEND; + + /* reset fifo */ + dregs->csr &= ~CSR_FIFO; + dregs->csr |= CSR_FIFO; + + sun3_dma_setup_done = NULL; + + return ret; + +} + +#include "sun3_NCR5380.c" #ifdef MODULE @@ -414,3 +539,4 @@ #include "scsi_module.c" #endif + diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/sun3_scsi.h linux/drivers/scsi/sun3_scsi.h --- v2.3.44/linux/drivers/scsi/sun3_scsi.h Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/sun3_scsi.h Sun Feb 13 11:21:42 2000 @@ -1,6 +1,8 @@ /* * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) * + * Sun3 DMA additions by Sam Creasey (sammy@oh.verio.com) + * * Adapted from mac_scsinew.h: */ /* @@ -102,17 +104,271 @@ #define NCR5380_setup(instance) \ _instance = instance -#define NCR5380_read(reg) sun3scsi_read(_instance, reg) -#define NCR5380_write(reg, value) sun3scsi_write(_instance, reg, value) +#define NCR5380_read(reg) sun3scsi_read(reg) +#define NCR5380_write(reg, value) sun3scsi_write(reg, value) #define NCR5380_intr sun3scsi_intr #define NCR5380_queue_command sun3scsi_queue_command -#define NCR5380_abort sun3scsi_abort #define NCR5380_reset sun3scsi_reset +#define NCR5380_abort sun3scsi_abort #define NCR5380_proc_info sun3scsi_proc_info +#define NCR5380_dma_xfer_len(i, cmd, phase) \ + sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) + +#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1) +#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0) +#define NCR5380_dma_residual sun3scsi_dma_residual #define BOARD_NORMAL 0 #define BOARD_NCR53C400 1 + +/* additional registers - mainly DMA control regs */ +/* these start at regbase + 8 -- directly after the NCR regs */ +struct sun3_dma_regs { + unsigned short vmeregs[4]; /* unimpl vme stuff */ + unsigned short udc_data; /* udc dma data reg */ + unsigned short udc_addr; /* uda dma addr reg */ + unsigned short fifo_data; /* fifo data reg, holds extra byte on + odd dma reads */ + unsigned short fifo_count; + unsigned short csr; /* control/status reg */ +}; + +/* ucd chip specific regs - live in dvma space */ +struct sun3_udc_regs { + unsigned short rsel; /* select regs to load */ + unsigned short addr_hi; /* high word of addr */ + unsigned short addr_lo; /* low word */ + unsigned short count; /* words to be xfer'd */ + unsigned short mode_hi; /* high word of channel mode */ + unsigned short mode_lo; /* low word of channel mode */ +}; + +/* addresses of the udc registers */ +#define UDC_MODE 0x38 +#define UDC_CSR 0x2e /* command/status */ +#define UDC_CHN_HI 0x26 /* chain high word */ +#define UDC_CHN_LO 0x22 /* chain lo word */ +#define UDC_CURA_HI 0x1a /* cur reg A high */ +#define UDC_CURA_LO 0x0a /* cur reg A low */ +#define UDC_CURB_HI 0x12 /* cur reg B high */ +#define UDC_CURB_LO 0x02 /* cur reg B low */ +#define UDC_MODE_HI 0x56 /* mode reg high */ +#define UDC_MODE_LO 0x52 /* mode reg low */ +#define UDC_COUNT 0x32 /* words to xfer */ + +/* some udc commands */ +#define UDC_RESET 0 +#define UDC_CHN_START 0xa0 /* start chain */ +#define UDC_INT_ENABLE 0x32 /* channel 1 int on */ + +/* udc mode words */ +#define UDC_MODE_HIWORD 0x40 +#define UDC_MODE_LSEND 0xc2 +#define UDC_MODE_LRECV 0xd2 + +/* udc reg selections */ +#define UDC_RSEL_SEND 0x282 +#define UDC_RSEL_RECV 0x182 + +/* bits in csr reg */ +#define CSR_DMA_ACTIVE 0x8000 +#define CSR_DMA_CONFLICT 0x4000 +#define CSR_DMA_BUSERR 0x2000 + +#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */ +#define CSR_SDB_INT 0x200 /* sbc interrupt pending */ +#define CSR_DMA_INT 0x100 /* dma interrupt pending */ + +#define CSR_SEND 0x8 /* 1 = send 0 = recv */ +#define CSR_FIFO 0x2 /* reset fifo */ +#define CSR_INTR 0x4 /* interrupt enable */ +#define CSR_SCSI 0x1 + +// debugging printk's, taken from atari_scsi.h +/* Debugging printk definitions: + * + * ARB -> arbitration + * ASEN -> auto-sense + * DMA -> DMA + * HSH -> PIO handshake + * INF -> information transfer + * INI -> initialization + * INT -> interrupt + * LNK -> linked commands + * MAIN -> NCR5380_main() control flow + * NDAT -> no data-out phase + * NWR -> no write commands + * PIO -> PIO transfers + * PDMA -> pseudo DMA (unused on Atari) + * QU -> queues + * RSL -> reselections + * SEL -> selections + * USL -> usleep cpde (unused on Atari) + * LBS -> last byte sent (unused on Atari) + * RSS -> restarting of selections + * EXT -> extended messages + * ABRT -> aborting and resetting + * TAG -> queue tag handling + * MER -> merging of consec. buffers + * + */ + + + +#if NDEBUG & NDEBUG_ARBITRATION +#define ARB_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define ARB_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_AUTOSENSE +#define ASEN_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define ASEN_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_DMA +#define DMA_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define DMA_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_HANDSHAKE +#define HSH_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define HSH_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_INFORMATION +#define INF_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define INF_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_INIT +#define INI_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define INI_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_INTR +#define INT_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define INT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_LINKED +#define LNK_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define LNK_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_MAIN +#define MAIN_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define MAIN_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_NO_DATAOUT +#define NDAT_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define NDAT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_NO_WRITE +#define NWR_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define NWR_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_PIO +#define PIO_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define PIO_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_PSEUDO_DMA +#define PDMA_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define PDMA_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_QUEUES +#define QU_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define QU_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_RESELECTION +#define RSL_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define RSL_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_SELECTION +#define SEL_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define SEL_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_USLEEP +#define USL_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define USL_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_LAST_BYTE_SENT +#define LBS_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define LBS_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_RESTART_SELECT +#define RSS_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define RSS_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_EXTENDED +#define EXT_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define EXT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_ABORT +#define ABRT_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define ABRT_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_TAGS +#define TAG_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define TAG_PRINTK(format, args...) +#endif +#if NDEBUG & NDEBUG_MERGING +#define MER_PRINTK(format, args...) \ + printk(KERN_DEBUG format , ## args) +#else +#define MER_PRINTK(format, args...) +#endif + +/* conditional macros for NCR5380_print_{,phase,status} */ + +#define NCR_PRINT(mask) \ + ((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0) + +#define NCR_PRINT_PHASE(mask) \ + ((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0) + +#define NCR_PRINT_STATUS(mask) \ + ((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0) + +#define NDEBUG_ANY 0xffffffff + + #endif /* ndef HOSTS_C */ #endif /* SUN3_NCR5380_H */ diff -u --recursive --new-file v2.3.44/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.3.44/linux/drivers/sound/ac97_codec.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/sound/ac97_codec.c Sun Feb 13 18:50:12 2000 @@ -19,9 +19,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * History - * Jan 14 2000 Ollie Lho - * Isloated from trident.c to support multiple ac97 codec + * History + * v0.2 Feb 10 2000 Ollie Lho + * add ac97_read_proc for /proc/driver/vnedor/ac97 + * v0.1 Jan 14 2000 Ollie Lho + * Isolated from trident.c to support multiple ac97 codec */ #include #include @@ -40,7 +42,7 @@ unsigned int id; char *name; int (*init) (struct ac97_codec *codec); -} snd_ac97_codec_ids[] = { +} ac97_codec_ids[] = { {0x414B4D00, "Asahi Kasei AK4540" , NULL}, {0x41445340, "Analog Devices AD1881" , NULL}, {0x43525900, "Cirrus Logic CS4297" , NULL}, @@ -52,9 +54,46 @@ {0x83847605, "SigmaTel STAC9704" , NULL}, {0x83847608, "SigmaTel STAC9708" , NULL}, {0x83847609, "SigmaTel STAC9721/23" , NULL}, + {0x54524108, "TriTech TR28028" , NULL}, + {0x574D4C00, "Wolfson WM9704" , NULL}, {0x00000000, NULL, NULL} }; +static const char *ac97_stereo_enhancements[] = +{ + /* 0 */ "No 3D Stereo Enhancement", + /* 1 */ "Analog Devices Phat Stereo", + /* 2 */ "Creative Stereo Enhancement", + /* 3 */ "National Semi 3D Stereo Enhancement", + /* 4 */ "YAMAHA Ymersion", + /* 5 */ "BBE 3D Stereo Enhancement", + /* 6 */ "Crystal Semi 3D Stereo Enhancement", + /* 7 */ "Qsound QXpander", + /* 8 */ "Spatializer 3D Stereo Enhancement", + /* 9 */ "SRS 3D Stereo Enhancement", + /* 10 */ "Platform Tech 3D Stereo Enhancement", + /* 11 */ "AKM 3D Audio", + /* 12 */ "Aureal Stereo Enhancement", + /* 13 */ "Aztech 3D Enhancement", + /* 14 */ "Binaura 3D Audio Enhancement", + /* 15 */ "ESS Technology Stereo Enhancement", + /* 16 */ "Harman International VMAx", + /* 17 */ "Nvidea 3D Stereo Enhancement", + /* 18 */ "Philips Incredible Sound", + /* 19 */ "Texas Instruments 3D Stereo Enhancement", + /* 20 */ "VLSI Technology 3D Stereo Enhancement", + /* 21 */ "TriTech 3D Stereo Enhancement", + /* 22 */ "Realtek 3D Stereo Enhancement", + /* 23 */ "Samsung 3D Stereo Enhancement", + /* 24 */ "Wolfson Microelectronics 3D Enhancement", + /* 25 */ "Delta Integration 3D Enhancement", + /* 26 */ "SigmaTel 3D Enhancement", + /* 27 */ "Reserved 27", + /* 28 */ "Rockwell 3D Stereo Enhancement", + /* 29 */ "Reserved 29", + /* 30 */ "Reserved 30", + /* 31 */ "Reserved 31" +}; /* this table has default mixer values for all OSS mixers. */ static struct mixer_defaults { @@ -86,9 +125,9 @@ } ac97_hw[SOUND_MIXER_NRDEVICES]= { [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63}, [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15}, - [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, + [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31}, - [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, + [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31}, [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31}, [SOUND_MIXER_CD] = {AC97_CD_VOL, 31}, @@ -155,10 +194,13 @@ right = 100 - ((right * 100) / mh->scale); left = 100 - ((left * 100) / mh->scale); } - ret = left | (right << 8); } else if (oss_channel == SOUND_MIXER_SPEAKER) { ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_PHONEIN) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); + } else if (oss_channel == SOUND_MIXER_PHONEOUT) { + ret = 100 - (((val & 0x1f) * 100) / mh->scale); } else if (oss_channel == SOUND_MIXER_MIC) { ret = 100 - (((val & 0x1f) * 100) / mh->scale); /* the low bit is optional in the tone sliders and masking @@ -200,10 +242,14 @@ } else { right = ((100 - right) * mh->scale) / 100; left = ((100 - left) * mh->scale) / 100; - } + } val = (left << 8) | right; } else if (oss_channel == SOUND_MIXER_SPEAKER) { val = (((100 - left) * mh->scale) / 100) << 1; + } else if (oss_channel == SOUND_MIXER_PHONEIN) { + val = (((100 - left) * mh->scale) / 100); + } else if (oss_channel == SOUND_MIXER_PHONEOUT) { + val = (((100 - left) * mh->scale) / 100); } else if (oss_channel == SOUND_MIXER_MIC) { val = codec->codec_read(codec , mh->offset) & ~0x801f; val |= (((100 - left) * mh->scale) / 100); @@ -212,11 +258,10 @@ } else if (oss_channel == SOUND_MIXER_BASS) { val = codec->codec_read(codec , mh->offset) & ~0x0f00; val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; - } else if (oss_channel == SOUND_MIXER_TREBLE) { + } else if (oss_channel == SOUND_MIXER_TREBLE) { val = codec->codec_read(codec , mh->offset) & ~0x000f; val |= (((100 - left) * mh->scale) / 100) & 0x000e; } - #ifdef DEBUG printk(" 0x%04x", val); #endif @@ -335,11 +380,11 @@ return -EINVAL; /* do we ever want to touch the hardware? */ - /* val = codec->read_mixer(card,i); */ - val = codec->mixer_state[i]; + val = codec->read_mixer(card, i); + /* val = codec->mixer_state[i]; */ break; } - return put_user(val,(int *)arg); + return put_user(val, (int *)arg); } if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) { @@ -368,6 +413,76 @@ return -EINVAL; } +/* entry point for /proc/driver/controller_vendor/ac97/%d */ +int ac97_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0, cap, extid, val, id1, id2; + struct ac97_codec *codec; + + if ((codec = data) == NULL) + return -ENODEV; + + id1 = codec->codec_read(codec, AC97_VENDOR_ID1); + id2 = codec->codec_read(codec, AC97_VENDOR_ID2); + len += sprintf (page+len, "Vendor name : %s\n", codec->name); + len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2); + + extid = codec->codec_read(codec, AC97_EXTENDED_ID); + extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13)); + len += sprintf (page+len, "AC97 Version : %s\n", + extid ? "2.0 or later" : "1.0"); + + cap = codec->codec_read(codec, AC97_RESET); + len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n", + cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "", + cap & 0x0002 ? " -reserved1-" : "", + cap & 0x0004 ? " -bass & treble-" : "", + cap & 0x0008 ? " -simulated stereo-" : "", + cap & 0x0010 ? " -headphone out-" : "", + cap & 0x0020 ? " -loudness-" : ""); + val = cap & 0x00c0; + len += sprintf (page+len, "DAC resolutions :%s%s%s\n", + " -16-bit-", + val & 0x0040 ? " -18-bit-" : "", + val & 0x0080 ? " -20-bit-" : ""); + val = cap & 0x0300; + len += sprintf (page+len, "ADC resolutions :%s%s%s\n", + " -16-bit-", + val & 0x0100 ? " -18-bit-" : "", + val & 0x0200 ? " -20-bit-" : ""); + len += sprintf (page+len, "3D enhancement : %s\n", + ac97_stereo_enhancements[(cap >> 10) & 0x1f]); + + val = codec->codec_read(codec, AC97_GENERAL_PURPOSE); + len += sprintf (page+len, "POP path : %s 3D\n" + "Sim. stereo : %s\n" + "3D enhancement : %s\n" + "Loudness : %s\n" + "Mono output : %s\n" + "MIC select : %s\n" + "ADC/DAC loopback : %s\n", + val & 0x8000 ? "post" : "pre", + val & 0x4000 ? "on" : "off", + val & 0x2000 ? "on" : "off", + val & 0x1000 ? "on" : "off", + val & 0x0200 ? "MIC" : "MIX", + val & 0x0100 ? "MIC2" : "MIC1", + val & 0x0080 ? "on" : "off"); + + cap = extid; + len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n", + cap & 0x0001 ? " -var rate PCM audio-" : "", + cap & 0x0002 ? " -2x PCM audio out-" : "", + cap & 0x0008 ? " -var rate MIC in-" : "", + cap & 0x0040 ? " -PCM center DAC-" : "", + cap & 0x0080 ? " -PCM surround DAC-" : "", + cap & 0x0100 ? " -PCM LFE DAC-" : "", + cap & 0x0200 ? " -slot/DAC mappings-" : ""); + + return len; +} + int ac97_probe_codec(struct ac97_codec *codec) { u16 id1, id2, cap; @@ -381,10 +496,10 @@ id1 = codec->codec_read(codec, AC97_VENDOR_ID1); id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) { - if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) { - codec->name = snd_ac97_codec_ids[i].name; - codec->codec_init = snd_ac97_codec_ids[i].init; + for (i = 0, codec->name = NULL; i < arraysize (ac97_codec_ids[i]); i++) { + if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { + codec->name = ac97_codec_ids[i].name; + codec->codec_init = ac97_codec_ids[i].init; break; } } @@ -392,7 +507,6 @@ codec->name = "Unknown"; printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n", id1, id2, codec->name); - printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap); /* mixer masks */ codec->supported_mixers = AC97_SUPPORTED_MASK; @@ -437,4 +551,5 @@ return 1; } +EXPORT_SYMBOL(ac97_read_proc); EXPORT_SYMBOL(ac97_probe_codec); diff -u --recursive --new-file v2.3.44/linux/drivers/sound/ac97_codec.h linux/drivers/sound/ac97_codec.h --- v2.3.44/linux/drivers/sound/ac97_codec.h Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/ac97_codec.h Sun Feb 13 18:49:08 2000 @@ -116,7 +116,8 @@ SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT) #define AC97_RECORD_MASK (SOUND_MASK_MIC|\ - SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\ + SOUND_MASK_CD|SOUND_MASK_VIDEO|\ + SOUND_MASK_LINE1| SOUND_MASK_LINE|\ SOUND_MASK_PHONEIN) #define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1< #include #include +#include #include "awacs_defs.h" #include #include @@ -178,6 +179,7 @@ static int awacs_rate_index; static int awacs_subframe; static int awacs_spkr_vol; +static struct device_node* awacs_node; static int awacs_revision; #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ @@ -898,7 +900,7 @@ void dmasound_init(void); -void dmasound_setup(char *str, int *ints); +static int dmasound_setup(char *str); /*** Translations ************************************************************/ @@ -3208,9 +3210,15 @@ out_le32(&awacs_txdma->control, RUN<<16); /* disable interrupts from awacs interface */ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); - free_irq(awacs_irq, pmac_awacs_intr); - free_irq(awacs_tx_irq, pmac_awacs_tx_intr); - free_irq(awacs_rx_irq, pmac_awacs_rx_intr); +#ifdef CONFIG_PMAC_PBOOK + if (is_pbook_G3) { + feature_clear(awacs_node, FEATURE_Sound_power); + feature_clear(awacs_node, FEATURE_Sound_CLK_enable); + } +#endif + free_irq(awacs_irq, 0); + free_irq(awacs_tx_irq, 0); + free_irq(awacs_rx_irq, 0); kfree(awacs_tx_cmd_space); if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); @@ -3281,12 +3289,10 @@ /* We really want to execute a DMA stop command, after the AWACS * is initialized. * For reasons I don't understand, it stops the hissing noise - * common to many PowerBook G3 systems (like mine :-). Maybe it - * is just the AWACS control register change...... + * common to many PowerBook G3 systems (like mine :-). */ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); - out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00)); out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); out_le32(&awacs_txdma->control, RUN | (RUN << 16)); @@ -3544,6 +3550,11 @@ save_flags(flags); cli(); if (beep_playing) { st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); + out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); + out_le32(&awacs->control, + (in_le32(&awacs->control) & ~0x1f00) + | (awacs_rate_index << 8)); + out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); beep_playing = 0; } restore_flags(flags); @@ -3645,8 +3656,23 @@ PMacSilence(); disable_irq(awacs_irq); disable_irq(awacs_tx_irq); + if (is_pbook_G3) { + feature_clear(awacs_node, FEATURE_Sound_CLK_enable); + feature_clear(awacs_node, FEATURE_Sound_power); + } break; case PBOOK_WAKE: + /* There is still a problem on wake. Sound seems to work fine + if I launch mpg123 and resumes fine if mpg123 was playing, + but the console beep is dead until I do something with the + mixer. Probably yet another timing issue */ + if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable) + || !feature_test(awacs_node, FEATURE_Sound_power)) { + /* these aren't present on the 3400 AFAIK -- paulus */ + feature_set(awacs_node, FEATURE_Sound_CLK_enable); + feature_set(awacs_node, FEATURE_Sound_power); + mdelay(1000); + } out_le32(&awacs->control, MASK_IEPC | (awacs_rate_index << 8) | 0x11 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0)); @@ -3663,6 +3689,16 @@ mdelay(2); awacs_write(awacs_reg[1] | MASK_ADDR1); } + /* enable CD sound input */ + if (macio_base && is_pbook_G3) { + out_8(macio_base + 0x37, 3); + } else if (is_pbook_3400) { + feature_set(awacs_node, FEATURE_IOBUS_enable); + udelay(10); + in_8((unsigned char *)0xf301a190); + } + /* Resume pending sounds. */ + PMacPlay(); } return PBOOK_SLEEP_OK; } @@ -5139,6 +5175,7 @@ u_long fmt; int data; int size, nbufs; + audio_buf_info info; switch (cmd) { case SNDCTL_DSP_RESET: @@ -5214,6 +5251,14 @@ sq_setup(numBufs, size, sound_buffers); sq.max_active = nbufs; return 0; + case SNDCTL_DSP_GETOSPACE: + info.fragments = sq.max_active - sq.count; + info.fragstotal = sq.max_active; + info.fragsize = sq.block_size; + info.bytes = info.fragments * info.fragsize; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; default: return mixer_ioctl(inode, file, cmd, arg); @@ -5308,7 +5353,7 @@ { char *buffer = state.buf, *mach = ""; #ifdef CONFIG_PPC - char awacs_buf[50]; + char awacs_buf[64]; #endif int len = 0; @@ -5576,6 +5621,16 @@ printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); return; } + awacs_node = np; +#ifdef CONFIG_PMAC_PBOOK + if (machine_is_compatible("PowerBook1,1") + || machine_is_compatible("AAPL,PowerBook1998")) { + feature_set(np, FEATURE_Sound_CLK_enable); + feature_set(np, FEATURE_Sound_power); + /* Shorter delay will not work */ + mdelay(1000); + } +#endif awacs_tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(awacs_tx_cmd_space); @@ -5607,7 +5662,10 @@ awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; if (awacs_revision == 3) { + mdelay(100); awacs_write(0x6000); + mdelay(2); + awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_enable_amp(100 * 0x101); } } @@ -5629,26 +5687,34 @@ /* Powerbooks have odd ways of enabling inputs such as an expansion-bay CD or sound from an internal modem or a PC-card modem. */ - if (machine_is_compatible("AAPL,3400/2400")) { + if (machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500")) { is_pbook_3400 = 1; /* * Enable CD and PC-card sound inputs. * This is done by reading from address * f301a000, + 0x10 to enable the expansion-bay * CD sound input, + 0x80 to enable the PC-card - * sound input. The 0x100 seems to enable the - * MESH and/or its SCSI bus drivers. + * sound input. The 0x100 enables the SCSI bus + * terminator power. */ in_8((unsigned char *)0xf301a190); - } else if (machine_is_compatible("PowerBook1,1")) { - np = find_devices("mac-io"); - if (np && np->n_addrs > 0) { - is_pbook_G3 = 1; - macio_base = (unsigned char *) - ioremap(np->addrs[0].address, 0x40); - /* enable CD sound input */ - out_8(macio_base + 0x37, 3); + } else if (machine_is_compatible("PowerBook1,1") + || machine_is_compatible("AAPL,PowerBook1998")) { + struct device_node* mio; + macio_base = 0; + is_pbook_G3 = 1; + for (mio = np->parent; mio; mio = mio->parent) { + if (strcmp(mio->name, "mac-io") == 0 + && mio->n_addrs > 0) { + macio_base = (unsigned char *) ioremap + (mio->addrs[0].address, 0x40); + break; + } } + /* enable CD sound input */ + if (macio_base) + out_8(macio_base + 0x37, 3); } } #endif /* CONFIG_PPC */ diff -u --recursive --new-file v2.3.44/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.3.44/linux/drivers/usb/keybdev.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/usb/keybdev.c Sun Feb 13 10:30:38 2000 @@ -36,7 +36,7 @@ #include #include -#ifdef CONFIG_X86 +#if defined(CONFIG_X86) || defined(CONFIG_IA64) static unsigned char keybdev_x86_e0s[] = { 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48, @@ -77,7 +77,7 @@ { if (type != EV_KEY || code > 255) return; -#ifdef CONFIG_X86 +#if defined(CONFIG_X86) || defined(CONFIG_IA64) if (code >= 189) { printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code); diff -u --recursive --new-file v2.3.44/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.44/linux/drivers/video/Config.in Fri Jan 28 15:09:08 2000 +++ linux/drivers/video/Config.in Sun Feb 13 11:21:42 2000 @@ -73,6 +73,8 @@ fi if [ "$CONFIG_MAC" = "y" ]; then define_bool CONFIG_FB_MAC y + bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE +# bool ' Apple DAFB display support' CONFIG_FB_DAFB fi if [ "$CONFIG_HP300" = "y" ]; then define_bool CONFIG_FB_HP300 y @@ -88,6 +90,13 @@ if [ "$CONFIG_VISWS" = "y" ]; then tristate ' SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW define_bool CONFIG_BUS_I2C y + fi + if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then + bool 'Sun3 framebuffer support' CONFIG_FB_SUN3 + if [ "$CONFIG_FB_SUN3" != "n" ]; then + bool ' BWtwo support' CONFIG_FB_BWTWO + bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX + fi fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_PCI" != "n" ]; then diff -u --recursive --new-file v2.3.44/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.44/linux/drivers/video/Makefile Wed Dec 29 13:13:19 1999 +++ linux/drivers/video/Makefile Sun Feb 13 11:21:43 2000 @@ -60,7 +60,7 @@ obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_RIVA) += rivafb.o riva_hw.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o -obj-$(CONFIG_FB_MAC) += macfb.o +obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o obj-$(CONFIG_FB_HP300) += hpfb.o obj-$(CONFIG_FB_OF) += offb.o macmodes.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o @@ -82,6 +82,8 @@ obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o obj-$(CONFIG_FB_MATROX) += matroxfb.o +obj-$(CONFIG_FB_SUN3) += sun3fb.o +obj-$(CONFIG_FB_BWTWO) += bwtwofb.o obj-$(CONFIG_FB_VIRTUAL) += vfb.o # Generic Low Level Drivers diff -u --recursive --new-file v2.3.44/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.3.44/linux/drivers/video/aty128fb.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/video/aty128fb.c Sun Feb 13 10:47:01 2000 @@ -1675,9 +1675,9 @@ #endif /* CONFIG_PPC */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1) - if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, - &defaultmode, 8)) - var = default_var; + if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, + &defaultmode, 8)) + var = default_var; #endif #ifdef CONFIG_PPC @@ -1685,6 +1685,7 @@ if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; #endif /* CONFIG_PPC */ + } #endif /* MODULE */ if (noaccel) diff -u --recursive --new-file v2.3.44/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.3.44/linux/drivers/video/atyfb.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/video/atyfb.c Sun Feb 13 10:18:03 2000 @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.138 2000/02/10 02:52:12 davem Exp $ +/* $Id: atyfb.c,v 1.139 2000/02/12 22:47:04 davem Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven diff -u --recursive --new-file v2.3.44/linux/drivers/video/bwtwofb.c linux/drivers/video/bwtwofb.c --- v2.3.44/linux/drivers/video/bwtwofb.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/video/bwtwofb.c Sun Feb 13 11:21:43 2000 @@ -25,7 +25,7 @@ #include