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/)
#define DEBUG_ALLOC 0
-
#if DEBUG_ALLOC > 0
# define DBGA(args...) printk(KERN_DEBUG ##args)
#else
{
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;
+}
\f
struct pci_iommu_arena *
iommu_arena_new(dma_addr_t base, unsigned long window_size,
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));
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. */
*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;
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;
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
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;
}
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);
+ if (0 && leader->dma_address == 0) {
+ /* All physically contiguous. We already have the
+ length, all we need is to fill in the ptes. */
- DBGA(" (%ld) [%p,%x]\n",
- sg - leader, sg->address, sg->length);
-
- 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) {
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, 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;
+ }
- /* Second, iterate over the scatterlist leaders and allocate
+ /* 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;
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;
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;
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)
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);
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);
#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]
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
.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"
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)
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
* 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
+ ");
+
# 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
--- /dev/null
+/*
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+/* 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;
+ }
+}
.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
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);
#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
---------------------------------- */
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
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
movw $0x0201, %ax # service 2, 1 sector
int $0x13
jc probe_loop # try next value
-#endif
got_sectors:
movw $INITSEG, %ax
# 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
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:
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)
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 \
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 */
}
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);
}
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);
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);
}
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);
};
static void
-xlate_dirent(void *dirent, long n)
+xlate_dirent(void *dirent64, void *dirent32, long n)
{
long off;
struct dirent *dirp;
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;
}
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);
}
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 {
struct timeval32 ru_utime;
struct timeval32 ru_stime;
*
* Implemented EFI runtime services and virtual mode calls. --davidm
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
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);
(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
#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
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
#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:
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
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
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
unsigned long eoi_ptr;
# ifdef CONFIG_USB
- disable_usb();
+ if (usbfix)
+ disable_usb();
# endif
/*
* Stop IPIs by getting the ivr_read_lock
spin_unlock(&ivr_read_lock);
# ifdef CONFIG_USB
- reenable_usb();
+ if (usbfix)
+ reenable_usb();
# endif
# ifndef CONFIG_SMP
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)
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);
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
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 */
alive:
/* Remember the AP data */
- cpu_number_map[cpuid] = cpunum;
+ __cpu_number_map[cpuid] = cpunum;
#ifdef CONFIG_KDB
cpu_online_map |= (1<<cpunum);
printk ("DEBUGGER: cpu_online_map = 0x%08x\n", cpu_online_map);
extern int acpi_apic_map[32];
/* Take care of some initial bookkeeping. */
- memset(&cpu_number_map, -1, sizeof(cpu_number_map));
+ memset(&__cpu_number_map, -1, sizeof(__cpu_number_map));
memset(&__cpu_logical_map, -1, sizeof(__cpu_logical_map));
memset(&ipi_op, 0, sizeof(ipi_op));
/* Setup BSP mappings */
- cpu_number_map[bootstrap_processor] = 0;
+ __cpu_number_map[bootstrap_processor] = 0;
__cpu_logical_map[0] = bootstrap_processor;
current->processor = bootstrap_processor;
* 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 <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
#include <linux/config.h>
#include <linux/errno.h>
#
.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 \
{ "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) },
.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
# 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
#
# Block devices
#
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
#
# 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
#
# 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
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
# USB Controllers
#
# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
#
# 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
#
#
# 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
#
# 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
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
#
# 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
# 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
#
# 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
# 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
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
#
# 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
# 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
#
# 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
#
# Block devices
#
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
#
# 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
#
# 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
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
# USB Controllers
#
# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
#
# 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
#
#
# 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
#
# 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
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
/*
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)
SYNC
rfi
-#ifdef __SMP__
+#ifdef CONFIG_SMP
.globl ret_from_smpfork
ret_from_smpfork:
bl schedule_tail
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 */
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 */
/*
. = 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
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)
-
- /* 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)
+/*
+ * 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.
+ */
+
+ .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)
#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
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];
atomic_t global_irq_count;
atomic_t global_bh_count;
-atomic_t global_bh_lock;
static void show(char * str)
{
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;
* 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;
}
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))
if (flags & (1 << 15)) {
int cpu = smp_processor_id();
__cli();
- if (!ppc_local_irq_count[cpu])
+ if (!local_irq_count[cpu])
get_irqlock(cpu);
}
}
{
int cpu = smp_processor_id();
- if (!ppc_local_irq_count[cpu])
+ if (!local_irq_count[cpu])
release_irqlock(cpu);
__sti();
}
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())
bdnz 1b
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
*
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);
/* 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))
/* 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));
}
/* 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));
}
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];
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__ */
/* Yeah, I know, this could be a separate do_IRQ function */
#include <asm/machdep.h>
#include <asm/keyboard.h>
#include <asm/dma.h>
+#include <asm/bootx.h>
#include "time.h"
#include "local_irq.h"
{
char *p;
int n;
+ kdev_t __init pmac_find_ide_boot(char *bootdevice, int n);
if (bootdevice == NULL)
return 0;
#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');
}
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:
#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
#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
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__ */
EXPORT_SYMBOL(decrementer_count);
EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(console_drivers);
-EXPORT_SYMBOL(do_bottom_half);
}
#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)
{
#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)
*/
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
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__ */
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;
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:
{
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;
/* 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
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;
#ifdef CONFIG_BOOTX_TEXT
map_bootx_text();
- prom_print("identify machine\n");
#endif
#ifdef CONFIG_XMON
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 *);
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)
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;
}
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);
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)
{
#include <asm/processor.h>
#include <asm/errno.h>
+CACHELINE_BYTES = 32
+LG_CACHELINE_BYTES = 5
+CACHELINE_MASK = 0x1f
+CACHELINE_WORDS = 8
+
.globl strcpy
strcpy:
addi r5,r3,-1
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
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)
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
.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 */
.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
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
*/
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.
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) {
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;
{
int i, x;
- if (macio_node != 0) {
+ if (via_modem && macio_node != 0) {
unsigned int t0;
feature_set(macio_node, FEATURE_Modem_power);
-/* $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)
{
int x;
for (x = 0; x < n; x += PAGE_SIZE) {
- (*_sparc_unmapioaddr)(p + n);
+ (*_sparc_unmapioaddr)((unsigned long)p + n);
}
}
-/* $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
static __inline__ unsigned long do_gettimeoffset(void)
{
+ struct tasklet_struct *t;
unsigned long offset = 0;
/*
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;
}
-/* $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)
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 */
-/* $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)
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
#include <asm/iomd.h>
#include <asm/system.h>
+extern struct tasklet_struct keyboard_tasklet;
extern void kbd_reset_kdown(void);
int kbd_read_mask;
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)
* 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 <linux/module.h>
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;
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;
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;
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)
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;
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;
cookie.lo = lo;
cookie.data = data;
+ cookie.blksize = blksize;
desc.written = 0;
desc.count = len;
desc.buf = (char*)&cookie;
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)]) {
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;
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:
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(),
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;
/* 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.
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
void __init serial_console_init(void)
{
register_console(&sercons);
- return kmem_start;
}
#endif /* ifdef CONFIG_SERIAL_CONSOLE */
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;
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. */
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;
}
--- /dev/null
+/*
+
+ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
+
+ Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/io.h>
+
+
+#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<<val. */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (6*HZ)
+
+
+enum {
+ HAS_CHIP_XCVR = 0x020000,
+ HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_IO_SIZE 256
+
+#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
+
+typedef enum {
+ UNKNOWN = 0,
+ RTL8139,
+ RTL8139_CB,
+ SMC1211TX,
+ MPX5030,
+ SIS900,
+ SIS7016,
+} chip_t;
+
+static struct {
+ chip_t chip;
+ const char *name;
+} chip_info[] __devinitdata = {
+ { RTL8139, "RealTek RTL8139 Fast Ethernet"},
+ { RTL8139_CB, "RealTek RTL8139B PCI/CardBus"},
+ { SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"},
+ { MPX5030, "Accton MPX5030 (RealTek RTL8139)"},
+ { SIS900, "SiS 900 (RealTek RTL8139) Fast Ethernet"},
+ { SIS7016, "SiS 7016 (RealTek RTL8139) Fast Ethernet"},
+ {0,},
+};
+
+static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {
+ {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB },
+ {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
+ {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },
+ {0x1039, 0x0900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS900 },
+ {0x1039, 0x7016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS7016 },
+ {0,},
+};
+MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
+
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */
+
+/* Symbolic offsets to registers. */
+enum RTL8139_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,
+ Config4 = 0x5A, /* absent on RTL-8139A */
+ HltClk = 0x5B,
+ MultiIntr = 0x5C,
+ TxSummary = 0x60,
+ BasicModeCtrl = 0x62,
+ BasicModeStatus = 0x64,
+ NWayAdvert = 0x66,
+ NWayLPAR = 0x68,
+ NWayExpansion = 0x6A,
+ /* Undocumented registers, but required for proper operation. */
+ FIFOTMS = 0x70, /* FIFO Control and test. */
+ 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,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+};
+
+/* Bits in Config1 */
+enum Config1Bits {
+ Cfg1_PM_Enable = 0x01,
+ Cfg1_VPD_Enable = 0x02,
+ Cfg1_PIO = 0x04,
+ Cfg1_MMIO = 0x08,
+ Cfg1_LWAKE = 0x10,
+ Cfg1_Driver_Load = 0x20,
+ Cfg1_LED0 = 0x40,
+ Cfg1_LED1 = 0x80,
+};
+
+/* 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,
+};
+#define PARA78_default 0x78fa8388
+#define PARA7c_default 0xcb38de43 /* param[0][3] */
+#define PARA7c_xxx 0xcb38de43
+unsigned long param[4][4] = {
+ {0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+};
+
+struct ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+};
+
+
+#define PRIV_ALIGN 15 /* Required alignment mask */
+struct rtl8139_private {
+ chip_t chip;
+ void *mmio_addr;
+ spinlock_t lock;
+ int drv_flags;
+ struct pci_dev *pci_dev;
+ struct net_device_stats stats;
+ struct timer_list timer; /* Media selection timer. */
+ unsigned char *rx_ring;
+ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
+ unsigned int rx_config;
+ 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 *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_row, twist_col; /* Twister tune state. */
+ 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 ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+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);
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
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
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
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
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
#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;
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;
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);
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;
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);
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;
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);
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;
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);
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;
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);
}
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;
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;
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;
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;
}
-#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);
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);
* Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards
*
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
{
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);
}
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
* <jojo@repas.de>
*/
-#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 <linux/module.h>
#include <linux/config.h>
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);
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;
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;
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;
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
lp->intmask = NORXflag | RECONflag;
AINTMASK(lp->intmask);
+ netif_start_queue(dev);
+
return 0;
}
{
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);
"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];
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);
}
+/* 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
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;
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) {
AINTMASK(0);
udelay(1);
AINTMASK(lp->intmask);
-
- dev->interrupt = 0;
}
}
/* 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.
- */
}
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
{
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);
}
*
* Written 1994-1999 by Avery Pennarun,
* based on an ISA version by David Woodhouse.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
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);
}
*
* Written 1997 by David Woodhouse.
* Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
* Derived from skeleton.c by Donald Becker.
*
* Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
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);
}
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S1: ");
+ BUGMSG2(D_INIT, "S1: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
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--;
}
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--;
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
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S2: ");
+ BUGMSG2(D_INIT, "S2: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
}
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--;
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--;
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
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S4: ");
+ BUGMSG2(D_INIT, "S4: ");
}
BUGMSG2(D_INIT, "%lXh ", *shmem);
}
numprint %= 8;
if (!numprint) {
BUGMSG2(D_INIT, "\n");
- BUGMSG(D_INIT, "S5: ");
+ BUGMSG2(D_INIT, "S5: ");
}
BUGMSG2(D_INIT, "%Xh ", *port);
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--;
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--;
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--;
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;
}
/* 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);
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 */
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);
}
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;
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++;
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;
"(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++;
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;
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 {
};
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);
};
#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,
+ 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);
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();
}
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
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
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);
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);
/* 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 */
/* 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);
}
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) {
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);
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;
/* 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 */
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);
/* 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;
}
/*
- * Add requested mcast addr to BMac's hash table filter.
- *
+ * Add requested mcast addr to BMac's hash table filter.
+ *
*/
static void
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;
}
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);
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)
bmwrite(dev, BHASH2, hash_table[2]);
bmwrite(dev, BHASH3, hash_table[3]);
}
-
- /* Let us get going again. */
- /* dev->tbusy = 0; */
}
#endif /* SUNHME_MULTICAST */
}
/*
- * Procedure for reading EEPROM
+ * Procedure for reading EEPROM
*/
#define SROMAddressLength 5
#define DataInOn 0x0008
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);
/* 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);
{
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++) {
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;
}
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;
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
-
- 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;
+ 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 (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) {
}
XXDEBUG((", base_addr=%#0lx", dev->base_addr));
printk("\n");
-
+
dev->open = bmac_open;
dev->stop = bmac_close;
dev->hard_start_xmit = bmac_output;
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);
-
- return 0;
+ 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);
+
+ 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;
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);
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);
/* 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);
}
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");
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;
}
static void __exit bmac_cleanup (void)
{
-#ifdef MODULE
- struct bmac_data *bp;
+ struct bmac_data *bp;
+ struct net_device *dev;
- if (bmac_devs == 0)
- return;
+ if (bmac_devs == 0)
+ return;
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
+#endif
+ proc_net_remove("bmac");
- bp = (struct bmac_data *) bmac_devs->priv;
- unregister_netdev(bmac_devs);
- proc_net_remove("bmac");
+ do {
+ dev = bmac_devs;
+ bp = (struct bmac_data *) dev->priv;
+ bmac_devs = bp->next_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);
+ free_irq(dev->irq, dev);
+ free_irq(bp->tx_dma_intr, dev);
+ free_irq(bp->rx_dma_intr, dev);
-#ifdef CONFIG_PMAC_PBOOK
- pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
-#endif
- kfree(bmac_devs);
- bmac_devs = NULL;
-#endif
+ unregister_netdev(dev);
+ kfree(dev);
+ } while (bmac_devs != NULL);
}
module_init(bmac_probe);
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;
}
#include <linux/version.h>
#include <linux/module.h>
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
-#ifdef HAS_PCI_NETIF
-#include "pci-netif.h"
-#else
#include <linux/pci.h>
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h> /* Ignore the bogus warning in 2.1.100+ */
-#endif
-#endif
#include <linux/spinlock.h>
#include <linux/init.h>
#include <asm/bitops.h>
#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. */
*/
/* 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);
+static struct net_device *speedo_found1(struct pci_dev *pdev, 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 0x1000
#endif
-#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,
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);
+ struct net_device *(*probe1)(struct pci_dev *pdev, 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
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.. */
/* 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)
+static int __init 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;
+ struct pci_dev *pdev = NULL;
+ long ioaddr;
+ int irq;
- 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);
+ while ((pdev = pci_find_device (PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82557, pdev))) {
#ifdef USE_IO
- ioaddr = pdev->resource[1].start;
+ 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;
- }
+ ioaddr = pdev->resource[0].start;
#endif
+ irq = pdev->irq;
+
/* Remove I/O space marker in bit 0. */
#ifdef USE_IO
- if (check_region(ioaddr, 32))
+ if (check_region(ioaddr, 32)) {
+ printk(KERN_ERR "eepro100: %ld mem region busy\n", ioaddr);
continue;
+ }
#else
{
unsigned long orig_ioaddr = ioaddr;
+
+ if (check_mem_region(ioaddr, 32)) {
+ printk(KERN_ERR "eepro100: %ld mem region busy\n",
+ ioaddr);
+ continue;
+ }
- if ((ioaddr = (long)ioremap(ioaddr & ~0xfUL, 0x1000)) == 0) {
+ if ((ioaddr = (long)ioremap(orig_ioaddr, 0x1000)) == 0) {
printk(KERN_INFO "Failed to map PCI address %#lx.\n",
orig_ioaddr);
continue;
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))
+ if(speedo_found1(pdev, ioaddr, irq, 0,cards_found))
cards_found++;
}
return cards_found;
}
-#endif
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
+
+static struct net_device *speedo_found1(struct pci_dev *pdev,
long ioaddr, int irq, int chip_idx, int card_idx)
{
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;
static int did_version = 0; /* Already printed version info. */
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) {
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
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. */
#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
+ pci_set_power_state (pdev, acpi_idle_state);
- /* We do a request_region() only to register /proc/ioports info. */
+#ifdef USE_IO
request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
+#else
+ request_mem_region(ioaddr, 0x1000, "Intel Speedo3 Ethernet");
+#endif
dev->base_addr = ioaddr;
dev->irq = irq;
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;
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;
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;
+ (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
ioaddr + SCBPointer);
outw(CUStart, ioaddr + SCBCmd);
+
+ netif_start_queue (dev);
}
/* Media monitoring and control. */
}
sp->stats.tx_errors++;
dev->trans_start = jiffies;
+ netif_start_queue (dev);
return;
}
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. */
}
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;
}
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. */
/* 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) {
&& 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) {
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, inw(ioaddr + SCBStatus));
- return;
+ spin_unlock (&sp->lock);
}
static int
#if LINUX_VERSION_CODE < 0x20100
skb->free = 1;
#endif
- dev_free_skb(skb);
+ dev_kfree_skb(skb);
}
}
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) {
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;
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);
+ saved_acpi = pci_set_power_state(sp->pdev, 0);
mdio_write(ioaddr, data[0], data[1], data[2]);
- acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
- mdio_write(ioaddr, data[0], data[1], data[2]);
-#endif
+ pci_set_power_state(sp->pdev, saved_acpi);
return 0;
default:
return -EOPNOTSUPP;
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();
if (cards_found <= 0) {
printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
return -ENODEV;
}
-#endif
return 0;
}
#ifdef USE_IO
release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
#else
+ release_mem_region(root_speedo_dev->base_addr, 0x1000);
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
+ pci_set_power_state(sp->pdev, sp->acpi_pwr);
next_dev = sp->next_module;
if (sp->priv_addr)
kfree(sp->priv_addr);
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
}
/* Free the original skb. */
- DEV_FREE_SKB(ep->tx_skbuff[entry]);
+ dev_kfree_skb_irq(ep->tx_skbuff[entry]);
ep->tx_skbuff[entry] = 0;
}
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;
}
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;
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);
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))
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
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;
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;
}
++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;
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)
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));
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];
}
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);
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;
-
- /* 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;
+ struct net_device *dev;
+
+ 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);
#include <asm/pgtable.h>
#include "mace.h"
-#ifdef MODULE
static struct net_device *mace_devs = NULL;
-#endif
#define N_RX_RING 8
#define N_TX_RING 6
struct net_device_stats stats;
struct timer_list tx_timeout;
int timeout_active;
+ struct net_device *next_mace;
};
/*
+ (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);
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);
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) {
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)
/* enable all interrupts except receive interrupts */
out_8(&mb->imr, RCVINT);
-#ifdef MOD_INC_USE_COUNT
MOD_INC_USE_COUNT;
-#endif
return 0;
}
mace_clean_rings(mp);
-#ifdef MOD_DEC_USE_COUNT
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
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;
}
}
-
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);
+ struct net_device *dev;
+ struct mace_data *mp;
- 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);
+ while ((dev = mace_devs) != 0) {
+ mp = (struct mace_data *) mace_devs->priv;
+ mace_devs = mp->next_mace;
- kfree(mace_devs);
- mace_devs = NULL;
-#endif
+ 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);
*/
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 <linux/config.h>
+
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
int ncr885e_debug = NCR885E_DEBUG;
static int print_version = 0;
-static int debug = NCR885E_DEBUG; /* module parm */
-
struct ncr885e_private {
if ( xfer ) {
dev_kfree_skb( sp->tx_skbufs[i] );
- mark_bh( NET_BH );
if ( txbits & TX_STATUS_TXOK ) {
sp->stats.tx_packets++;
}
- dev->tbusy = 0;
+ netif_start_queue(dev);
return;
}
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)
ncr885e_rx( dev );
}
- dev->interrupt = 0;
spin_unlock( &sp->lock );
return;
/* 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,
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;
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 ) {
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 );
* 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;
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 */
#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;
module_init(ncr885e_probe);
module_exit(ncr885e_cleanup);
-
/*
* Local variables:
* compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c"
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.
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";
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;
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;
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);
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;
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);
}
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);
}
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
tc574_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
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;
/* 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)
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));
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);
/* 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. */
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);
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)
#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);
}
/*
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 */
{
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;
}
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);
}
link->open--;
- dev->start = 0;
del_timer(&lp->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
#error You must compile this driver with "-O".
#endif
-#include <linux/config.h>
-#include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/delay.h>
-#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 <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
MODULE_PARM(compaq_ioaddr, "i");
MODULE_PARM(compaq_irq, "i");
MODULE_PARM(compaq_device_id, "i");
-#endif
/* Operational parameter that usually are not changed. */
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},
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;
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.
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);
\f
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
{
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",
"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);
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;
}
}
}
-#endif /* NO_PCI */
/* Now check all slots of the EISA bus. */
if (EISA_bus) {
}
#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;
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)
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);
}
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;
}
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);
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. */
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
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) {
} 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);
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 =
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]));
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;
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);
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) {
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. */
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. */
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)
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);
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) {
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;
}
}
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;
}
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
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);
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;
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;
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);
}
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);
}
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
tc589_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
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;
/* 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)
{
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... */
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);
ioaddr_t ioaddr, status;
int i = 0;
- if ((lp == NULL) || !dev->start)
+ if (lp == NULL)
return;
ioaddr = dev->base_addr;
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);
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)
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
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. */
}
link->open--;
- dev->start = 0;
del_timer(&lp->media);
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
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
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);
}
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);
}
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
// awc_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
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
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);
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;
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;
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 */
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;
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;
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);
}
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);
}
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
netwave_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
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,
* 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.
* 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;
}
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;
/* 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) {
*/
}
/* done.. */
- dev->interrupt = 0;
- return;
+ spin_unlock (&priv->lock);
} /* netwave_interrupt */
/*
netwave_reset(dev);
/* We are not waiting anymore... */
- dev->tbusy = 0;
+ netif_start_queue (dev);
} /* netwave_watchdog */
link->open++;
MOD_INC_USE_COUNT;
- dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
netwave_reset(dev);
return 0;
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;
#undef MACE_IMR_DEFAULT
#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
+#define TX_TIMEOUT (5*HZ)
+
+
+
/* ----------------------------------------------------------------------------
Type Definitions
---------------------------------------------------------------------------- */
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 */
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);
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;
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;
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");
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);
}
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);
}
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;
MACEBANK(0);
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
-
+ netif_start_queue (dev);
nmclan_reset(dev);
return 0; /* Always succeed */
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;
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,
{
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. */
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()] . . . */
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)
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 "
/* 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! */
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) {
} while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
exception:
- dev->interrupt = 0;
- return;
+ spin_unlock (&lp->lock);
} /* mace_interrupt */
/* ----------------------------------------------------------------------------
u_short media_status;
u_short fast_poll;
u_long last_rx;
+
+ spinlock_t lock;
};
/* Special definitions for Megahertz multifunction cards */
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);
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;
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 */
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;
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");
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);
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);
}
}
if (link->open) {
smc_reset(dev);
- dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
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;
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. */
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;
" 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;
}
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)
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. */
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
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++;
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
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);
/* 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 <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
MODULE_PARM(debug, "i");
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
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 */
};
restore_flags(flags);
}
\f
-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;
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);
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;
#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) {
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++) {
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",
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. */
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);
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);
}
/* Free the original skb. */
- dev_free_skb(tp->tx_skbuff[entry]);
+ dev_kfree_skb_irq(tp->tx_skbuff[entry]);
tp->tx_skbuff[entry] = 0;
}
}
#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) {
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
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);
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);
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;
}
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;
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;
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;
* (wavelan modem or i82593)
*/
-/*------------------------------------------------------------------*/
-/*
- * 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
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;
{
ioaddr_t base = lp->dev->base_addr;
mm_t m;
- unsigned long x;
+ unsigned long flags;
if(wavepoint==lp->curr_point) /* Sanity check... */
{
#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;
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;
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);
* 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
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");
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
#endif
/* Disable interrupts & save flags */
- x = wv_splhi();
+ spin_lock_irqsave (&lp->lock, flags);
/* Look what is the request */
switch(cmd)
}
/* 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);
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;
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);
{
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;
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)
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");
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
#endif
+
+ netif_start_queue (dev);
}
/*------------------------------------------------------------------*/
* 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 **********************/
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;
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));
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));
#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;
}
/* 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",
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)
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 */
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);
#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);
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++;
(unsigned int) dev);
#endif
+ netif_stop_queue (dev);
+
/* If the device isn't open, then nothing to do */
if(!link->open)
{
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);
/* 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 */
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);
{
if(link->open)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
}
CardServices(ReleaseConfiguration, link->handle);
}
if(link->open) /* If RESET -> True, If RESUME -> False ??? */
{
wv_hw_reset(dev);
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
*/
struct net_local
{
+ spinlock_t lock;
dev_node_t node; /* ???? What is this stuff ???? */
device * dev; /* Reverse link... */
dev_link_t * link; /* pcmcia structure */
#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,
int suspended;
unsigned last_ptr_value; /* last packets transmitted value */
const char *manf_str;
+ spinlock_t lock;
} local_info_t;
/****************
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
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;
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;
/* 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;
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);
}
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);
}
if (link->open) {
do_reset(dev,1);
lp->suspended=0;
- dev->tbusy = 0; dev->start = 1;
+ netif_start_queue (dev);
}
}
break;
* -- 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);
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");
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:
/*====================================================================*/
-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
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 */
dev_kfree_skb (skb);
dev->trans_start = jiffies;
- dev->tbusy = 0;
+ netif_start_queue (dev);
lp->stats.tx_bytes += pktlen;
return 0;
}
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);
if (!link)
return -ENODEV;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
SelectPage(0);
PutByte(XIRCREG_CR, 0); /* disable interrupts */
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;
#endif
dev->base_addr = (unsigned long)vaddr;
dev->irq = irq;
- dev->interrupt = 0;
/*
* Request a shared interrupt line.
printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers);
#endif
MOD_INC_USE_COUNT;
+ netif_start_queue(dev);
return 0;
}
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.
#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!
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
(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;
}
(uint)pDpa->numOutRcvBuffers);
}
printk("rc: Initialization done.\n");
- dev->tbusy=0;
+ netif_wake_queue(dev);
retry=0;
return;
case RC_RTN_FREE_Q_EMPTY:
PDPA pDpa = (PDPA) dev->priv;
+ netif_stop_queue(dev);
+
#ifdef RCDEBUG
printk("rc: RCclose\r\n");
#endif
--- /dev/null
+/* 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 <shangh@realtek.com.tw>.
+*/
+
+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<<val. */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+/* 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 <linux/delay.h>
+
+#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 <linux/bios32.h>
+#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
+
+*/
+\f
+
+/* 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. */
+};
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+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);
+\f
+
+/* 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;
+}
+\f
+/* 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;
+}
+
+\f
+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;
+ 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;
+}
+\f
+#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 */
+\f
+/*
+ * 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:
+ */
+++ /dev/null
-/* 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 <shangh@realtek.com.tw>.
-*/
-
-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<<val. */
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (4*HZ)
-
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-/* 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 <linux/delay.h>
-
-#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 <linux/bios32.h>
-#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
-
-*/
-\f
-
-/* 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 <becker@cesdis.gsfc.nasa.gov>");
-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);
-\f
-
-/* 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;
-}
-\f
-/* 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;
-}
-
-\f
-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;
-}
-\f
-#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 */
-\f
-/*
- * 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:
- */
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);
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);
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;
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;
- struct net_local *lp = (struct net_local *)dev->priv;
+ 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);
+}
- 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;
- }
+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;
- /* 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;
\f
/* 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;
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). */
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;
}
/* 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);
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?)
{
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);
static const char *version =
"smc9194.c:v0.12 03/06/96 by Erik Stahlman (erik@vt.edu)\n";
-#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
.
-------------------------------------------------------------------------*/
-/*
- . 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.
.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
#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
-------------------------------------------------------------------------*/
#define CARDNAME "SMC9194"
-#ifdef SUPPORT_OLD_KERNEL
-char kernel_version[] = UTS_RELEASE;
-#endif
/* store this information for the driver.. */
struct smc_local {
*/
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
. 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 );
/*---------------------------------------------------------------
.
/*
. 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
/* 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 )
}
-#ifndef SUPPORT_OLD_KERNEL
/*
. Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
. Purpose:
return crc_value;
}
-#endif
-
/*
. Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
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 */
}
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
-
+ netif_wake_queue(dev);
return 0;
}
printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
kfree(skb);
lp->saved_skb = NULL;
- dev->tbusy = 0;
+ netif_wake_queue(dev);
return;
}
dev->trans_start = jiffies;
/* we can send another packet */
- dev->tbusy = 0;
-
+ netif_wake_queue(dev);
return;
}
return -ENODEV;
}
-#ifndef NO_AUTOPROBE
/*----------------------------------------------------------------------
. smc_findirq
.
/* and return what I found */
return autoirq_report( 0 );
}
-#endif
/*----------------------------------------------------------------------
. Function: smc_probe( int ioaddr )
/* 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;
}
. what (s)he is doing. No checking is done!!!!
.
*/
-#ifndef NO_AUTOPROBE
if ( dev->irq < 2 ) {
int trials;
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.
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;
}
/* 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 */
address |= dev->dev_addr[ i ];
outw( address, ioaddr + ADDR0 + i );
}
+
+ netif_start_queue(dev);
return 0;
}
. skeleton.c, from Becker.
.--------------------------------------------------------
*/
-static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
+
+static void smc_timeout(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;
- }
+ /* 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);
+}
- /* 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;
+static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ 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 );
}
/*--------------------------------------------------------------------
. 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;
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);
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"));
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++;
SMC_SELECT_BANK( saved_bank );
- dev->interrupt = 0;
PRINTK3((CARDNAME ": Interrupt done\n"));
return;
}
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
! 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
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 {
-----------------------------------------------------*/
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;
}
. 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.
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 */
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 );
*/
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);
}
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)
{
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
strip_unlock(strip_info);
- mark_bh(NET_BH);
}
}
{
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 */
strip_send(strip_info, skb);
- if (skb) dev_kfree_skb(skb);
+ if (skb)
+ dev_kfree_skb(skb);
return(0);
}
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 */
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);
}
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.
*/
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;
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);
}
/* 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.
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;
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;
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);
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.
/* 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);
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)
if (chan->protocol == ETH_P_X25)
chan_x25_send_event(dev, 2);
- dev->tbusy = 0;
+ netif_wake_queue(dev);
break;
}
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) {
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 = 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;
}
* 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;
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;
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;
}
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)
#include <linux/version.h>
-#if LINUX_VERSION_CODE >=0x020200
-#define v22
-#endif
-
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/types.h>
#include <net/arp.h>
-
-
-#ifdef v22
#include <asm/uaccess.h>
#include <linux/init.h>
-#endif
#include "sbni.h"
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;
{
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;
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;
}
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;
{
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;
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;
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)
/* 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;
}
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);
/*
* reset output active flags
*/
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
/*} if */
}
case PACKET_RESEND:
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;
*/
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)
}
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);
}
}
lp->waitack=0;
- dev->tbusy = 0;
-
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
+
DP( printk("%s: queue dropping stoped\n",dev->name); );
}
/* 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;
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;
int carrier;
-
+ spinlock_t lock;
};
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);
}
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. */
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)
sl->tx_packets++;
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
x25_asy_unlock(sl);
- mark_bh(NET_BH);
return;
}
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)
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;
* 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)
{
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);
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
*/
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;
}
{
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;
/*
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;
* 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]);
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 ! */
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)
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)
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;
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;
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)
}
}
-/* 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)
{
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
* 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)
}
-/*
- * 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)
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);
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)
}
}
+/**
+ * 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)
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;
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.
*/
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);
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)
};
+/**
+ * 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;
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;
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;
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;
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;
}
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;
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,
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.
*/
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 */
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)
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)
}
}
}
-
+
+/**
+ * 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)
{
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)
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;
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);
}
}
-/*
- * 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)
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
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;
*/
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.
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 *);
* 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.
/*
* 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
* 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 *********************/
/*
/*
* 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;
-
- x = wv_splhi();
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned long flags;
- lp->hacr &= ~HACR_INTRON;
- hacr_write(ioaddr, lp->hacr);
+ save_flags(flags);
+ cli();
+
+ 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);
+ net_local *lp = (net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned long flags;
- wv_splx(x);
-} /* wv_ints_on */
+ save_flags(flags);
+ cli();
+ lp->hacr |= HACR_INTRON;
+ hacr_write(ioaddr, lp->hacr);
+ restore_flags(flags);
+} /* wv_ints_on */
/******************* MODEM MANAGEMENT SUBROUTINES *******************/
/*
/*
* 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;
+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);
+ wv_16_off(ioaddr, hacr);
- while(n-- > 0)
- {
- outw(o, PIOR2(ioaddr));
- o++;
+ while (n-- > 0) {
+ outw(o, PIOR2(ioaddr));
+ o++;
- outb(*b, PIOP2(ioaddr));
- b++;
+ 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);
- }
+ /* 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
/*------------------------------------------------------------------*/
* 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 */
-
- for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
- {
- if(crc_bytes & 0x0001)
- crc_bytes = (crc_bytes >> 1) ^ 0xA001;
- else
- crc_bytes >>= 1 ;
- }
- }
+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;
+ }
+ }
- 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));
+ /* 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;
+ 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);
+ /* 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));
+ /* 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 */
+ 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)
+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)
- ;
+ /* 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));
}
/*------------------------------------------------------------------*/
* 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)
+static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
{
- o += n;
- b += n;
+ o += n;
+ b += n;
- while(n-- > 0 )
- mmc_out(ioaddr, --o, *(--b));
-} /* mmc_write */
+ 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)
+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);
+ outw(o << 1, MMCR(ioaddr));
- while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
- ;
- return (u_char) (inw(MMCR(ioaddr)) >> 8);
+ while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+ return (u8) (inw(MMCR(ioaddr)) >> 8);
}
/*------------------------------------------------------------------*/
* (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)
+static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n)
{
- o += n;
- b += n;
+ o += n;
+ b += n;
- while(n-- > 0)
- *(--b) = mmc_in(ioaddr, --o);
-} /* mmc_read */
+ 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;
}
/*------------------------------------------------------------------*/
* 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 */
/*------------------------------------------------------------------*/
/*
* 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 */
+ /* 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);
+ /* 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);
+ 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);
+ /* 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 */
+ /* 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 */
+ 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);
+ /* 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);
+ fee_wait(ioaddr, 10, 100);
- /* Write the EEPROM address. */
- mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+ /* 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);
+ /* 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);
+ /* 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);
- }
+ /* 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);
+ /* 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 *************************/
/*
* 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;
+ 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;
+ 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;
+ if (scb_cs == 0)
+ return;
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
- (unsigned char *) &scb_cs, sizeof(scb_cs));
+ obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+ (unsigned char *) &scb_cs, sizeof(scb_cs));
- set_chan_attn(ioaddr, lp->hacr);
+ 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;
+ 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);
+ 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
}
* 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);
-
- if(i <= 0 || !(cb.ac_status & AC_SFLD_OK))
- {
+ 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;
+
+ 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;
}
/*------------------------------------------------------------------*/
* Check if done, and if OK.
*/
static inline int
-wv_config_complete(device * dev,
- u_long ioaddr,
- net_local * lp)
+wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
{
- unsigned short mcs_addr;
- unsigned short status;
- int ret;
+ 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);
-
- /* 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 */
- }
+ 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);
+
+ /* 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 */
+ }
#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;
}
/*------------------------------------------------------------------*/
* 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;
+ /* 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));
+ /* 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;
+ /* 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 */
+ /* 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;
+ /* 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);
+ 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++;
+ } 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);
+ 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++;
+ }
+ 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);
+ 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++;
+ }
+ 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);
+ 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++;
+ }
+ 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);
+ 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++;
+ }
+ 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;
}
/*------------------------------------------------------------------*/
* 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 *********************/
/*
* 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
/*------------------------------------------------------------------*/
* 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 */
-
- printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
+ 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");
#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;
-
- obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
-
- 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);
+ scb_t scb;
+
+ obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+ sizeof(scb));
+
+ 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);
}
/*------------------------------------------------------------------*/
/*
* 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=\"");
-
- 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 */
+ 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 */
}
-#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("?");
+ /* 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(", ");
- 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 *********************/
/*
* 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);
}
/*------------------------------------------------------------------*/
* 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
- */
+ /* 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))
+ 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);
- }
- }
+ {
+ 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
}
* (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 */
/*------------------------------------------------------------------*/
/*
* 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
- printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
- dac[0], dac[1]);
+ /* 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]);
#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);
+ /* 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);
+ /* 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 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);
- }
-
- 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);
}
#ifdef WIRELESS_SPY
* 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
/*------------------------------------------------------------------*/
* 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++]))
- ;
-
- /* Increment interval counter. */
- (lp->his_sum[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])++;
}
-#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);
- }
-
- /* Reset structure. */
- memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_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);
+ }
+
+ /* 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 */
+
+ /* ------------------- OTHER IOCTL ------------------- */
- /* 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);
+ default:
+ ret = -EOPNOTSUPP;
}
- 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 */
- /* ------------------- OTHER IOCTL ------------------- */
-
- 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;
}
/*------------------------------------------------------------------*/
* 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();
-
- 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;
-
- /* Enable interrupts and restore flags. */
- wv_splx(x);
+ /* 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);
+
+ 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. */
+ 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 *************************/
/*
* (called by wv_packet_rcv())
*/
static inline void
-wv_packet_read(device * dev,
- u_short buf_off,
- int sksize)
+wv_packet_read(device * dev, u16 buf_off, int sksize)
{
- net_local * lp = (net_local *) dev->priv;
- u_long ioaddr = dev->base_addr;
- struct sk_buff * skb;
+ 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;
- }
+ lp->stats.rx_dropped++;
+ return;
+ }
- skb->dev = dev;
+ 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);
+ /* 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) */
+ wl_his_gather(dev, stats);
+#endif /* HISTOGRAM */
+ }
+#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
- /*
- * Hand the packet to the network module.
- */
- netif_rx(skb);
+ /*
+ * 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;
+ /* 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
}
* 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);
+ 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_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 = 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));
+ 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 */
+ 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
}
*
* (called in wavelan_packet_xmit())
*/
-static inline void
-wv_packet_write(device * dev,
- void * buf,
- short length)
+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;
+ 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;
+ /* 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);
- x = wv_splhi();
+ /*
+ * 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));
- /* 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;
+ /*
+ * 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));
-/*
-if (lp->tx_n_in_use > 0)
- printk("%c", "0123456789abcdefghijk"[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));
+
+ /*
+ * 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);
+ }
- 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);
-
- /*
- * 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);
- }
-
- if(lp->tx_first_in_use == I82586NULL)
- lp->tx_first_in_use = txblock;
-
- if(lp->tx_n_in_use < NTXBLOCKS - 1)
- dev->tbusy = 0;
-
- wv_splx(x);
+ if (lp->tx_first_in_use == I82586NULL)
+ lp->tx_first_in_use = txblock;
+ 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
}
* 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 ***********************/
* 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;
-
- /* It is configured */
- psa.psa_conf_status |= 1;
+ /* 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;
#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);
+ /* 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);
-
- /* Wait until the download is finished. */
- fee_wait(ioaddr, 100, 100);
+ }
+
+ /* 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, (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. */
+ 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);
+ /* 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 */
+ /* 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;
}
/*------------------------------------------------------------------*/
* 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;
+ 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;
+ 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;
+ 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));
+ 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));
+ 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;
- }
+ lp->rx_last = rx;
+ }
- obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
- (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
+ 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));
+ 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);
+ 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;
+ 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;
}
/*------------------------------------------------------------------*/
*
* (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;
-
- 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;
-
- udelay(10);
- }
-
- if(i <= 0)
- {
+ 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));
+ }
+
+ 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);
+ }
+
+ 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;
}
/*------------------------------------------------------------------*/
*
* (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));
-
- if(iscp.iscp_busy == (unsigned short) 0)
- break;
-
- udelay(10);
- }
-
- if(i <= 0)
- {
+ /*
+ * 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;
+
+ udelay(10);
+ }
+
+ 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);
+ 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));
+ /* 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;
+ 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;
}
/*------------------------------------------------------------------*/
*
* (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();
-
- /* 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);
+ 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));
+
+ /*
+ * 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_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_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), (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] );
+ 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;
-
- if(lp->tx_first_in_use == I82586NULL)
- lp->tx_first_in_use = txblock;
-
- if(lp->tx_n_in_use < NTXBLOCKS - 1)
- dev->tbusy = 0;
-
- wv_splx(x);
+ }
+
+ /*
+ * 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;
+ if (lp->tx_first_in_use == I82586NULL)
+ lp->tx_first_in_use = txblock;
+
+ 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
}
* 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
}
* 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;
}
/*------------------------------------------------------------------*/
* 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)
+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;
+ 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 ************************/
* 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)
+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;
+ 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;
+ /* Prevent reentrance. What should we do here? */
- if((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR)
- {
- u_char dce_status;
+ 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));
+ /*
+ * 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));
+ /* 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);
+ /*
+ * 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);
-
- /* 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);
+ 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)
- {
+ /* 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
}
* 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;
+ 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;
+ 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;
+ save_flags(flags);
+ cli();
+
+ dev = (device *) a;
+ ioaddr = dev->base_addr;
+ lp = (net_local *) dev->priv;
- if(lp->tx_n_in_use <= 0)
- {
- wv_splx(x);
- return;
- }
+ 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
}
* 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;
- }
-
- x = wv_splhi();
- if(wv_hw_reset(dev) != -1)
- {
- dev->interrupt = 0;
- dev->start = 1;
- }
- else
- {
- free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+
+ 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;
}
/*------------------------------------------------------------------*/
* 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;
}
/*------------------------------------------------------------------*/
* 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);
+ 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_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)
- {
+ 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;
- }
-
- dev->irq = irq;
-
- 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;
+ return EAGAIN;
+ }
+
+ dev->irq = irq;
+
+ 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;
#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;
}
/*------------------------------------------------------------------*/
* 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;
- }
-
- /* 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)
- {
+ 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) {
#ifdef DEBUG_CALLBACK_TRACE
- printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
+ printk(KERN_DEBUG
+ "%s: <-wavelan_probe()\n",
+ dev->name);
#endif
- return 0;
- }
+ 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 ******************************/
* 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];
- }
+ /* 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;
-
- /* 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
*
* 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),
#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;
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, };
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)
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);
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
&& 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;
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);
}
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;
return;
}
- dev->interrupt = 1;
+ spin_lock (&lp->lock);
+
ioaddr = dev->base_addr;
outb(CMD0_STAT0, ioaddr);
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);
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)
outb(CMD0_ACK,ioaddr);
} while (boguscnt--);
- dev->interrupt = 0;
+ spin_unlock (&lp->lock);
+
return;
}
unsigned long flags;
int ioaddr = dev->base_addr;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
outb(CMD0_RESET, ioaddr); /* CMD0_RESET */
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)
- Initial Beta Release.
*****************************************************************************/
+
#ifdef MODULE
#include <linux/module.h>
#endif
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; */
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])) )
{
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);
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/dbdma.h>
+#include <asm/feature.h>
#include "awacs_defs.h"
#include <linux/nvram.h>
#include <linux/vt_kern.h>
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 */
void dmasound_init(void);
-void dmasound_setup(char *str, int *ints);
+static int dmasound_setup(char *str);
/*** Translations ************************************************************/
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);
/* 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));
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);
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));
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;
}
u_long fmt;
int data;
int size, nbufs;
+ audio_buf_info info;
switch (cmd) {
case SNDCTL_DSP_RESET:
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);
{
char *buffer = state.buf, *mach = "";
#ifdef CONFIG_PPC
- char awacs_buf[50];
+ char awacs_buf[64];
#endif
int len = 0;
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);
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);
}
}
/* 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 */
#include <linux/module.h>
#include <linux/kbd_kern.h>
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
static unsigned char keybdev_x86_e0s[] =
{ 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48,
{
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);
#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
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
#endif /* CONFIG_PPC */
+ }
#endif /* MODULE */
if (noaccel)
-/* $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
info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
if (!info->mmap_map) {
printk("igafb_init: can't alloc mmap_map\n");
- iounmap(info->io_base);
- iounmap((void *)info->frame_buffer);
+ iounmap((void *)info->io_base);
+ iounmap(info->frame_buffer);
kfree(info);
return -ENOMEM;
}
#endif
if (!iga_init(info)) {
- iounmap(info->io_base);
- iounmap((void *)info->frame_buffer);
+ iounmap((void *)info->io_base);
+ iounmap(info->frame_buffer);
if (info->mmap_map)
kfree(info->mmap_map);
kfree(info);
dep_bool ' SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL
tristate 'UDF filesystem support (read only)' CONFIG_UDF_FS
-dep_bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW $CONFIG_UDF_FS $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW
+fi
tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
dep_bool ' UFS filesystem write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
struct inode_operations adfs_file_inode_operations = {
&adfs_file_operations, /* default file operations */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+ readpage: generic_readpage,
+ bmap: adfs_bmap,
+#endif
};
abort_toobig:
return 0;
}
+
static int adfs_writepage(struct dentry *dentry, struct page *page)
{
- return block_write_full_page(page,adfs_get_block);
+ return block_write_full_page(page, adfs_get_block);
}
+
static int adfs_readpage(struct dentry *dentry, struct page *page)
{
- return block_read_full_page(page,adfs_get_block);
+ return block_read_full_page(page, adfs_get_block);
}
-static int adfs_prepare_write(struct page *page, unsigned from, unsigned to)
+
+static int adfs_prepare_write(struct page *page, unsigned int from, unsigned int to)
{
- return cont_prepare_write(page,from,to,adfs_get_block,
- &((struct inode*)page->mapping->host)->u.adfs_i.mmu_private);
+ return cont_prepare_write(page, from, to, adfs_get_block,
+ &((struct inode *)page->mapping->host)->u.adfs_i.mmu_private);
}
+
static int _adfs_bmap(struct address_space *mapping, long block)
{
- return generic_block_bmap(mapping,block,adfs_get_block);
+ return generic_block_bmap(mapping, block, adfs_get_block);
}
-struct address_space_operations adfs_aops = {
- readpage: adfs_readpage,
- writepage: adfs_writepage,
- prepare_write: adfs_prepare_write,
- commit_write: generic_commit_write,
- bmap: _adfs_bmap
+
+static struct address_space_operations adfs_aops = {
+ readpage: adfs_readpage,
+ writepage: adfs_writepage,
+ prepare_write: adfs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: _adfs_bmap
};
+
#else
int adfs_bmap(struct inode *inode, int block)
{
if (S_ISDIR(inode->i_mode))
inode->i_op = &adfs_dir_inode_operations;
else if (S_ISREG(inode->i_mode)) {
- inode->i_op = &adfs_file_inode_operations;
+ inode->i_op = &adfs_file_inode_operations;
inode->i_mapping->a_ops = &adfs_aops;
inode->u.adfs_i.mmu_private = inode->i_size;
}
/*
* get fragment id
*/
- //asm("@ get fragment id start");
{
unsigned long v2;
unsigned int tmp;
frag &= idmask;
}
- //asm("@ get fragment id end");
mapptr = start + idlen;
/*
* find end of fragment
*/
- //asm("@ find end of fragment start");
{
unsigned long v2;
mapptr += 1 + ffz(~v2);
}
- //asm("@ find end of fragment end");
if (frag == frag_id)
goto found;
/*
* get fragment id
*/
- //asm("@ get fragment id start");
{
unsigned long v2;
unsigned int tmp;
frag &= idmask;
}
- //asm("@ get fragment id end");
/*
* If the freelink is null, then no free fragments
/*
* get fragment id
*/
- //asm("@ get fragment id start");
{
unsigned long v2;
unsigned int tmp;
frag &= idmask;
}
- //asm("@ get fragment id end");
mapptr = start + idlen;
/*
* find end of fragment
*/
- //asm("@ find end of fragment start");
{
unsigned long v2;
mapptr += 1 + ffz(~v2);
}
- //asm("@ find end of fragment end");
total += mapptr - start;
} while (frag >= idlen + 1);
if (!error)
inode_setattr(inode, attr);
}
+ if (!error && (attr->ia_valid & ATTR_SIZE))
+ vmtruncate(inode, attr->ia_size);
return error;
}
d_delete(dentry);
} else { /* no space for deleting, try to truncate file */
struct iattr newattrs;
+ int err;
hpfs_unlock_2inodes(dir, inode);
if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret;
/*printk("HPFS: truncating file before delete.\n");*/
- down(&inode->i_sem); /* do_truncate should be called here, but it's */
- newattrs.ia_size = 0; /* not exported */
+ down(&inode->i_sem);
+ newattrs.ia_size = 0;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
- if (notify_change(dentry, &newattrs)) {
- up(&inode->i_sem);
- put_write_access(inode);
- goto ret;
- }
- vmtruncate(inode, 0);
- if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode);
+ err = notify_change(dentry, &newattrs);
up(&inode->i_sem);
put_write_access(inode);
+ if (err)
+ goto ret;
rep = 1;
goto again;
}
struct dentry *dentry, *result = NULL;
struct dentry *tmp;
int found =0;
- u32 err;
+ long err;
/* This semaphore is needed to make sure that only one unconnected (free)
* dcache path ever exists, as otherwise two partial paths might get
* joined together, which would be very confusing.
if (iap->ia_valid & ATTR_SIZE) {
fh_lock(fhp);
err = notify_change(dentry, iap);
- if (!err) {
- vmtruncate(inode,iap->ia_size);
- if (inode->i_op && inode->i_op->truncate)
- inode->i_op->truncate(inode);
- }
fh_unlock(fhp);
put_write_access(inode);
}
cap_clear(current->cap_effective);
}
err = notify_change(dentry, &newattrs);
- if (!err) {
- vmtruncate(inode, size);
- if (inode->i_op && inode->i_op->truncate)
- inode->i_op->truncate(inode);
- }
if (current->fsuid != 0)
current->cap_effective = saved_cap;
put_write_access(inode);
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
error = notify_change(dentry, &newattrs);
- if (!error) {
- /* truncate virtual mappings of this file */
- vmtruncate(inode, length);
- if (inode->i_op && inode->i_op->truncate)
- inode->i_op->truncate(inode);
- }
up(&inode->i_sem);
return error;
}
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* to find an entry in a page-table-directory. */
-#define __pgd_offset(address) ((address >> PGDIR_SHIFT) & PTRS_PER_PGD)
-#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address))
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & PTRS_PER_PGD)
+#define __pgd_offset(address) pgd_index(address)
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
/* Find an entry in the second-level page table.. */
extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
*/
-#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+#define in_interrupt() ({ const int __cpu = smp_processor_id(); \
+ (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
#ifndef __SMP__
#ifndef __ASM_ARM_IO_H
#define __ASM_ARM_IO_H
+#include <linux/types.h>
#include <asm/arch/hardware.h>
#include <asm/arch/io.h>
#include <asm/proc/io.h>
/*
* ioremap and friends
*/
-extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags);
extern void __iounmap(void *addr);
#define ioremap(off,sz) __arch_ioremap((off),(sz),0)
#define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1)
#define iounmap(_addr) __iounmap(_addr)
+/*
+ * DMA-consistent mapping functions. These allocate/free a region of
+ * uncached, unwrite-buffered mapped memory space for use with DMA
+ * devices. This is the "generic" version. The PCI specific version
+ * is in pci.h
+ */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
+extern void consistent_free(void *vaddr);
+extern void consistent_sync(void *vaddr, size_t size, int rw);
+
extern void __readwrite_bug(const char *fn);
/*
* String version of IO memory access ops:
*/
-extern void _memcpy_fromio(void *, unsigned long, unsigned long);
-extern void _memcpy_toio(unsigned long, const void *, unsigned long);
-extern void _memset_io(unsigned long, int, unsigned long);
+extern void _memcpy_fromio(void *, unsigned long, size_t);
+extern void _memcpy_toio(unsigned long, const void *, size_t);
+extern void _memset_io(unsigned long, int, size_t);
#define __raw_writeb(val,addr) __arch_putb(val,addr)
#define __raw_writew(val,addr) __arch_putw(val,addr)
+++ /dev/null
-/* $Id: md.h,v 1.1 1997/12/15 15:11:57 jj Exp $
- * md.h: High speed xor_block operation for RAID4/5
- *
- */
-
-#ifndef __ASM_MD_H
-#define __ASM_MD_H
-
-/* #define HAVE_ARCH_XORBLOCK */
-
-#define MD_XORBLOCK_ALIGNMENT sizeof(long)
-
-#endif /* __ASM_MD_H */
#define pcibios_assign_all_busses() 0
-#endif
+#define PCIBIOS_MIN_IO 0x8000
+#define PCIBIOS_MIN_MEM 0x40000000
+
+#ifdef __KERNEL__
+
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+struct pci_dev;
+
+/* Allocate and map kernel buffer using consistent mode DMA for a device.
+ * hwdev should be valid struct pci_dev pointer for PCI devices,
+ * NULL for PCI-like buses (ISA, EISA).
+ * Returns non-NULL cpu-view pointer to the buffer if successful and
+ * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
+ * is undefined.
+ */
+#define pci_alloc_consistent(hwdev,size,handle) \
+ ({ \
+ void *__ret; \
+ int __gfp = GFP_KERNEL; \
+ \
+ if ((hwdev) == NULL || \
+ (hwdev)->dma_mask != 0xffffffff) \
+ __gfp |= GFP_DMA; \
+ \
+ __ret = consistent_alloc(__gfp, (size), \
+ (handle)); \
+ __ret; \
+ })
+
+/* Free and unmap a consistent DMA buffer.
+ * cpu_addr is what was returned from pci_alloc_consistent,
+ * size must be the same as what as passed into pci_alloc_consistent,
+ * and likewise dma_addr must be the same as what *dma_addrp was set to.
+ *
+ * References to the memory and mappings associated with cpu_addr/dma_addr
+ * past this call are illegal.
+ */
+extern inline void
+pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ consistent_free(vaddr);
+}
+
+/* Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+extern inline dma_addr_t
+pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size)
+{
+ consistent_sync(ptr, size, 3);
+ return virt_to_bus(ptr);
+}
+
+/* Unmap a single streaming mode DMA translation. The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call. All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+extern inline void
+pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
+{
+ /* nothing to do */
+}
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA. This is the scather-gather version of the
+ * above pci_map_single interface. Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length. They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ * DMA address/length pairs than there are SG table elements.
+ * (for example via virtual mapping capabilities)
+ * The routine returns the number of addr/length pairs actually
+ * used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+extern inline int
+pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+{
+ int i;
+ for (i = 0; i < nents; i++, sg++)
+ consistent_sync(sg->address, sg->length, 3);
+
+ return nents;
+}
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+extern inline void
+pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+{
+ /* nothing to do */
+}
+
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so. At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+extern inline void
+pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size)
+{
+ consistent_sync(bus_to_virt(dma_handle), size, 3);
+}
+
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+extern inline void
+pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems)
+{
+ int i;
+
+ for (i = 0; i < nelems; i++, sg++)
+ consistent_sync(sg->address, sg->length, 3);
+}
+
+/* These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg) (virt_to_bus((sg)->address))
+#define sg_dma_len(sg) ((sg)->length)
+
+#endif /* __KERNEL__ */
+
+#endif
#define page_pte(page) mk_pte(page, __pgprot(0))
/* to find an entry in a page-table-directory */
-#define __pgd_offset(addr) ((addr) >> PGDIR_SHIFT)
+#define pgd_index(addr) ((addr) >> PGDIR_SHIFT)
+#define __pgd_offset(addr) pgd_index(addr)
-#define pgd_offset(mm, addr) ((mm)->pgd+__pgd_offset(addr))
+#define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
/*
- * linux/include/asm-arm/proc-armo/semaphore.h
+ * linux/include/asm-arm/proc-armo/locks.h
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * Interrupt safe locking assembler.
*/
-#ifndef __ASM_PROC_SEMAPHORE_H
-#define __ASM_PROC_SEMAPHORE_H
+#ifndef __ASM_PROC_LOCKS_H
+#define __ASM_PROC_LOCKS_H
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down" is the actual routine that waits...
- */
-extern inline void down(struct semaphore * sem)
-{
- __asm__ __volatile__ ("
- @ atomic down operation
- mov r0, pc
- orr lr, r0, #0x08000000
- teqp lr, #0
- ldr lr, [%0]
- and r0, r0, #0x0c000003
- subs lr, lr, #1
- str lr, [%0]
- orrmi r0, r0, #0x80000000 @ set N
- teqp r0, #0
- movmi r0, %0
- blmi " SYMBOL_NAME_STR(__down_failed)
- :
- : "r" (sem)
- : "r0", "lr", "cc");
-}
+#define __down_op(ptr,fail) \
+ ({ \
+ __asm__ __volatile__ ( \
+ "@ atomic down operation\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+" ldr lr, [%0]\n" \
+" and r0, r0, #0x0c000003\n" \
+" subs lr, lr, #1\n" \
+" str lr, [%0]\n" \
+" orrmi r0, r0, #0x80000000 @ set N\n" \
+" teqp r0, #0\n" \
+" movmi r0, %0\n" \
+ blmi " SYMBOL_NAME_STR(fail) \
+ : \
+ : "r" (ptr) \
+ : "r0", "lr", "cc"); \
+ })
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down_interruptible" is the actual routine that waits...
- */
-extern inline int down_interruptible (struct semaphore * sem)
-{
- int result;
- __asm__ __volatile__ ("
- @ atomic down operation
- mov r0, pc
- orr lr, r0, #0x08000000
- teqp lr, #0
- ldr lr, [%1]
- and r0, r0, #0x0c000003
- subs lr, lr, #1
- str lr, [%1]
- orrmi r0, r0, #0x80000000 @ set N
- teqp r0, #0
- movmi r0, %1
- movpl r0, #0
- blmi " SYMBOL_NAME_STR(__down_interruptible_failed) "
- mov %0, r0"
- : "=r" (result)
- : "r" (sem)
- : "r0", "lr", "cc");
- return result;
-}
+#define __down_op_ret(ptr,fail) \
+ ({ \
+ unsigned int result; \
+ __asm__ __volatile__ ( \
+" @ down_op_ret\n" \
+" mov r0, pc\n" \
+" orr lr, r0, #0x08000000\n" \
+" teqp lr, #0\n" \
+" ldr lr, [%1]\m" \
+" and r0, r0, #0x0c000003\n" \
+" subs lr, lr, #1\n" \
+" str lr, [%1]\n" \
+" orrmi r0, r0, #0x80000000 @ set N\n" \
+" teqp r0, #0\n" \
+" movmi r0, %1\n" \
+" movpl r0, #0\n" \
+" blmi " SYMBOL_NAME_STR(fail) "\n" \
+" mov %0, r0" \
+ : "=&r" (result) \
+ : "r" (ptr) \
+ : "r0", "lr", "cc"); \
+ result; \
+ })
-extern inline int down_trylock(struct semaphore * sem)
-{
- int result;
- __asm__ __volatile__ ("
- @ atomic down operation
- mov r0, pc
- orr lr, r0, #0x08000000
- teqp lr, #0
- ldr lr, [%1]
- and r0, r0, #0x0c000003
- subs lr, lr, #1
- str lr, [%1]
- orrmi r0, r0, #0x80000000 @ set N
- teqp r0, #0
- movmi r0, %1
- movpl r0, #0
- blmi " SYMBOL_NAME_STR(__down_trylock_failed) "
- mov %0, r0"
- : "=r" (result)
- : "r" (sem)
- : "r0", "lr", "cc");
- return result;
-}
-
-/*
- * Note! This is subtle. We jump to wake people up only if
- * the semaphore was negative (== somebody was waiting on it).
- * The default case (no contention) will result in NO
- * jumps for both down() and up().
- */
-extern inline void up(struct semaphore * sem)
-{
- __asm__ __volatile__ ("
- @ atomic up operation
- mov r0, pc
- orr lr, r0, #0x08000000
- teqp lr, #0
- ldr lr, [%0]
- and r0, r0, #0x0c000003
- adds lr, lr, #1
- str lr, [%0]
- orrle r0, r0, #0x80000000 @ set N
- teqp r0, #0
- movmi r0, %0
- blmi " SYMBOL_NAME_STR(__up_wakeup)
- :
- : "r" (sem)
- : "r0", "lr", "cc");
-}
+#define __up_op(ptr,wake) \
+ ({ \
+ __asm__ __volatile__ ( \
+ "@ up_op\n" \
+ mov r0, pc\n" \
+ orr lr, r0, #0x08000000\n" \
+ teqp lr, #0\n" \
+ ldr lr, [%0]\n" \
+ and r0, r0, #0x0c000003\n" \
+ adds lr, lr, #1\n" \
+ str lr, [%0]\n" \
+ orrle r0, r0, #0x80000000 @ set N\n" \
+ teqp r0, #0\n" \
+ movmi r0, %0\n" \
+ blmi " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr) \
+ : "r0", "lr", "cc"); \
+ })
#endif
--- /dev/null
+/*
+ * linux/include/asm-arm/proc-armv/locks.h
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * Interrupt safe locking assembler.
+ */
+#ifndef __ASM_PROC_LOCKS_H
+#define __ASM_PROC_LOCKS_H
+
+#define __down_op(ptr,fail) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ down_op\n" \
+" mrs r0, cpsr\n" \
+" orr lr, r0, #128\n" \
+" msr cpsr_c, lr\n" \
+" ldr lr, [%0]\n" \
+" subs lr, lr, %1\n" \
+" str lr, [%0]\n" \
+" msr cpsr_c, r0\n" \
+" movmi r0, %0\n" \
+" blmi " SYMBOL_NAME_STR(fail) \
+ : \
+ : "r" (ptr), "I" (1) \
+ : "r0", "lr", "cc"); \
+ })
+
+#define __down_op_ret(ptr,fail) \
+ ({ \
+ unsigned int ret; \
+ __asm__ __volatile__( \
+ "@ down_op_ret\n" \
+" mrs r0, cpsr\n" \
+" orr lr, r0, #128\n" \
+" msr cpsr_c, lr\n" \
+" ldr lr, [%1]\n" \
+" subs lr, lr, %2\n" \
+" str lr, [%1]\n" \
+" msr cpsr_c, r0\n" \
+" movmi r0, %1\n" \
+" movpl r0, #0\n" \
+" blmi " SYMBOL_NAME_STR(fail) "\n" \
+" mov %0, r0" \
+ : "=&r" (ret) \
+ : "r" (ptr), "I" (1) \
+ : "r0", "lr", "cc"); \
+ ret; \
+ })
+
+#define __up_op(ptr,wake) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ up_op\n" \
+" mrs r0, cpsr\n" \
+" orr lr, r0, #128\n" \
+" msr cpsr_c, lr\n" \
+" ldr lr, [%0]\n" \
+" adds lr, lr, %1\n" \
+" str lr, [%0]\n" \
+" msr cpsr_c, r0\n" \
+" movle r0, %0\n" \
+" blle " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr), "I" (1) \
+ : "r0", "lr", "cc"); \
+ })
+
+/*
+ * The value 0x01000000 supports up to 128 processors and
+ * lots of processes. BIAS must be chosen such that sub'ing
+ * BIAS once per CPU will result in the long remaining
+ * negative.
+ */
+#define RW_LOCK_BIAS 0x01000000
+
+#define __down_op_write(ptr,fail) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ down_op_write\n" \
+" mrs r0, cpsr\n" \
+" orr lr, r0, #128\n" \
+" msr cpsr_c, lr\n" \
+" ldr lr, [%0]\n" \
+" subs lr, lr, %1\n" \
+" str lr, [%0]\n" \
+" msr cpsr_c, r0\n" \
+" movne r0, %0\n" \
+" blne " SYMBOL_NAME_STR(fail) \
+ : \
+ : "r" (ptr), "I" (RW_LOCK_BIAS) \
+ : "r0", "lr", "cc"); \
+ })
+
+#define __up_op_write(ptr,wake) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ up_op_read\n" \
+" mrs r0, cpsr\n" \
+" orr lr, r0, #128\n" \
+" msr cpsr_c, lr\n" \
+" ldr lr, [%0]\n" \
+" adds lr, lr, %1\n" \
+" str lr, [%0]\n" \
+" msr cpsr_c, r0\n" \
+" movcs r0, %0\n" \
+" blcs " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr), "I" (RW_LOCK_BIAS) \
+ : "r0", "lr", "cc"); \
+ })
+
+#define __down_op_read(ptr,fail) \
+ __down_op(ptr, fail)
+
+#define __up_op_read(ptr,wake) \
+ ({ \
+ __asm__ __volatile__( \
+ "@ up_op_read\n" \
+" mrs r0, cpsr\n" \
+" orr lr, r0, #128\n" \
+" msr cpsr_c, lr\n" \
+" ldr lr, [%0]\n" \
+" adds lr, lr, %1\n" \
+" str lr, [%0]\n" \
+" msr cpsr_c, r0\n" \
+" moveq r0, %0\n" \
+" bleq " SYMBOL_NAME_STR(wake) \
+ : \
+ : "r" (ptr), "I" (1) \
+ : "r0", "lr", "cc"); \
+ })
+
+#endif
+++ /dev/null
-/*
- * linux/include/asm-arm/semaphore.h
- */
-#ifndef __ASM_PROC_SEMAPHORE_H
-#define __ASM_PROC_SEMAPHORE_H
-
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down" is the actual routine that waits...
- */
-extern inline void down(struct semaphore * sem)
-{
- unsigned int cpsr, temp;
-
- __asm__ __volatile__ ("
- @ atomic down operation
- mrs %0, cpsr
- orr %1, %0, #128 @ disable IRQs
- msr cpsr, %1
- ldr %1, [%2]
- bic %0, %0, #0x80000000 @ clear N
- subs %1, %1, #1
- str %1, [%2]
- orrmi %0, %0, #0x80000000 @ set N
- msr cpsr, %0
- movmi r0, %2
- blmi " SYMBOL_NAME_STR(__down_failed)
- : "=&r" (cpsr), "=&r" (temp)
- : "r" (sem)
- : "r0", "lr", "cc");
-}
-
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down_interruptible" is the actual routine that waits...
- */
-extern inline int down_interruptible (struct semaphore * sem)
-{
- unsigned int cpsr, temp;
-
- __asm__ __volatile__ ("
- @ atomic down interruptible operation
- mrs %0, cpsr
- orr %1, %0, #128 @ disable IRQs
- msr cpsr, %1
- ldr %1, [%2]
- bic %0, %0, #0x80000000 @ clear N
- subs %1, %1, #1
- str %1, [%2]
- orrmi %0, %0, #0x80000000 @ set N
- msr cpsr, %0
- movmi r0, %2
- movpl r0, #0
- blmi " SYMBOL_NAME_STR(__down_interruptible_failed) "
- mov %1, r0"
- : "=&r" (cpsr), "=&r" (temp)
- : "r" (sem)
- : "r0", "lr", "cc");
-
- return temp;
-}
-
-extern inline int down_trylock(struct semaphore *sem)
-{
- unsigned int cpsr, temp;
-
- __asm__ __volatile__ ("
- @ atomic down try lock operation
- mrs %0, cpsr
- orr %1, %0, #128 @ disable IRQs
- msr cpsr, %1
- ldr %1, [%2]
- bic %0, %0, #0x80000000 @ clear N
- subs %1, %1, #1
- str %1, [%2]
- orrmi %0, %0, #0x80000000 @ set N
- msr cpsr, %0
- movmi r0, %2
- movpl r0, #0
- blmi " SYMBOL_NAME_STR(__down_trylock_failed) "
- mov %1, r0"
- : "=&r" (cpsr), "=&r" (temp)
- : "r" (sem)
- : "r0", "lr", "cc");
-
- return temp;
-}
-
-/*
- * Note! This is subtle. We jump to wake people up only if
- * the semaphore was negative (== somebody was waiting on it).
- * The default case (no contention) will result in NO
- * jumps for both down() and up().
- */
-extern inline void up(struct semaphore * sem)
-{
- unsigned int cpsr, temp;
-
- __asm__ __volatile__ ("
- @ atomic up operation
- mrs %0, cpsr
- orr %1, %0, #128 @ disable IRQs
- msr cpsr, %1
- ldr %1, [%2]
- bic %0, %0, #0x80000000 @ clear N
- adds %1, %1, #1
- str %1, [%2]
- orrle %0, %0, #0x80000000 @ set N
- msr cpsr, %0
- movmi r0, %2
- blmi " SYMBOL_NAME_STR(__up_wakeup)
- : "=&r" (cpsr), "=&r" (temp)
- : "r" (sem)
- : "r0", "lr", "cc");
-}
-
-#endif
#include <linux/wait.h>
#include <asm/atomic.h>
+#include <asm/proc/locks.h>
struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+ long __magic;
+#endif
};
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+ , (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
#define __SEMAPHORE_INIT(name,count) \
{ ATOMIC_INIT(count), 0, \
- __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }
+ __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+ __SEM_DEBUG_INIT(name) }
#define __MUTEX_INITIALIZER(name) \
__SEMAPHORE_INIT(name,1)
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
-#define sema_init(sem, val) \
-do { \
- atomic_set(&((sem)->count), (val)); \
- (sem)->sleepers = 0; \
- init_waitqueue_head(&(sem)->wait); \
-} while (0)
+extern inline void sema_init(struct semaphore *sem, int val)
+{
+ atomic_set(&sem->count, val);
+ sem->sleepers = 0;
+ init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+ sem->__magic = (long)&sem->__magic;
+#endif
+}
static inline void init_MUTEX(struct semaphore *sem)
{
sema_init(sem, 0);
}
-asmlinkage void __down_failed (void /* special register calling convention */);
-asmlinkage int __down_interruptible_failed (void /* special register calling convention */);
-asmlinkage int __down_trylock_failed(void /* params in registers */);
-asmlinkage void __up_wakeup (void /* special register calling convention */);
+/*
+ * special register calling convention
+ */
+asmlinkage void __down_failed(void);
+asmlinkage int __down_interruptible_failed(void);
+asmlinkage int __down_trylock_failed(void);
+asmlinkage void __up_wakeup(void);
extern void __down(struct semaphore * sem);
extern int __down_interruptible(struct semaphore * sem);
extern int __down_trylock(struct semaphore * sem);
extern void __up(struct semaphore * sem);
-extern spinlock_t semaphore_wake_lock;
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "__down" is the actual routine that waits...
+ */
+extern inline void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ __down_op(sem, __down_failed);
+}
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "__down_interruptible" is the actual routine that waits...
+ */
+extern inline int down_interruptible (struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ return __down_op_ret(sem, __down_interruptible_failed);
+}
+
+extern inline int down_trylock(struct semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ return __down_op_ret(sem, __down_trylock_failed);
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+extern inline void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ __up_op(sem, __up_wakeup);
+}
+
+/* rw mutexes (should that be mutices? =) -- throw rw
+ * spinlocks and semaphores together, and this is what we
+ * end up with...
+ *
+ * The lock is initialized to BIAS. This way, a writer
+ * subtracts BIAS ands gets 0 for the case of an uncontended
+ * lock. Readers decrement by 1 and see a positive value
+ * when uncontended, negative if there are writers waiting
+ * (in which case it goes to sleep).
+ *
+ * In terms of fairness, this should result in the lock
+ * flopping back and forth between readers and writers
+ * under heavy use.
+ *
+ * -ben
+ */
+struct rw_semaphore {
+ atomic_t count;
+ volatile unsigned char write_bias_granted;
+ volatile unsigned char read_bias_granted;
+ volatile unsigned char pad1;
+ volatile unsigned char pad2;
+ wait_queue_head_t wait;
+ wait_queue_head_t write_bias_wait;
+#if WAITQUEUE_DEBUG
+ long __magic;
+ atomic_t readers;
+ atomic_t writers;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+#define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
+#else
+#define __RWSEM_DEBUG_INIT /* */
+#endif
+
+#define __RWSEM_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+ __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
+ __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+ struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
+
+extern inline void init_rwsem(struct rw_semaphore *sem)
+{
+ atomic_set(&sem->count, RW_LOCK_BIAS);
+ sem->read_bias_granted = 0;
+ sem->write_bias_granted = 0;
+ init_waitqueue_head(&sem->wait);
+ init_waitqueue_head(&sem->write_bias_wait);
+#if WAITQUEUE_DEBUG
+ sem->__magic = (long)&sem->__magic;
+ atomic_set(&sem->readers, 0);
+ atomic_set(&sem->writers, 0);
+#endif
+}
+
+extern struct rw_semaphore *__down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *__down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
+
+extern inline void down_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+ __down_op_read(sem, __down_read_failed);
+#if WAITQUEUE_DEBUG
+ if (sem->write_bias_granted)
+ BUG();
+ if (atomic_read(&sem->writers))
+ BUG();
+ atomic_inc(&sem->readers);
+#endif
+}
+
+extern inline void down_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+ __down_op_write(sem, __down_write_failed);
+#if WAITQUEUE_DEBUG
+ if (atomic_read(&sem->writers))
+ BUG();
+ if (atomic_read(&sem->readers))
+ BUG();
+ if (sem->read_bias_granted)
+ BUG();
+ if (sem->write_bias_granted)
+ BUG();
+ atomic_inc(&sem->writers);
+#endif
+}
+
+extern inline void up_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ if (sem->write_bias_granted)
+ BUG();
+ if (atomic_read(&sem->writers))
+ BUG();
+ atomic_dec(&sem->readers);
+#endif
+ __up_op_read(sem, __rwsem_wake);
+}
-#include <asm/proc/semaphore.h>
+extern inline void up_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ if (sem->read_bias_granted)
+ BUG();
+ if (sem->write_bias_granted)
+ BUG();
+ if (atomic_read(&sem->readers))
+ BUG();
+ if (atomic_read(&sem->writers) != 1)
+ BUG();
+ atomic_dec(&sem->writers);
+#endif
+ __up_op_write(sem, __rwsem_wake);
+}
#endif
#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0)
#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0)
-#define cpu_bh_trylock(cpu) (local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
-#define cpu_bh_endlock(cpu) (local_bh_count[(cpu)] = 0)
-
#define local_bh_disable() cpu_bh_disable(smp_processor_id())
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-#define get_active_bhs() (bh_mask & bh_active)
-#define clear_active_bhs(x) atomic_clear_mask((x),&bh_active)
-
-extern inline void init_bh(int nr, void (*routine)(void))
-{
- bh_base[nr] = routine;
- atomic_set(&bh_mask_count[nr], 0);
- bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
- bh_mask &= ~(1 << nr);
- mb();
- bh_base[nr] = NULL;
-}
-
-extern inline void mark_bh(int nr)
-{
- set_bit(nr, &bh_active);
-}
-
-#ifdef __SMP__
-#error SMP not supported
-#else
-
-extern inline void start_bh_atomic(void)
-{
- local_bh_disable();
- barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
- barrier();
- local_bh_enable();
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu) (cpu_bh_trylock(cpu))
-#define softirq_endlock(cpu) (cpu_bh_endlock(cpu))
-#define synchronize_bh() barrier()
-
-#endif /* SMP */
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
- bh_mask &= ~(1 << nr);
- atomic_inc(&bh_mask_count[nr]);
- synchronize_bh();
-}
-
-extern inline void enable_bh(int nr)
-{
- if (atomic_dec_and_test(&bh_mask_count[nr]))
- bh_mask |= 1 << nr;
-}
+#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
#endif /* __ASM_SOFTIRQ_H */
((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
/* to find an entry in a page-table-directory. */
-#define __pgd_offset(address) \
- ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address))
+#define __pgd_offset(address) pgd_index(address)
+
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
* Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
*/
-#include <asm/io.h> /* need byte IO */
#include <linux/config.h>
#include <linux/spinlock.h> /* And spinlocks */
#include <linux/delay.h>
+#include <asm/io.h> /* need byte IO */
#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
#define dma_outb outb_p
* Copyright (C) 1999 Goutham Rao <goutham.rao@intel.com>
*/
-#if 0
+#if 1
#define FPSWA_BUG
#endif
* or hardware interrupt processing?
*/
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+
#define in_interrupt() \
({ \
int __cpu = smp_processor_id(); \
(local_irq_count[__cpu] + local_bh_count[__cpu]) != 0; \
})
+
+
#ifndef CONFIG_SMP
# define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
# define hardirq_endlock(cpu) ((void) 0)
extern void get_new_mmu_context (struct mm_struct *mm);
+static inline void
+enter_lazy_tlb (struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+
extern inline unsigned long
ia64_rid (unsigned long context, unsigned long region_addr)
{
#define PF_PTRACED_BIT 4
-#define IA64_TASK_SIZE 2752 /* 0xac0 */
+#define IA64_TASK_SIZE 3280 /* 0xcd0 */
#define IA64_PT_REGS_SIZE 400 /* 0x190 */
#define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */
#define IA64_SIGINFO_SIZE 136 /* 0x88 */
#define IA64_TASK_FLAGS_OFFSET 8 /* 0x8 */
#define IA64_TASK_SIGPENDING_OFFSET 16 /* 0x10 */
#define IA64_TASK_NEED_RESCHED_OFFSET 40 /* 0x28 */
-#define IA64_TASK_THREAD_OFFSET 912 /* 0x390 */
-#define IA64_TASK_THREAD_KSP_OFFSET 912 /* 0x390 */
+#define IA64_TASK_PROCESSOR_OFFSET 108 /* 0x6c */
+#define IA64_TASK_THREAD_OFFSET 1424 /* 0x590 */
+#define IA64_TASK_THREAD_KSP_OFFSET 1424 /* 0x590 */
#define IA64_TASK_PID_OFFSET 188 /* 0xbc */
#define IA64_TASK_MM_OFFSET 88 /* 0x58 */
#define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
+
extern void ia64_flush_icache_page (unsigned long addr);
-#define flush_icache_page(pg) ia64_flush_icache_page(page_address(pg))
+#define flush_icache_page(vma,pg) \
+do { \
+ if ((vma)->vm_flags & PROT_EXEC) \
+ ia64_flush_icache_page(page_address(pg)); \
+} while (0)
/*
* Now come the defines and routines to manage and access the three-level
*/
#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC)
+extern __inline__ unsigned long
+pgd_index (unsigned long address)
+{
+ unsigned long region = address >> 61;
+ unsigned long l1index = (address >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
+
+ return (region << (PAGE_SHIFT - 6)) | l1index;
+}
+
/* The offset in the 1-level directory is given by the 3 region bits
(61..63) and the seven level-1 bits (33-39). */
extern __inline__ pgd_t*
pgd_offset (struct mm_struct *mm, unsigned long address)
{
- unsigned long region = address >> 61;
- unsigned long l1index = (address >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
-
- return mm->pgd + ((region << (PAGE_SHIFT - 6)) | l1index);
+ return mm->pgd + pgd_index(address);
}
/* In the kernel's mapped region we have a full 43 bit space available and completely
* Floating point registers that the kernel considers
* scratch:
*/
- struct ia64_fpreg f6; /* scratch*/
- struct ia64_fpreg f7; /* scratch*/
- struct ia64_fpreg f8; /* scratch*/
- struct ia64_fpreg f9; /* scratch*/
+ struct ia64_fpreg f6; /* scratch */
+ struct ia64_fpreg f7; /* scratch */
+ struct ia64_fpreg f8; /* scratch */
+ struct ia64_fpreg f9; /* scratch */
};
/*
* In terms of fairness, when there is heavy use of the lock, we want
* to see the lock being passed back and forth between readers and
* writers (like in a producer/consumer style of communication).
- *
-
- For
- * liveness, it would be necessary to process the blocked readers and
- * writers in FIFO order. However, we don't do this (yet). I suppose
- * if you have a lock that is _that_ heavily contested, you're in big
- * trouble anyhow.
*
* -ben (with clarifications & IA-64 comments by davidm)
*/
#define _ASM_IA64_SMP_H
#include <linux/config.h>
+
#include <linux/init.h>
#include <linux/threads.h>
#include <linux/kernel.h>
extern unsigned long cpu_online_map;
extern unsigned long ipi_base_addr;
extern int bootstrap_processor;
-extern volatile int cpu_number_map[NR_CPUS];
+extern volatile int __cpu_number_map[NR_CPUS];
extern volatile int __cpu_logical_map[NR_CPUS];
+#define cpu_number_map(i) __cpu_number_map[i]
#define cpu_logical_map(i) __cpu_logical_map[i]
#if defined(CONFIG_KDB)
#define _ASM_IA64_SOFTIRQ_H
/*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
-#include <linux/config.h>
-#include <linux/stddef.h>
-
-#include <asm/system.h>
#include <asm/hardirq.h>
extern unsigned int local_bh_count[NR_CPUS];
#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0)
#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0)
-#define cpu_bh_trylock(cpu) (local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
-#define cpu_bh_endlock(cpu) (local_bh_count[(cpu)] = 0)
-
#define local_bh_disable() cpu_bh_disable(smp_processor_id())
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-#define get_active_bhs() (bh_mask & bh_active)
-
-static inline void
-clear_active_bhs (unsigned long x)
-{
- unsigned long old, new;
- volatile unsigned long *bh_activep = (void *) &bh_active;
- CMPXCHG_BUGCHECK_DECL
-
- do {
- CMPXCHG_BUGCHECK(bh_activep);
- old = *bh_activep;
- new = old & ~x;
- } while (ia64_cmpxchg(bh_activep, old, new, 8) != old);
-}
-
-extern inline void
-init_bh (int nr, void (*routine)(void))
-{
- bh_base[nr] = routine;
- atomic_set(&bh_mask_count[nr], 0);
- bh_mask |= 1 << nr;
-}
-
-extern inline void
-remove_bh (int nr)
-{
- bh_mask &= ~(1 << nr);
- mb();
- bh_base[nr] = NULL;
-}
-
-extern inline void
-mark_bh (int nr)
-{
- set_bit(nr, &bh_active);
-}
-
-#ifdef CONFIG_SMP
-
-/*
- * The locking mechanism for base handlers, to prevent re-entrancy,
- * is entirely private to an implementation, it should not be
- * referenced at all outside of this file.
- */
-extern atomic_t global_bh_lock;
-extern atomic_t global_bh_count;
-
-extern void synchronize_bh(void);
-
-static inline void
-start_bh_atomic (void)
-{
- atomic_inc(&global_bh_lock);
- synchronize_bh();
-}
-
-static inline void
-end_bh_atomic (void)
-{
- atomic_dec(&global_bh_lock);
-}
-
-/* These are for the irq's testing the lock */
-static inline int
-softirq_trylock (int cpu)
-{
- if (cpu_bh_trylock(cpu)) {
- if (!test_and_set_bit(0, &global_bh_count)) {
- if (atomic_read(&global_bh_lock) == 0)
- return 1;
- clear_bit(0,&global_bh_count);
- }
- cpu_bh_endlock(cpu);
- }
- return 0;
-}
-
-static inline void
-softirq_endlock (int cpu)
-{
- cpu_bh_enable(cpu);
- clear_bit(0,&global_bh_count);
-}
-
-#else /* !CONFIG_SMP */
-
-extern inline void
-start_bh_atomic (void)
-{
- local_bh_disable();
- barrier();
-}
-
-extern inline void
-end_bh_atomic (void)
-{
- barrier();
- local_bh_enable();
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu) (cpu_bh_trylock(cpu))
-#define softirq_endlock(cpu) (cpu_bh_endlock(cpu))
-#define synchronize_bh() barrier()
-
-#endif /* !CONFIG_SMP */
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void
-disable_bh (int nr)
-{
- bh_mask &= ~(1 << nr);
- atomic_inc(&bh_mask_count[nr]);
- synchronize_bh();
-}
-
-extern inline void
-enable_bh (int nr)
-{
- if (atomic_dec_and_test(&bh_mask_count[nr]))
- bh_mask |= 1 << nr;
-}
+#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
#endif /* _ASM_IA64_SOFTIRQ_H */
* not a major issue. However, for interoperability, libraries still
* need to be careful to avoid a name clashes.
*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
#ifdef __ASSEMBLY__
typedef __signed__ int __s32;
typedef unsigned int __u32;
-/*
- * There are 32-bit compilers for the ia-64 out there..
- */
-# if ((~0UL) == 0xffffffff)
-# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-typedef __signed__ long long __s64;
-typedef unsigned long long __u64;
-# endif
-# else
typedef __signed__ long __s64;
typedef unsigned long __u64;
-# endif
/*
* These aren't exported outside the kernel to avoid name space clashes
*/
# ifdef __KERNEL__
-typedef signed char s8;
-typedef unsigned char u8;
+typedef __s8 s8;
+typedef __u8 u8;
-typedef signed short s16;
-typedef unsigned short u16;
+typedef __s16 s16;
+typedef __u16 u16;
-typedef signed int s32;
-typedef unsigned int u32;
+typedef __s32 s32;
+typedef __u32 u32;
-/*
- * There are 32-bit compilers for the ia-64 out there... (don't rely
- * on cpp because that may cause su problem in a 32->64 bit
- * cross-compilation environment).
- */
-# ifdef __LP64__
+typedef __s64 s64;
+typedef __u64 u64;
-typedef signed long s64;
-typedef unsigned long u64;
#define BITS_PER_LONG 64
-# else
-
-typedef signed long long s64;
-typedef unsigned long long u64;
-#define BITS_PER_LONG 32
-
-# endif
-
/* DMA addresses are 64-bits wide, in general. */
typedef u64 dma_addr_t;
#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
/* to find an entry in a page-table-directory */
extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
{
- return mm->pgd + (address >> PGDIR_SHIFT);
+ return mm->pgd + pgd_index(address);
}
#define swapper_pg_dir kernel_pg_dir
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
/* to find an entry in a page-table-directory */
extern inline pgd_t *pgd_offset(struct mm_struct *mm, unsigned long address)
{
- return mm->pgd + (address >> PGDIR_SHIFT);
+ return mm->pgd + pgd_index(address);
}
/* Find an entry in the second-level page table.. */
#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */
#define ELF_NFPREG 33 /* includes fpscr */
+#define ELF_NVRREG 33 /* includes vscr */
/*
* This is used to ensure we don't load something for the wrong architecture.
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+/* Altivec registers */
+typedef vector128 elf_vrreg_t;
+typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
+
#define ELF_CORE_COPY_REGS(gregs, regs) \
memcpy(gregs, regs, \
sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
#include <asm/smp.h>
-extern unsigned int ppc_local_irq_count[NR_CPUS];
+extern unsigned int local_irq_count[NR_CPUS];
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
*/
#define in_interrupt() ({ int __cpu = smp_processor_id(); \
- (ppc_local_irq_count[__cpu] + ppc_local_bh_count[__cpu] != 0); })
+ (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
#ifndef __SMP__
-#define hardirq_trylock(cpu) (ppc_local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
#define hardirq_endlock(cpu) do { } while (0)
-#define hardirq_enter(cpu) (ppc_local_irq_count[cpu]++)
-#define hardirq_exit(cpu) (ppc_local_irq_count[cpu]--)
+#define hardirq_enter(cpu) (local_irq_count[cpu]++)
+#define hardirq_exit(cpu) (local_irq_count[cpu]--)
#define synchronize_irq() do { } while (0)
static inline void hardirq_enter(int cpu)
{
- ++ppc_local_irq_count[cpu];
+ unsigned int loops = 10000000;
+
+ ++local_irq_count[cpu];
atomic_inc(&global_irq_count);
+ 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
+ }
+ }
}
static inline void hardirq_exit(int cpu)
{
atomic_dec(&global_irq_count);
- --ppc_local_irq_count[cpu];
+ --local_irq_count[cpu];
}
static inline int hardirq_trylock(int cpu)
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
extern void clear_page(void *page);
-#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+extern void copy_page(void *to, void *from);
/* map phys->virtual and virtual->phys for RAM pages */
static inline unsigned long ___pa(unsigned long v)
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* to find an entry in a page-table-directory */
-#define pgd_offset(mm, address) ((mm)->pgd + ((address) >> PGDIR_SHIFT))
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
/* Find an entry in the second-level page table.. */
extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
typedef int __kernel_daddr_t;
typedef char * __kernel_caddr_t;
typedef short __kernel_ipc_pid_t;
-typedef unsigned int __kernel_uid16_t;
-typedef unsigned int __kernel_gid16_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
typedef unsigned int __kernel_uid32_t;
typedef unsigned int __kernel_gid32_t;
#include <asm/ptrace.h>
#include <asm/residual.h>
+#include <asm/types.h>
/* Machine State Register (MSR) Fields */
double fpr[32]; /* Complete floating point set */
unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */
unsigned long fpscr; /* Floating point status */
- unsigned long vrf[128];
- unsigned long vscr;
+#ifdef CONFIG_ALTIVEC
+ vector128 vr[32]; /* Complete AltiVec set */
+ vector128 vscr; /* AltiVec status */
unsigned long vrsave;
+#endif /* CONFIG_ALTIVEC */
};
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
/* 1 to 1 mapping on PPC -- Cort */
#define cpu_logical_map(cpu) (cpu)
-extern int cpu_number_map[NR_CPUS];
+#define cpu_number_map(x) (x)
extern volatile unsigned long cpu_callin_map[NR_CPUS];
#define hard_smp_processor_id() (0)
#include <asm/atomic.h>
#include <asm/hardirq.h>
-#define get_active_bhs() (bh_mask & bh_active)
-#define clear_active_bhs(x) atomic_clear_mask((x),&bh_active)
+extern unsigned int local_bh_count[NR_CPUS];
-extern unsigned int ppc_local_bh_count[NR_CPUS];
+#define local_bh_disable() do { local_bh_count[smp_processor_id()]++; barrier(); } while (0)
+#define local_bh_enable() do { barrier(); local_bh_count[smp_processor_id()]--; } while (0)
-extern inline void init_bh(int nr, void (*routine)(void))
-{
- bh_base[nr] = routine;
- atomic_set(&bh_mask_count[nr], 0);
- bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
- bh_mask &= ~(1 << nr);
- wmb();
- bh_base[nr] = 0;
-}
-
-extern inline void mark_bh(int nr)
-{
- set_bit(nr, &bh_active);
-}
-
-#ifdef __SMP__
-
-/*
- * The locking mechanism for base handlers, to prevent re-entrancy,
- * is entirely private to an implementation, it should not be
- * referenced at all outside of this file.
- */
-extern atomic_t global_bh_lock;
-extern atomic_t global_bh_count;
-
-extern void synchronize_bh(void);
-
-static inline void start_bh_atomic(void)
-{
- atomic_inc(&global_bh_lock);
- synchronize_bh();
-}
-
-static inline void end_bh_atomic(void)
-{
- atomic_dec(&global_bh_lock);
-}
-
-/* These are for the IRQs testing the lock */
-static inline int softirq_trylock(int cpu)
-{
- if (ppc_local_bh_count[cpu] == 0) {
- ppc_local_bh_count[cpu] = 1;
- if (!test_and_set_bit(0,&global_bh_count)) {
- mb();
- if (atomic_read(&global_bh_lock) == 0)
- return 1;
- clear_bit(0,&global_bh_count);
- }
- ppc_local_bh_count[cpu] = 0;
- mb();
- }
- return 0;
-}
-
-static inline void softirq_endlock(int cpu)
-{
- mb();
- ppc_local_bh_count[cpu]--;
- clear_bit(0,&global_bh_count);
-}
-
-#else
-
-extern inline void start_bh_atomic(void)
-{
- ppc_local_bh_count[smp_processor_id()]++;
- barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
- barrier();
- ppc_local_bh_count[smp_processor_id()]--;
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu) (ppc_local_bh_count[cpu] ? 0 : (ppc_local_bh_count[cpu]=1))
-#define softirq_endlock(cpu) (ppc_local_bh_count[cpu] = 0)
-#define synchronize_bh() barrier()
-
-#endif /* SMP */
-
-#define local_bh_disable() (ppc_local_bh_count[smp_processor_id()]++)
-#define local_bh_enable() (ppc_local_bh_count[smp_processor_id()]--)
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
- bh_mask &= ~(1 << nr);
- atomic_inc(&bh_mask_count[nr]);
- synchronize_bh();
-}
-
-extern inline void enable_bh(int nr)
-{
- if (atomic_dec_and_test(&bh_mask_count[nr]))
- bh_mask |= 1 << nr;
-}
+#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
#endif /* __ASM_SOFTIRQ_H */
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0 }
#define spin_lock_init(lp) do { (lp)->lock = 0; } while(0)
#define spin_unlock_wait(lp) do { barrier(); } while((lp)->lock)
+#define spin_is_locked(x) ((x)->lock != 0)
extern void _spin_lock(spinlock_t *lock);
extern void _spin_unlock(spinlock_t *lock);
#ifndef _PPC_TYPES_H
#define _PPC_TYPES_H
+#ifndef __ASSEMBLY__
/*
* __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
* header files exported to user space
#define BITS_PER_LONG 32
+typedef struct {
+ u32 u[4];
+} __attribute((aligned(16))) vector128;
+
/* DMA addresses are 32-bits wide */
typedef u32 dma_addr_t;
#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
#endif
((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
/* to find an entry in a page-table-directory. */
-#define __pgd_offset(address) \
- ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-
-#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define __pgd_offset(address) pgd_index(address)
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-/* $Id: floppy.h,v 1.25 2000/01/28 13:43:14 jj Exp $
+/* $Id: floppy.h,v 1.26 2000/02/12 23:32:35 davem Exp $
* asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* which the generic floppy driver tries to do once again.
*/
sun_fdc = (struct sun_flpy_controller *)
- (PAGE_OFFSET + fd_regs[0].phys_addr +
- (((unsigned long)fd_regs[0].which_io) << 32));
+ ((unsigned long)fd_regs[0].phys_addr +
+ (((unsigned long)fd_regs[0].which_io) << 32UL));
/* Last minute sanity check... */
if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
}
/* to find an entry in a page-table-directory. */
-#define pgd_offset(mm, address) ((mm)->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD)))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD))
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
* adfs file system inode data in memory
*/
struct adfs_inode_info {
- unsigned long mmu_private;
+ unsigned long mmu_private;
unsigned long parent_id; /* object id of parent */
__u32 loadaddr; /* RISC OS load address */
__u32 execaddr; /* RISC OS exec address */
#define I2C_DRIVERID_SAA7110 22 /* */
#define I2C_DRIVERID_MGATVO 23 /* Matrox TVOut */
#define I2C_DRIVERID_SAA5249 24 /* SAA5249 and compatibles */
+#define I2C_DRIVERID_PCF8583 25 /* real time clock */
#define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
#define I2C_DRIVERID_EXP1 0xF1
#define I2C_HW_B_G400 0x09 /* Matrox G400 */
#define I2C_HW_B_I810 0x0a /* Intel I810 */
#define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */
+#define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */
/* --- PCF 8584 based algorithms */
#define I2C_HW_P_LP 0x00 /* Parallel port interface */
*/
#include <linux/config.h>
+#include <linux/errno.h>
#ifdef CONFIG_KMOD
extern int request_module(const char * name);
extern struct softnet_data softnet_data[NR_CPUS];
-#define HAS_NETIF_QUEUE
+#define HAVE_NETIF_QUEUE
extern __inline__ void __netif_schedule(struct net_device *dev)
{
#endif
/* filesystem internal functions */
+EXPORT_SYMBOL(def_blk_fops);
EXPORT_SYMBOL(in_group_p);
EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_super);
maddr = kmap(page);
memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
flush_page_to_ram(page);
+ flush_icache_page(vma, page);
kunmap(page);
} else {
maddr = kmap(page);
} while ((mpnt = mpnt->vm_next_share) != NULL);
out_unlock:
spin_unlock(&inode->i_shared_lock);
+ if (inode->i_op && inode->i_op->truncate)
+ inode->i_op->truncate(inode);
}
return -1;
flush_page_to_ram(page);
+ flush_icache_page(vma, page);
}
vma->vm_mm->rss++;
* handle that later.
*/
flush_page_to_ram(new_page);
+ flush_icache_page(vma, new_page);
entry = mk_pte(new_page, vma->vm_page_prot);
if (write_access) {
entry = pte_mkwrite(pte_mkdirty(entry));
{
unsigned long first = start & PGDIR_MASK;
unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK;
+ unsigned long start_index, end_index;
if (!prev) {
prev = mm->mmap;
break;
}
no_mmaps:
- first = first >> PGDIR_SHIFT;
- last = last >> PGDIR_SHIFT;
- if (last > first) {
- clear_page_tables(mm, first, last-first);
- flush_tlb_pgtables(mm, first << PGDIR_SHIFT, last << PGDIR_SHIFT);
- }
+ /*
+ * If the PGD bits are not consecutive in the virtual address, the
+ * old method of shifting the VA >> by PGDIR_SHIFT doesn't work.
+ */
+ start_index = pgd_index(first);
+ end_index = pgd_index(last);
+ if (end_index > start_index)
+ clear_page_tables(mm, start_index, end_index - start_index);
}
/* Munmap is split into 2 main parts -- this part which finds
static void net_tx_action(struct softirq_action *h)
{
int cpu = smp_processor_id();
- unsigned long flags;
if (softnet_data[cpu].completion_queue) {
struct sk_buff *clist;
- local_irq_save(flags);
+ local_irq_disable();
clist = softnet_data[cpu].completion_queue;
softnet_data[cpu].completion_queue = NULL;
- local_irq_restore(flags);
+ local_irq_enable();
while (clist != NULL) {
struct sk_buff *skb = clist;
if (softnet_data[cpu].output_queue) {
struct net_device *head;
- local_irq_save(flags);
+ local_irq_disable();
head = softnet_data[cpu].output_queue;
softnet_data[cpu].output_queue = NULL;
- local_irq_restore(flags);
+ local_irq_enable();
while (head != NULL) {
struct net_device *dev = head;
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.53 2000/02/04 21:04:08 davem Exp $
+ * $Id: af_inet6.c,v 1.54 2000/02/12 23:34:45 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
inet6_bind,
inet_dgram_connect, /* ok */
sock_no_socketpair, /* a do nothing */
- inet_accept, /* ok */
+ sock_no_accept, /* a do nothing */
inet6_getname,
datagram_poll, /* ok */
inet6_ioctl, /* must change */
/* Grrr... setsockopt() does this. */
sock->sk->reuse = 1;
- /* Wow!!! */
- sock->sk->linger = 1;
/* Now, start listening on the socket */
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(sysctl_wmem_max);
EXPORT_SYMBOL(sysctl_rmem_max);
+EXPORT_SYMBOL(sysctl_ip_default_ttl);
#endif
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
case token_define_int:
case token_define_string:
case token_define_tristate:
+ case token_endmenu:
case token_hex:
case token_int:
case token_mainmenu_option: