Index: head/sys/amd64/isa/intr_machdep.h =================================================================== --- head/sys/amd64/isa/intr_machdep.h (revision 99012) +++ head/sys/amd64/isa/intr_machdep.h (revision 99013) @@ -1,241 +1,241 @@ /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _I386_ISA_INTR_MACHDEP_H_ #define _I386_ISA_INTR_MACHDEP_H_ /* * Low level interrupt code. */ #ifdef _KERNEL #if defined(SMP) || defined(APIC_IO) /* * XXX FIXME: rethink location for all IPI vectors. */ /* APIC TPR priority vector levels: 0xff (255) +-------------+ | | 15 (IPIs: Xspuriousint) 0xf0 (240) +-------------+ | | 14 0xe0 (224) +-------------+ | | 13 0xd0 (208) +-------------+ | | 12 0xc0 (192) +-------------+ | | 11 0xb0 (176) +-------------+ | | 10 (IPIs: Xcpustop) 0xa0 (160) +-------------+ | | 9 (IPIs: Xinvltlb) 0x90 (144) +-------------+ | | 8 (linux/BSD syscall, IGNORE FAST HW INTS) 0x80 (128) +-------------+ | | 7 (FAST_INTR 16-23) 0x70 (112) +-------------+ | | 6 (FAST_INTR 0-15) 0x60 (96) +-------------+ | | 5 (IGNORE HW INTS) 0x50 (80) +-------------+ | | 4 (2nd IO APIC) 0x40 (64) +------+------+ | | | 3 (upper APIC hardware INTs: PCI) 0x30 (48) +------+------+ | | 2 (start of hardware INTs: ISA) 0x20 (32) +-------------+ | | 1 (exceptions, traps, etc.) 0x10 (16) +-------------+ | | 0 (exceptions, traps, etc.) 0x00 (0) +-------------+ */ /* IDT vector base for regular (aka. slow) and fast interrupts */ #define TPR_SLOW_INTS 0x20 #define TPR_FAST_INTS 0x60 /* blocking values for local APIC Task Priority Register */ #define TPR_BLOCK_HWI 0x4f /* hardware INTs */ #define TPR_IGNORE_HWI 0x5f /* ignore INTs */ #define TPR_BLOCK_FHWI 0x7f /* hardware FAST INTs */ #define TPR_IGNORE_FHWI 0x8f /* ignore FAST INTs */ #define TPR_BLOCK_XINVLTLB 0x9f /* */ #define TPR_BLOCK_XCPUSTOP 0xaf /* */ #define TPR_BLOCK_ALL 0xff /* all INTs */ #ifdef TEST_TEST1 /* put a 'fake' HWI in top of APIC prio 0x3x, 32 + 31 = 63 = 0x3f */ #define XTEST1_OFFSET (ICU_OFFSET + 31) #endif /** TEST_TEST1 */ /* TLB shootdowns */ #define XINVLTLB_OFFSET (ICU_OFFSET + 112) /* inter-cpu clock handling */ #define XHARDCLOCK_OFFSET (ICU_OFFSET + 113) #define XSTATCLOCK_OFFSET (ICU_OFFSET + 114) /* inter-CPU rendezvous */ #define XRENDEZVOUS_OFFSET (ICU_OFFSET + 115) /* IPI to generate an additional software trap at the target CPU */ #define XCPUAST_OFFSET (ICU_OFFSET + 48) /* IPI to signal CPUs to stop and wait for another CPU to restart them */ #define XCPUSTOP_OFFSET (ICU_OFFSET + 128) /* * Note: this vector MUST be xxxx1111, 32 + 223 = 255 = 0xff: */ #define XSPURIOUSINT_OFFSET (ICU_OFFSET + 223) #endif /* SMP || APIC_IO */ #ifdef LOCORE /* * Protects the IO APIC, 8259 PIC, imen, and apic_imen */ #define ICU_LOCK MTX_LOCK_SPIN(icu_lock, 0) #define ICU_UNLOCK MTX_UNLOCK_SPIN(icu_lock) #else /* LOCORE */ /* * Type of the first (asm) part of an interrupt handler. */ typedef void inthand_t(u_int cs, u_int ef, u_int esp, u_int ss); -typedef void unpendhand_t __P((void)); +typedef void unpendhand_t(void); #define IDTVEC(name) __CONCAT(X,name) extern u_long *intr_countp[]; /* pointers into intrcnt[] */ extern driver_intr_t *intr_handler[]; /* C entry points of intr handlers */ extern struct ithd *ithds[]; extern void *intr_unit[]; /* cookies to pass to intr handlers */ extern struct mtx icu_lock; inthand_t IDTVEC(fastintr0), IDTVEC(fastintr1), IDTVEC(fastintr2), IDTVEC(fastintr3), IDTVEC(fastintr4), IDTVEC(fastintr5), IDTVEC(fastintr6), IDTVEC(fastintr7), IDTVEC(fastintr8), IDTVEC(fastintr9), IDTVEC(fastintr10), IDTVEC(fastintr11), IDTVEC(fastintr12), IDTVEC(fastintr13), IDTVEC(fastintr14), IDTVEC(fastintr15); inthand_t IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); unpendhand_t IDTVEC(fastunpend0), IDTVEC(fastunpend1), IDTVEC(fastunpend2), IDTVEC(fastunpend3), IDTVEC(fastunpend4), IDTVEC(fastunpend5), IDTVEC(fastunpend6), IDTVEC(fastunpend7), IDTVEC(fastunpend8), IDTVEC(fastunpend9), IDTVEC(fastunpend10), IDTVEC(fastunpend11), IDTVEC(fastunpend12), IDTVEC(fastunpend13), IDTVEC(fastunpend14), IDTVEC(fastunpend15), IDTVEC(fastunpend16), IDTVEC(fastunpend17), IDTVEC(fastunpend18), IDTVEC(fastunpend19), IDTVEC(fastunpend20), IDTVEC(fastunpend21), IDTVEC(fastunpend22), IDTVEC(fastunpend23), IDTVEC(fastunpend24), IDTVEC(fastunpend25), IDTVEC(fastunpend26), IDTVEC(fastunpend27), IDTVEC(fastunpend28), IDTVEC(fastunpend29), IDTVEC(fastunpend30), IDTVEC(fastunpend31); #if defined(SMP) || defined(APIC_IO) inthand_t IDTVEC(fastintr16), IDTVEC(fastintr17), IDTVEC(fastintr18), IDTVEC(fastintr19), IDTVEC(fastintr20), IDTVEC(fastintr21), IDTVEC(fastintr22), IDTVEC(fastintr23), IDTVEC(fastintr24), IDTVEC(fastintr25), IDTVEC(fastintr26), IDTVEC(fastintr27), IDTVEC(fastintr28), IDTVEC(fastintr29), IDTVEC(fastintr30), IDTVEC(fastintr31); inthand_t IDTVEC(intr16), IDTVEC(intr17), IDTVEC(intr18), IDTVEC(intr19), IDTVEC(intr20), IDTVEC(intr21), IDTVEC(intr22), IDTVEC(intr23), IDTVEC(intr24), IDTVEC(intr25), IDTVEC(intr26), IDTVEC(intr27), IDTVEC(intr28), IDTVEC(intr29), IDTVEC(intr30), IDTVEC(intr31); inthand_t Xinvltlb, /* TLB shootdowns */ Xhardclock, /* Forward hardclock() */ Xstatclock, /* Forward statclock() */ Xcpuast, /* Additional software trap on other cpu */ Xcpustop, /* CPU stops & waits for another CPU to restart it */ Xspuriousint, /* handle APIC "spurious INTs" */ Xrendezvous; /* handle CPU rendezvous */ #ifdef TEST_TEST1 inthand_t Xtest1; /* 'fake' HWI at top of APIC prio 0x3x, 32+31 = 0x3f */ #endif /** TEST_TEST1 */ #endif /* SMP || APIC_IO */ #ifdef APIC_IO /* * This is to accommodate "mixed-mode" programming for * motherboards that don't connect the 8254 to the IO APIC. */ #define AUTO_EOI_1 1 #endif #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN) void isa_defaultirq(void); int isa_nmi(int cd); int icu_setup(int intr, driver_intr_t *func, void *arg, int flags); int icu_unset(int intr, driver_intr_t *handler); void icu_reinit(void); /* * WARNING: These are internal functions and not to be used by device drivers! * They are subject to change without notice. */ int inthand_add(const char *name, int irq, driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep); int inthand_remove(void *cookie); void sched_ithd(void *dummy); void call_fast_unpend(int irq); #endif /* LOCORE */ #endif /* _KERNEL */ #endif /* !_I386_ISA_INTR_MACHDEP_H_ */ Index: head/sys/boot/alpha/boot1/boot1.c =================================================================== --- head/sys/boot/alpha/boot1/boot1.c (revision 99012) +++ head/sys/boot/alpha/boot1/boot1.c (revision 99013) @@ -1,279 +1,279 @@ /* * $FreeBSD$ * From $NetBSD: bootxx.c,v 1.4 1997/09/06 14:08:29 drochner Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #include #include #include #include #include #include #define DEBUGxx void puts(const char *s); void puthex(u_long v); static int dskread(void *, u_int64_t, size_t); #define printf(...) \ while (0) #define memcpy(dst, src, len) \ bcopy(src, dst, len) #include "ufsread.c" extern end[]; int errno; char *heap = (char*) end; void bcopy(const void *src, void *dst, size_t len) { const char *s; char *d; for (d = dst, s = src; len; len--) *d++ = *s++; } void putchar(int c) { if (c == '\n') prom_putchar('\r'); prom_putchar(c); } int getchar() { return prom_getchar(); } int ischar() { return prom_poll(); } void puts(const char *s) { while (*s) putchar(*s++); } void panic(const char *message, ...) { puts(message); puts("\r\n"); halt(); } int prom_fd = 0; int devopen() { prom_return_t ret; char devname[64]; if (prom_fd) return; ret.bits = prom_getenv(PROM_E_BOOTED_DEV, devname, sizeof devname); ret.bits = prom_open(devname, ret.u.retval + 1); if (ret.u.status) panic("devopen: open failed\n"); prom_fd = ret.u.retval; /* XXX read disklabel and setup partition offset */ return 0; } #ifdef DEBUG void puthex(u_long v) { int digit; char hex[] = "0123456789abcdef"; puts("0x"); if (!v) { puts("0"); return; } for (digit = 0; v >= (0x10L << digit); digit += 4) ; for (; digit >= 0; digit -= 4) putchar(hex[(v >> digit) & 0xf]); } #endif int dskread(void *buf, u_int64_t block, size_t size) { #ifdef DEBUG puts("dskread("); puthex((u_long)buf); puts(","); puthex(block); puts(","); puthex(size); puts(")\n"); #endif prom_read(prom_fd, size * DEV_BSIZE, buf, block); return (0); } static inline void devclose() { if (prom_fd) { prom_close(prom_fd); prom_fd = 0; } } static inline void getfilename(char *filename, const char *defname) { int c; char *p = filename; puts("Boot: "); while ((c = getchar()) != '\r') { if (c == '\b' || c == 0177) { if (p > filename) { puts("\b \b"); p--; } } else { putchar(c); *p++ = c; } } putchar('\n'); *p = '\0'; if (!*filename) strcpy(filename, defname); return; } static struct dmadat __dmadat; static inline void loadfile(char *name, char *addr) { int n; char *p; ino_t ino; puts("Loading "); puts(name); puts("\n"); dmadat = &__dmadat; if (devopen() || (ino = lookup(name)) == 0) { puts("Can't open file "); puts(name); puts("\n"); halt(); } p = addr; do { n = fsread(ino, p, VBLKSIZE); if (n < 0) { puts("Can't read file "); puts(name); puts("\n"); halt(); } p += n; twiddle(); } while (n == VBLKSIZE); devclose(); } static inline u_long rpcc() { u_long v; __asm__ __volatile__ ("rpcc %0" : "=r"(v)); return v & 0xffffffff; } int main() { char *loadaddr = (char*) SECONDARY_LOAD_ADDRESS; char *name = "/boot/loader"; char *p; char filename[512]; - void (*entry) __P((void)); + void (*entry)(void); u_long start, freq; int i; init_prom_calls(); start = rpcc(); freq = ((struct rpb *)HWRPB_ADDR)->rpb_cc_freq; while (((rpcc() - start) & 0xffffffff) < freq) { twiddle(); if (ischar()) { getfilename(filename, name); name = filename; break; } } loadfile(name, loadaddr); entry = (void (*)())loadaddr; (*entry)(); return 0; } Index: head/sys/boot/alpha/libalpha/common.h =================================================================== --- head/sys/boot/alpha/libalpha/common.h (revision 99012) +++ head/sys/boot/alpha/libalpha/common.h (revision 99013) @@ -1,11 +1,11 @@ /* * $FreeBSD$ * From: $NetBSD: common.h,v 1.2 1998/01/05 07:02:48 perry Exp $ */ -int prom_open __P((char*, int)); -void OSFpal __P((void)); -void halt __P((void)); -u_int64_t prom_dispatch __P((int, ...)); -int cpu_number __P((void)); -void switch_palcode __P((void)); +int prom_open(char*, int); +void OSFpal(void); +void halt(void); +u_int64_t prom_dispatch(int, ...); +int cpu_number(void); +void switch_palcode(void); Index: head/sys/ddb/db_elf.c =================================================================== --- head/sys/ddb/db_elf.c (revision 99012) +++ head/sys/ddb/db_elf.c (revision 99013) @@ -1,385 +1,385 @@ /* $FreeBSD$ */ /* $NetBSD: db_elf.c,v 1.4 1998/05/03 18:49:54 thorpej Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef __ELF__ #include "opt_ddb.h" #ifdef DDB_NOKLDSYM #include #include #include #include #include #include #include #include -static char *db_elf_find_strtab __P((db_symtab_t *)); +static char *db_elf_find_strtab(db_symtab_t *); #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start)) #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end)) #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private)) #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff)) void X_db_sym_init(void *symtab, void *esymtab, char *name); /* * Find the symbol table and strings; tell ddb about them. */ void X_db_sym_init(symtab, esymtab, name) void *symtab; /* pointer to start of symbol table */ void *esymtab; /* pointer to end of string table, for checking - rounded up to integer boundary */ char *name; { Elf_Ehdr *elf; Elf_Shdr *shp; Elf_Sym *symp, *symtab_start, *symtab_end; char *strtab_start, *strtab_end; int i; if (ALIGNED_POINTER(symtab, long) == 0) { printf("DDB: bad symbol table start address %p\n", symtab); return; } symtab_start = symtab_end = NULL; strtab_start = strtab_end = NULL; /* * The format of the symbols loaded by the boot program is: * * Elf exec header * first section header * . . . * . . . * last section header * first symbol or string table section * . . . * . . . * last symbol or string table section */ /* * Validate the Elf header. */ elf = (Elf_Ehdr *)symtab; if (elf->e_ident[EI_MAG0] != ELFMAG0 || elf->e_ident[EI_MAG1] != ELFMAG1 || elf->e_ident[EI_MAG2] != ELFMAG2 || elf->e_ident[EI_MAG3] != ELFMAG3) goto badheader; if (!ELF_MACHINE_OK(elf->e_machine)) goto badheader; /* * We need to avoid the section header string table (small string * table which names the sections). We do this by assuming that * the following two conditions will be true: * * (1) .shstrtab will be smaller than one page. * (2) .strtab will be larger than one page. * * When we encounter what we think is the .shstrtab, we change * its section type Elf_sht_null so that it will be ignored * later. */ shp = (Elf_Shdr *)((char*)symtab + elf->e_shoff); for (i = 0; i < elf->e_shnum; i++) { if (shp[i].sh_addr || i == elf->e_shstrndx) continue; switch (shp[i].sh_type) { case SHT_STRTAB: if (shp[i].sh_size < PAGE_SIZE) { shp[i].sh_type = SHT_NULL; continue; } if (strtab_start != NULL) goto multiple_strtab; strtab_start = (char *)symtab + shp[i].sh_offset; strtab_end = (char *)symtab + shp[i].sh_offset + shp[i].sh_size; break; case SHT_SYMTAB: if (symtab_start != NULL) goto multiple_symtab; symtab_start = (Elf_Sym *)((char*)symtab + shp[i].sh_offset); symtab_end = (Elf_Sym *)((char*)symtab + shp[i].sh_offset + shp[i].sh_size); break; default: /* Ignore all other sections. */ break; } } /* * Now, sanity check the symbols against the string table. */ if (symtab_start == NULL || strtab_start == NULL || ALIGNED_POINTER(symtab_start, long) == 0 || ALIGNED_POINTER(strtab_start, long) == 0) goto badheader; for (symp = symtab_start; symp < symtab_end; symp++) if (symp->st_name + strtab_start > strtab_end) goto badheader; /* * Link the symbol table into the debugger. */ db_add_symbol_table((char *)symtab_start, (char *)symtab_end, name, (char *)symtab); printf("[ preserving %lu bytes of %s symbol table ]\n", (u_long)roundup(((char*)esymtab - (char*)symtab), sizeof(u_long)), name); return; badheader: printf("[ %s symbol table not valid ]\n", name); return; multiple_strtab: printf("[ %s has multiple string tables ]\n", name); return; multiple_symtab: printf("[ %s has multiple symbol tables ]\n", name); return; } /* * Internal helper function - return a pointer to the string table * for the current symbol table. */ static char * db_elf_find_strtab(stab) db_symtab_t *stab; { Elf_Ehdr *elf = STAB_TO_EHDR(stab); Elf_Shdr *shp = STAB_TO_SHDR(stab, elf); int i; for (i = 0; i < elf->e_shnum; i++) { if (shp[i].sh_type == SHT_STRTAB && !shp[i].sh_addr && i != elf->e_shstrndx) return (stab->private + shp[i].sh_offset); } return (NULL); } /* * Lookup the symbol with the given name. */ db_sym_t X_db_lookup(stab, symstr) db_symtab_t *stab; const char *symstr; { Elf_Sym *symp, *symtab_start, *symtab_end; char *strtab; symtab_start = STAB_TO_SYMSTART(stab); symtab_end = STAB_TO_SYMEND(stab); strtab = db_elf_find_strtab(stab); if (strtab == NULL) return ((db_sym_t)0); for (symp = symtab_start; symp < symtab_end; symp++) { if (symp->st_name != 0 && db_eqname(strtab + symp->st_name, symstr, 0)) return ((db_sym_t)symp); } return ((db_sym_t)0); } /* * Search for the symbol with the given address (matching within the * provided threshold). */ db_sym_t X_db_search_symbol(symtab, off, strategy, diffp) db_symtab_t *symtab; db_addr_t off; db_strategy_t strategy; db_expr_t *diffp; /* in/out */ { Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end; db_expr_t diff = *diffp; symtab_start = STAB_TO_SYMSTART(symtab); symtab_end = STAB_TO_SYMEND(symtab); rsymp = NULL; for (symp = symtab_start; symp < symtab_end; symp++) { if (symp->st_name == 0) continue; if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT && ELF_ST_TYPE(symp->st_info) != STT_FUNC) continue; if (off >= symp->st_value) { if ((off - symp->st_value) < diff) { diff = off - symp->st_value; rsymp = symp; if (diff == 0) { if (strategy == DB_STGY_PROC && ELF_ST_TYPE(symp->st_info) == STT_FUNC && ELF_ST_BIND(symp->st_info) != STB_LOCAL) break; if (strategy == DB_STGY_ANY && ELF_ST_BIND(symp->st_info) != STB_LOCAL) break; } } else if ((off - symp->st_value) == diff) { if (rsymp == NULL) rsymp = symp; else if (ELF_ST_BIND(rsymp->st_info) == STB_LOCAL && ELF_ST_BIND(symp->st_info) != STB_LOCAL) { /* pick the external symbol */ rsymp = symp; } } } } if (rsymp == NULL) *diffp = off; else *diffp = diff; return ((db_sym_t)rsymp); } /* * Return the name and value for a symbol. */ void X_db_symbol_values(symtab, sym, namep, valuep) db_symtab_t *symtab; db_sym_t sym; const char **namep; db_expr_t *valuep; { Elf_Sym *symp = (Elf_Sym *)sym; char *strtab; if (namep) { strtab = db_elf_find_strtab(symtab); if (strtab == NULL) *namep = NULL; else *namep = strtab + symp->st_name; } if (valuep) *valuep = symp->st_value; } /* * Return the file and line number of the current program counter * if we can find the appropriate debugging symbol. */ boolean_t X_db_line_at_pc(symtab, cursym, filename, linenum, off) db_symtab_t *symtab; db_sym_t cursym; char **filename; int *linenum; db_expr_t off; { /* * XXX We don't support this (yet). */ return (FALSE); } /* * Returns the number of arguments to a function and their * names if we can find the appropriate debugging symbol. */ boolean_t X_db_sym_numargs(symtab, cursym, nargp, argnamep) db_symtab_t *symtab; c_db_sym_t cursym; int *nargp; char **argnamep; { /* * XXX We don't support this (yet). */ return (FALSE); } /* * Initialization routine for Elf files. */ extern void *ksym_start, *ksym_end; void kdb_init(void) { if (ksym_end > ksym_start) X_db_sym_init(ksym_start, ksym_end, "kernel"); } #endif /* DDB_NOKLDSYM */ #endif /* __ELF__ */ Index: head/sys/dev/sio/sio_ebus.c =================================================================== --- head/sys/dev/sio/sio_ebus.c (revision 99012) +++ head/sys/dev/sio/sio_ebus.c (revision 99013) @@ -1,113 +1,113 @@ /*- * Copyright (c) 2001 by Thomas Moestl . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID($FreeBSD$); #include #include #include #include #include #include #include #include #include #include -int sio_ofw_inlist __P((char *name, char *list[])); -static int sio_ebus_attach __P((device_t dev)); -static int sio_ebus_probe __P((device_t dev)); +int sio_ofw_inlist(char *name, char *list[]); +static int sio_ebus_attach(device_t dev); +static int sio_ebus_probe(device_t dev); static device_method_t sio_ebus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sio_ebus_probe), DEVMETHOD(device_attach, sio_ebus_attach), { 0, 0 } }; static driver_t sio_ebus_driver = { sio_driver_name, sio_ebus_methods, 0, }; DRIVER_MODULE(sio, ebus, sio_ebus_driver, sio_devclass, 0, 0); /* Needed for EBus attach and sparc64 console support */ char *sio_ofw_names[] = { "serial", "su", "su_pnp", NULL }; char *sio_ofw_compat[] = { "su", "su16550", NULL }; int sio_ofw_inlist(name, list) char *name; char *list[]; { int i; if (name == NULL) return (0); for (i = 0; list[i] != NULL; i++) { if (strcmp(name, list[i]) == 0) return (1); } return (0); } static int sio_ebus_probe(dev) device_t dev; { char *n; n = ebus_get_name(dev); if (!sio_ofw_inlist(n, sio_ofw_names) && (strcmp(n, "serial") != 0 || !sio_ofw_inlist(ebus_get_compat(dev), sio_ofw_compat))) return (ENXIO); /* Do not probe IRQ - isa_irq_pending() does not work for ebus. */ return (sioprobe(dev, 0, 0UL, 1)); } static int sio_ebus_attach(dev) device_t dev; { return (sioattach(dev, 0, 0UL)); } Index: head/sys/dev/ti/if_ti.c =================================================================== --- head/sys/dev/ti/if_ti.c (revision 99012) +++ head/sys/dev/ti/if_ti.c (revision 99013) @@ -1,3628 +1,3628 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * Alteon Networks Tigon PCI gigabit ethernet driver for FreeBSD. * Manuals, sample driver and firmware source kits are available * from http://www.alteon.com/support/openkits. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ /* * The Alteon Networks Tigon chip contains an embedded R4000 CPU, * gigabit MAC, dual DMA channels and a PCI interface unit. NICs * using the Tigon may have anywhere from 512K to 2MB of SRAM. The * Tigon supports hardware IP, TCP and UCP checksumming, multicast * filtering and jumbo (9014 byte) frames. The hardware is largely * controlled by firmware, which must be loaded into the NIC during * initialization. * * The Tigon 2 contains 2 R4000 CPUs and requires a newer firmware * revision, which supports new features such as extended commands, * extended jumbo receive ring desciptors and a mini receive ring. * * Alteon Networks is to be commended for releasing such a vast amount * of development material for the Tigon NIC without requiring an NDA * (although they really should have done it a long time ago). With * any luck, the other vendors will finally wise up and follow Alteon's * stellar example. * * The firmware for the Tigon 1 and 2 NICs is compiled directly into * this driver by #including it as a C header file. This bloats the * driver somewhat, but it's the easiest method considering that the * driver code and firmware code need to be kept in sync. The source * for the firmware is not provided with the FreeBSD distribution since * compiling it requires a GNU toolchain targeted for mips-sgi-irix5.3. * * The following people deserve special thanks: * - Terry Murphy of 3Com, for providing a 3c985 Tigon 1 board * for testing * - Raymond Lee of Netgear, for providing a pair of Netgear * GA620 Tigon 2 boards for testing * - Ulf Zimmermann, for bringing the GA260 to my attention and * convincing me to write this driver. * - Andrew Gallatin for providing FreeBSD/Alpha support. */ #include "opt_ti.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for vtophys */ #include /* for vtophys */ #include #include #include #include #include /* #define TI_PRIVATE_JUMBOS */ #if !defined(TI_PRIVATE_JUMBOS) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* !TI_PRIVATE_JUMBOS */ #include /* for vfindev, vgone */ #include #include #include #include #include #include #define TI_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_IP_FRAGS) /* * We can only turn on header splitting if we're using extended receive * BDs. */ #if defined(TI_JUMBO_HDRSPLIT) && defined(TI_PRIVATE_JUMBOS) #error "options TI_JUMBO_HDRSPLIT and TI_PRIVATE_JUMBOS are mutually exclusive" #endif /* TI_JUMBO_HDRSPLIT && TI_JUMBO_HDRSPLIT */ #if !defined(lint) static const char rcsid[] = "$FreeBSD$"; #endif struct ti_softc *tis[8]; typedef enum { TI_SWAP_HTON, TI_SWAP_NTOH } ti_swap_type; /* * Various supported device vendors/types and their names. */ static struct ti_type ti_devs[] = { { ALT_VENDORID, ALT_DEVICEID_ACENIC, "Alteon AceNIC 1000baseSX Gigabit Ethernet" }, { ALT_VENDORID, ALT_DEVICEID_ACENIC_COPPER, "Alteon AceNIC 1000baseT Gigabit Ethernet" }, { TC_VENDORID, TC_DEVICEID_3C985, "3Com 3c985-SX Gigabit Ethernet" }, { NG_VENDORID, NG_DEVICEID_GA620, "Netgear GA620 1000baseSX Gigabit Ethernet" }, { NG_VENDORID, NG_DEVICEID_GA620T, "Netgear GA620 1000baseT Gigabit Ethernet" }, { SGI_VENDORID, SGI_DEVICEID_TIGON, "Silicon Graphics Gigabit Ethernet" }, { DEC_VENDORID, DEC_DEVICEID_FARALLON_PN9000SX, "Farallon PN9000SX Gigabit Ethernet" }, { 0, 0, NULL } }; #define TI_CDEV_MAJOR 153 static d_open_t ti_open; static d_close_t ti_close; static d_ioctl_t ti_ioctl2; static struct cdevsw ti_cdevsw = { /* open */ ti_open, /* close */ ti_close, /* read */ NULL, /* write */ NULL, /* ioctl */ ti_ioctl2, /* poll */ seltrue, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "ti", /* maj */ TI_CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, }; static int ti_probe (device_t); static int ti_attach (device_t); static int ti_detach (device_t); static void ti_txeof (struct ti_softc *); static void ti_rxeof (struct ti_softc *); static void ti_stats_update (struct ti_softc *); static int ti_encap (struct ti_softc *, struct mbuf *, u_int32_t *); static void ti_intr (void *); static void ti_start (struct ifnet *); static int ti_ioctl (struct ifnet *, u_long, caddr_t); static void ti_init (void *); static void ti_init2 (struct ti_softc *); static void ti_stop (struct ti_softc *); static void ti_watchdog (struct ifnet *); static void ti_shutdown (device_t); static int ti_ifmedia_upd (struct ifnet *); static void ti_ifmedia_sts (struct ifnet *, struct ifmediareq *); static u_int32_t ti_eeprom_putbyte (struct ti_softc *, int); static u_int8_t ti_eeprom_getbyte (struct ti_softc *, int, u_int8_t *); static int ti_read_eeprom (struct ti_softc *, caddr_t, int, int); static void ti_add_mcast (struct ti_softc *, struct ether_addr *); static void ti_del_mcast (struct ti_softc *, struct ether_addr *); static void ti_setmulti (struct ti_softc *); static void ti_mem (struct ti_softc *, u_int32_t, u_int32_t, caddr_t); static int ti_copy_mem (struct ti_softc *, u_int32_t, u_int32_t, caddr_t, int, int); static int ti_copy_scratch (struct ti_softc *, u_int32_t, u_int32_t, caddr_t, int, int, int); static int ti_bcopy_swap (const void *, void *, size_t, ti_swap_type); static void ti_loadfw (struct ti_softc *); static void ti_cmd (struct ti_softc *, struct ti_cmd_desc *); static void ti_cmd_ext (struct ti_softc *, struct ti_cmd_desc *, caddr_t, int); static void ti_handle_events (struct ti_softc *); #ifdef TI_PRIVATE_JUMBOS static int ti_alloc_jumbo_mem (struct ti_softc *); static void *ti_jalloc (struct ti_softc *); static void ti_jfree (caddr_t, void *); #endif /* TI_PRIVATE_JUMBOS */ static int ti_newbuf_std (struct ti_softc *, int, struct mbuf *); static int ti_newbuf_mini (struct ti_softc *, int, struct mbuf *); static int ti_newbuf_jumbo (struct ti_softc *, int, struct mbuf *); static int ti_init_rx_ring_std (struct ti_softc *); static void ti_free_rx_ring_std (struct ti_softc *); static int ti_init_rx_ring_jumbo (struct ti_softc *); static void ti_free_rx_ring_jumbo (struct ti_softc *); static int ti_init_rx_ring_mini (struct ti_softc *); static void ti_free_rx_ring_mini (struct ti_softc *); static void ti_free_tx_ring (struct ti_softc *); static int ti_init_tx_ring (struct ti_softc *); static int ti_64bitslot_war (struct ti_softc *); static int ti_chipinit (struct ti_softc *); static int ti_gibinit (struct ti_softc *); #ifdef TI_JUMBO_HDRSPLIT -static __inline void ti_hdr_split __P((struct mbuf *top, int hdr_len, - int pkt_len, int idx)); +static __inline void ti_hdr_split (struct mbuf *top, int hdr_len, + int pkt_len, int idx); #endif /* TI_JUMBO_HDRSPLIT */ static device_method_t ti_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ti_probe), DEVMETHOD(device_attach, ti_attach), DEVMETHOD(device_detach, ti_detach), DEVMETHOD(device_shutdown, ti_shutdown), { 0, 0 } }; static driver_t ti_driver = { "ti", ti_methods, sizeof(struct ti_softc) }; static devclass_t ti_devclass; DRIVER_MODULE(if_ti, pci, ti_driver, ti_devclass, 0, 0); /* List of Tigon softcs */ static STAILQ_HEAD(ti_softc_list, ti_softc) ti_sc_list; static struct ti_softc * ti_lookup_softc(int unit) { struct ti_softc *sc; for (sc = STAILQ_FIRST(&ti_sc_list); sc != NULL; sc = STAILQ_NEXT(sc, ti_links)) if (sc->ti_unit == unit) return(sc); return(NULL); } /* * Send an instruction or address to the EEPROM, check for ACK. */ static u_int32_t ti_eeprom_putbyte(sc, byte) struct ti_softc *sc; int byte; { register int i, ack = 0; /* * Make sure we're in TX mode. */ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* * Feed in each bit and stobe the clock. */ for (i = 0x80; i; i >>= 1) { if (byte & i) { TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); } else { TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); } DELAY(1); TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); DELAY(1); TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); } /* * Turn off TX mode. */ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* * Check for ack. */ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); ack = CSR_READ_4(sc, TI_MISC_LOCAL_CTL) & TI_MLC_EE_DIN; TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); return(ack); } /* * Read a byte of data stored in the EEPROM at address 'addr.' * We have to send two address bytes since the EEPROM can hold * more than 256 bytes of data. */ static u_int8_t ti_eeprom_getbyte(sc, addr, dest) struct ti_softc *sc; int addr; u_int8_t *dest; { register int i; u_int8_t byte = 0; EEPROM_START; /* * Send write control code to EEPROM. */ if (ti_eeprom_putbyte(sc, EEPROM_CTL_WRITE)) { printf("ti%d: failed to send write command, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } /* * Send first byte of address of byte we want to read. */ if (ti_eeprom_putbyte(sc, (addr >> 8) & 0xFF)) { printf("ti%d: failed to send address, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } /* * Send second byte address of byte we want to read. */ if (ti_eeprom_putbyte(sc, addr & 0xFF)) { printf("ti%d: failed to send address, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } EEPROM_STOP; EEPROM_START; /* * Send read control code to EEPROM. */ if (ti_eeprom_putbyte(sc, EEPROM_CTL_READ)) { printf("ti%d: failed to send read command, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } /* * Start reading bits from EEPROM. */ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); for (i = 0x80; i; i >>= 1) { TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); DELAY(1); if (CSR_READ_4(sc, TI_MISC_LOCAL_CTL) & TI_MLC_EE_DIN) byte |= i; TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); DELAY(1); } EEPROM_STOP; /* * No ACK generated for read, so just return byte. */ *dest = byte; return(0); } /* * Read a sequence of bytes from the EEPROM. */ static int ti_read_eeprom(sc, dest, off, cnt) struct ti_softc *sc; caddr_t dest; int off; int cnt; { int err = 0, i; u_int8_t byte = 0; for (i = 0; i < cnt; i++) { err = ti_eeprom_getbyte(sc, off + i, &byte); if (err) break; *(dest + i) = byte; } return(err ? 1 : 0); } /* * NIC memory access function. Can be used to either clear a section * of NIC local memory or (if buf is non-NULL) copy data into it. */ static void ti_mem(sc, addr, len, buf) struct ti_softc *sc; u_int32_t addr, len; caddr_t buf; { int segptr, segsize, cnt; caddr_t ti_winbase, ptr; segptr = addr; cnt = len; ti_winbase = (caddr_t)(sc->ti_vhandle + TI_WINDOW); ptr = buf; while(cnt) { if (cnt < TI_WINLEN) segsize = cnt; else segsize = TI_WINLEN - (segptr % TI_WINLEN); CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1))); if (buf == NULL) bzero((char *)ti_winbase + (segptr & (TI_WINLEN - 1)), segsize); else { bcopy((char *)ptr, (char *)ti_winbase + (segptr & (TI_WINLEN - 1)), segsize); ptr += segsize; } segptr += segsize; cnt -= segsize; } return; } static int ti_copy_mem(sc, tigon_addr, len, buf, useraddr, readdata) struct ti_softc *sc; u_int32_t tigon_addr, len; caddr_t buf; int useraddr, readdata; { int segptr, segsize, cnt; caddr_t ptr; u_int32_t origwin; u_int8_t tmparray[TI_WINLEN], tmparray2[TI_WINLEN]; int resid, segresid; int first_pass; /* * At the moment, we don't handle non-aligned cases, we just bail. * If this proves to be a problem, it will be fixed. */ if ((readdata == 0) && (tigon_addr & 0x3)) { printf("ti%d: ti_copy_mem: tigon address %#x isn't " "word-aligned\n", sc->ti_unit, tigon_addr); printf("ti%d: ti_copy_mem: unaligned writes aren't yet " "supported\n", sc->ti_unit); return(EINVAL); } segptr = tigon_addr & ~0x3; segresid = tigon_addr - segptr; /* * This is the non-aligned amount left over that we'll need to * copy. */ resid = len & 0x3; /* Add in the left over amount at the front of the buffer */ resid += segresid; cnt = len & ~0x3; /* * If resid + segresid is >= 4, add multiples of 4 to the count and * decrease the residual by that much. */ cnt += resid & ~0x3; resid -= resid & ~0x3; ptr = buf; first_pass = 1; /* * Make sure we aren't interrupted while we're changing the window * pointer. */ TI_LOCK(sc); /* * Save the old window base value. */ origwin = CSR_READ_4(sc, TI_WINBASE); while(cnt) { bus_size_t ti_offset; if (cnt < TI_WINLEN) segsize = cnt; else segsize = TI_WINLEN - (segptr % TI_WINLEN); CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1))); ti_offset = TI_WINDOW + (segptr & (TI_WINLEN -1)); if (readdata) { bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, (u_int32_t *)tmparray, segsize >> 2); if (useraddr) { /* * Yeah, this is a little on the kludgy * side, but at least this code is only * used for debugging. */ ti_bcopy_swap(tmparray, tmparray2, segsize, TI_SWAP_NTOH); if (first_pass) { copyout(&tmparray2[segresid], ptr, segsize - segresid); first_pass = 0; } else copyout(tmparray2, ptr, segsize); } else { if (first_pass) { ti_bcopy_swap(tmparray, tmparray2, segsize, TI_SWAP_NTOH); bcopy(&tmparray2[segresid], ptr, segsize - segresid); first_pass = 0; } else ti_bcopy_swap(tmparray, ptr, segsize, TI_SWAP_NTOH); } } else { if (useraddr) { copyin(ptr, tmparray2, segsize); ti_bcopy_swap(tmparray2, tmparray, segsize, TI_SWAP_HTON); } else ti_bcopy_swap(ptr, tmparray, segsize, TI_SWAP_HTON); bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, (u_int32_t *)tmparray, segsize >> 2); } segptr += segsize; ptr += segsize; cnt -= segsize; } /* * Handle leftover, non-word-aligned bytes. */ if (resid != 0) { u_int32_t tmpval, tmpval2; bus_size_t ti_offset; /* * Set the segment pointer. */ CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1))); ti_offset = TI_WINDOW + (segptr & (TI_WINLEN - 1)); /* * First, grab whatever is in our source/destination. * We'll obviously need this for reads, but also for * writes, since we'll be doing read/modify/write. */ bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, &tmpval, 1); /* * Next, translate this from little-endian to big-endian * (at least on i386 boxes). */ tmpval2 = ntohl(tmpval); if (readdata) { /* * If we're reading, just copy the leftover number * of bytes from the host byte order buffer to * the user's buffer. */ if (useraddr) copyout(&tmpval2, ptr, resid); else bcopy(&tmpval2, ptr, resid); } else { /* * If we're writing, first copy the bytes to be * written into the network byte order buffer, * leaving the rest of the buffer with whatever was * originally in there. Then, swap the bytes * around into host order and write them out. * * XXX KDM the read side of this has been verified * to work, but the write side of it has not been * verified. So user beware. */ if (useraddr) copyin(ptr, &tmpval2, resid); else bcopy(ptr, &tmpval2, resid); tmpval = htonl(tmpval2); bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, &tmpval, 1); } } CSR_WRITE_4(sc, TI_WINBASE, origwin); TI_UNLOCK(sc); return(0); } static int ti_copy_scratch(sc, tigon_addr, len, buf, useraddr, readdata, cpu) struct ti_softc *sc; u_int32_t tigon_addr, len; caddr_t buf; int useraddr, readdata; int cpu; { u_int32_t segptr; int cnt; u_int32_t tmpval, tmpval2; caddr_t ptr; /* * At the moment, we don't handle non-aligned cases, we just bail. * If this proves to be a problem, it will be fixed. */ if (tigon_addr & 0x3) { printf("ti%d: ti_copy_scratch: tigon address %#x isn't " "word-aligned\n", sc->ti_unit, tigon_addr); return(EINVAL); } if (len & 0x3) { printf("ti%d: ti_copy_scratch: transfer length %d isn't " "word-aligned\n", sc->ti_unit, len); return(EINVAL); } segptr = tigon_addr; cnt = len; ptr = buf; TI_LOCK(sc); while (cnt) { CSR_WRITE_4(sc, CPU_REG(TI_SRAM_ADDR, cpu), segptr); if (readdata) { tmpval2 = CSR_READ_4(sc, CPU_REG(TI_SRAM_DATA, cpu)); tmpval = ntohl(tmpval2); /* * Note: I've used this debugging interface * extensively with Alteon's 12.3.15 firmware, * compiled with GCC 2.7.2.1 and binutils 2.9.1. * * When you compile the firmware without * optimization, which is necessary sometimes in * order to properly step through it, you sometimes * read out a bogus value of 0xc0017c instead of * whatever was supposed to be in that scratchpad * location. That value is on the stack somewhere, * but I've never been able to figure out what was * causing the problem. * * The address seems to pop up in random places, * often not in the same place on two subsequent * reads. * * In any case, the underlying data doesn't seem * to be affected, just the value read out. * * KDM, 3/7/2000 */ if (tmpval2 == 0xc0017c) printf("ti%d: found 0xc0017c at %#x " "(tmpval2)\n", sc->ti_unit, segptr); if (tmpval == 0xc0017c) printf("ti%d: found 0xc0017c at %#x " "(tmpval)\n", sc->ti_unit, segptr); if (useraddr) copyout(&tmpval, ptr, 4); else bcopy(&tmpval, ptr, 4); } else { if (useraddr) copyin(ptr, &tmpval2, 4); else bcopy(ptr, &tmpval2, 4); tmpval = htonl(tmpval2); CSR_WRITE_4(sc, CPU_REG(TI_SRAM_DATA, cpu), tmpval); } cnt -= 4; segptr += 4; ptr += 4; } TI_UNLOCK(sc); return(0); } static int ti_bcopy_swap(src, dst, len, swap_type) const void *src; void *dst; size_t len; ti_swap_type swap_type; { const u_int8_t *tmpsrc; u_int8_t *tmpdst; size_t tmplen; if (len & 0x3) { printf("ti_bcopy_swap: length %d isn't 32-bit aligned\n", len); return(-1); } tmpsrc = src; tmpdst = dst; tmplen = len; while (tmplen) { if (swap_type == TI_SWAP_NTOH) *(u_int32_t *)tmpdst = ntohl(*(const u_int32_t *)tmpsrc); else *(u_int32_t *)tmpdst = htonl(*(const u_int32_t *)tmpsrc); tmpsrc += 4; tmpdst += 4; tmplen -= 4; } return(0); } /* * Load firmware image into the NIC. Check that the firmware revision * is acceptable and see if we want the firmware for the Tigon 1 or * Tigon 2. */ static void ti_loadfw(sc) struct ti_softc *sc; { switch(sc->ti_hwrev) { case TI_HWREV_TIGON: if (tigonFwReleaseMajor != TI_FIRMWARE_MAJOR || tigonFwReleaseMinor != TI_FIRMWARE_MINOR || tigonFwReleaseFix != TI_FIRMWARE_FIX) { printf("ti%d: firmware revision mismatch; want " "%d.%d.%d, got %d.%d.%d\n", sc->ti_unit, TI_FIRMWARE_MAJOR, TI_FIRMWARE_MINOR, TI_FIRMWARE_FIX, tigonFwReleaseMajor, tigonFwReleaseMinor, tigonFwReleaseFix); return; } ti_mem(sc, tigonFwTextAddr, tigonFwTextLen, (caddr_t)tigonFwText); ti_mem(sc, tigonFwDataAddr, tigonFwDataLen, (caddr_t)tigonFwData); ti_mem(sc, tigonFwRodataAddr, tigonFwRodataLen, (caddr_t)tigonFwRodata); ti_mem(sc, tigonFwBssAddr, tigonFwBssLen, NULL); ti_mem(sc, tigonFwSbssAddr, tigonFwSbssLen, NULL); CSR_WRITE_4(sc, TI_CPU_PROGRAM_COUNTER, tigonFwStartAddr); break; case TI_HWREV_TIGON_II: if (tigon2FwReleaseMajor != TI_FIRMWARE_MAJOR || tigon2FwReleaseMinor != TI_FIRMWARE_MINOR || tigon2FwReleaseFix != TI_FIRMWARE_FIX) { printf("ti%d: firmware revision mismatch; want " "%d.%d.%d, got %d.%d.%d\n", sc->ti_unit, TI_FIRMWARE_MAJOR, TI_FIRMWARE_MINOR, TI_FIRMWARE_FIX, tigon2FwReleaseMajor, tigon2FwReleaseMinor, tigon2FwReleaseFix); return; } ti_mem(sc, tigon2FwTextAddr, tigon2FwTextLen, (caddr_t)tigon2FwText); ti_mem(sc, tigon2FwDataAddr, tigon2FwDataLen, (caddr_t)tigon2FwData); ti_mem(sc, tigon2FwRodataAddr, tigon2FwRodataLen, (caddr_t)tigon2FwRodata); ti_mem(sc, tigon2FwBssAddr, tigon2FwBssLen, NULL); ti_mem(sc, tigon2FwSbssAddr, tigon2FwSbssLen, NULL); CSR_WRITE_4(sc, TI_CPU_PROGRAM_COUNTER, tigon2FwStartAddr); break; default: printf("ti%d: can't load firmware: unknown hardware rev\n", sc->ti_unit); break; } return; } /* * Send the NIC a command via the command ring. */ static void ti_cmd(sc, cmd) struct ti_softc *sc; struct ti_cmd_desc *cmd; { u_int32_t index; if (sc->ti_rdata->ti_cmd_ring == NULL) return; index = sc->ti_cmd_saved_prodidx; CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(cmd)); TI_INC(index, TI_CMD_RING_CNT); CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, index); sc->ti_cmd_saved_prodidx = index; return; } /* * Send the NIC an extended command. The 'len' parameter specifies the * number of command slots to include after the initial command. */ static void ti_cmd_ext(sc, cmd, arg, len) struct ti_softc *sc; struct ti_cmd_desc *cmd; caddr_t arg; int len; { u_int32_t index; register int i; if (sc->ti_rdata->ti_cmd_ring == NULL) return; index = sc->ti_cmd_saved_prodidx; CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(cmd)); TI_INC(index, TI_CMD_RING_CNT); for (i = 0; i < len; i++) { CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(&arg[i * 4])); TI_INC(index, TI_CMD_RING_CNT); } CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, index); sc->ti_cmd_saved_prodidx = index; return; } /* * Handle events that have triggered interrupts. */ static void ti_handle_events(sc) struct ti_softc *sc; { struct ti_event_desc *e; if (sc->ti_rdata->ti_event_ring == NULL) return; while (sc->ti_ev_saved_considx != sc->ti_ev_prodidx.ti_idx) { e = &sc->ti_rdata->ti_event_ring[sc->ti_ev_saved_considx]; switch(e->ti_event) { case TI_EV_LINKSTAT_CHANGED: sc->ti_linkstat = e->ti_code; if (e->ti_code == TI_EV_CODE_LINK_UP) printf("ti%d: 10/100 link up\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_GIG_LINK_UP) printf("ti%d: gigabit link up\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_LINK_DOWN) printf("ti%d: link down\n", sc->ti_unit); break; case TI_EV_ERROR: if (e->ti_code == TI_EV_CODE_ERR_INVAL_CMD) printf("ti%d: invalid command\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_ERR_UNIMP_CMD) printf("ti%d: unknown command\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_ERR_BADCFG) printf("ti%d: bad config data\n", sc->ti_unit); break; case TI_EV_FIRMWARE_UP: ti_init2(sc); break; case TI_EV_STATS_UPDATED: ti_stats_update(sc); break; case TI_EV_RESET_JUMBO_RING: case TI_EV_MCAST_UPDATED: /* Who cares. */ break; default: printf("ti%d: unknown event: %d\n", sc->ti_unit, e->ti_event); break; } /* Advance the consumer index. */ TI_INC(sc->ti_ev_saved_considx, TI_EVENT_RING_CNT); CSR_WRITE_4(sc, TI_GCR_EVENTCONS_IDX, sc->ti_ev_saved_considx); } return; } #ifdef TI_PRIVATE_JUMBOS /* * Memory management for the jumbo receive ring is a pain in the * butt. We need to allocate at least 9018 bytes of space per frame, * _and_ it has to be contiguous (unless you use the extended * jumbo descriptor format). Using malloc() all the time won't * work: malloc() allocates memory in powers of two, which means we * would end up wasting a considerable amount of space by allocating * 9K chunks. We don't have a jumbo mbuf cluster pool. Thus, we have * to do our own memory management. * * The driver needs to allocate a contiguous chunk of memory at boot * time. We then chop this up ourselves into 9K pieces and use them * as external mbuf storage. * * One issue here is how much memory to allocate. The jumbo ring has * 256 slots in it, but at 9K per slot than can consume over 2MB of * RAM. This is a bit much, especially considering we also need * RAM for the standard ring and mini ring (on the Tigon 2). To * save space, we only actually allocate enough memory for 64 slots * by default, which works out to between 500 and 600K. This can * be tuned by changing a #define in if_tireg.h. */ static int ti_alloc_jumbo_mem(sc) struct ti_softc *sc; { caddr_t ptr; register int i; struct ti_jpool_entry *entry; /* Grab a big chunk o' storage. */ sc->ti_cdata.ti_jumbo_buf = contigmalloc(TI_JMEM, M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); if (sc->ti_cdata.ti_jumbo_buf == NULL) { printf("ti%d: no memory for jumbo buffers!\n", sc->ti_unit); return(ENOBUFS); } SLIST_INIT(&sc->ti_jfree_listhead); SLIST_INIT(&sc->ti_jinuse_listhead); /* * Now divide it up into 9K pieces and save the addresses * in an array. */ ptr = sc->ti_cdata.ti_jumbo_buf; for (i = 0; i < TI_JSLOTS; i++) { sc->ti_cdata.ti_jslots[i] = ptr; ptr += TI_JLEN; entry = malloc(sizeof(struct ti_jpool_entry), M_DEVBUF, M_NOWAIT); if (entry == NULL) { contigfree(sc->ti_cdata.ti_jumbo_buf, TI_JMEM, M_DEVBUF); sc->ti_cdata.ti_jumbo_buf = NULL; printf("ti%d: no memory for jumbo " "buffer queue!\n", sc->ti_unit); return(ENOBUFS); } entry->slot = i; SLIST_INSERT_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries); } return(0); } /* * Allocate a jumbo buffer. */ static void *ti_jalloc(sc) struct ti_softc *sc; { struct ti_jpool_entry *entry; entry = SLIST_FIRST(&sc->ti_jfree_listhead); if (entry == NULL) { printf("ti%d: no free jumbo buffers\n", sc->ti_unit); return(NULL); } SLIST_REMOVE_HEAD(&sc->ti_jfree_listhead, jpool_entries); SLIST_INSERT_HEAD(&sc->ti_jinuse_listhead, entry, jpool_entries); return(sc->ti_cdata.ti_jslots[entry->slot]); } /* * Release a jumbo buffer. */ static void ti_jfree(buf, args) caddr_t buf; void *args; { struct ti_softc *sc; int i; struct ti_jpool_entry *entry; /* Extract the softc struct pointer. */ sc = (struct ti_softc *)args; if (sc == NULL) panic("ti_jfree: didn't get softc pointer!"); /* calculate the slot this buffer belongs to */ i = ((vm_offset_t)buf - (vm_offset_t)sc->ti_cdata.ti_jumbo_buf) / TI_JLEN; if ((i < 0) || (i >= TI_JSLOTS)) panic("ti_jfree: asked to free buffer that we don't manage!"); entry = SLIST_FIRST(&sc->ti_jinuse_listhead); if (entry == NULL) panic("ti_jfree: buffer not in use!"); entry->slot = i; SLIST_REMOVE_HEAD(&sc->ti_jinuse_listhead, jpool_entries); SLIST_INSERT_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries); return; } #endif /* TI_PRIVATE_JUMBOS */ /* * Intialize a standard receive ring descriptor. */ static int ti_newbuf_std(sc, i, m) struct ti_softc *sc; int i; struct mbuf *m; { struct mbuf *m_new = NULL; struct ti_rx_desc *r; if (m == NULL) { MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) return(ENOBUFS); MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { m_freem(m_new); return(ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; } else { m_new = m; m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; m_new->m_data = m_new->m_ext.ext_buf; } m_adj(m_new, ETHER_ALIGN); sc->ti_cdata.ti_rx_std_chain[i] = m_new; r = &sc->ti_rdata->ti_rx_std_ring[i]; TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t)); r->ti_type = TI_BDTYPE_RECV_BD; r->ti_flags = 0; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM; r->ti_len = m_new->m_len; r->ti_idx = i; return(0); } /* * Intialize a mini receive ring descriptor. This only applies to * the Tigon 2. */ static int ti_newbuf_mini(sc, i, m) struct ti_softc *sc; int i; struct mbuf *m; { struct mbuf *m_new = NULL; struct ti_rx_desc *r; if (m == NULL) { MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { return(ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MHLEN; } else { m_new = m; m_new->m_data = m_new->m_pktdat; m_new->m_len = m_new->m_pkthdr.len = MHLEN; } m_adj(m_new, ETHER_ALIGN); r = &sc->ti_rdata->ti_rx_mini_ring[i]; sc->ti_cdata.ti_rx_mini_chain[i] = m_new; TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t)); r->ti_type = TI_BDTYPE_RECV_BD; r->ti_flags = TI_BDFLAG_MINI_RING; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM; r->ti_len = m_new->m_len; r->ti_idx = i; return(0); } #ifdef TI_PRIVATE_JUMBOS /* * Initialize a jumbo receive ring descriptor. This allocates * a jumbo buffer from the pool managed internally by the driver. */ static int ti_newbuf_jumbo(sc, i, m) struct ti_softc *sc; int i; struct mbuf *m; { struct mbuf *m_new = NULL; struct ti_rx_desc *r; if (m == NULL) { caddr_t *buf = NULL; /* Allocate the mbuf. */ MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { return(ENOBUFS); } /* Allocate the jumbo buffer */ buf = ti_jalloc(sc); if (buf == NULL) { m_freem(m_new); printf("ti%d: jumbo allocation failed " "-- packet dropped!\n", sc->ti_unit); return(ENOBUFS); } /* Attach the buffer to the mbuf. */ m_new->m_data = (void *) buf; m_new->m_len = m_new->m_pkthdr.len = TI_JUMBO_FRAMELEN; MEXTADD(m_new, buf, TI_JUMBO_FRAMELEN, ti_jfree, (struct ti_softc *)sc, 0, EXT_NET_DRV); } else { m_new = m; m_new->m_data = m_new->m_ext.ext_buf; m_new->m_ext.ext_size = TI_JUMBO_FRAMELEN; } m_adj(m_new, ETHER_ALIGN); /* Set up the descriptor. */ r = &sc->ti_rdata->ti_rx_jumbo_ring[i]; sc->ti_cdata.ti_rx_jumbo_chain[i] = m_new; TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t)); r->ti_type = TI_BDTYPE_RECV_JUMBO_BD; r->ti_flags = TI_BDFLAG_JUMBO_RING; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM; r->ti_len = m_new->m_len; r->ti_idx = i; return(0); } #else #include #if (PAGE_SIZE == 4096) #define NPAYLOAD 2 #else #define NPAYLOAD 1 #endif #define TCP_HDR_LEN (52 + sizeof(struct ether_header)) #define UDP_HDR_LEN (28 + sizeof(struct ether_header)) #define NFS_HDR_LEN (UDP_HDR_LEN) int HDR_LEN = TCP_HDR_LEN; /* * Initialize a jumbo receive ring descriptor. This allocates * a jumbo buffer from the pool managed internally by the driver. */ static int ti_newbuf_jumbo(sc, idx, m_old) struct ti_softc *sc; int idx; struct mbuf *m_old; { struct mbuf *cur, *m_new = NULL; struct mbuf *m[3] = {NULL, NULL, NULL}; struct ti_rx_desc_ext *r; vm_page_t frame; /* 1 extra buf to make nobufs easy*/ caddr_t buf[3] = {NULL, NULL, NULL}; int i; if (m_old != NULL) { m_new = m_old; cur = m_old->m_next; for (i = 0; i <= NPAYLOAD; i++){ m[i] = cur; cur = cur->m_next; } } else { /* Allocate the mbufs. */ MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("ti%d: mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } MGET(m[NPAYLOAD], M_DONTWAIT, MT_DATA); if (m[NPAYLOAD] == NULL) { printf("ti%d: cluster mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } MCLGET(m[NPAYLOAD], M_DONTWAIT); if ((m[NPAYLOAD]->m_flags & M_EXT) == 0) { printf("ti%d: mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } m[NPAYLOAD]->m_len = MCLBYTES; for (i = 0; i < NPAYLOAD; i++){ MGET(m[i], M_DONTWAIT, MT_DATA); if (m[i] == NULL) { printf("ti%d: mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } if (!(frame = jumbo_pg_alloc())){ printf("ti%d: buffer allocation failed " "-- packet dropped!\n", sc->ti_unit); printf(" index %d page %d\n", idx, i); goto nobufs; } buf[i] = jumbo_phys_to_kva(VM_PAGE_TO_PHYS(frame)); } for (i = 0; i < NPAYLOAD; i++){ /* Attach the buffer to the mbuf. */ m[i]->m_data = (void *)buf[i]; m[i]->m_len = PAGE_SIZE; MEXTADD(m[i], (void *)buf[i], PAGE_SIZE, jumbo_freem, NULL, 0, EXT_DISPOSABLE); m[i]->m_next = m[i+1]; } /* link the buffers to the header */ m_new->m_next = m[0]; m_new->m_data += ETHER_ALIGN; if (sc->ti_hdrsplit) m_new->m_len = MHLEN - ETHER_ALIGN; else m_new->m_len = HDR_LEN; m_new->m_pkthdr.len = NPAYLOAD * PAGE_SIZE + m_new->m_len; } /* Set up the descriptor. */ r = &sc->ti_rdata->ti_rx_jumbo_ring[idx]; sc->ti_cdata.ti_rx_jumbo_chain[idx] = m_new; TI_HOSTADDR(r->ti_addr0) = vtophys(mtod(m_new, caddr_t)); r->ti_len0 = m_new->m_len; TI_HOSTADDR(r->ti_addr1) = vtophys(mtod(m[0], caddr_t)); r->ti_len1 = PAGE_SIZE; TI_HOSTADDR(r->ti_addr2) = vtophys(mtod(m[1], caddr_t)); r->ti_len2 = m[1]->m_ext.ext_size; /* could be PAGE_SIZE or MCLBYTES */ if (PAGE_SIZE == 4096) { TI_HOSTADDR(r->ti_addr3) = vtophys(mtod(m[2], caddr_t)); r->ti_len3 = MCLBYTES; } else { r->ti_len3 = 0; } r->ti_type = TI_BDTYPE_RECV_JUMBO_BD; r->ti_flags = TI_BDFLAG_JUMBO_RING|TI_RCB_FLAG_USE_EXT_RX_BD; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM|TI_BDFLAG_IP_CKSUM; r->ti_idx = idx; return(0); nobufs: /* * Warning! : * This can only be called before the mbufs are strung together. * If the mbufs are strung together, m_freem() will free the chain, * so that the later mbufs will be freed multiple times. */ if (m_new) m_freem(m_new); for(i = 0; i < 3; i++){ if (m[i]) m_freem(m[i]); if (buf[i]) jumbo_pg_free((vm_offset_t)buf[i]); } return ENOBUFS; } #endif /* * The standard receive ring has 512 entries in it. At 2K per mbuf cluster, * that's 1MB or memory, which is a lot. For now, we fill only the first * 256 ring entries and hope that our CPU is fast enough to keep up with * the NIC. */ static int ti_init_rx_ring_std(sc) struct ti_softc *sc; { register int i; struct ti_cmd_desc cmd; for (i = 0; i < TI_SSLOTS; i++) { if (ti_newbuf_std(sc, i, NULL) == ENOBUFS) return(ENOBUFS); }; TI_UPDATE_STDPROD(sc, i - 1); sc->ti_std = i - 1; return(0); } static void ti_free_rx_ring_std(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_STD_RX_RING_CNT; i++) { if (sc->ti_cdata.ti_rx_std_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_rx_std_chain[i]); sc->ti_cdata.ti_rx_std_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_rx_std_ring[i], sizeof(struct ti_rx_desc)); } return; } static int ti_init_rx_ring_jumbo(sc) struct ti_softc *sc; { register int i; struct ti_cmd_desc cmd; for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) { if (ti_newbuf_jumbo(sc, i, NULL) == ENOBUFS) return(ENOBUFS); }; TI_UPDATE_JUMBOPROD(sc, i - 1); sc->ti_jumbo = i - 1; return(0); } static void ti_free_rx_ring_jumbo(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) { if (sc->ti_cdata.ti_rx_jumbo_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_rx_jumbo_chain[i]); sc->ti_cdata.ti_rx_jumbo_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_rx_jumbo_ring[i], sizeof(struct ti_rx_desc)); } return; } static int ti_init_rx_ring_mini(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_MSLOTS; i++) { if (ti_newbuf_mini(sc, i, NULL) == ENOBUFS) return(ENOBUFS); }; TI_UPDATE_MINIPROD(sc, i - 1); sc->ti_mini = i - 1; return(0); } static void ti_free_rx_ring_mini(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_MINI_RX_RING_CNT; i++) { if (sc->ti_cdata.ti_rx_mini_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_rx_mini_chain[i]); sc->ti_cdata.ti_rx_mini_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_rx_mini_ring[i], sizeof(struct ti_rx_desc)); } return; } static void ti_free_tx_ring(sc) struct ti_softc *sc; { register int i; if (sc->ti_rdata->ti_tx_ring == NULL) return; for (i = 0; i < TI_TX_RING_CNT; i++) { if (sc->ti_cdata.ti_tx_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_tx_chain[i]); sc->ti_cdata.ti_tx_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_tx_ring[i], sizeof(struct ti_tx_desc)); } return; } static int ti_init_tx_ring(sc) struct ti_softc *sc; { sc->ti_txcnt = 0; sc->ti_tx_saved_considx = 0; CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, 0); return(0); } /* * The Tigon 2 firmware has a new way to add/delete multicast addresses, * but we have to support the old way too so that Tigon 1 cards will * work. */ void ti_add_mcast(sc, addr) struct ti_softc *sc; struct ether_addr *addr; { struct ti_cmd_desc cmd; u_int16_t *m; u_int32_t ext[2] = {0, 0}; m = (u_int16_t *)&addr->octet[0]; switch(sc->ti_hwrev) { case TI_HWREV_TIGON: CSR_WRITE_4(sc, TI_GCR_MAR0, htons(m[0])); CSR_WRITE_4(sc, TI_GCR_MAR1, (htons(m[1]) << 16) | htons(m[2])); TI_DO_CMD(TI_CMD_ADD_MCAST_ADDR, 0, 0); break; case TI_HWREV_TIGON_II: ext[0] = htons(m[0]); ext[1] = (htons(m[1]) << 16) | htons(m[2]); TI_DO_CMD_EXT(TI_CMD_EXT_ADD_MCAST, 0, 0, (caddr_t)&ext, 2); break; default: printf("ti%d: unknown hwrev\n", sc->ti_unit); break; } return; } void ti_del_mcast(sc, addr) struct ti_softc *sc; struct ether_addr *addr; { struct ti_cmd_desc cmd; u_int16_t *m; u_int32_t ext[2] = {0, 0}; m = (u_int16_t *)&addr->octet[0]; switch(sc->ti_hwrev) { case TI_HWREV_TIGON: CSR_WRITE_4(sc, TI_GCR_MAR0, htons(m[0])); CSR_WRITE_4(sc, TI_GCR_MAR1, (htons(m[1]) << 16) | htons(m[2])); TI_DO_CMD(TI_CMD_DEL_MCAST_ADDR, 0, 0); break; case TI_HWREV_TIGON_II: ext[0] = htons(m[0]); ext[1] = (htons(m[1]) << 16) | htons(m[2]); TI_DO_CMD_EXT(TI_CMD_EXT_DEL_MCAST, 0, 0, (caddr_t)&ext, 2); break; default: printf("ti%d: unknown hwrev\n", sc->ti_unit); break; } return; } /* * Configure the Tigon's multicast address filter. * * The actual multicast table management is a bit of a pain, thanks to * slight brain damage on the part of both Alteon and us. With our * multicast code, we are only alerted when the multicast address table * changes and at that point we only have the current list of addresses: * we only know the current state, not the previous state, so we don't * actually know what addresses were removed or added. The firmware has * state, but we can't get our grubby mits on it, and there is no 'delete * all multicast addresses' command. Hence, we have to maintain our own * state so we know what addresses have been programmed into the NIC at * any given time. */ static void ti_setmulti(sc) struct ti_softc *sc; { struct ifnet *ifp; struct ifmultiaddr *ifma; struct ti_cmd_desc cmd; struct ti_mc_entry *mc; u_int32_t intrs; ifp = &sc->arpcom.ac_if; if (ifp->if_flags & IFF_ALLMULTI) { TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_ENB, 0); return; } else { TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_DIS, 0); } /* Disable interrupts. */ intrs = CSR_READ_4(sc, TI_MB_HOSTINTR); CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* First, zot all the existing filters. */ while (SLIST_FIRST(&sc->ti_mc_listhead) != NULL) { mc = SLIST_FIRST(&sc->ti_mc_listhead); ti_del_mcast(sc, &mc->mc_addr); SLIST_REMOVE_HEAD(&sc->ti_mc_listhead, mc_entries); free(mc, M_DEVBUF); } /* Now program new ones. */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; mc = malloc(sizeof(struct ti_mc_entry), M_DEVBUF, M_NOWAIT); bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), (char *)&mc->mc_addr, ETHER_ADDR_LEN); SLIST_INSERT_HEAD(&sc->ti_mc_listhead, mc, mc_entries); ti_add_mcast(sc, &mc->mc_addr); } /* Re-enable interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs); return; } /* * Check to see if the BIOS has configured us for a 64 bit slot when * we aren't actually in one. If we detect this condition, we can work * around it on the Tigon 2 by setting a bit in the PCI state register, * but for the Tigon 1 we must give up and abort the interface attach. */ static int ti_64bitslot_war(sc) struct ti_softc *sc; { if (!(CSR_READ_4(sc, TI_PCI_STATE) & TI_PCISTATE_32BIT_BUS)) { CSR_WRITE_4(sc, 0x600, 0); CSR_WRITE_4(sc, 0x604, 0); CSR_WRITE_4(sc, 0x600, 0x5555AAAA); if (CSR_READ_4(sc, 0x604) == 0x5555AAAA) { if (sc->ti_hwrev == TI_HWREV_TIGON) return(EINVAL); else { TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_32BIT_BUS); return(0); } } } return(0); } /* * Do endian, PCI and DMA initialization. Also check the on-board ROM * self-test results. */ static int ti_chipinit(sc) struct ti_softc *sc; { u_int32_t cacheline; u_int32_t pci_writemax = 0; u_int32_t hdrsplit; /* Initialize link to down state. */ sc->ti_linkstat = TI_EV_CODE_LINK_DOWN; if (sc->arpcom.ac_if.if_capenable & IFCAP_HWCSUM) sc->arpcom.ac_if.if_hwassist = TI_CSUM_FEATURES; else sc->arpcom.ac_if.if_hwassist = 0; /* Set endianness before we access any non-PCI registers. */ #if BYTE_ORDER == BIG_ENDIAN CSR_WRITE_4(sc, TI_MISC_HOST_CTL, TI_MHC_BIGENDIAN_INIT | (TI_MHC_BIGENDIAN_INIT << 24)); #else CSR_WRITE_4(sc, TI_MISC_HOST_CTL, TI_MHC_LITTLEENDIAN_INIT | (TI_MHC_LITTLEENDIAN_INIT << 24)); #endif /* Check the ROM failed bit to see if self-tests passed. */ if (CSR_READ_4(sc, TI_CPU_STATE) & TI_CPUSTATE_ROMFAIL) { printf("ti%d: board self-diagnostics failed!\n", sc->ti_unit); return(ENODEV); } /* Halt the CPU. */ TI_SETBIT(sc, TI_CPU_STATE, TI_CPUSTATE_HALT); /* Figure out the hardware revision. */ switch(CSR_READ_4(sc, TI_MISC_HOST_CTL) & TI_MHC_CHIP_REV_MASK) { case TI_REV_TIGON_I: sc->ti_hwrev = TI_HWREV_TIGON; break; case TI_REV_TIGON_II: sc->ti_hwrev = TI_HWREV_TIGON_II; break; default: printf("ti%d: unsupported chip revision\n", sc->ti_unit); return(ENODEV); } /* Do special setup for Tigon 2. */ if (sc->ti_hwrev == TI_HWREV_TIGON_II) { TI_SETBIT(sc, TI_CPU_CTL_B, TI_CPUSTATE_HALT); TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_SRAM_BANK_512K); TI_SETBIT(sc, TI_MISC_CONF, TI_MCR_SRAM_SYNCHRONOUS); } /* * We don't have firmware source for the Tigon 1, so Tigon 1 boards * can't do header splitting. */ #ifdef TI_JUMBO_HDRSPLIT if (sc->ti_hwrev != TI_HWREV_TIGON) sc->ti_hdrsplit = 1; else printf("ti%d: can't do header splitting on a Tigon I board\n", sc->ti_unit); #endif /* TI_JUMBO_HDRSPLIT */ /* Set up the PCI state register. */ CSR_WRITE_4(sc, TI_PCI_STATE, TI_PCI_READ_CMD|TI_PCI_WRITE_CMD); if (sc->ti_hwrev == TI_HWREV_TIGON_II) { TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_USE_MEM_RD_MULT); } /* Clear the read/write max DMA parameters. */ TI_CLRBIT(sc, TI_PCI_STATE, (TI_PCISTATE_WRITE_MAXDMA| TI_PCISTATE_READ_MAXDMA)); /* Get cache line size. */ cacheline = CSR_READ_4(sc, TI_PCI_BIST) & 0xFF; /* * If the system has set enabled the PCI memory write * and invalidate command in the command register, set * the write max parameter accordingly. This is necessary * to use MWI with the Tigon 2. */ if (CSR_READ_4(sc, TI_PCI_CMDSTAT) & PCIM_CMD_MWIEN) { switch(cacheline) { case 1: case 4: case 8: case 16: case 32: case 64: break; default: /* Disable PCI memory write and invalidate. */ if (bootverbose) printf("ti%d: cache line size %d not " "supported; disabling PCI MWI\n", sc->ti_unit, cacheline); CSR_WRITE_4(sc, TI_PCI_CMDSTAT, CSR_READ_4(sc, TI_PCI_CMDSTAT) & ~PCIM_CMD_MWIEN); break; } } #ifdef __brokenalpha__ /* * From the Alteon sample driver: * Must insure that we do not cross an 8K (bytes) boundary * for DMA reads. Our highest limit is 1K bytes. This is a * restriction on some ALPHA platforms with early revision * 21174 PCI chipsets, such as the AlphaPC 164lx */ TI_SETBIT(sc, TI_PCI_STATE, pci_writemax|TI_PCI_READMAX_1024); #else TI_SETBIT(sc, TI_PCI_STATE, pci_writemax); #endif /* This sets the min dma param all the way up (0xff). */ TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_MINDMA); if (sc->ti_hdrsplit) hdrsplit = TI_OPMODE_JUMBO_HDRSPLIT; else hdrsplit = 0; /* Configure DMA variables. */ #if BYTE_ORDER == BIG_ENDIAN CSR_WRITE_4(sc, TI_GCR_OPMODE, TI_OPMODE_BYTESWAP_BD | TI_OPMODE_BYTESWAP_DATA | TI_OPMODE_WORDSWAP_BD | TI_OPMODE_WARN_ENB | TI_OPMODE_FATAL_ENB | TI_OPMODE_DONT_FRAG_JUMBO | hdrsplit); #else /* BYTE_ORDER */ CSR_WRITE_4(sc, TI_GCR_OPMODE, TI_OPMODE_BYTESWAP_DATA| TI_OPMODE_WORDSWAP_BD|TI_OPMODE_DONT_FRAG_JUMBO| TI_OPMODE_WARN_ENB|TI_OPMODE_FATAL_ENB | hdrsplit); #endif /* BYTE_ORDER */ /* * Only allow 1 DMA channel to be active at a time. * I don't think this is a good idea, but without it * the firmware racks up lots of nicDmaReadRingFull * errors. This is not compatible with hardware checksums. */ if (sc->arpcom.ac_if.if_hwassist == 0) TI_SETBIT(sc, TI_GCR_OPMODE, TI_OPMODE_1_DMA_ACTIVE); /* Recommended settings from Tigon manual. */ CSR_WRITE_4(sc, TI_GCR_DMA_WRITECFG, TI_DMA_STATE_THRESH_8W); CSR_WRITE_4(sc, TI_GCR_DMA_READCFG, TI_DMA_STATE_THRESH_8W); if (ti_64bitslot_war(sc)) { printf("ti%d: bios thinks we're in a 64 bit slot, " "but we aren't", sc->ti_unit); return(EINVAL); } return(0); } /* * Initialize the general information block and firmware, and * start the CPU(s) running. */ static int ti_gibinit(sc) struct ti_softc *sc; { struct ti_rcb *rcb; int i; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* Disable interrupts for now. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* Tell the chip where to find the general information block. */ CSR_WRITE_4(sc, TI_GCR_GENINFO_HI, 0); CSR_WRITE_4(sc, TI_GCR_GENINFO_LO, vtophys(&sc->ti_rdata->ti_info)); /* Load the firmware into SRAM. */ ti_loadfw(sc); /* Set up the contents of the general info and ring control blocks. */ /* Set up the event ring and producer pointer. */ rcb = &sc->ti_rdata->ti_info.ti_ev_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_event_ring); rcb->ti_flags = 0; TI_HOSTADDR(sc->ti_rdata->ti_info.ti_ev_prodidx_ptr) = vtophys(&sc->ti_ev_prodidx); sc->ti_ev_prodidx.ti_idx = 0; CSR_WRITE_4(sc, TI_GCR_EVENTCONS_IDX, 0); sc->ti_ev_saved_considx = 0; /* Set up the command ring and producer mailbox. */ rcb = &sc->ti_rdata->ti_info.ti_cmd_rcb; sc->ti_rdata->ti_cmd_ring = (struct ti_cmd_desc *)(sc->ti_vhandle + TI_GCR_CMDRING); TI_HOSTADDR(rcb->ti_hostaddr) = TI_GCR_NIC_ADDR(TI_GCR_CMDRING); rcb->ti_flags = 0; rcb->ti_max_len = 0; for (i = 0; i < TI_CMD_RING_CNT; i++) { CSR_WRITE_4(sc, TI_GCR_CMDRING + (i * 4), 0); } CSR_WRITE_4(sc, TI_GCR_CMDCONS_IDX, 0); CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, 0); sc->ti_cmd_saved_prodidx = 0; /* * Assign the address of the stats refresh buffer. * We re-use the current stats buffer for this to * conserve memory. */ TI_HOSTADDR(sc->ti_rdata->ti_info.ti_refresh_stats_ptr) = vtophys(&sc->ti_rdata->ti_info.ti_stats); /* Set up the standard receive ring. */ rcb = &sc->ti_rdata->ti_info.ti_std_rx_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_std_ring); rcb->ti_max_len = TI_FRAMELEN; rcb->ti_flags = 0; if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; /* Set up the jumbo receive ring. */ rcb = &sc->ti_rdata->ti_info.ti_jumbo_rx_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_jumbo_ring); #ifdef TI_PRIVATE_JUMBOS rcb->ti_max_len = TI_JUMBO_FRAMELEN; rcb->ti_flags = 0; #else rcb->ti_max_len = PAGE_SIZE; rcb->ti_flags = TI_RCB_FLAG_USE_EXT_RX_BD; #endif if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; /* * Set up the mini ring. Only activated on the * Tigon 2 but the slot in the config block is * still there on the Tigon 1. */ rcb = &sc->ti_rdata->ti_info.ti_mini_rx_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_mini_ring); rcb->ti_max_len = MHLEN - ETHER_ALIGN; if (sc->ti_hwrev == TI_HWREV_TIGON) rcb->ti_flags = TI_RCB_FLAG_RING_DISABLED; else rcb->ti_flags = 0; if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; /* * Set up the receive return ring. */ rcb = &sc->ti_rdata->ti_info.ti_return_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_return_ring); rcb->ti_flags = 0; rcb->ti_max_len = TI_RETURN_RING_CNT; TI_HOSTADDR(sc->ti_rdata->ti_info.ti_return_prodidx_ptr) = vtophys(&sc->ti_return_prodidx); /* * Set up the tx ring. Note: for the Tigon 2, we have the option * of putting the transmit ring in the host's address space and * letting the chip DMA it instead of leaving the ring in the NIC's * memory and accessing it through the shared memory region. We * do this for the Tigon 2, but it doesn't work on the Tigon 1, * so we have to revert to the shared memory scheme if we detect * a Tigon 1 chip. */ CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE); if (sc->ti_hwrev == TI_HWREV_TIGON) { sc->ti_rdata->ti_tx_ring_nic = (struct ti_tx_desc *)(sc->ti_vhandle + TI_WINDOW); } bzero((char *)sc->ti_rdata->ti_tx_ring, TI_TX_RING_CNT * sizeof(struct ti_tx_desc)); rcb = &sc->ti_rdata->ti_info.ti_tx_rcb; if (sc->ti_hwrev == TI_HWREV_TIGON) rcb->ti_flags = 0; else rcb->ti_flags = TI_RCB_FLAG_HOST_RING; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_max_len = TI_TX_RING_CNT; if (sc->ti_hwrev == TI_HWREV_TIGON) TI_HOSTADDR(rcb->ti_hostaddr) = TI_TX_RING_BASE; else TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_tx_ring); TI_HOSTADDR(sc->ti_rdata->ti_info.ti_tx_considx_ptr) = vtophys(&sc->ti_tx_considx); /* Set up tuneables */ #if 0 if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, (sc->ti_rx_coal_ticks / 10)); else #endif CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, sc->ti_rx_coal_ticks); CSR_WRITE_4(sc, TI_GCR_TX_COAL_TICKS, sc->ti_tx_coal_ticks); CSR_WRITE_4(sc, TI_GCR_STAT_TICKS, sc->ti_stat_ticks); CSR_WRITE_4(sc, TI_GCR_RX_MAX_COAL_BD, sc->ti_rx_max_coal_bds); CSR_WRITE_4(sc, TI_GCR_TX_MAX_COAL_BD, sc->ti_tx_max_coal_bds); CSR_WRITE_4(sc, TI_GCR_TX_BUFFER_RATIO, sc->ti_tx_buf_ratio); /* Turn interrupts on. */ CSR_WRITE_4(sc, TI_GCR_MASK_INTRS, 0); CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0); /* Start CPU. */ TI_CLRBIT(sc, TI_CPU_STATE, (TI_CPUSTATE_HALT|TI_CPUSTATE_STEP)); return(0); } /* * Probe for a Tigon chip. Check the PCI vendor and device IDs * against our list and return its name if we find a match. */ static int ti_probe(dev) device_t dev; { struct ti_type *t; t = ti_devs; while(t->ti_name != NULL) { if ((pci_get_vendor(dev) == t->ti_vid) && (pci_get_device(dev) == t->ti_did)) { device_set_desc(dev, t->ti_name); return(0); } t++; } return(ENXIO); } #ifdef KLD_MODULE static int log2rndup(int len) { int log2size = 0, t = len; while (t > 1) { log2size++; t >>= 1; } if (len != (1 << log2size)) log2size++; return log2size; } static int ti_mbuf_sanity(device_t dev) { if ((mbstat.m_msize != MSIZE) || mbstat.m_mclbytes != MCLBYTES){ device_printf(dev, "\n"); device_printf(dev, "This module was compiled with " "-DMCLSHIFT=%d -DMSIZE=%d\n", MCLSHIFT, MSIZE); device_printf(dev, "The kernel was compiled with MCLSHIFT=%d," " MSIZE=%d\n", log2rndup(mbstat.m_mclbytes), (int)mbstat.m_msize); return(EINVAL); } return(0); } #endif static int ti_attach(dev) device_t dev; { u_int32_t command; struct ifnet *ifp; struct ti_softc *sc; int unit, error = 0, rid; sc = NULL; #ifdef KLD_MODULE if (ti_mbuf_sanity(dev)){ device_printf(dev, "Module mbuf constants do not match " "kernel constants!\n"); device_printf(dev, "Rebuild the module or the kernel so " "they match\n"); device_printf(dev, "\n"); error = EINVAL; goto fail; } #endif sc = device_get_softc(dev); unit = device_get_unit(dev); bzero(sc, sizeof(struct ti_softc)); mtx_init(&sc->ti_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); sc->arpcom.ac_if.if_capabilities = IFCAP_HWCSUM; sc->arpcom.ac_if.if_capenable = sc->arpcom.ac_if.if_capabilities; /* * Map control/status registers. */ pci_enable_busmaster(dev); pci_enable_io(dev, SYS_RES_MEMORY); command = pci_read_config(dev, PCIR_COMMAND, 4); if (!(command & PCIM_CMD_MEMEN)) { printf("ti%d: failed to enable memory mapping!\n", unit); error = ENXIO; goto fail; } rid = TI_PCI_LOMEM; sc->ti_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE|PCI_RF_DENSE); if (sc->ti_res == NULL) { printf ("ti%d: couldn't map memory\n", unit); error = ENXIO; goto fail; } sc->ti_btag = rman_get_bustag(sc->ti_res); sc->ti_bhandle = rman_get_bushandle(sc->ti_res); sc->ti_vhandle = (vm_offset_t)rman_get_virtual(sc->ti_res); /* Allocate interrupt */ rid = 0; sc->ti_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->ti_irq == NULL) { printf("ti%d: couldn't map interrupt\n", unit); error = ENXIO; goto fail; } error = bus_setup_intr(dev, sc->ti_irq, INTR_TYPE_NET, ti_intr, sc, &sc->ti_intrhand); if (error) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); printf("ti%d: couldn't set up irq\n", unit); goto fail; } sc->ti_unit = unit; if (ti_chipinit(sc)) { printf("ti%d: chip initialization failed\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; goto fail; } /* Zero out the NIC's on-board SRAM. */ ti_mem(sc, 0x2000, 0x100000 - 0x2000, NULL); /* Init again -- zeroing memory may have clobbered some registers. */ if (ti_chipinit(sc)) { printf("ti%d: chip initialization failed\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; goto fail; } /* * Get station address from the EEPROM. Note: the manual states * that the MAC address is at offset 0x8c, however the data is * stored as two longwords (since that's how it's loaded into * the NIC). This means the MAC address is actually preceded * by two zero bytes. We need to skip over those. */ if (ti_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, TI_EE_MAC_OFFSET + 2, ETHER_ADDR_LEN)) { printf("ti%d: failed to read station address\n", unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; goto fail; } /* * A Tigon chip was detected. Inform the world. */ printf("ti%d: Ethernet address: %6D\n", unit, sc->arpcom.ac_enaddr, ":"); /* Allocate the general information block and ring buffers. */ sc->ti_rdata = contigmalloc(sizeof(struct ti_ring_data), M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); if (sc->ti_rdata == NULL) { bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; printf("ti%d: no memory for list buffers!\n", sc->ti_unit); goto fail; } bzero(sc->ti_rdata, sizeof(struct ti_ring_data)); /* Try to allocate memory for jumbo buffers. */ #ifdef TI_PRIVATE_JUMBOS if (ti_alloc_jumbo_mem(sc)) { printf("ti%d: jumbo buffer allocation failed\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); contigfree(sc->ti_rdata, sizeof(struct ti_ring_data), M_DEVBUF); error = ENXIO; goto fail; } #else if (!jumbo_vm_init()) { printf("ti%d: VM initialization failed!\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); free(sc->ti_rdata, M_DEVBUF); error = ENOMEM; goto fail; } #endif /* * We really need a better way to tell a 1000baseTX card * from a 1000baseSX one, since in theory there could be * OEMed 1000baseTX cards from lame vendors who aren't * clever enough to change the PCI ID. For the moment * though, the AceNIC is the only copper card available. */ if (pci_get_vendor(dev) == ALT_VENDORID && pci_get_device(dev) == ALT_DEVICEID_ACENIC_COPPER) sc->ti_copper = 1; /* Ok, it's not the only copper card available. */ if (pci_get_vendor(dev) == NG_VENDORID && pci_get_device(dev) == NG_DEVICEID_GA620T) sc->ti_copper = 1; /* Set default tuneable values. */ sc->ti_stat_ticks = 2 * TI_TICKS_PER_SEC; #if 0 sc->ti_rx_coal_ticks = TI_TICKS_PER_SEC / 5000; #endif sc->ti_rx_coal_ticks = 170; sc->ti_tx_coal_ticks = TI_TICKS_PER_SEC / 500; sc->ti_rx_max_coal_bds = 64; #if 0 sc->ti_tx_max_coal_bds = 128; #endif sc->ti_tx_max_coal_bds = 32; sc->ti_tx_buf_ratio = 21; /* Set up ifnet structure */ ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = sc->ti_unit; ifp->if_name = "ti"; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; tis[unit] = sc; ifp->if_ioctl = ti_ioctl; ifp->if_output = ether_output; ifp->if_start = ti_start; ifp->if_watchdog = ti_watchdog; ifp->if_init = ti_init; ifp->if_mtu = ETHERMTU; ifp->if_snd.ifq_maxlen = TI_TX_RING_CNT - 1; /* Set up ifmedia support. */ ifmedia_init(&sc->ifmedia, IFM_IMASK, ti_ifmedia_upd, ti_ifmedia_sts); if (sc->ti_copper) { /* * Copper cards allow manual 10/100 mode selection, * but not manual 1000baseTX mode selection. Why? * Becuase currently there's no way to specify the * master/slave setting through the firmware interface, * so Alteon decided to just bag it and handle it * via autonegotiation. */ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_T, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL); } else { /* Fiber cards don't support 10/100 modes. */ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL); } ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); /* * We're assuming here that card initialization is a sequential * thing. If it isn't, multiple cards probing at the same time * could stomp on the list of softcs here. */ /* * If this is the first card to be initialized, initialize the * softc queue. */ if (unit == 0) STAILQ_INIT(&ti_sc_list); STAILQ_INSERT_TAIL(&ti_sc_list, sc, ti_links); /* Register the device */ sc->dev = make_dev(&ti_cdevsw, sc->ti_unit, UID_ROOT, GID_OPERATOR, 0600, "ti%d", sc->ti_unit); /* * Call MI attach routine. */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); return(0); fail: mtx_destroy(&sc->ti_mtx); return(error); } /* * Verify that our character special device is not currently * open. Also track down any cached vnodes & kill them before * the module is unloaded */ static int ti_unref_special(device_t dev) { struct vnode *ti_vn; int count; struct ti_softc *sc = sc = device_get_softc(dev); if (!vfinddev(sc->dev, VCHR, &ti_vn)) { return 0; } if ((count = vcount(ti_vn))) { device_printf(dev, "%d refs to special device, " "denying unload\n", count); return count; } /* now we know that there's a vnode in the cache. We hunt it down and kill it now, before unloading */ vgone(ti_vn); return(0); } static int ti_detach(dev) device_t dev; { struct ti_softc *sc; struct ifnet *ifp; if (ti_unref_special(dev)) return EBUSY; sc = device_get_softc(dev); TI_LOCK(sc); ifp = &sc->arpcom.ac_if; ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); ti_stop(sc); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); #ifdef TI_PRIVATE_JUMBOS contigfree(sc->ti_cdata.ti_jumbo_buf, TI_JMEM, M_DEVBUF); #endif contigfree(sc->ti_rdata, sizeof(struct ti_ring_data), M_DEVBUF); ifmedia_removeall(&sc->ifmedia); TI_UNLOCK(sc); mtx_destroy(&sc->ti_mtx); return(0); } #ifdef TI_JUMBO_HDRSPLIT /* * If hdr_len is 0, that means that header splitting wasn't done on * this packet for some reason. The two most likely reasons are that * the protocol isn't a supported protocol for splitting, or this * packet had a fragment offset that wasn't 0. * * The header length, if it is non-zero, will always be the length of * the headers on the packet, but that length could be longer than the * first mbuf. So we take the minimum of the two as the actual * length. */ static __inline void ti_hdr_split(struct mbuf *top, int hdr_len, int pkt_len, int idx) { int i = 0; int lengths[4] = {0, 0, 0, 0}; struct mbuf *m, *mp; if (hdr_len != 0) top->m_len = min(hdr_len, top->m_len); pkt_len -= top->m_len; lengths[i++] = top->m_len; mp = top; for (m = top->m_next; m && pkt_len; m = m->m_next) { m->m_len = m->m_ext.ext_size = min(m->m_len, pkt_len); pkt_len -= m->m_len; lengths[i++] = m->m_len; mp = m; } #if 0 if (hdr_len != 0) printf("got split packet: "); else printf("got non-split packet: "); printf("%d,%d,%d,%d = %d\n", lengths[0], lengths[1], lengths[2], lengths[3], lengths[0] + lengths[1] + lengths[2] + lengths[3]); #endif if (pkt_len) panic("header splitting didn't"); if (m) { m_freem(m); mp->m_next = NULL; } if (mp->m_next != NULL) panic("ti_hdr_split: last mbuf in chain should be null"); } #endif /* TI_JUMBO_HDRSPLIT */ /* * Frame reception handling. This is called if there's a frame * on the receive return list. * * Note: we have to be able to handle three possibilities here: * 1) the frame is from the mini receive ring (can only happen) * on Tigon 2 boards) * 2) the frame is from the jumbo recieve ring * 3) the frame is from the standard receive ring */ static void ti_rxeof(sc) struct ti_softc *sc; { struct ifnet *ifp; struct ti_cmd_desc cmd; ifp = &sc->arpcom.ac_if; while(sc->ti_rx_saved_considx != sc->ti_return_prodidx.ti_idx) { struct ti_rx_desc *cur_rx; u_int32_t rxidx; struct ether_header *eh; struct mbuf *m = NULL; u_int16_t vlan_tag = 0; int have_tag = 0; cur_rx = &sc->ti_rdata->ti_rx_return_ring[sc->ti_rx_saved_considx]; rxidx = cur_rx->ti_idx; TI_INC(sc->ti_rx_saved_considx, TI_RETURN_RING_CNT); if (cur_rx->ti_flags & TI_BDFLAG_VLAN_TAG) { have_tag = 1; vlan_tag = cur_rx->ti_vlan_tag & 0xfff; } if (cur_rx->ti_flags & TI_BDFLAG_JUMBO_RING) { TI_INC(sc->ti_jumbo, TI_JUMBO_RX_RING_CNT); m = sc->ti_cdata.ti_rx_jumbo_chain[rxidx]; sc->ti_cdata.ti_rx_jumbo_chain[rxidx] = NULL; if (cur_rx->ti_flags & TI_BDFLAG_ERROR) { ifp->if_ierrors++; ti_newbuf_jumbo(sc, sc->ti_jumbo, m); continue; } if (ti_newbuf_jumbo(sc, sc->ti_jumbo, NULL) == ENOBUFS) { ifp->if_ierrors++; ti_newbuf_jumbo(sc, sc->ti_jumbo, m); continue; } #ifdef TI_PRIVATE_JUMBOS m->m_len = cur_rx->ti_len; #else /* TI_PRIVATE_JUMBOS */ #ifdef TI_JUMBO_HDRSPLIT if (sc->ti_hdrsplit) ti_hdr_split(m, TI_HOSTADDR(cur_rx->ti_addr), cur_rx->ti_len, rxidx); else #endif /* TI_JUMBO_HDRSPLIT */ m_adj(m, cur_rx->ti_len - m->m_pkthdr.len); #endif /* TI_PRIVATE_JUMBOS */ } else if (cur_rx->ti_flags & TI_BDFLAG_MINI_RING) { TI_INC(sc->ti_mini, TI_MINI_RX_RING_CNT); m = sc->ti_cdata.ti_rx_mini_chain[rxidx]; sc->ti_cdata.ti_rx_mini_chain[rxidx] = NULL; if (cur_rx->ti_flags & TI_BDFLAG_ERROR) { ifp->if_ierrors++; ti_newbuf_mini(sc, sc->ti_mini, m); continue; } if (ti_newbuf_mini(sc, sc->ti_mini, NULL) == ENOBUFS) { ifp->if_ierrors++; ti_newbuf_mini(sc, sc->ti_mini, m); continue; } m->m_len = cur_rx->ti_len; } else { TI_INC(sc->ti_std, TI_STD_RX_RING_CNT); m = sc->ti_cdata.ti_rx_std_chain[rxidx]; sc->ti_cdata.ti_rx_std_chain[rxidx] = NULL; if (cur_rx->ti_flags & TI_BDFLAG_ERROR) { ifp->if_ierrors++; ti_newbuf_std(sc, sc->ti_std, m); continue; } if (ti_newbuf_std(sc, sc->ti_std, NULL) == ENOBUFS) { ifp->if_ierrors++; ti_newbuf_std(sc, sc->ti_std, m); continue; } m->m_len = cur_rx->ti_len; } m->m_pkthdr.len = cur_rx->ti_len; ifp->if_ipackets++; eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; /* Remove header from mbuf and pass it on. */ m_adj(m, sizeof(struct ether_header)); if (ifp->if_hwassist) { m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_DATA_VALID; if ((cur_rx->ti_ip_cksum ^ 0xffff) == 0) m->m_pkthdr.csum_flags |= CSUM_IP_VALID; m->m_pkthdr.csum_data = cur_rx->ti_tcp_udp_cksum; } /* * If we received a packet with a vlan tag, pass it * to vlan_input() instead of ether_input(). */ if (have_tag) { VLAN_INPUT_TAG(eh, m, vlan_tag); have_tag = vlan_tag = 0; continue; } ether_input(ifp, eh, m); } /* Only necessary on the Tigon 1. */ if (sc->ti_hwrev == TI_HWREV_TIGON) CSR_WRITE_4(sc, TI_GCR_RXRETURNCONS_IDX, sc->ti_rx_saved_considx); TI_UPDATE_STDPROD(sc, sc->ti_std); TI_UPDATE_MINIPROD(sc, sc->ti_mini); TI_UPDATE_JUMBOPROD(sc, sc->ti_jumbo); return; } static void ti_txeof(sc) struct ti_softc *sc; { struct ti_tx_desc *cur_tx = NULL; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* * Go through our tx ring and free mbufs for those * frames that have been sent. */ while (sc->ti_tx_saved_considx != sc->ti_tx_considx.ti_idx) { u_int32_t idx = 0; idx = sc->ti_tx_saved_considx; if (sc->ti_hwrev == TI_HWREV_TIGON) { if (idx > 383) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 6144); else if (idx > 255) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 4096); else if (idx > 127) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 2048); else CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE); cur_tx = &sc->ti_rdata->ti_tx_ring_nic[idx % 128]; } else cur_tx = &sc->ti_rdata->ti_tx_ring[idx]; if (cur_tx->ti_flags & TI_BDFLAG_END) ifp->if_opackets++; if (sc->ti_cdata.ti_tx_chain[idx] != NULL) { m_freem(sc->ti_cdata.ti_tx_chain[idx]); sc->ti_cdata.ti_tx_chain[idx] = NULL; } sc->ti_txcnt--; TI_INC(sc->ti_tx_saved_considx, TI_TX_RING_CNT); ifp->if_timer = 0; } if (cur_tx != NULL) ifp->if_flags &= ~IFF_OACTIVE; return; } static void ti_intr(xsc) void *xsc; { struct ti_softc *sc; struct ifnet *ifp; sc = xsc; TI_LOCK(sc); ifp = &sc->arpcom.ac_if; /*#ifdef notdef*/ /* Avoid this for now -- checking this register is expensive. */ /* Make sure this is really our interrupt. */ if (!(CSR_READ_4(sc, TI_MISC_HOST_CTL) & TI_MHC_INTSTATE)) { TI_UNLOCK(sc); return; } /*#endif*/ /* Ack interrupt and stop others from occuring. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); if (ifp->if_flags & IFF_RUNNING) { /* Check RX return ring producer/consumer */ ti_rxeof(sc); /* Check TX ring producer/consumer */ ti_txeof(sc); } ti_handle_events(sc); /* Re-enable interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0); if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) ti_start(ifp); TI_UNLOCK(sc); return; } static void ti_stats_update(sc) struct ti_softc *sc; { struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_collisions += (sc->ti_rdata->ti_info.ti_stats.dot3StatsSingleCollisionFrames + sc->ti_rdata->ti_info.ti_stats.dot3StatsMultipleCollisionFrames + sc->ti_rdata->ti_info.ti_stats.dot3StatsExcessiveCollisions + sc->ti_rdata->ti_info.ti_stats.dot3StatsLateCollisions) - ifp->if_collisions; return; } /* * Encapsulate an mbuf chain in the tx ring by coupling the mbuf data * pointers to descriptors. */ static int ti_encap(sc, m_head, txidx) struct ti_softc *sc; struct mbuf *m_head; u_int32_t *txidx; { struct ti_tx_desc *f = NULL; struct mbuf *m; u_int32_t frag, cur, cnt = 0; u_int16_t csum_flags = 0; struct ifvlan *ifv = NULL; if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && m_head->m_pkthdr.rcvif != NULL && m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) ifv = m_head->m_pkthdr.rcvif->if_softc; m = m_head; cur = frag = *txidx; if (m_head->m_pkthdr.csum_flags) { if (m_head->m_pkthdr.csum_flags & CSUM_IP) csum_flags |= TI_BDFLAG_IP_CKSUM; if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) csum_flags |= TI_BDFLAG_TCP_UDP_CKSUM; if (m_head->m_flags & M_LASTFRAG) csum_flags |= TI_BDFLAG_IP_FRAG_END; else if (m_head->m_flags & M_FRAG) csum_flags |= TI_BDFLAG_IP_FRAG; } /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ for (m = m_head; m != NULL; m = m->m_next) { if (m->m_len != 0) { if (sc->ti_hwrev == TI_HWREV_TIGON) { if (frag > 383) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 6144); else if (frag > 255) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 4096); else if (frag > 127) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 2048); else CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE); f = &sc->ti_rdata->ti_tx_ring_nic[frag % 128]; } else f = &sc->ti_rdata->ti_tx_ring[frag]; if (sc->ti_cdata.ti_tx_chain[frag] != NULL) break; TI_HOSTADDR(f->ti_addr) = vtophys(mtod(m, vm_offset_t)); f->ti_len = m->m_len; f->ti_flags = csum_flags; if (ifv != NULL) { f->ti_flags |= TI_BDFLAG_VLAN_TAG; f->ti_vlan_tag = ifv->ifv_tag & 0xfff; } else { f->ti_vlan_tag = 0; } /* * Sanity check: avoid coming within 16 descriptors * of the end of the ring. */ if ((TI_TX_RING_CNT - (sc->ti_txcnt + cnt)) < 16) return(ENOBUFS); cur = frag; TI_INC(frag, TI_TX_RING_CNT); cnt++; } } if (m != NULL) return(ENOBUFS); if (frag == sc->ti_tx_saved_considx) return(ENOBUFS); if (sc->ti_hwrev == TI_HWREV_TIGON) sc->ti_rdata->ti_tx_ring_nic[cur % 128].ti_flags |= TI_BDFLAG_END; else sc->ti_rdata->ti_tx_ring[cur].ti_flags |= TI_BDFLAG_END; sc->ti_cdata.ti_tx_chain[cur] = m_head; sc->ti_txcnt += cnt; *txidx = frag; return(0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit descriptors. */ static void ti_start(ifp) struct ifnet *ifp; { struct ti_softc *sc; struct mbuf *m_head = NULL; u_int32_t prodidx = 0; sc = ifp->if_softc; TI_LOCK(sc); prodidx = CSR_READ_4(sc, TI_MB_SENDPROD_IDX); while(sc->ti_cdata.ti_tx_chain[prodidx] == NULL) { IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; /* * XXX * safety overkill. If this is a fragmented packet chain * with delayed TCP/UDP checksums, then only encapsulate * it if we have enough descriptors to handle the entire * chain at once. * (paranoia -- may not actually be needed) */ if (m_head->m_flags & M_FIRSTFRAG && m_head->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { if ((TI_TX_RING_CNT - sc->ti_txcnt) < m_head->m_pkthdr.csum_data + 16) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } } /* * Pack the data into the transmit ring. If we * don't have room, set the OACTIVE flag and wait * for the NIC to drain the ring. */ if (ti_encap(sc, m_head, &prodidx)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } /* * If there's a BPF listener, bounce a copy of this frame * to him. */ if (ifp->if_bpf) bpf_mtap(ifp, m_head); } /* Transmit */ CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, prodidx); /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; TI_UNLOCK(sc); return; } static void ti_init(xsc) void *xsc; { struct ti_softc *sc = xsc; /* Cancel pending I/O and flush buffers. */ ti_stop(sc); TI_LOCK(sc); /* Init the gen info block, ring control blocks and firmware. */ if (ti_gibinit(sc)) { printf("ti%d: initialization failure\n", sc->ti_unit); TI_UNLOCK(sc); return; } TI_UNLOCK(sc); return; } static void ti_init2(sc) struct ti_softc *sc; { struct ti_cmd_desc cmd; struct ifnet *ifp; u_int16_t *m; struct ifmedia *ifm; int tmp; ifp = &sc->arpcom.ac_if; /* Specify MTU and interface index. */ CSR_WRITE_4(sc, TI_GCR_IFINDEX, ifp->if_unit); CSR_WRITE_4(sc, TI_GCR_IFMTU, ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN); TI_DO_CMD(TI_CMD_UPDATE_GENCOM, 0, 0); /* Load our MAC address. */ m = (u_int16_t *)&sc->arpcom.ac_enaddr[0]; CSR_WRITE_4(sc, TI_GCR_PAR0, htons(m[0])); CSR_WRITE_4(sc, TI_GCR_PAR1, (htons(m[1]) << 16) | htons(m[2])); TI_DO_CMD(TI_CMD_SET_MAC_ADDR, 0, 0); /* Enable or disable promiscuous mode as needed. */ if (ifp->if_flags & IFF_PROMISC) { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_ENB, 0); } else { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_DIS, 0); } /* Program multicast filter. */ ti_setmulti(sc); /* * If this is a Tigon 1, we should tell the * firmware to use software packet filtering. */ if (sc->ti_hwrev == TI_HWREV_TIGON) { TI_DO_CMD(TI_CMD_FDR_FILTERING, TI_CMD_CODE_FILT_ENB, 0); } /* Init RX ring. */ ti_init_rx_ring_std(sc); /* Init jumbo RX ring. */ if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) ti_init_rx_ring_jumbo(sc); /* * If this is a Tigon 2, we can also configure the * mini ring. */ if (sc->ti_hwrev == TI_HWREV_TIGON_II) ti_init_rx_ring_mini(sc); CSR_WRITE_4(sc, TI_GCR_RXRETURNCONS_IDX, 0); sc->ti_rx_saved_considx = 0; /* Init TX ring. */ ti_init_tx_ring(sc); /* Tell firmware we're alive. */ TI_DO_CMD(TI_CMD_HOST_STATE, TI_CMD_CODE_STACK_UP, 0); /* Enable host interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* * Make sure to set media properly. We have to do this * here since we have to issue commands in order to set * the link negotiation and we can't issue commands until * the firmware is running. */ ifm = &sc->ifmedia; tmp = ifm->ifm_media; ifm->ifm_media = ifm->ifm_cur->ifm_media; ti_ifmedia_upd(ifp); ifm->ifm_media = tmp; return; } /* * Set media options. */ static int ti_ifmedia_upd(ifp) struct ifnet *ifp; { struct ti_softc *sc; struct ifmedia *ifm; struct ti_cmd_desc cmd; u_int32_t flowctl; sc = ifp->if_softc; ifm = &sc->ifmedia; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return(EINVAL); flowctl = 0; switch(IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: /* * Transmit flow control doesn't work on the Tigon 1. */ flowctl = TI_GLNK_RX_FLOWCTL_Y; /* * Transmit flow control can also cause problems on the * Tigon 2, apparantly with both the copper and fiber * boards. The symptom is that the interface will just * hang. This was reproduced with Alteon 180 switches. */ #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_GLNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB| TI_GLNK_FULL_DUPLEX| flowctl | TI_GLNK_AUTONEGENB|TI_GLNK_ENB); flowctl = TI_LNK_RX_FLOWCTL_Y; #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_LNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_100MB|TI_LNK_10MB| TI_LNK_FULL_DUPLEX|TI_LNK_HALF_DUPLEX| flowctl | TI_LNK_AUTONEGENB|TI_LNK_ENB); TI_DO_CMD(TI_CMD_LINK_NEGOTIATION, TI_CMD_CODE_NEGOTIATE_BOTH, 0); break; case IFM_1000_SX: case IFM_1000_T: flowctl = TI_GLNK_RX_FLOWCTL_Y; #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_GLNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB| flowctl |TI_GLNK_ENB); CSR_WRITE_4(sc, TI_GCR_LINK, 0); if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { TI_SETBIT(sc, TI_GCR_GLINK, TI_GLNK_FULL_DUPLEX); } TI_DO_CMD(TI_CMD_LINK_NEGOTIATION, TI_CMD_CODE_NEGOTIATE_GIGABIT, 0); break; case IFM_100_FX: case IFM_10_FL: case IFM_100_TX: case IFM_10_T: flowctl = TI_LNK_RX_FLOWCTL_Y; #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_LNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_GLINK, 0); CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_ENB|TI_LNK_PREF|flowctl); if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX || IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_100MB); } else { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_10MB); } if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_FULL_DUPLEX); } else { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_HALF_DUPLEX); } TI_DO_CMD(TI_CMD_LINK_NEGOTIATION, TI_CMD_CODE_NEGOTIATE_10_100, 0); break; } return(0); } /* * Report current media status. */ static void ti_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct ti_softc *sc; u_int32_t media = 0; sc = ifp->if_softc; ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN) return; ifmr->ifm_status |= IFM_ACTIVE; if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP) { media = CSR_READ_4(sc, TI_GCR_GLINK_STAT); if (sc->ti_copper) ifmr->ifm_active |= IFM_1000_T; else ifmr->ifm_active |= IFM_1000_SX; if (media & TI_GLNK_FULL_DUPLEX) ifmr->ifm_active |= IFM_FDX; else ifmr->ifm_active |= IFM_HDX; } else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) { media = CSR_READ_4(sc, TI_GCR_LINK_STAT); if (sc->ti_copper) { if (media & TI_LNK_100MB) ifmr->ifm_active |= IFM_100_TX; if (media & TI_LNK_10MB) ifmr->ifm_active |= IFM_10_T; } else { if (media & TI_LNK_100MB) ifmr->ifm_active |= IFM_100_FX; if (media & TI_LNK_10MB) ifmr->ifm_active |= IFM_10_FL; } if (media & TI_LNK_FULL_DUPLEX) ifmr->ifm_active |= IFM_FDX; if (media & TI_LNK_HALF_DUPLEX) ifmr->ifm_active |= IFM_HDX; } return; } static int ti_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data; { struct ti_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; int mask, error = 0; struct ti_cmd_desc cmd; TI_LOCK(sc); switch(command) { case SIOCSIFADDR: case SIOCGIFADDR: error = ether_ioctl(ifp, command, data); break; case SIOCSIFMTU: if (ifr->ifr_mtu > TI_JUMBO_MTU) error = EINVAL; else { ifp->if_mtu = ifr->ifr_mtu; ti_init(sc); } break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { /* * If only the state of the PROMISC flag changed, * then just use the 'set promisc mode' command * instead of reinitializing the entire NIC. Doing * a full re-init means reloading the firmware and * waiting for it to start up, which may take a * second or two. */ if (ifp->if_flags & IFF_RUNNING && ifp->if_flags & IFF_PROMISC && !(sc->ti_if_flags & IFF_PROMISC)) { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_ENB, 0); } else if (ifp->if_flags & IFF_RUNNING && !(ifp->if_flags & IFF_PROMISC) && sc->ti_if_flags & IFF_PROMISC) { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_DIS, 0); } else ti_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { ti_stop(sc); } } sc->ti_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifp->if_flags & IFF_RUNNING) { ti_setmulti(sc); error = 0; } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; case SIOCSIFCAP: mask = ifr->ifr_reqcap ^ ifp->if_capenable; if (mask & IFCAP_HWCSUM) { if (IFCAP_HWCSUM & ifp->if_capenable) ifp->if_capenable &= ~IFCAP_HWCSUM; else ifp->if_capenable |= IFCAP_HWCSUM; if (ifp->if_flags & IFF_RUNNING) ti_init(sc); } error = 0; break; default: error = EINVAL; break; } TI_UNLOCK(sc); return(error); } static int ti_open(dev_t dev, int flags, int fmt, struct thread *td) { int unit; struct ti_softc *sc; unit = minor(dev) & 0xff; sc = ti_lookup_softc(unit); if (sc == NULL) return(ENODEV); TI_LOCK(sc); sc->ti_flags |= TI_FLAG_DEBUGING; TI_UNLOCK(sc); return(0); } static int ti_close(dev_t dev, int flag, int fmt, struct thread *td) { int unit; struct ti_softc *sc; unit = minor(dev) & 0xff; sc = ti_lookup_softc(unit); if (sc == NULL) return(ENODEV); TI_LOCK(sc); sc->ti_flags &= ~TI_FLAG_DEBUGING; TI_UNLOCK(sc); return(0); } /* * This ioctl routine goes along with the Tigon character device. */ static int ti_ioctl2(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) { int unit, error; struct ti_softc *sc; unit = minor(dev) & 0xff; sc = ti_lookup_softc(unit); if (sc == NULL) return(ENODEV); error = 0; switch(cmd) { case TIIOCGETSTATS: { struct ti_stats *outstats; outstats = (struct ti_stats *)addr; bcopy(&sc->ti_rdata->ti_info.ti_stats, outstats, sizeof(struct ti_stats)); break; } case TIIOCGETPARAMS: { struct ti_params *params; params = (struct ti_params *)addr; params->ti_stat_ticks = sc->ti_stat_ticks; params->ti_rx_coal_ticks = sc->ti_rx_coal_ticks; params->ti_tx_coal_ticks = sc->ti_tx_coal_ticks; params->ti_rx_max_coal_bds = sc->ti_rx_max_coal_bds; params->ti_tx_max_coal_bds = sc->ti_tx_max_coal_bds; params->ti_tx_buf_ratio = sc->ti_tx_buf_ratio; params->param_mask = TI_PARAM_ALL; error = 0; break; } case TIIOCSETPARAMS: { struct ti_params *params; params = (struct ti_params *)addr; if (params->param_mask & TI_PARAM_STAT_TICKS) { sc->ti_stat_ticks = params->ti_stat_ticks; CSR_WRITE_4(sc, TI_GCR_STAT_TICKS, sc->ti_stat_ticks); } if (params->param_mask & TI_PARAM_RX_COAL_TICKS) { sc->ti_rx_coal_ticks = params->ti_rx_coal_ticks; CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, sc->ti_rx_coal_ticks); } if (params->param_mask & TI_PARAM_TX_COAL_TICKS) { sc->ti_tx_coal_ticks = params->ti_tx_coal_ticks; CSR_WRITE_4(sc, TI_GCR_TX_COAL_TICKS, sc->ti_tx_coal_ticks); } if (params->param_mask & TI_PARAM_RX_COAL_BDS) { sc->ti_rx_max_coal_bds = params->ti_rx_max_coal_bds; CSR_WRITE_4(sc, TI_GCR_RX_MAX_COAL_BD, sc->ti_rx_max_coal_bds); } if (params->param_mask & TI_PARAM_TX_COAL_BDS) { sc->ti_tx_max_coal_bds = params->ti_tx_max_coal_bds; CSR_WRITE_4(sc, TI_GCR_TX_MAX_COAL_BD, sc->ti_tx_max_coal_bds); } if (params->param_mask & TI_PARAM_TX_BUF_RATIO) { sc->ti_tx_buf_ratio = params->ti_tx_buf_ratio; CSR_WRITE_4(sc, TI_GCR_TX_BUFFER_RATIO, sc->ti_tx_buf_ratio); } error = 0; break; } case TIIOCSETTRACE: { ti_trace_type trace_type; trace_type = *(ti_trace_type *)addr; /* * Set tracing to whatever the user asked for. Setting * this register to 0 should have the effect of disabling * tracing. */ CSR_WRITE_4(sc, TI_GCR_NIC_TRACING, trace_type); error = 0; break; } case TIIOCGETTRACE: { struct ti_trace_buf *trace_buf; u_int32_t trace_start, cur_trace_ptr, trace_len; trace_buf = (struct ti_trace_buf *)addr; trace_start = CSR_READ_4(sc, TI_GCR_NICTRACE_START); cur_trace_ptr = CSR_READ_4(sc, TI_GCR_NICTRACE_PTR); trace_len = CSR_READ_4(sc, TI_GCR_NICTRACE_LEN); #if 0 printf("ti%d: trace_start = %#x, cur_trace_ptr = %#x, " "trace_len = %d\n", sc->ti_unit, trace_start, cur_trace_ptr, trace_len); printf("ti%d: trace_buf->buf_len = %d\n", sc->ti_unit, trace_buf->buf_len); #endif error = ti_copy_mem(sc, trace_start, min(trace_len, trace_buf->buf_len), (caddr_t)trace_buf->buf, 1, 1); if (error == 0) { trace_buf->fill_len = min(trace_len, trace_buf->buf_len); if (cur_trace_ptr < trace_start) trace_buf->cur_trace_ptr = trace_start - cur_trace_ptr; else trace_buf->cur_trace_ptr = cur_trace_ptr - trace_start; } else trace_buf->fill_len = 0; break; } /* * For debugging, five ioctls are needed: * ALT_ATTACH * ALT_READ_TG_REG * ALT_WRITE_TG_REG * ALT_READ_TG_MEM * ALT_WRITE_TG_MEM */ case ALT_ATTACH: /* * From what I can tell, Alteon's Solaris Tigon driver * only has one character device, so you have to attach * to the Tigon board you're interested in. This seems * like a not-so-good way to do things, since unless you * subsequently specify the unit number of the device * you're interested in in every ioctl, you'll only be * able to debug one board at a time. */ error = 0; break; case ALT_READ_TG_MEM: case ALT_WRITE_TG_MEM: { struct tg_mem *mem_param; u_int32_t sram_end, scratch_end; mem_param = (struct tg_mem *)addr; if (sc->ti_hwrev == TI_HWREV_TIGON) { sram_end = TI_END_SRAM_I; scratch_end = TI_END_SCRATCH_I; } else { sram_end = TI_END_SRAM_II; scratch_end = TI_END_SCRATCH_II; } /* * For now, we'll only handle accessing regular SRAM, * nothing else. */ if ((mem_param->tgAddr >= TI_BEG_SRAM) && ((mem_param->tgAddr + mem_param->len) <= sram_end)) { /* * In this instance, we always copy to/from user * space, so the user space argument is set to 1. */ error = ti_copy_mem(sc, mem_param->tgAddr, mem_param->len, mem_param->userAddr, 1, (cmd == ALT_READ_TG_MEM) ? 1 : 0); } else if ((mem_param->tgAddr >= TI_BEG_SCRATCH) && (mem_param->tgAddr <= scratch_end)) { error = ti_copy_scratch(sc, mem_param->tgAddr, mem_param->len, mem_param->userAddr, 1, (cmd == ALT_READ_TG_MEM) ? 1 : 0, TI_PROCESSOR_A); } else if ((mem_param->tgAddr >= TI_BEG_SCRATCH_B_DEBUG) && (mem_param->tgAddr <= TI_BEG_SCRATCH_B_DEBUG)) { if (sc->ti_hwrev == TI_HWREV_TIGON) { printf("ti%d: invalid memory range for " "Tigon I\n", sc->ti_unit); error = EINVAL; break; } error = ti_copy_scratch(sc, mem_param->tgAddr - TI_SCRATCH_DEBUG_OFF, mem_param->len, mem_param->userAddr, 1, (cmd == ALT_READ_TG_MEM) ? 1 : 0, TI_PROCESSOR_B); } else { printf("ti%d: memory address %#x len %d is out of " "supported range\n", sc->ti_unit, mem_param->tgAddr, mem_param->len); error = EINVAL; } break; } case ALT_READ_TG_REG: case ALT_WRITE_TG_REG: { struct tg_reg *regs; u_int32_t tmpval; regs = (struct tg_reg *)addr; /* * Make sure the address in question isn't out of range. */ if (regs->addr > TI_REG_MAX) { error = EINVAL; break; } if (cmd == ALT_READ_TG_REG) { bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle, regs->addr, &tmpval, 1); regs->data = ntohl(tmpval); #if 0 if ((regs->addr == TI_CPU_STATE) || (regs->addr == TI_CPU_CTL_B)) { printf("ti%d: register %#x = %#x\n", sc->ti_unit, regs->addr, tmpval); } #endif } else { tmpval = htonl(regs->data); bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle, regs->addr, &tmpval, 1); } break; } default: error = ENOTTY; break; } return(error); } static void ti_watchdog(ifp) struct ifnet *ifp; { struct ti_softc *sc; sc = ifp->if_softc; TI_LOCK(sc); /* * When we're debugging, the chip is often stopped for long periods * of time, and that would normally cause the watchdog timer to fire. * Since that impedes debugging, we don't want to do that. */ if (sc->ti_flags & TI_FLAG_DEBUGING) { TI_UNLOCK(sc); return; } printf("ti%d: watchdog timeout -- resetting\n", sc->ti_unit); ti_stop(sc); ti_init(sc); ifp->if_oerrors++; TI_UNLOCK(sc); return; } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ static void ti_stop(sc) struct ti_softc *sc; { struct ifnet *ifp; struct ti_cmd_desc cmd; TI_LOCK(sc); ifp = &sc->arpcom.ac_if; /* Disable host interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* * Tell firmware we're shutting down. */ TI_DO_CMD(TI_CMD_HOST_STATE, TI_CMD_CODE_STACK_DOWN, 0); /* Halt and reinitialize. */ ti_chipinit(sc); ti_mem(sc, 0x2000, 0x100000 - 0x2000, NULL); ti_chipinit(sc); /* Free the RX lists. */ ti_free_rx_ring_std(sc); /* Free jumbo RX list. */ ti_free_rx_ring_jumbo(sc); /* Free mini RX list. */ ti_free_rx_ring_mini(sc); /* Free TX buffers. */ ti_free_tx_ring(sc); sc->ti_ev_prodidx.ti_idx = 0; sc->ti_return_prodidx.ti_idx = 0; sc->ti_tx_considx.ti_idx = 0; sc->ti_tx_saved_considx = TI_TXCONS_UNSET; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); TI_UNLOCK(sc); return; } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ static void ti_shutdown(dev) device_t dev; { struct ti_softc *sc; sc = device_get_softc(dev); TI_LOCK(sc); ti_chipinit(sc); TI_UNLOCK(sc); return; } Index: head/sys/i386/isa/intr_machdep.h =================================================================== --- head/sys/i386/isa/intr_machdep.h (revision 99012) +++ head/sys/i386/isa/intr_machdep.h (revision 99013) @@ -1,241 +1,241 @@ /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _I386_ISA_INTR_MACHDEP_H_ #define _I386_ISA_INTR_MACHDEP_H_ /* * Low level interrupt code. */ #ifdef _KERNEL #if defined(SMP) || defined(APIC_IO) /* * XXX FIXME: rethink location for all IPI vectors. */ /* APIC TPR priority vector levels: 0xff (255) +-------------+ | | 15 (IPIs: Xspuriousint) 0xf0 (240) +-------------+ | | 14 0xe0 (224) +-------------+ | | 13 0xd0 (208) +-------------+ | | 12 0xc0 (192) +-------------+ | | 11 0xb0 (176) +-------------+ | | 10 (IPIs: Xcpustop) 0xa0 (160) +-------------+ | | 9 (IPIs: Xinvltlb) 0x90 (144) +-------------+ | | 8 (linux/BSD syscall, IGNORE FAST HW INTS) 0x80 (128) +-------------+ | | 7 (FAST_INTR 16-23) 0x70 (112) +-------------+ | | 6 (FAST_INTR 0-15) 0x60 (96) +-------------+ | | 5 (IGNORE HW INTS) 0x50 (80) +-------------+ | | 4 (2nd IO APIC) 0x40 (64) +------+------+ | | | 3 (upper APIC hardware INTs: PCI) 0x30 (48) +------+------+ | | 2 (start of hardware INTs: ISA) 0x20 (32) +-------------+ | | 1 (exceptions, traps, etc.) 0x10 (16) +-------------+ | | 0 (exceptions, traps, etc.) 0x00 (0) +-------------+ */ /* IDT vector base for regular (aka. slow) and fast interrupts */ #define TPR_SLOW_INTS 0x20 #define TPR_FAST_INTS 0x60 /* blocking values for local APIC Task Priority Register */ #define TPR_BLOCK_HWI 0x4f /* hardware INTs */ #define TPR_IGNORE_HWI 0x5f /* ignore INTs */ #define TPR_BLOCK_FHWI 0x7f /* hardware FAST INTs */ #define TPR_IGNORE_FHWI 0x8f /* ignore FAST INTs */ #define TPR_BLOCK_XINVLTLB 0x9f /* */ #define TPR_BLOCK_XCPUSTOP 0xaf /* */ #define TPR_BLOCK_ALL 0xff /* all INTs */ #ifdef TEST_TEST1 /* put a 'fake' HWI in top of APIC prio 0x3x, 32 + 31 = 63 = 0x3f */ #define XTEST1_OFFSET (ICU_OFFSET + 31) #endif /** TEST_TEST1 */ /* TLB shootdowns */ #define XINVLTLB_OFFSET (ICU_OFFSET + 112) /* inter-cpu clock handling */ #define XHARDCLOCK_OFFSET (ICU_OFFSET + 113) #define XSTATCLOCK_OFFSET (ICU_OFFSET + 114) /* inter-CPU rendezvous */ #define XRENDEZVOUS_OFFSET (ICU_OFFSET + 115) /* IPI to generate an additional software trap at the target CPU */ #define XCPUAST_OFFSET (ICU_OFFSET + 48) /* IPI to signal CPUs to stop and wait for another CPU to restart them */ #define XCPUSTOP_OFFSET (ICU_OFFSET + 128) /* * Note: this vector MUST be xxxx1111, 32 + 223 = 255 = 0xff: */ #define XSPURIOUSINT_OFFSET (ICU_OFFSET + 223) #endif /* SMP || APIC_IO */ #ifdef LOCORE /* * Protects the IO APIC, 8259 PIC, imen, and apic_imen */ #define ICU_LOCK MTX_LOCK_SPIN(icu_lock, 0) #define ICU_UNLOCK MTX_UNLOCK_SPIN(icu_lock) #else /* LOCORE */ /* * Type of the first (asm) part of an interrupt handler. */ typedef void inthand_t(u_int cs, u_int ef, u_int esp, u_int ss); -typedef void unpendhand_t __P((void)); +typedef void unpendhand_t(void); #define IDTVEC(name) __CONCAT(X,name) extern u_long *intr_countp[]; /* pointers into intrcnt[] */ extern driver_intr_t *intr_handler[]; /* C entry points of intr handlers */ extern struct ithd *ithds[]; extern void *intr_unit[]; /* cookies to pass to intr handlers */ extern struct mtx icu_lock; inthand_t IDTVEC(fastintr0), IDTVEC(fastintr1), IDTVEC(fastintr2), IDTVEC(fastintr3), IDTVEC(fastintr4), IDTVEC(fastintr5), IDTVEC(fastintr6), IDTVEC(fastintr7), IDTVEC(fastintr8), IDTVEC(fastintr9), IDTVEC(fastintr10), IDTVEC(fastintr11), IDTVEC(fastintr12), IDTVEC(fastintr13), IDTVEC(fastintr14), IDTVEC(fastintr15); inthand_t IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); unpendhand_t IDTVEC(fastunpend0), IDTVEC(fastunpend1), IDTVEC(fastunpend2), IDTVEC(fastunpend3), IDTVEC(fastunpend4), IDTVEC(fastunpend5), IDTVEC(fastunpend6), IDTVEC(fastunpend7), IDTVEC(fastunpend8), IDTVEC(fastunpend9), IDTVEC(fastunpend10), IDTVEC(fastunpend11), IDTVEC(fastunpend12), IDTVEC(fastunpend13), IDTVEC(fastunpend14), IDTVEC(fastunpend15), IDTVEC(fastunpend16), IDTVEC(fastunpend17), IDTVEC(fastunpend18), IDTVEC(fastunpend19), IDTVEC(fastunpend20), IDTVEC(fastunpend21), IDTVEC(fastunpend22), IDTVEC(fastunpend23), IDTVEC(fastunpend24), IDTVEC(fastunpend25), IDTVEC(fastunpend26), IDTVEC(fastunpend27), IDTVEC(fastunpend28), IDTVEC(fastunpend29), IDTVEC(fastunpend30), IDTVEC(fastunpend31); #if defined(SMP) || defined(APIC_IO) inthand_t IDTVEC(fastintr16), IDTVEC(fastintr17), IDTVEC(fastintr18), IDTVEC(fastintr19), IDTVEC(fastintr20), IDTVEC(fastintr21), IDTVEC(fastintr22), IDTVEC(fastintr23), IDTVEC(fastintr24), IDTVEC(fastintr25), IDTVEC(fastintr26), IDTVEC(fastintr27), IDTVEC(fastintr28), IDTVEC(fastintr29), IDTVEC(fastintr30), IDTVEC(fastintr31); inthand_t IDTVEC(intr16), IDTVEC(intr17), IDTVEC(intr18), IDTVEC(intr19), IDTVEC(intr20), IDTVEC(intr21), IDTVEC(intr22), IDTVEC(intr23), IDTVEC(intr24), IDTVEC(intr25), IDTVEC(intr26), IDTVEC(intr27), IDTVEC(intr28), IDTVEC(intr29), IDTVEC(intr30), IDTVEC(intr31); inthand_t Xinvltlb, /* TLB shootdowns */ Xhardclock, /* Forward hardclock() */ Xstatclock, /* Forward statclock() */ Xcpuast, /* Additional software trap on other cpu */ Xcpustop, /* CPU stops & waits for another CPU to restart it */ Xspuriousint, /* handle APIC "spurious INTs" */ Xrendezvous; /* handle CPU rendezvous */ #ifdef TEST_TEST1 inthand_t Xtest1; /* 'fake' HWI at top of APIC prio 0x3x, 32+31 = 0x3f */ #endif /** TEST_TEST1 */ #endif /* SMP || APIC_IO */ #ifdef APIC_IO /* * This is to accommodate "mixed-mode" programming for * motherboards that don't connect the 8254 to the IO APIC. */ #define AUTO_EOI_1 1 #endif #define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN) void isa_defaultirq(void); int isa_nmi(int cd); int icu_setup(int intr, driver_intr_t *func, void *arg, int flags); int icu_unset(int intr, driver_intr_t *handler); void icu_reinit(void); /* * WARNING: These are internal functions and not to be used by device drivers! * They are subject to change without notice. */ int inthand_add(const char *name, int irq, driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep); int inthand_remove(void *cookie); void sched_ithd(void *dummy); void call_fast_unpend(int irq); #endif /* LOCORE */ #endif /* _KERNEL */ #endif /* !_I386_ISA_INTR_MACHDEP_H_ */ Index: head/sys/pci/if_ti.c =================================================================== --- head/sys/pci/if_ti.c (revision 99012) +++ head/sys/pci/if_ti.c (revision 99013) @@ -1,3628 +1,3628 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * Alteon Networks Tigon PCI gigabit ethernet driver for FreeBSD. * Manuals, sample driver and firmware source kits are available * from http://www.alteon.com/support/openkits. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ /* * The Alteon Networks Tigon chip contains an embedded R4000 CPU, * gigabit MAC, dual DMA channels and a PCI interface unit. NICs * using the Tigon may have anywhere from 512K to 2MB of SRAM. The * Tigon supports hardware IP, TCP and UCP checksumming, multicast * filtering and jumbo (9014 byte) frames. The hardware is largely * controlled by firmware, which must be loaded into the NIC during * initialization. * * The Tigon 2 contains 2 R4000 CPUs and requires a newer firmware * revision, which supports new features such as extended commands, * extended jumbo receive ring desciptors and a mini receive ring. * * Alteon Networks is to be commended for releasing such a vast amount * of development material for the Tigon NIC without requiring an NDA * (although they really should have done it a long time ago). With * any luck, the other vendors will finally wise up and follow Alteon's * stellar example. * * The firmware for the Tigon 1 and 2 NICs is compiled directly into * this driver by #including it as a C header file. This bloats the * driver somewhat, but it's the easiest method considering that the * driver code and firmware code need to be kept in sync. The source * for the firmware is not provided with the FreeBSD distribution since * compiling it requires a GNU toolchain targeted for mips-sgi-irix5.3. * * The following people deserve special thanks: * - Terry Murphy of 3Com, for providing a 3c985 Tigon 1 board * for testing * - Raymond Lee of Netgear, for providing a pair of Netgear * GA620 Tigon 2 boards for testing * - Ulf Zimmermann, for bringing the GA260 to my attention and * convincing me to write this driver. * - Andrew Gallatin for providing FreeBSD/Alpha support. */ #include "opt_ti.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for vtophys */ #include /* for vtophys */ #include #include #include #include #include /* #define TI_PRIVATE_JUMBOS */ #if !defined(TI_PRIVATE_JUMBOS) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* !TI_PRIVATE_JUMBOS */ #include /* for vfindev, vgone */ #include #include #include #include #include #include #define TI_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_IP_FRAGS) /* * We can only turn on header splitting if we're using extended receive * BDs. */ #if defined(TI_JUMBO_HDRSPLIT) && defined(TI_PRIVATE_JUMBOS) #error "options TI_JUMBO_HDRSPLIT and TI_PRIVATE_JUMBOS are mutually exclusive" #endif /* TI_JUMBO_HDRSPLIT && TI_JUMBO_HDRSPLIT */ #if !defined(lint) static const char rcsid[] = "$FreeBSD$"; #endif struct ti_softc *tis[8]; typedef enum { TI_SWAP_HTON, TI_SWAP_NTOH } ti_swap_type; /* * Various supported device vendors/types and their names. */ static struct ti_type ti_devs[] = { { ALT_VENDORID, ALT_DEVICEID_ACENIC, "Alteon AceNIC 1000baseSX Gigabit Ethernet" }, { ALT_VENDORID, ALT_DEVICEID_ACENIC_COPPER, "Alteon AceNIC 1000baseT Gigabit Ethernet" }, { TC_VENDORID, TC_DEVICEID_3C985, "3Com 3c985-SX Gigabit Ethernet" }, { NG_VENDORID, NG_DEVICEID_GA620, "Netgear GA620 1000baseSX Gigabit Ethernet" }, { NG_VENDORID, NG_DEVICEID_GA620T, "Netgear GA620 1000baseT Gigabit Ethernet" }, { SGI_VENDORID, SGI_DEVICEID_TIGON, "Silicon Graphics Gigabit Ethernet" }, { DEC_VENDORID, DEC_DEVICEID_FARALLON_PN9000SX, "Farallon PN9000SX Gigabit Ethernet" }, { 0, 0, NULL } }; #define TI_CDEV_MAJOR 153 static d_open_t ti_open; static d_close_t ti_close; static d_ioctl_t ti_ioctl2; static struct cdevsw ti_cdevsw = { /* open */ ti_open, /* close */ ti_close, /* read */ NULL, /* write */ NULL, /* ioctl */ ti_ioctl2, /* poll */ seltrue, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "ti", /* maj */ TI_CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, }; static int ti_probe (device_t); static int ti_attach (device_t); static int ti_detach (device_t); static void ti_txeof (struct ti_softc *); static void ti_rxeof (struct ti_softc *); static void ti_stats_update (struct ti_softc *); static int ti_encap (struct ti_softc *, struct mbuf *, u_int32_t *); static void ti_intr (void *); static void ti_start (struct ifnet *); static int ti_ioctl (struct ifnet *, u_long, caddr_t); static void ti_init (void *); static void ti_init2 (struct ti_softc *); static void ti_stop (struct ti_softc *); static void ti_watchdog (struct ifnet *); static void ti_shutdown (device_t); static int ti_ifmedia_upd (struct ifnet *); static void ti_ifmedia_sts (struct ifnet *, struct ifmediareq *); static u_int32_t ti_eeprom_putbyte (struct ti_softc *, int); static u_int8_t ti_eeprom_getbyte (struct ti_softc *, int, u_int8_t *); static int ti_read_eeprom (struct ti_softc *, caddr_t, int, int); static void ti_add_mcast (struct ti_softc *, struct ether_addr *); static void ti_del_mcast (struct ti_softc *, struct ether_addr *); static void ti_setmulti (struct ti_softc *); static void ti_mem (struct ti_softc *, u_int32_t, u_int32_t, caddr_t); static int ti_copy_mem (struct ti_softc *, u_int32_t, u_int32_t, caddr_t, int, int); static int ti_copy_scratch (struct ti_softc *, u_int32_t, u_int32_t, caddr_t, int, int, int); static int ti_bcopy_swap (const void *, void *, size_t, ti_swap_type); static void ti_loadfw (struct ti_softc *); static void ti_cmd (struct ti_softc *, struct ti_cmd_desc *); static void ti_cmd_ext (struct ti_softc *, struct ti_cmd_desc *, caddr_t, int); static void ti_handle_events (struct ti_softc *); #ifdef TI_PRIVATE_JUMBOS static int ti_alloc_jumbo_mem (struct ti_softc *); static void *ti_jalloc (struct ti_softc *); static void ti_jfree (caddr_t, void *); #endif /* TI_PRIVATE_JUMBOS */ static int ti_newbuf_std (struct ti_softc *, int, struct mbuf *); static int ti_newbuf_mini (struct ti_softc *, int, struct mbuf *); static int ti_newbuf_jumbo (struct ti_softc *, int, struct mbuf *); static int ti_init_rx_ring_std (struct ti_softc *); static void ti_free_rx_ring_std (struct ti_softc *); static int ti_init_rx_ring_jumbo (struct ti_softc *); static void ti_free_rx_ring_jumbo (struct ti_softc *); static int ti_init_rx_ring_mini (struct ti_softc *); static void ti_free_rx_ring_mini (struct ti_softc *); static void ti_free_tx_ring (struct ti_softc *); static int ti_init_tx_ring (struct ti_softc *); static int ti_64bitslot_war (struct ti_softc *); static int ti_chipinit (struct ti_softc *); static int ti_gibinit (struct ti_softc *); #ifdef TI_JUMBO_HDRSPLIT -static __inline void ti_hdr_split __P((struct mbuf *top, int hdr_len, - int pkt_len, int idx)); +static __inline void ti_hdr_split (struct mbuf *top, int hdr_len, + int pkt_len, int idx); #endif /* TI_JUMBO_HDRSPLIT */ static device_method_t ti_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ti_probe), DEVMETHOD(device_attach, ti_attach), DEVMETHOD(device_detach, ti_detach), DEVMETHOD(device_shutdown, ti_shutdown), { 0, 0 } }; static driver_t ti_driver = { "ti", ti_methods, sizeof(struct ti_softc) }; static devclass_t ti_devclass; DRIVER_MODULE(if_ti, pci, ti_driver, ti_devclass, 0, 0); /* List of Tigon softcs */ static STAILQ_HEAD(ti_softc_list, ti_softc) ti_sc_list; static struct ti_softc * ti_lookup_softc(int unit) { struct ti_softc *sc; for (sc = STAILQ_FIRST(&ti_sc_list); sc != NULL; sc = STAILQ_NEXT(sc, ti_links)) if (sc->ti_unit == unit) return(sc); return(NULL); } /* * Send an instruction or address to the EEPROM, check for ACK. */ static u_int32_t ti_eeprom_putbyte(sc, byte) struct ti_softc *sc; int byte; { register int i, ack = 0; /* * Make sure we're in TX mode. */ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* * Feed in each bit and stobe the clock. */ for (i = 0x80; i; i >>= 1) { if (byte & i) { TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); } else { TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_DOUT); } DELAY(1); TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); DELAY(1); TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); } /* * Turn off TX mode. */ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); /* * Check for ack. */ TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); ack = CSR_READ_4(sc, TI_MISC_LOCAL_CTL) & TI_MLC_EE_DIN; TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); return(ack); } /* * Read a byte of data stored in the EEPROM at address 'addr.' * We have to send two address bytes since the EEPROM can hold * more than 256 bytes of data. */ static u_int8_t ti_eeprom_getbyte(sc, addr, dest) struct ti_softc *sc; int addr; u_int8_t *dest; { register int i; u_int8_t byte = 0; EEPROM_START; /* * Send write control code to EEPROM. */ if (ti_eeprom_putbyte(sc, EEPROM_CTL_WRITE)) { printf("ti%d: failed to send write command, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } /* * Send first byte of address of byte we want to read. */ if (ti_eeprom_putbyte(sc, (addr >> 8) & 0xFF)) { printf("ti%d: failed to send address, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } /* * Send second byte address of byte we want to read. */ if (ti_eeprom_putbyte(sc, addr & 0xFF)) { printf("ti%d: failed to send address, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } EEPROM_STOP; EEPROM_START; /* * Send read control code to EEPROM. */ if (ti_eeprom_putbyte(sc, EEPROM_CTL_READ)) { printf("ti%d: failed to send read command, status: %x\n", sc->ti_unit, CSR_READ_4(sc, TI_MISC_LOCAL_CTL)); return(1); } /* * Start reading bits from EEPROM. */ TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_TXEN); for (i = 0x80; i; i >>= 1) { TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); DELAY(1); if (CSR_READ_4(sc, TI_MISC_LOCAL_CTL) & TI_MLC_EE_DIN) byte |= i; TI_CLRBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_EE_CLK); DELAY(1); } EEPROM_STOP; /* * No ACK generated for read, so just return byte. */ *dest = byte; return(0); } /* * Read a sequence of bytes from the EEPROM. */ static int ti_read_eeprom(sc, dest, off, cnt) struct ti_softc *sc; caddr_t dest; int off; int cnt; { int err = 0, i; u_int8_t byte = 0; for (i = 0; i < cnt; i++) { err = ti_eeprom_getbyte(sc, off + i, &byte); if (err) break; *(dest + i) = byte; } return(err ? 1 : 0); } /* * NIC memory access function. Can be used to either clear a section * of NIC local memory or (if buf is non-NULL) copy data into it. */ static void ti_mem(sc, addr, len, buf) struct ti_softc *sc; u_int32_t addr, len; caddr_t buf; { int segptr, segsize, cnt; caddr_t ti_winbase, ptr; segptr = addr; cnt = len; ti_winbase = (caddr_t)(sc->ti_vhandle + TI_WINDOW); ptr = buf; while(cnt) { if (cnt < TI_WINLEN) segsize = cnt; else segsize = TI_WINLEN - (segptr % TI_WINLEN); CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1))); if (buf == NULL) bzero((char *)ti_winbase + (segptr & (TI_WINLEN - 1)), segsize); else { bcopy((char *)ptr, (char *)ti_winbase + (segptr & (TI_WINLEN - 1)), segsize); ptr += segsize; } segptr += segsize; cnt -= segsize; } return; } static int ti_copy_mem(sc, tigon_addr, len, buf, useraddr, readdata) struct ti_softc *sc; u_int32_t tigon_addr, len; caddr_t buf; int useraddr, readdata; { int segptr, segsize, cnt; caddr_t ptr; u_int32_t origwin; u_int8_t tmparray[TI_WINLEN], tmparray2[TI_WINLEN]; int resid, segresid; int first_pass; /* * At the moment, we don't handle non-aligned cases, we just bail. * If this proves to be a problem, it will be fixed. */ if ((readdata == 0) && (tigon_addr & 0x3)) { printf("ti%d: ti_copy_mem: tigon address %#x isn't " "word-aligned\n", sc->ti_unit, tigon_addr); printf("ti%d: ti_copy_mem: unaligned writes aren't yet " "supported\n", sc->ti_unit); return(EINVAL); } segptr = tigon_addr & ~0x3; segresid = tigon_addr - segptr; /* * This is the non-aligned amount left over that we'll need to * copy. */ resid = len & 0x3; /* Add in the left over amount at the front of the buffer */ resid += segresid; cnt = len & ~0x3; /* * If resid + segresid is >= 4, add multiples of 4 to the count and * decrease the residual by that much. */ cnt += resid & ~0x3; resid -= resid & ~0x3; ptr = buf; first_pass = 1; /* * Make sure we aren't interrupted while we're changing the window * pointer. */ TI_LOCK(sc); /* * Save the old window base value. */ origwin = CSR_READ_4(sc, TI_WINBASE); while(cnt) { bus_size_t ti_offset; if (cnt < TI_WINLEN) segsize = cnt; else segsize = TI_WINLEN - (segptr % TI_WINLEN); CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1))); ti_offset = TI_WINDOW + (segptr & (TI_WINLEN -1)); if (readdata) { bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, (u_int32_t *)tmparray, segsize >> 2); if (useraddr) { /* * Yeah, this is a little on the kludgy * side, but at least this code is only * used for debugging. */ ti_bcopy_swap(tmparray, tmparray2, segsize, TI_SWAP_NTOH); if (first_pass) { copyout(&tmparray2[segresid], ptr, segsize - segresid); first_pass = 0; } else copyout(tmparray2, ptr, segsize); } else { if (first_pass) { ti_bcopy_swap(tmparray, tmparray2, segsize, TI_SWAP_NTOH); bcopy(&tmparray2[segresid], ptr, segsize - segresid); first_pass = 0; } else ti_bcopy_swap(tmparray, ptr, segsize, TI_SWAP_NTOH); } } else { if (useraddr) { copyin(ptr, tmparray2, segsize); ti_bcopy_swap(tmparray2, tmparray, segsize, TI_SWAP_HTON); } else ti_bcopy_swap(ptr, tmparray, segsize, TI_SWAP_HTON); bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, (u_int32_t *)tmparray, segsize >> 2); } segptr += segsize; ptr += segsize; cnt -= segsize; } /* * Handle leftover, non-word-aligned bytes. */ if (resid != 0) { u_int32_t tmpval, tmpval2; bus_size_t ti_offset; /* * Set the segment pointer. */ CSR_WRITE_4(sc, TI_WINBASE, (segptr & ~(TI_WINLEN - 1))); ti_offset = TI_WINDOW + (segptr & (TI_WINLEN - 1)); /* * First, grab whatever is in our source/destination. * We'll obviously need this for reads, but also for * writes, since we'll be doing read/modify/write. */ bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, &tmpval, 1); /* * Next, translate this from little-endian to big-endian * (at least on i386 boxes). */ tmpval2 = ntohl(tmpval); if (readdata) { /* * If we're reading, just copy the leftover number * of bytes from the host byte order buffer to * the user's buffer. */ if (useraddr) copyout(&tmpval2, ptr, resid); else bcopy(&tmpval2, ptr, resid); } else { /* * If we're writing, first copy the bytes to be * written into the network byte order buffer, * leaving the rest of the buffer with whatever was * originally in there. Then, swap the bytes * around into host order and write them out. * * XXX KDM the read side of this has been verified * to work, but the write side of it has not been * verified. So user beware. */ if (useraddr) copyin(ptr, &tmpval2, resid); else bcopy(ptr, &tmpval2, resid); tmpval = htonl(tmpval2); bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle, ti_offset, &tmpval, 1); } } CSR_WRITE_4(sc, TI_WINBASE, origwin); TI_UNLOCK(sc); return(0); } static int ti_copy_scratch(sc, tigon_addr, len, buf, useraddr, readdata, cpu) struct ti_softc *sc; u_int32_t tigon_addr, len; caddr_t buf; int useraddr, readdata; int cpu; { u_int32_t segptr; int cnt; u_int32_t tmpval, tmpval2; caddr_t ptr; /* * At the moment, we don't handle non-aligned cases, we just bail. * If this proves to be a problem, it will be fixed. */ if (tigon_addr & 0x3) { printf("ti%d: ti_copy_scratch: tigon address %#x isn't " "word-aligned\n", sc->ti_unit, tigon_addr); return(EINVAL); } if (len & 0x3) { printf("ti%d: ti_copy_scratch: transfer length %d isn't " "word-aligned\n", sc->ti_unit, len); return(EINVAL); } segptr = tigon_addr; cnt = len; ptr = buf; TI_LOCK(sc); while (cnt) { CSR_WRITE_4(sc, CPU_REG(TI_SRAM_ADDR, cpu), segptr); if (readdata) { tmpval2 = CSR_READ_4(sc, CPU_REG(TI_SRAM_DATA, cpu)); tmpval = ntohl(tmpval2); /* * Note: I've used this debugging interface * extensively with Alteon's 12.3.15 firmware, * compiled with GCC 2.7.2.1 and binutils 2.9.1. * * When you compile the firmware without * optimization, which is necessary sometimes in * order to properly step through it, you sometimes * read out a bogus value of 0xc0017c instead of * whatever was supposed to be in that scratchpad * location. That value is on the stack somewhere, * but I've never been able to figure out what was * causing the problem. * * The address seems to pop up in random places, * often not in the same place on two subsequent * reads. * * In any case, the underlying data doesn't seem * to be affected, just the value read out. * * KDM, 3/7/2000 */ if (tmpval2 == 0xc0017c) printf("ti%d: found 0xc0017c at %#x " "(tmpval2)\n", sc->ti_unit, segptr); if (tmpval == 0xc0017c) printf("ti%d: found 0xc0017c at %#x " "(tmpval)\n", sc->ti_unit, segptr); if (useraddr) copyout(&tmpval, ptr, 4); else bcopy(&tmpval, ptr, 4); } else { if (useraddr) copyin(ptr, &tmpval2, 4); else bcopy(ptr, &tmpval2, 4); tmpval = htonl(tmpval2); CSR_WRITE_4(sc, CPU_REG(TI_SRAM_DATA, cpu), tmpval); } cnt -= 4; segptr += 4; ptr += 4; } TI_UNLOCK(sc); return(0); } static int ti_bcopy_swap(src, dst, len, swap_type) const void *src; void *dst; size_t len; ti_swap_type swap_type; { const u_int8_t *tmpsrc; u_int8_t *tmpdst; size_t tmplen; if (len & 0x3) { printf("ti_bcopy_swap: length %d isn't 32-bit aligned\n", len); return(-1); } tmpsrc = src; tmpdst = dst; tmplen = len; while (tmplen) { if (swap_type == TI_SWAP_NTOH) *(u_int32_t *)tmpdst = ntohl(*(const u_int32_t *)tmpsrc); else *(u_int32_t *)tmpdst = htonl(*(const u_int32_t *)tmpsrc); tmpsrc += 4; tmpdst += 4; tmplen -= 4; } return(0); } /* * Load firmware image into the NIC. Check that the firmware revision * is acceptable and see if we want the firmware for the Tigon 1 or * Tigon 2. */ static void ti_loadfw(sc) struct ti_softc *sc; { switch(sc->ti_hwrev) { case TI_HWREV_TIGON: if (tigonFwReleaseMajor != TI_FIRMWARE_MAJOR || tigonFwReleaseMinor != TI_FIRMWARE_MINOR || tigonFwReleaseFix != TI_FIRMWARE_FIX) { printf("ti%d: firmware revision mismatch; want " "%d.%d.%d, got %d.%d.%d\n", sc->ti_unit, TI_FIRMWARE_MAJOR, TI_FIRMWARE_MINOR, TI_FIRMWARE_FIX, tigonFwReleaseMajor, tigonFwReleaseMinor, tigonFwReleaseFix); return; } ti_mem(sc, tigonFwTextAddr, tigonFwTextLen, (caddr_t)tigonFwText); ti_mem(sc, tigonFwDataAddr, tigonFwDataLen, (caddr_t)tigonFwData); ti_mem(sc, tigonFwRodataAddr, tigonFwRodataLen, (caddr_t)tigonFwRodata); ti_mem(sc, tigonFwBssAddr, tigonFwBssLen, NULL); ti_mem(sc, tigonFwSbssAddr, tigonFwSbssLen, NULL); CSR_WRITE_4(sc, TI_CPU_PROGRAM_COUNTER, tigonFwStartAddr); break; case TI_HWREV_TIGON_II: if (tigon2FwReleaseMajor != TI_FIRMWARE_MAJOR || tigon2FwReleaseMinor != TI_FIRMWARE_MINOR || tigon2FwReleaseFix != TI_FIRMWARE_FIX) { printf("ti%d: firmware revision mismatch; want " "%d.%d.%d, got %d.%d.%d\n", sc->ti_unit, TI_FIRMWARE_MAJOR, TI_FIRMWARE_MINOR, TI_FIRMWARE_FIX, tigon2FwReleaseMajor, tigon2FwReleaseMinor, tigon2FwReleaseFix); return; } ti_mem(sc, tigon2FwTextAddr, tigon2FwTextLen, (caddr_t)tigon2FwText); ti_mem(sc, tigon2FwDataAddr, tigon2FwDataLen, (caddr_t)tigon2FwData); ti_mem(sc, tigon2FwRodataAddr, tigon2FwRodataLen, (caddr_t)tigon2FwRodata); ti_mem(sc, tigon2FwBssAddr, tigon2FwBssLen, NULL); ti_mem(sc, tigon2FwSbssAddr, tigon2FwSbssLen, NULL); CSR_WRITE_4(sc, TI_CPU_PROGRAM_COUNTER, tigon2FwStartAddr); break; default: printf("ti%d: can't load firmware: unknown hardware rev\n", sc->ti_unit); break; } return; } /* * Send the NIC a command via the command ring. */ static void ti_cmd(sc, cmd) struct ti_softc *sc; struct ti_cmd_desc *cmd; { u_int32_t index; if (sc->ti_rdata->ti_cmd_ring == NULL) return; index = sc->ti_cmd_saved_prodidx; CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(cmd)); TI_INC(index, TI_CMD_RING_CNT); CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, index); sc->ti_cmd_saved_prodidx = index; return; } /* * Send the NIC an extended command. The 'len' parameter specifies the * number of command slots to include after the initial command. */ static void ti_cmd_ext(sc, cmd, arg, len) struct ti_softc *sc; struct ti_cmd_desc *cmd; caddr_t arg; int len; { u_int32_t index; register int i; if (sc->ti_rdata->ti_cmd_ring == NULL) return; index = sc->ti_cmd_saved_prodidx; CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(cmd)); TI_INC(index, TI_CMD_RING_CNT); for (i = 0; i < len; i++) { CSR_WRITE_4(sc, TI_GCR_CMDRING + (index * 4), *(u_int32_t *)(&arg[i * 4])); TI_INC(index, TI_CMD_RING_CNT); } CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, index); sc->ti_cmd_saved_prodidx = index; return; } /* * Handle events that have triggered interrupts. */ static void ti_handle_events(sc) struct ti_softc *sc; { struct ti_event_desc *e; if (sc->ti_rdata->ti_event_ring == NULL) return; while (sc->ti_ev_saved_considx != sc->ti_ev_prodidx.ti_idx) { e = &sc->ti_rdata->ti_event_ring[sc->ti_ev_saved_considx]; switch(e->ti_event) { case TI_EV_LINKSTAT_CHANGED: sc->ti_linkstat = e->ti_code; if (e->ti_code == TI_EV_CODE_LINK_UP) printf("ti%d: 10/100 link up\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_GIG_LINK_UP) printf("ti%d: gigabit link up\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_LINK_DOWN) printf("ti%d: link down\n", sc->ti_unit); break; case TI_EV_ERROR: if (e->ti_code == TI_EV_CODE_ERR_INVAL_CMD) printf("ti%d: invalid command\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_ERR_UNIMP_CMD) printf("ti%d: unknown command\n", sc->ti_unit); else if (e->ti_code == TI_EV_CODE_ERR_BADCFG) printf("ti%d: bad config data\n", sc->ti_unit); break; case TI_EV_FIRMWARE_UP: ti_init2(sc); break; case TI_EV_STATS_UPDATED: ti_stats_update(sc); break; case TI_EV_RESET_JUMBO_RING: case TI_EV_MCAST_UPDATED: /* Who cares. */ break; default: printf("ti%d: unknown event: %d\n", sc->ti_unit, e->ti_event); break; } /* Advance the consumer index. */ TI_INC(sc->ti_ev_saved_considx, TI_EVENT_RING_CNT); CSR_WRITE_4(sc, TI_GCR_EVENTCONS_IDX, sc->ti_ev_saved_considx); } return; } #ifdef TI_PRIVATE_JUMBOS /* * Memory management for the jumbo receive ring is a pain in the * butt. We need to allocate at least 9018 bytes of space per frame, * _and_ it has to be contiguous (unless you use the extended * jumbo descriptor format). Using malloc() all the time won't * work: malloc() allocates memory in powers of two, which means we * would end up wasting a considerable amount of space by allocating * 9K chunks. We don't have a jumbo mbuf cluster pool. Thus, we have * to do our own memory management. * * The driver needs to allocate a contiguous chunk of memory at boot * time. We then chop this up ourselves into 9K pieces and use them * as external mbuf storage. * * One issue here is how much memory to allocate. The jumbo ring has * 256 slots in it, but at 9K per slot than can consume over 2MB of * RAM. This is a bit much, especially considering we also need * RAM for the standard ring and mini ring (on the Tigon 2). To * save space, we only actually allocate enough memory for 64 slots * by default, which works out to between 500 and 600K. This can * be tuned by changing a #define in if_tireg.h. */ static int ti_alloc_jumbo_mem(sc) struct ti_softc *sc; { caddr_t ptr; register int i; struct ti_jpool_entry *entry; /* Grab a big chunk o' storage. */ sc->ti_cdata.ti_jumbo_buf = contigmalloc(TI_JMEM, M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); if (sc->ti_cdata.ti_jumbo_buf == NULL) { printf("ti%d: no memory for jumbo buffers!\n", sc->ti_unit); return(ENOBUFS); } SLIST_INIT(&sc->ti_jfree_listhead); SLIST_INIT(&sc->ti_jinuse_listhead); /* * Now divide it up into 9K pieces and save the addresses * in an array. */ ptr = sc->ti_cdata.ti_jumbo_buf; for (i = 0; i < TI_JSLOTS; i++) { sc->ti_cdata.ti_jslots[i] = ptr; ptr += TI_JLEN; entry = malloc(sizeof(struct ti_jpool_entry), M_DEVBUF, M_NOWAIT); if (entry == NULL) { contigfree(sc->ti_cdata.ti_jumbo_buf, TI_JMEM, M_DEVBUF); sc->ti_cdata.ti_jumbo_buf = NULL; printf("ti%d: no memory for jumbo " "buffer queue!\n", sc->ti_unit); return(ENOBUFS); } entry->slot = i; SLIST_INSERT_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries); } return(0); } /* * Allocate a jumbo buffer. */ static void *ti_jalloc(sc) struct ti_softc *sc; { struct ti_jpool_entry *entry; entry = SLIST_FIRST(&sc->ti_jfree_listhead); if (entry == NULL) { printf("ti%d: no free jumbo buffers\n", sc->ti_unit); return(NULL); } SLIST_REMOVE_HEAD(&sc->ti_jfree_listhead, jpool_entries); SLIST_INSERT_HEAD(&sc->ti_jinuse_listhead, entry, jpool_entries); return(sc->ti_cdata.ti_jslots[entry->slot]); } /* * Release a jumbo buffer. */ static void ti_jfree(buf, args) caddr_t buf; void *args; { struct ti_softc *sc; int i; struct ti_jpool_entry *entry; /* Extract the softc struct pointer. */ sc = (struct ti_softc *)args; if (sc == NULL) panic("ti_jfree: didn't get softc pointer!"); /* calculate the slot this buffer belongs to */ i = ((vm_offset_t)buf - (vm_offset_t)sc->ti_cdata.ti_jumbo_buf) / TI_JLEN; if ((i < 0) || (i >= TI_JSLOTS)) panic("ti_jfree: asked to free buffer that we don't manage!"); entry = SLIST_FIRST(&sc->ti_jinuse_listhead); if (entry == NULL) panic("ti_jfree: buffer not in use!"); entry->slot = i; SLIST_REMOVE_HEAD(&sc->ti_jinuse_listhead, jpool_entries); SLIST_INSERT_HEAD(&sc->ti_jfree_listhead, entry, jpool_entries); return; } #endif /* TI_PRIVATE_JUMBOS */ /* * Intialize a standard receive ring descriptor. */ static int ti_newbuf_std(sc, i, m) struct ti_softc *sc; int i; struct mbuf *m; { struct mbuf *m_new = NULL; struct ti_rx_desc *r; if (m == NULL) { MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) return(ENOBUFS); MCLGET(m_new, M_DONTWAIT); if (!(m_new->m_flags & M_EXT)) { m_freem(m_new); return(ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; } else { m_new = m; m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; m_new->m_data = m_new->m_ext.ext_buf; } m_adj(m_new, ETHER_ALIGN); sc->ti_cdata.ti_rx_std_chain[i] = m_new; r = &sc->ti_rdata->ti_rx_std_ring[i]; TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t)); r->ti_type = TI_BDTYPE_RECV_BD; r->ti_flags = 0; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM; r->ti_len = m_new->m_len; r->ti_idx = i; return(0); } /* * Intialize a mini receive ring descriptor. This only applies to * the Tigon 2. */ static int ti_newbuf_mini(sc, i, m) struct ti_softc *sc; int i; struct mbuf *m; { struct mbuf *m_new = NULL; struct ti_rx_desc *r; if (m == NULL) { MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { return(ENOBUFS); } m_new->m_len = m_new->m_pkthdr.len = MHLEN; } else { m_new = m; m_new->m_data = m_new->m_pktdat; m_new->m_len = m_new->m_pkthdr.len = MHLEN; } m_adj(m_new, ETHER_ALIGN); r = &sc->ti_rdata->ti_rx_mini_ring[i]; sc->ti_cdata.ti_rx_mini_chain[i] = m_new; TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t)); r->ti_type = TI_BDTYPE_RECV_BD; r->ti_flags = TI_BDFLAG_MINI_RING; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM; r->ti_len = m_new->m_len; r->ti_idx = i; return(0); } #ifdef TI_PRIVATE_JUMBOS /* * Initialize a jumbo receive ring descriptor. This allocates * a jumbo buffer from the pool managed internally by the driver. */ static int ti_newbuf_jumbo(sc, i, m) struct ti_softc *sc; int i; struct mbuf *m; { struct mbuf *m_new = NULL; struct ti_rx_desc *r; if (m == NULL) { caddr_t *buf = NULL; /* Allocate the mbuf. */ MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { return(ENOBUFS); } /* Allocate the jumbo buffer */ buf = ti_jalloc(sc); if (buf == NULL) { m_freem(m_new); printf("ti%d: jumbo allocation failed " "-- packet dropped!\n", sc->ti_unit); return(ENOBUFS); } /* Attach the buffer to the mbuf. */ m_new->m_data = (void *) buf; m_new->m_len = m_new->m_pkthdr.len = TI_JUMBO_FRAMELEN; MEXTADD(m_new, buf, TI_JUMBO_FRAMELEN, ti_jfree, (struct ti_softc *)sc, 0, EXT_NET_DRV); } else { m_new = m; m_new->m_data = m_new->m_ext.ext_buf; m_new->m_ext.ext_size = TI_JUMBO_FRAMELEN; } m_adj(m_new, ETHER_ALIGN); /* Set up the descriptor. */ r = &sc->ti_rdata->ti_rx_jumbo_ring[i]; sc->ti_cdata.ti_rx_jumbo_chain[i] = m_new; TI_HOSTADDR(r->ti_addr) = vtophys(mtod(m_new, caddr_t)); r->ti_type = TI_BDTYPE_RECV_JUMBO_BD; r->ti_flags = TI_BDFLAG_JUMBO_RING; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM | TI_BDFLAG_IP_CKSUM; r->ti_len = m_new->m_len; r->ti_idx = i; return(0); } #else #include #if (PAGE_SIZE == 4096) #define NPAYLOAD 2 #else #define NPAYLOAD 1 #endif #define TCP_HDR_LEN (52 + sizeof(struct ether_header)) #define UDP_HDR_LEN (28 + sizeof(struct ether_header)) #define NFS_HDR_LEN (UDP_HDR_LEN) int HDR_LEN = TCP_HDR_LEN; /* * Initialize a jumbo receive ring descriptor. This allocates * a jumbo buffer from the pool managed internally by the driver. */ static int ti_newbuf_jumbo(sc, idx, m_old) struct ti_softc *sc; int idx; struct mbuf *m_old; { struct mbuf *cur, *m_new = NULL; struct mbuf *m[3] = {NULL, NULL, NULL}; struct ti_rx_desc_ext *r; vm_page_t frame; /* 1 extra buf to make nobufs easy*/ caddr_t buf[3] = {NULL, NULL, NULL}; int i; if (m_old != NULL) { m_new = m_old; cur = m_old->m_next; for (i = 0; i <= NPAYLOAD; i++){ m[i] = cur; cur = cur->m_next; } } else { /* Allocate the mbufs. */ MGETHDR(m_new, M_DONTWAIT, MT_DATA); if (m_new == NULL) { printf("ti%d: mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } MGET(m[NPAYLOAD], M_DONTWAIT, MT_DATA); if (m[NPAYLOAD] == NULL) { printf("ti%d: cluster mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } MCLGET(m[NPAYLOAD], M_DONTWAIT); if ((m[NPAYLOAD]->m_flags & M_EXT) == 0) { printf("ti%d: mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } m[NPAYLOAD]->m_len = MCLBYTES; for (i = 0; i < NPAYLOAD; i++){ MGET(m[i], M_DONTWAIT, MT_DATA); if (m[i] == NULL) { printf("ti%d: mbuf allocation failed " "-- packet dropped!\n", sc->ti_unit); goto nobufs; } if (!(frame = jumbo_pg_alloc())){ printf("ti%d: buffer allocation failed " "-- packet dropped!\n", sc->ti_unit); printf(" index %d page %d\n", idx, i); goto nobufs; } buf[i] = jumbo_phys_to_kva(VM_PAGE_TO_PHYS(frame)); } for (i = 0; i < NPAYLOAD; i++){ /* Attach the buffer to the mbuf. */ m[i]->m_data = (void *)buf[i]; m[i]->m_len = PAGE_SIZE; MEXTADD(m[i], (void *)buf[i], PAGE_SIZE, jumbo_freem, NULL, 0, EXT_DISPOSABLE); m[i]->m_next = m[i+1]; } /* link the buffers to the header */ m_new->m_next = m[0]; m_new->m_data += ETHER_ALIGN; if (sc->ti_hdrsplit) m_new->m_len = MHLEN - ETHER_ALIGN; else m_new->m_len = HDR_LEN; m_new->m_pkthdr.len = NPAYLOAD * PAGE_SIZE + m_new->m_len; } /* Set up the descriptor. */ r = &sc->ti_rdata->ti_rx_jumbo_ring[idx]; sc->ti_cdata.ti_rx_jumbo_chain[idx] = m_new; TI_HOSTADDR(r->ti_addr0) = vtophys(mtod(m_new, caddr_t)); r->ti_len0 = m_new->m_len; TI_HOSTADDR(r->ti_addr1) = vtophys(mtod(m[0], caddr_t)); r->ti_len1 = PAGE_SIZE; TI_HOSTADDR(r->ti_addr2) = vtophys(mtod(m[1], caddr_t)); r->ti_len2 = m[1]->m_ext.ext_size; /* could be PAGE_SIZE or MCLBYTES */ if (PAGE_SIZE == 4096) { TI_HOSTADDR(r->ti_addr3) = vtophys(mtod(m[2], caddr_t)); r->ti_len3 = MCLBYTES; } else { r->ti_len3 = 0; } r->ti_type = TI_BDTYPE_RECV_JUMBO_BD; r->ti_flags = TI_BDFLAG_JUMBO_RING|TI_RCB_FLAG_USE_EXT_RX_BD; if (sc->arpcom.ac_if.if_hwassist) r->ti_flags |= TI_BDFLAG_TCP_UDP_CKSUM|TI_BDFLAG_IP_CKSUM; r->ti_idx = idx; return(0); nobufs: /* * Warning! : * This can only be called before the mbufs are strung together. * If the mbufs are strung together, m_freem() will free the chain, * so that the later mbufs will be freed multiple times. */ if (m_new) m_freem(m_new); for(i = 0; i < 3; i++){ if (m[i]) m_freem(m[i]); if (buf[i]) jumbo_pg_free((vm_offset_t)buf[i]); } return ENOBUFS; } #endif /* * The standard receive ring has 512 entries in it. At 2K per mbuf cluster, * that's 1MB or memory, which is a lot. For now, we fill only the first * 256 ring entries and hope that our CPU is fast enough to keep up with * the NIC. */ static int ti_init_rx_ring_std(sc) struct ti_softc *sc; { register int i; struct ti_cmd_desc cmd; for (i = 0; i < TI_SSLOTS; i++) { if (ti_newbuf_std(sc, i, NULL) == ENOBUFS) return(ENOBUFS); }; TI_UPDATE_STDPROD(sc, i - 1); sc->ti_std = i - 1; return(0); } static void ti_free_rx_ring_std(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_STD_RX_RING_CNT; i++) { if (sc->ti_cdata.ti_rx_std_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_rx_std_chain[i]); sc->ti_cdata.ti_rx_std_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_rx_std_ring[i], sizeof(struct ti_rx_desc)); } return; } static int ti_init_rx_ring_jumbo(sc) struct ti_softc *sc; { register int i; struct ti_cmd_desc cmd; for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) { if (ti_newbuf_jumbo(sc, i, NULL) == ENOBUFS) return(ENOBUFS); }; TI_UPDATE_JUMBOPROD(sc, i - 1); sc->ti_jumbo = i - 1; return(0); } static void ti_free_rx_ring_jumbo(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_JUMBO_RX_RING_CNT; i++) { if (sc->ti_cdata.ti_rx_jumbo_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_rx_jumbo_chain[i]); sc->ti_cdata.ti_rx_jumbo_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_rx_jumbo_ring[i], sizeof(struct ti_rx_desc)); } return; } static int ti_init_rx_ring_mini(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_MSLOTS; i++) { if (ti_newbuf_mini(sc, i, NULL) == ENOBUFS) return(ENOBUFS); }; TI_UPDATE_MINIPROD(sc, i - 1); sc->ti_mini = i - 1; return(0); } static void ti_free_rx_ring_mini(sc) struct ti_softc *sc; { register int i; for (i = 0; i < TI_MINI_RX_RING_CNT; i++) { if (sc->ti_cdata.ti_rx_mini_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_rx_mini_chain[i]); sc->ti_cdata.ti_rx_mini_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_rx_mini_ring[i], sizeof(struct ti_rx_desc)); } return; } static void ti_free_tx_ring(sc) struct ti_softc *sc; { register int i; if (sc->ti_rdata->ti_tx_ring == NULL) return; for (i = 0; i < TI_TX_RING_CNT; i++) { if (sc->ti_cdata.ti_tx_chain[i] != NULL) { m_freem(sc->ti_cdata.ti_tx_chain[i]); sc->ti_cdata.ti_tx_chain[i] = NULL; } bzero((char *)&sc->ti_rdata->ti_tx_ring[i], sizeof(struct ti_tx_desc)); } return; } static int ti_init_tx_ring(sc) struct ti_softc *sc; { sc->ti_txcnt = 0; sc->ti_tx_saved_considx = 0; CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, 0); return(0); } /* * The Tigon 2 firmware has a new way to add/delete multicast addresses, * but we have to support the old way too so that Tigon 1 cards will * work. */ void ti_add_mcast(sc, addr) struct ti_softc *sc; struct ether_addr *addr; { struct ti_cmd_desc cmd; u_int16_t *m; u_int32_t ext[2] = {0, 0}; m = (u_int16_t *)&addr->octet[0]; switch(sc->ti_hwrev) { case TI_HWREV_TIGON: CSR_WRITE_4(sc, TI_GCR_MAR0, htons(m[0])); CSR_WRITE_4(sc, TI_GCR_MAR1, (htons(m[1]) << 16) | htons(m[2])); TI_DO_CMD(TI_CMD_ADD_MCAST_ADDR, 0, 0); break; case TI_HWREV_TIGON_II: ext[0] = htons(m[0]); ext[1] = (htons(m[1]) << 16) | htons(m[2]); TI_DO_CMD_EXT(TI_CMD_EXT_ADD_MCAST, 0, 0, (caddr_t)&ext, 2); break; default: printf("ti%d: unknown hwrev\n", sc->ti_unit); break; } return; } void ti_del_mcast(sc, addr) struct ti_softc *sc; struct ether_addr *addr; { struct ti_cmd_desc cmd; u_int16_t *m; u_int32_t ext[2] = {0, 0}; m = (u_int16_t *)&addr->octet[0]; switch(sc->ti_hwrev) { case TI_HWREV_TIGON: CSR_WRITE_4(sc, TI_GCR_MAR0, htons(m[0])); CSR_WRITE_4(sc, TI_GCR_MAR1, (htons(m[1]) << 16) | htons(m[2])); TI_DO_CMD(TI_CMD_DEL_MCAST_ADDR, 0, 0); break; case TI_HWREV_TIGON_II: ext[0] = htons(m[0]); ext[1] = (htons(m[1]) << 16) | htons(m[2]); TI_DO_CMD_EXT(TI_CMD_EXT_DEL_MCAST, 0, 0, (caddr_t)&ext, 2); break; default: printf("ti%d: unknown hwrev\n", sc->ti_unit); break; } return; } /* * Configure the Tigon's multicast address filter. * * The actual multicast table management is a bit of a pain, thanks to * slight brain damage on the part of both Alteon and us. With our * multicast code, we are only alerted when the multicast address table * changes and at that point we only have the current list of addresses: * we only know the current state, not the previous state, so we don't * actually know what addresses were removed or added. The firmware has * state, but we can't get our grubby mits on it, and there is no 'delete * all multicast addresses' command. Hence, we have to maintain our own * state so we know what addresses have been programmed into the NIC at * any given time. */ static void ti_setmulti(sc) struct ti_softc *sc; { struct ifnet *ifp; struct ifmultiaddr *ifma; struct ti_cmd_desc cmd; struct ti_mc_entry *mc; u_int32_t intrs; ifp = &sc->arpcom.ac_if; if (ifp->if_flags & IFF_ALLMULTI) { TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_ENB, 0); return; } else { TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_DIS, 0); } /* Disable interrupts. */ intrs = CSR_READ_4(sc, TI_MB_HOSTINTR); CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* First, zot all the existing filters. */ while (SLIST_FIRST(&sc->ti_mc_listhead) != NULL) { mc = SLIST_FIRST(&sc->ti_mc_listhead); ti_del_mcast(sc, &mc->mc_addr); SLIST_REMOVE_HEAD(&sc->ti_mc_listhead, mc_entries); free(mc, M_DEVBUF); } /* Now program new ones. */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; mc = malloc(sizeof(struct ti_mc_entry), M_DEVBUF, M_NOWAIT); bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), (char *)&mc->mc_addr, ETHER_ADDR_LEN); SLIST_INSERT_HEAD(&sc->ti_mc_listhead, mc, mc_entries); ti_add_mcast(sc, &mc->mc_addr); } /* Re-enable interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs); return; } /* * Check to see if the BIOS has configured us for a 64 bit slot when * we aren't actually in one. If we detect this condition, we can work * around it on the Tigon 2 by setting a bit in the PCI state register, * but for the Tigon 1 we must give up and abort the interface attach. */ static int ti_64bitslot_war(sc) struct ti_softc *sc; { if (!(CSR_READ_4(sc, TI_PCI_STATE) & TI_PCISTATE_32BIT_BUS)) { CSR_WRITE_4(sc, 0x600, 0); CSR_WRITE_4(sc, 0x604, 0); CSR_WRITE_4(sc, 0x600, 0x5555AAAA); if (CSR_READ_4(sc, 0x604) == 0x5555AAAA) { if (sc->ti_hwrev == TI_HWREV_TIGON) return(EINVAL); else { TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_32BIT_BUS); return(0); } } } return(0); } /* * Do endian, PCI and DMA initialization. Also check the on-board ROM * self-test results. */ static int ti_chipinit(sc) struct ti_softc *sc; { u_int32_t cacheline; u_int32_t pci_writemax = 0; u_int32_t hdrsplit; /* Initialize link to down state. */ sc->ti_linkstat = TI_EV_CODE_LINK_DOWN; if (sc->arpcom.ac_if.if_capenable & IFCAP_HWCSUM) sc->arpcom.ac_if.if_hwassist = TI_CSUM_FEATURES; else sc->arpcom.ac_if.if_hwassist = 0; /* Set endianness before we access any non-PCI registers. */ #if BYTE_ORDER == BIG_ENDIAN CSR_WRITE_4(sc, TI_MISC_HOST_CTL, TI_MHC_BIGENDIAN_INIT | (TI_MHC_BIGENDIAN_INIT << 24)); #else CSR_WRITE_4(sc, TI_MISC_HOST_CTL, TI_MHC_LITTLEENDIAN_INIT | (TI_MHC_LITTLEENDIAN_INIT << 24)); #endif /* Check the ROM failed bit to see if self-tests passed. */ if (CSR_READ_4(sc, TI_CPU_STATE) & TI_CPUSTATE_ROMFAIL) { printf("ti%d: board self-diagnostics failed!\n", sc->ti_unit); return(ENODEV); } /* Halt the CPU. */ TI_SETBIT(sc, TI_CPU_STATE, TI_CPUSTATE_HALT); /* Figure out the hardware revision. */ switch(CSR_READ_4(sc, TI_MISC_HOST_CTL) & TI_MHC_CHIP_REV_MASK) { case TI_REV_TIGON_I: sc->ti_hwrev = TI_HWREV_TIGON; break; case TI_REV_TIGON_II: sc->ti_hwrev = TI_HWREV_TIGON_II; break; default: printf("ti%d: unsupported chip revision\n", sc->ti_unit); return(ENODEV); } /* Do special setup for Tigon 2. */ if (sc->ti_hwrev == TI_HWREV_TIGON_II) { TI_SETBIT(sc, TI_CPU_CTL_B, TI_CPUSTATE_HALT); TI_SETBIT(sc, TI_MISC_LOCAL_CTL, TI_MLC_SRAM_BANK_512K); TI_SETBIT(sc, TI_MISC_CONF, TI_MCR_SRAM_SYNCHRONOUS); } /* * We don't have firmware source for the Tigon 1, so Tigon 1 boards * can't do header splitting. */ #ifdef TI_JUMBO_HDRSPLIT if (sc->ti_hwrev != TI_HWREV_TIGON) sc->ti_hdrsplit = 1; else printf("ti%d: can't do header splitting on a Tigon I board\n", sc->ti_unit); #endif /* TI_JUMBO_HDRSPLIT */ /* Set up the PCI state register. */ CSR_WRITE_4(sc, TI_PCI_STATE, TI_PCI_READ_CMD|TI_PCI_WRITE_CMD); if (sc->ti_hwrev == TI_HWREV_TIGON_II) { TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_USE_MEM_RD_MULT); } /* Clear the read/write max DMA parameters. */ TI_CLRBIT(sc, TI_PCI_STATE, (TI_PCISTATE_WRITE_MAXDMA| TI_PCISTATE_READ_MAXDMA)); /* Get cache line size. */ cacheline = CSR_READ_4(sc, TI_PCI_BIST) & 0xFF; /* * If the system has set enabled the PCI memory write * and invalidate command in the command register, set * the write max parameter accordingly. This is necessary * to use MWI with the Tigon 2. */ if (CSR_READ_4(sc, TI_PCI_CMDSTAT) & PCIM_CMD_MWIEN) { switch(cacheline) { case 1: case 4: case 8: case 16: case 32: case 64: break; default: /* Disable PCI memory write and invalidate. */ if (bootverbose) printf("ti%d: cache line size %d not " "supported; disabling PCI MWI\n", sc->ti_unit, cacheline); CSR_WRITE_4(sc, TI_PCI_CMDSTAT, CSR_READ_4(sc, TI_PCI_CMDSTAT) & ~PCIM_CMD_MWIEN); break; } } #ifdef __brokenalpha__ /* * From the Alteon sample driver: * Must insure that we do not cross an 8K (bytes) boundary * for DMA reads. Our highest limit is 1K bytes. This is a * restriction on some ALPHA platforms with early revision * 21174 PCI chipsets, such as the AlphaPC 164lx */ TI_SETBIT(sc, TI_PCI_STATE, pci_writemax|TI_PCI_READMAX_1024); #else TI_SETBIT(sc, TI_PCI_STATE, pci_writemax); #endif /* This sets the min dma param all the way up (0xff). */ TI_SETBIT(sc, TI_PCI_STATE, TI_PCISTATE_MINDMA); if (sc->ti_hdrsplit) hdrsplit = TI_OPMODE_JUMBO_HDRSPLIT; else hdrsplit = 0; /* Configure DMA variables. */ #if BYTE_ORDER == BIG_ENDIAN CSR_WRITE_4(sc, TI_GCR_OPMODE, TI_OPMODE_BYTESWAP_BD | TI_OPMODE_BYTESWAP_DATA | TI_OPMODE_WORDSWAP_BD | TI_OPMODE_WARN_ENB | TI_OPMODE_FATAL_ENB | TI_OPMODE_DONT_FRAG_JUMBO | hdrsplit); #else /* BYTE_ORDER */ CSR_WRITE_4(sc, TI_GCR_OPMODE, TI_OPMODE_BYTESWAP_DATA| TI_OPMODE_WORDSWAP_BD|TI_OPMODE_DONT_FRAG_JUMBO| TI_OPMODE_WARN_ENB|TI_OPMODE_FATAL_ENB | hdrsplit); #endif /* BYTE_ORDER */ /* * Only allow 1 DMA channel to be active at a time. * I don't think this is a good idea, but without it * the firmware racks up lots of nicDmaReadRingFull * errors. This is not compatible with hardware checksums. */ if (sc->arpcom.ac_if.if_hwassist == 0) TI_SETBIT(sc, TI_GCR_OPMODE, TI_OPMODE_1_DMA_ACTIVE); /* Recommended settings from Tigon manual. */ CSR_WRITE_4(sc, TI_GCR_DMA_WRITECFG, TI_DMA_STATE_THRESH_8W); CSR_WRITE_4(sc, TI_GCR_DMA_READCFG, TI_DMA_STATE_THRESH_8W); if (ti_64bitslot_war(sc)) { printf("ti%d: bios thinks we're in a 64 bit slot, " "but we aren't", sc->ti_unit); return(EINVAL); } return(0); } /* * Initialize the general information block and firmware, and * start the CPU(s) running. */ static int ti_gibinit(sc) struct ti_softc *sc; { struct ti_rcb *rcb; int i; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* Disable interrupts for now. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* Tell the chip where to find the general information block. */ CSR_WRITE_4(sc, TI_GCR_GENINFO_HI, 0); CSR_WRITE_4(sc, TI_GCR_GENINFO_LO, vtophys(&sc->ti_rdata->ti_info)); /* Load the firmware into SRAM. */ ti_loadfw(sc); /* Set up the contents of the general info and ring control blocks. */ /* Set up the event ring and producer pointer. */ rcb = &sc->ti_rdata->ti_info.ti_ev_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_event_ring); rcb->ti_flags = 0; TI_HOSTADDR(sc->ti_rdata->ti_info.ti_ev_prodidx_ptr) = vtophys(&sc->ti_ev_prodidx); sc->ti_ev_prodidx.ti_idx = 0; CSR_WRITE_4(sc, TI_GCR_EVENTCONS_IDX, 0); sc->ti_ev_saved_considx = 0; /* Set up the command ring and producer mailbox. */ rcb = &sc->ti_rdata->ti_info.ti_cmd_rcb; sc->ti_rdata->ti_cmd_ring = (struct ti_cmd_desc *)(sc->ti_vhandle + TI_GCR_CMDRING); TI_HOSTADDR(rcb->ti_hostaddr) = TI_GCR_NIC_ADDR(TI_GCR_CMDRING); rcb->ti_flags = 0; rcb->ti_max_len = 0; for (i = 0; i < TI_CMD_RING_CNT; i++) { CSR_WRITE_4(sc, TI_GCR_CMDRING + (i * 4), 0); } CSR_WRITE_4(sc, TI_GCR_CMDCONS_IDX, 0); CSR_WRITE_4(sc, TI_MB_CMDPROD_IDX, 0); sc->ti_cmd_saved_prodidx = 0; /* * Assign the address of the stats refresh buffer. * We re-use the current stats buffer for this to * conserve memory. */ TI_HOSTADDR(sc->ti_rdata->ti_info.ti_refresh_stats_ptr) = vtophys(&sc->ti_rdata->ti_info.ti_stats); /* Set up the standard receive ring. */ rcb = &sc->ti_rdata->ti_info.ti_std_rx_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_std_ring); rcb->ti_max_len = TI_FRAMELEN; rcb->ti_flags = 0; if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; /* Set up the jumbo receive ring. */ rcb = &sc->ti_rdata->ti_info.ti_jumbo_rx_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_jumbo_ring); #ifdef TI_PRIVATE_JUMBOS rcb->ti_max_len = TI_JUMBO_FRAMELEN; rcb->ti_flags = 0; #else rcb->ti_max_len = PAGE_SIZE; rcb->ti_flags = TI_RCB_FLAG_USE_EXT_RX_BD; #endif if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; /* * Set up the mini ring. Only activated on the * Tigon 2 but the slot in the config block is * still there on the Tigon 1. */ rcb = &sc->ti_rdata->ti_info.ti_mini_rx_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_mini_ring); rcb->ti_max_len = MHLEN - ETHER_ALIGN; if (sc->ti_hwrev == TI_HWREV_TIGON) rcb->ti_flags = TI_RCB_FLAG_RING_DISABLED; else rcb->ti_flags = 0; if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; /* * Set up the receive return ring. */ rcb = &sc->ti_rdata->ti_info.ti_return_rcb; TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_rx_return_ring); rcb->ti_flags = 0; rcb->ti_max_len = TI_RETURN_RING_CNT; TI_HOSTADDR(sc->ti_rdata->ti_info.ti_return_prodidx_ptr) = vtophys(&sc->ti_return_prodidx); /* * Set up the tx ring. Note: for the Tigon 2, we have the option * of putting the transmit ring in the host's address space and * letting the chip DMA it instead of leaving the ring in the NIC's * memory and accessing it through the shared memory region. We * do this for the Tigon 2, but it doesn't work on the Tigon 1, * so we have to revert to the shared memory scheme if we detect * a Tigon 1 chip. */ CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE); if (sc->ti_hwrev == TI_HWREV_TIGON) { sc->ti_rdata->ti_tx_ring_nic = (struct ti_tx_desc *)(sc->ti_vhandle + TI_WINDOW); } bzero((char *)sc->ti_rdata->ti_tx_ring, TI_TX_RING_CNT * sizeof(struct ti_tx_desc)); rcb = &sc->ti_rdata->ti_info.ti_tx_rcb; if (sc->ti_hwrev == TI_HWREV_TIGON) rcb->ti_flags = 0; else rcb->ti_flags = TI_RCB_FLAG_HOST_RING; rcb->ti_flags |= TI_RCB_FLAG_VLAN_ASSIST; if (sc->arpcom.ac_if.if_hwassist) rcb->ti_flags |= TI_RCB_FLAG_TCP_UDP_CKSUM | TI_RCB_FLAG_IP_CKSUM | TI_RCB_FLAG_NO_PHDR_CKSUM; rcb->ti_max_len = TI_TX_RING_CNT; if (sc->ti_hwrev == TI_HWREV_TIGON) TI_HOSTADDR(rcb->ti_hostaddr) = TI_TX_RING_BASE; else TI_HOSTADDR(rcb->ti_hostaddr) = vtophys(&sc->ti_rdata->ti_tx_ring); TI_HOSTADDR(sc->ti_rdata->ti_info.ti_tx_considx_ptr) = vtophys(&sc->ti_tx_considx); /* Set up tuneables */ #if 0 if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, (sc->ti_rx_coal_ticks / 10)); else #endif CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, sc->ti_rx_coal_ticks); CSR_WRITE_4(sc, TI_GCR_TX_COAL_TICKS, sc->ti_tx_coal_ticks); CSR_WRITE_4(sc, TI_GCR_STAT_TICKS, sc->ti_stat_ticks); CSR_WRITE_4(sc, TI_GCR_RX_MAX_COAL_BD, sc->ti_rx_max_coal_bds); CSR_WRITE_4(sc, TI_GCR_TX_MAX_COAL_BD, sc->ti_tx_max_coal_bds); CSR_WRITE_4(sc, TI_GCR_TX_BUFFER_RATIO, sc->ti_tx_buf_ratio); /* Turn interrupts on. */ CSR_WRITE_4(sc, TI_GCR_MASK_INTRS, 0); CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0); /* Start CPU. */ TI_CLRBIT(sc, TI_CPU_STATE, (TI_CPUSTATE_HALT|TI_CPUSTATE_STEP)); return(0); } /* * Probe for a Tigon chip. Check the PCI vendor and device IDs * against our list and return its name if we find a match. */ static int ti_probe(dev) device_t dev; { struct ti_type *t; t = ti_devs; while(t->ti_name != NULL) { if ((pci_get_vendor(dev) == t->ti_vid) && (pci_get_device(dev) == t->ti_did)) { device_set_desc(dev, t->ti_name); return(0); } t++; } return(ENXIO); } #ifdef KLD_MODULE static int log2rndup(int len) { int log2size = 0, t = len; while (t > 1) { log2size++; t >>= 1; } if (len != (1 << log2size)) log2size++; return log2size; } static int ti_mbuf_sanity(device_t dev) { if ((mbstat.m_msize != MSIZE) || mbstat.m_mclbytes != MCLBYTES){ device_printf(dev, "\n"); device_printf(dev, "This module was compiled with " "-DMCLSHIFT=%d -DMSIZE=%d\n", MCLSHIFT, MSIZE); device_printf(dev, "The kernel was compiled with MCLSHIFT=%d," " MSIZE=%d\n", log2rndup(mbstat.m_mclbytes), (int)mbstat.m_msize); return(EINVAL); } return(0); } #endif static int ti_attach(dev) device_t dev; { u_int32_t command; struct ifnet *ifp; struct ti_softc *sc; int unit, error = 0, rid; sc = NULL; #ifdef KLD_MODULE if (ti_mbuf_sanity(dev)){ device_printf(dev, "Module mbuf constants do not match " "kernel constants!\n"); device_printf(dev, "Rebuild the module or the kernel so " "they match\n"); device_printf(dev, "\n"); error = EINVAL; goto fail; } #endif sc = device_get_softc(dev); unit = device_get_unit(dev); bzero(sc, sizeof(struct ti_softc)); mtx_init(&sc->ti_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); sc->arpcom.ac_if.if_capabilities = IFCAP_HWCSUM; sc->arpcom.ac_if.if_capenable = sc->arpcom.ac_if.if_capabilities; /* * Map control/status registers. */ pci_enable_busmaster(dev); pci_enable_io(dev, SYS_RES_MEMORY); command = pci_read_config(dev, PCIR_COMMAND, 4); if (!(command & PCIM_CMD_MEMEN)) { printf("ti%d: failed to enable memory mapping!\n", unit); error = ENXIO; goto fail; } rid = TI_PCI_LOMEM; sc->ti_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE|PCI_RF_DENSE); if (sc->ti_res == NULL) { printf ("ti%d: couldn't map memory\n", unit); error = ENXIO; goto fail; } sc->ti_btag = rman_get_bustag(sc->ti_res); sc->ti_bhandle = rman_get_bushandle(sc->ti_res); sc->ti_vhandle = (vm_offset_t)rman_get_virtual(sc->ti_res); /* Allocate interrupt */ rid = 0; sc->ti_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->ti_irq == NULL) { printf("ti%d: couldn't map interrupt\n", unit); error = ENXIO; goto fail; } error = bus_setup_intr(dev, sc->ti_irq, INTR_TYPE_NET, ti_intr, sc, &sc->ti_intrhand); if (error) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); printf("ti%d: couldn't set up irq\n", unit); goto fail; } sc->ti_unit = unit; if (ti_chipinit(sc)) { printf("ti%d: chip initialization failed\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; goto fail; } /* Zero out the NIC's on-board SRAM. */ ti_mem(sc, 0x2000, 0x100000 - 0x2000, NULL); /* Init again -- zeroing memory may have clobbered some registers. */ if (ti_chipinit(sc)) { printf("ti%d: chip initialization failed\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; goto fail; } /* * Get station address from the EEPROM. Note: the manual states * that the MAC address is at offset 0x8c, however the data is * stored as two longwords (since that's how it's loaded into * the NIC). This means the MAC address is actually preceded * by two zero bytes. We need to skip over those. */ if (ti_read_eeprom(sc, (caddr_t)&sc->arpcom.ac_enaddr, TI_EE_MAC_OFFSET + 2, ETHER_ADDR_LEN)) { printf("ti%d: failed to read station address\n", unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; goto fail; } /* * A Tigon chip was detected. Inform the world. */ printf("ti%d: Ethernet address: %6D\n", unit, sc->arpcom.ac_enaddr, ":"); /* Allocate the general information block and ring buffers. */ sc->ti_rdata = contigmalloc(sizeof(struct ti_ring_data), M_DEVBUF, M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); if (sc->ti_rdata == NULL) { bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); error = ENXIO; printf("ti%d: no memory for list buffers!\n", sc->ti_unit); goto fail; } bzero(sc->ti_rdata, sizeof(struct ti_ring_data)); /* Try to allocate memory for jumbo buffers. */ #ifdef TI_PRIVATE_JUMBOS if (ti_alloc_jumbo_mem(sc)) { printf("ti%d: jumbo buffer allocation failed\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); contigfree(sc->ti_rdata, sizeof(struct ti_ring_data), M_DEVBUF); error = ENXIO; goto fail; } #else if (!jumbo_vm_init()) { printf("ti%d: VM initialization failed!\n", sc->ti_unit); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); free(sc->ti_rdata, M_DEVBUF); error = ENOMEM; goto fail; } #endif /* * We really need a better way to tell a 1000baseTX card * from a 1000baseSX one, since in theory there could be * OEMed 1000baseTX cards from lame vendors who aren't * clever enough to change the PCI ID. For the moment * though, the AceNIC is the only copper card available. */ if (pci_get_vendor(dev) == ALT_VENDORID && pci_get_device(dev) == ALT_DEVICEID_ACENIC_COPPER) sc->ti_copper = 1; /* Ok, it's not the only copper card available. */ if (pci_get_vendor(dev) == NG_VENDORID && pci_get_device(dev) == NG_DEVICEID_GA620T) sc->ti_copper = 1; /* Set default tuneable values. */ sc->ti_stat_ticks = 2 * TI_TICKS_PER_SEC; #if 0 sc->ti_rx_coal_ticks = TI_TICKS_PER_SEC / 5000; #endif sc->ti_rx_coal_ticks = 170; sc->ti_tx_coal_ticks = TI_TICKS_PER_SEC / 500; sc->ti_rx_max_coal_bds = 64; #if 0 sc->ti_tx_max_coal_bds = 128; #endif sc->ti_tx_max_coal_bds = 32; sc->ti_tx_buf_ratio = 21; /* Set up ifnet structure */ ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; ifp->if_unit = sc->ti_unit; ifp->if_name = "ti"; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; tis[unit] = sc; ifp->if_ioctl = ti_ioctl; ifp->if_output = ether_output; ifp->if_start = ti_start; ifp->if_watchdog = ti_watchdog; ifp->if_init = ti_init; ifp->if_mtu = ETHERMTU; ifp->if_snd.ifq_maxlen = TI_TX_RING_CNT - 1; /* Set up ifmedia support. */ ifmedia_init(&sc->ifmedia, IFM_IMASK, ti_ifmedia_upd, ti_ifmedia_sts); if (sc->ti_copper) { /* * Copper cards allow manual 10/100 mode selection, * but not manual 1000baseTX mode selection. Why? * Becuase currently there's no way to specify the * master/slave setting through the firmware interface, * so Alteon decided to just bag it and handle it * via autonegotiation. */ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_T, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL); } else { /* Fiber cards don't support 10/100 modes. */ ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL); ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL); } ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); ifmedia_set(&sc->ifmedia, IFM_ETHER|IFM_AUTO); /* * We're assuming here that card initialization is a sequential * thing. If it isn't, multiple cards probing at the same time * could stomp on the list of softcs here. */ /* * If this is the first card to be initialized, initialize the * softc queue. */ if (unit == 0) STAILQ_INIT(&ti_sc_list); STAILQ_INSERT_TAIL(&ti_sc_list, sc, ti_links); /* Register the device */ sc->dev = make_dev(&ti_cdevsw, sc->ti_unit, UID_ROOT, GID_OPERATOR, 0600, "ti%d", sc->ti_unit); /* * Call MI attach routine. */ ether_ifattach(ifp, ETHER_BPF_SUPPORTED); return(0); fail: mtx_destroy(&sc->ti_mtx); return(error); } /* * Verify that our character special device is not currently * open. Also track down any cached vnodes & kill them before * the module is unloaded */ static int ti_unref_special(device_t dev) { struct vnode *ti_vn; int count; struct ti_softc *sc = sc = device_get_softc(dev); if (!vfinddev(sc->dev, VCHR, &ti_vn)) { return 0; } if ((count = vcount(ti_vn))) { device_printf(dev, "%d refs to special device, " "denying unload\n", count); return count; } /* now we know that there's a vnode in the cache. We hunt it down and kill it now, before unloading */ vgone(ti_vn); return(0); } static int ti_detach(dev) device_t dev; { struct ti_softc *sc; struct ifnet *ifp; if (ti_unref_special(dev)) return EBUSY; sc = device_get_softc(dev); TI_LOCK(sc); ifp = &sc->arpcom.ac_if; ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); ti_stop(sc); bus_teardown_intr(dev, sc->ti_irq, sc->ti_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ti_irq); bus_release_resource(dev, SYS_RES_MEMORY, TI_PCI_LOMEM, sc->ti_res); #ifdef TI_PRIVATE_JUMBOS contigfree(sc->ti_cdata.ti_jumbo_buf, TI_JMEM, M_DEVBUF); #endif contigfree(sc->ti_rdata, sizeof(struct ti_ring_data), M_DEVBUF); ifmedia_removeall(&sc->ifmedia); TI_UNLOCK(sc); mtx_destroy(&sc->ti_mtx); return(0); } #ifdef TI_JUMBO_HDRSPLIT /* * If hdr_len is 0, that means that header splitting wasn't done on * this packet for some reason. The two most likely reasons are that * the protocol isn't a supported protocol for splitting, or this * packet had a fragment offset that wasn't 0. * * The header length, if it is non-zero, will always be the length of * the headers on the packet, but that length could be longer than the * first mbuf. So we take the minimum of the two as the actual * length. */ static __inline void ti_hdr_split(struct mbuf *top, int hdr_len, int pkt_len, int idx) { int i = 0; int lengths[4] = {0, 0, 0, 0}; struct mbuf *m, *mp; if (hdr_len != 0) top->m_len = min(hdr_len, top->m_len); pkt_len -= top->m_len; lengths[i++] = top->m_len; mp = top; for (m = top->m_next; m && pkt_len; m = m->m_next) { m->m_len = m->m_ext.ext_size = min(m->m_len, pkt_len); pkt_len -= m->m_len; lengths[i++] = m->m_len; mp = m; } #if 0 if (hdr_len != 0) printf("got split packet: "); else printf("got non-split packet: "); printf("%d,%d,%d,%d = %d\n", lengths[0], lengths[1], lengths[2], lengths[3], lengths[0] + lengths[1] + lengths[2] + lengths[3]); #endif if (pkt_len) panic("header splitting didn't"); if (m) { m_freem(m); mp->m_next = NULL; } if (mp->m_next != NULL) panic("ti_hdr_split: last mbuf in chain should be null"); } #endif /* TI_JUMBO_HDRSPLIT */ /* * Frame reception handling. This is called if there's a frame * on the receive return list. * * Note: we have to be able to handle three possibilities here: * 1) the frame is from the mini receive ring (can only happen) * on Tigon 2 boards) * 2) the frame is from the jumbo recieve ring * 3) the frame is from the standard receive ring */ static void ti_rxeof(sc) struct ti_softc *sc; { struct ifnet *ifp; struct ti_cmd_desc cmd; ifp = &sc->arpcom.ac_if; while(sc->ti_rx_saved_considx != sc->ti_return_prodidx.ti_idx) { struct ti_rx_desc *cur_rx; u_int32_t rxidx; struct ether_header *eh; struct mbuf *m = NULL; u_int16_t vlan_tag = 0; int have_tag = 0; cur_rx = &sc->ti_rdata->ti_rx_return_ring[sc->ti_rx_saved_considx]; rxidx = cur_rx->ti_idx; TI_INC(sc->ti_rx_saved_considx, TI_RETURN_RING_CNT); if (cur_rx->ti_flags & TI_BDFLAG_VLAN_TAG) { have_tag = 1; vlan_tag = cur_rx->ti_vlan_tag & 0xfff; } if (cur_rx->ti_flags & TI_BDFLAG_JUMBO_RING) { TI_INC(sc->ti_jumbo, TI_JUMBO_RX_RING_CNT); m = sc->ti_cdata.ti_rx_jumbo_chain[rxidx]; sc->ti_cdata.ti_rx_jumbo_chain[rxidx] = NULL; if (cur_rx->ti_flags & TI_BDFLAG_ERROR) { ifp->if_ierrors++; ti_newbuf_jumbo(sc, sc->ti_jumbo, m); continue; } if (ti_newbuf_jumbo(sc, sc->ti_jumbo, NULL) == ENOBUFS) { ifp->if_ierrors++; ti_newbuf_jumbo(sc, sc->ti_jumbo, m); continue; } #ifdef TI_PRIVATE_JUMBOS m->m_len = cur_rx->ti_len; #else /* TI_PRIVATE_JUMBOS */ #ifdef TI_JUMBO_HDRSPLIT if (sc->ti_hdrsplit) ti_hdr_split(m, TI_HOSTADDR(cur_rx->ti_addr), cur_rx->ti_len, rxidx); else #endif /* TI_JUMBO_HDRSPLIT */ m_adj(m, cur_rx->ti_len - m->m_pkthdr.len); #endif /* TI_PRIVATE_JUMBOS */ } else if (cur_rx->ti_flags & TI_BDFLAG_MINI_RING) { TI_INC(sc->ti_mini, TI_MINI_RX_RING_CNT); m = sc->ti_cdata.ti_rx_mini_chain[rxidx]; sc->ti_cdata.ti_rx_mini_chain[rxidx] = NULL; if (cur_rx->ti_flags & TI_BDFLAG_ERROR) { ifp->if_ierrors++; ti_newbuf_mini(sc, sc->ti_mini, m); continue; } if (ti_newbuf_mini(sc, sc->ti_mini, NULL) == ENOBUFS) { ifp->if_ierrors++; ti_newbuf_mini(sc, sc->ti_mini, m); continue; } m->m_len = cur_rx->ti_len; } else { TI_INC(sc->ti_std, TI_STD_RX_RING_CNT); m = sc->ti_cdata.ti_rx_std_chain[rxidx]; sc->ti_cdata.ti_rx_std_chain[rxidx] = NULL; if (cur_rx->ti_flags & TI_BDFLAG_ERROR) { ifp->if_ierrors++; ti_newbuf_std(sc, sc->ti_std, m); continue; } if (ti_newbuf_std(sc, sc->ti_std, NULL) == ENOBUFS) { ifp->if_ierrors++; ti_newbuf_std(sc, sc->ti_std, m); continue; } m->m_len = cur_rx->ti_len; } m->m_pkthdr.len = cur_rx->ti_len; ifp->if_ipackets++; eh = mtod(m, struct ether_header *); m->m_pkthdr.rcvif = ifp; /* Remove header from mbuf and pass it on. */ m_adj(m, sizeof(struct ether_header)); if (ifp->if_hwassist) { m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_DATA_VALID; if ((cur_rx->ti_ip_cksum ^ 0xffff) == 0) m->m_pkthdr.csum_flags |= CSUM_IP_VALID; m->m_pkthdr.csum_data = cur_rx->ti_tcp_udp_cksum; } /* * If we received a packet with a vlan tag, pass it * to vlan_input() instead of ether_input(). */ if (have_tag) { VLAN_INPUT_TAG(eh, m, vlan_tag); have_tag = vlan_tag = 0; continue; } ether_input(ifp, eh, m); } /* Only necessary on the Tigon 1. */ if (sc->ti_hwrev == TI_HWREV_TIGON) CSR_WRITE_4(sc, TI_GCR_RXRETURNCONS_IDX, sc->ti_rx_saved_considx); TI_UPDATE_STDPROD(sc, sc->ti_std); TI_UPDATE_MINIPROD(sc, sc->ti_mini); TI_UPDATE_JUMBOPROD(sc, sc->ti_jumbo); return; } static void ti_txeof(sc) struct ti_softc *sc; { struct ti_tx_desc *cur_tx = NULL; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; /* * Go through our tx ring and free mbufs for those * frames that have been sent. */ while (sc->ti_tx_saved_considx != sc->ti_tx_considx.ti_idx) { u_int32_t idx = 0; idx = sc->ti_tx_saved_considx; if (sc->ti_hwrev == TI_HWREV_TIGON) { if (idx > 383) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 6144); else if (idx > 255) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 4096); else if (idx > 127) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 2048); else CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE); cur_tx = &sc->ti_rdata->ti_tx_ring_nic[idx % 128]; } else cur_tx = &sc->ti_rdata->ti_tx_ring[idx]; if (cur_tx->ti_flags & TI_BDFLAG_END) ifp->if_opackets++; if (sc->ti_cdata.ti_tx_chain[idx] != NULL) { m_freem(sc->ti_cdata.ti_tx_chain[idx]); sc->ti_cdata.ti_tx_chain[idx] = NULL; } sc->ti_txcnt--; TI_INC(sc->ti_tx_saved_considx, TI_TX_RING_CNT); ifp->if_timer = 0; } if (cur_tx != NULL) ifp->if_flags &= ~IFF_OACTIVE; return; } static void ti_intr(xsc) void *xsc; { struct ti_softc *sc; struct ifnet *ifp; sc = xsc; TI_LOCK(sc); ifp = &sc->arpcom.ac_if; /*#ifdef notdef*/ /* Avoid this for now -- checking this register is expensive. */ /* Make sure this is really our interrupt. */ if (!(CSR_READ_4(sc, TI_MISC_HOST_CTL) & TI_MHC_INTSTATE)) { TI_UNLOCK(sc); return; } /*#endif*/ /* Ack interrupt and stop others from occuring. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); if (ifp->if_flags & IFF_RUNNING) { /* Check RX return ring producer/consumer */ ti_rxeof(sc); /* Check TX ring producer/consumer */ ti_txeof(sc); } ti_handle_events(sc); /* Re-enable interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0); if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL) ti_start(ifp); TI_UNLOCK(sc); return; } static void ti_stats_update(sc) struct ti_softc *sc; { struct ifnet *ifp; ifp = &sc->arpcom.ac_if; ifp->if_collisions += (sc->ti_rdata->ti_info.ti_stats.dot3StatsSingleCollisionFrames + sc->ti_rdata->ti_info.ti_stats.dot3StatsMultipleCollisionFrames + sc->ti_rdata->ti_info.ti_stats.dot3StatsExcessiveCollisions + sc->ti_rdata->ti_info.ti_stats.dot3StatsLateCollisions) - ifp->if_collisions; return; } /* * Encapsulate an mbuf chain in the tx ring by coupling the mbuf data * pointers to descriptors. */ static int ti_encap(sc, m_head, txidx) struct ti_softc *sc; struct mbuf *m_head; u_int32_t *txidx; { struct ti_tx_desc *f = NULL; struct mbuf *m; u_int32_t frag, cur, cnt = 0; u_int16_t csum_flags = 0; struct ifvlan *ifv = NULL; if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && m_head->m_pkthdr.rcvif != NULL && m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) ifv = m_head->m_pkthdr.rcvif->if_softc; m = m_head; cur = frag = *txidx; if (m_head->m_pkthdr.csum_flags) { if (m_head->m_pkthdr.csum_flags & CSUM_IP) csum_flags |= TI_BDFLAG_IP_CKSUM; if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) csum_flags |= TI_BDFLAG_TCP_UDP_CKSUM; if (m_head->m_flags & M_LASTFRAG) csum_flags |= TI_BDFLAG_IP_FRAG_END; else if (m_head->m_flags & M_FRAG) csum_flags |= TI_BDFLAG_IP_FRAG; } /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ for (m = m_head; m != NULL; m = m->m_next) { if (m->m_len != 0) { if (sc->ti_hwrev == TI_HWREV_TIGON) { if (frag > 383) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 6144); else if (frag > 255) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 4096); else if (frag > 127) CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE + 2048); else CSR_WRITE_4(sc, TI_WINBASE, TI_TX_RING_BASE); f = &sc->ti_rdata->ti_tx_ring_nic[frag % 128]; } else f = &sc->ti_rdata->ti_tx_ring[frag]; if (sc->ti_cdata.ti_tx_chain[frag] != NULL) break; TI_HOSTADDR(f->ti_addr) = vtophys(mtod(m, vm_offset_t)); f->ti_len = m->m_len; f->ti_flags = csum_flags; if (ifv != NULL) { f->ti_flags |= TI_BDFLAG_VLAN_TAG; f->ti_vlan_tag = ifv->ifv_tag & 0xfff; } else { f->ti_vlan_tag = 0; } /* * Sanity check: avoid coming within 16 descriptors * of the end of the ring. */ if ((TI_TX_RING_CNT - (sc->ti_txcnt + cnt)) < 16) return(ENOBUFS); cur = frag; TI_INC(frag, TI_TX_RING_CNT); cnt++; } } if (m != NULL) return(ENOBUFS); if (frag == sc->ti_tx_saved_considx) return(ENOBUFS); if (sc->ti_hwrev == TI_HWREV_TIGON) sc->ti_rdata->ti_tx_ring_nic[cur % 128].ti_flags |= TI_BDFLAG_END; else sc->ti_rdata->ti_tx_ring[cur].ti_flags |= TI_BDFLAG_END; sc->ti_cdata.ti_tx_chain[cur] = m_head; sc->ti_txcnt += cnt; *txidx = frag; return(0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit descriptors. */ static void ti_start(ifp) struct ifnet *ifp; { struct ti_softc *sc; struct mbuf *m_head = NULL; u_int32_t prodidx = 0; sc = ifp->if_softc; TI_LOCK(sc); prodidx = CSR_READ_4(sc, TI_MB_SENDPROD_IDX); while(sc->ti_cdata.ti_tx_chain[prodidx] == NULL) { IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; /* * XXX * safety overkill. If this is a fragmented packet chain * with delayed TCP/UDP checksums, then only encapsulate * it if we have enough descriptors to handle the entire * chain at once. * (paranoia -- may not actually be needed) */ if (m_head->m_flags & M_FIRSTFRAG && m_head->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { if ((TI_TX_RING_CNT - sc->ti_txcnt) < m_head->m_pkthdr.csum_data + 16) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } } /* * Pack the data into the transmit ring. If we * don't have room, set the OACTIVE flag and wait * for the NIC to drain the ring. */ if (ti_encap(sc, m_head, &prodidx)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } /* * If there's a BPF listener, bounce a copy of this frame * to him. */ if (ifp->if_bpf) bpf_mtap(ifp, m_head); } /* Transmit */ CSR_WRITE_4(sc, TI_MB_SENDPROD_IDX, prodidx); /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; TI_UNLOCK(sc); return; } static void ti_init(xsc) void *xsc; { struct ti_softc *sc = xsc; /* Cancel pending I/O and flush buffers. */ ti_stop(sc); TI_LOCK(sc); /* Init the gen info block, ring control blocks and firmware. */ if (ti_gibinit(sc)) { printf("ti%d: initialization failure\n", sc->ti_unit); TI_UNLOCK(sc); return; } TI_UNLOCK(sc); return; } static void ti_init2(sc) struct ti_softc *sc; { struct ti_cmd_desc cmd; struct ifnet *ifp; u_int16_t *m; struct ifmedia *ifm; int tmp; ifp = &sc->arpcom.ac_if; /* Specify MTU and interface index. */ CSR_WRITE_4(sc, TI_GCR_IFINDEX, ifp->if_unit); CSR_WRITE_4(sc, TI_GCR_IFMTU, ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN); TI_DO_CMD(TI_CMD_UPDATE_GENCOM, 0, 0); /* Load our MAC address. */ m = (u_int16_t *)&sc->arpcom.ac_enaddr[0]; CSR_WRITE_4(sc, TI_GCR_PAR0, htons(m[0])); CSR_WRITE_4(sc, TI_GCR_PAR1, (htons(m[1]) << 16) | htons(m[2])); TI_DO_CMD(TI_CMD_SET_MAC_ADDR, 0, 0); /* Enable or disable promiscuous mode as needed. */ if (ifp->if_flags & IFF_PROMISC) { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_ENB, 0); } else { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_DIS, 0); } /* Program multicast filter. */ ti_setmulti(sc); /* * If this is a Tigon 1, we should tell the * firmware to use software packet filtering. */ if (sc->ti_hwrev == TI_HWREV_TIGON) { TI_DO_CMD(TI_CMD_FDR_FILTERING, TI_CMD_CODE_FILT_ENB, 0); } /* Init RX ring. */ ti_init_rx_ring_std(sc); /* Init jumbo RX ring. */ if (ifp->if_mtu > (ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN)) ti_init_rx_ring_jumbo(sc); /* * If this is a Tigon 2, we can also configure the * mini ring. */ if (sc->ti_hwrev == TI_HWREV_TIGON_II) ti_init_rx_ring_mini(sc); CSR_WRITE_4(sc, TI_GCR_RXRETURNCONS_IDX, 0); sc->ti_rx_saved_considx = 0; /* Init TX ring. */ ti_init_tx_ring(sc); /* Tell firmware we're alive. */ TI_DO_CMD(TI_CMD_HOST_STATE, TI_CMD_CODE_STACK_UP, 0); /* Enable host interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 0); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* * Make sure to set media properly. We have to do this * here since we have to issue commands in order to set * the link negotiation and we can't issue commands until * the firmware is running. */ ifm = &sc->ifmedia; tmp = ifm->ifm_media; ifm->ifm_media = ifm->ifm_cur->ifm_media; ti_ifmedia_upd(ifp); ifm->ifm_media = tmp; return; } /* * Set media options. */ static int ti_ifmedia_upd(ifp) struct ifnet *ifp; { struct ti_softc *sc; struct ifmedia *ifm; struct ti_cmd_desc cmd; u_int32_t flowctl; sc = ifp->if_softc; ifm = &sc->ifmedia; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return(EINVAL); flowctl = 0; switch(IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: /* * Transmit flow control doesn't work on the Tigon 1. */ flowctl = TI_GLNK_RX_FLOWCTL_Y; /* * Transmit flow control can also cause problems on the * Tigon 2, apparantly with both the copper and fiber * boards. The symptom is that the interface will just * hang. This was reproduced with Alteon 180 switches. */ #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_GLNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB| TI_GLNK_FULL_DUPLEX| flowctl | TI_GLNK_AUTONEGENB|TI_GLNK_ENB); flowctl = TI_LNK_RX_FLOWCTL_Y; #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_LNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_100MB|TI_LNK_10MB| TI_LNK_FULL_DUPLEX|TI_LNK_HALF_DUPLEX| flowctl | TI_LNK_AUTONEGENB|TI_LNK_ENB); TI_DO_CMD(TI_CMD_LINK_NEGOTIATION, TI_CMD_CODE_NEGOTIATE_BOTH, 0); break; case IFM_1000_SX: case IFM_1000_T: flowctl = TI_GLNK_RX_FLOWCTL_Y; #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_GLNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_GLINK, TI_GLNK_PREF|TI_GLNK_1000MB| flowctl |TI_GLNK_ENB); CSR_WRITE_4(sc, TI_GCR_LINK, 0); if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { TI_SETBIT(sc, TI_GCR_GLINK, TI_GLNK_FULL_DUPLEX); } TI_DO_CMD(TI_CMD_LINK_NEGOTIATION, TI_CMD_CODE_NEGOTIATE_GIGABIT, 0); break; case IFM_100_FX: case IFM_10_FL: case IFM_100_TX: case IFM_10_T: flowctl = TI_LNK_RX_FLOWCTL_Y; #if 0 if (sc->ti_hwrev != TI_HWREV_TIGON) flowctl |= TI_LNK_TX_FLOWCTL_Y; #endif CSR_WRITE_4(sc, TI_GCR_GLINK, 0); CSR_WRITE_4(sc, TI_GCR_LINK, TI_LNK_ENB|TI_LNK_PREF|flowctl); if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_FX || IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_100MB); } else { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_10MB); } if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_FULL_DUPLEX); } else { TI_SETBIT(sc, TI_GCR_LINK, TI_LNK_HALF_DUPLEX); } TI_DO_CMD(TI_CMD_LINK_NEGOTIATION, TI_CMD_CODE_NEGOTIATE_10_100, 0); break; } return(0); } /* * Report current media status. */ static void ti_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct ti_softc *sc; u_int32_t media = 0; sc = ifp->if_softc; ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; if (sc->ti_linkstat == TI_EV_CODE_LINK_DOWN) return; ifmr->ifm_status |= IFM_ACTIVE; if (sc->ti_linkstat == TI_EV_CODE_GIG_LINK_UP) { media = CSR_READ_4(sc, TI_GCR_GLINK_STAT); if (sc->ti_copper) ifmr->ifm_active |= IFM_1000_T; else ifmr->ifm_active |= IFM_1000_SX; if (media & TI_GLNK_FULL_DUPLEX) ifmr->ifm_active |= IFM_FDX; else ifmr->ifm_active |= IFM_HDX; } else if (sc->ti_linkstat == TI_EV_CODE_LINK_UP) { media = CSR_READ_4(sc, TI_GCR_LINK_STAT); if (sc->ti_copper) { if (media & TI_LNK_100MB) ifmr->ifm_active |= IFM_100_TX; if (media & TI_LNK_10MB) ifmr->ifm_active |= IFM_10_T; } else { if (media & TI_LNK_100MB) ifmr->ifm_active |= IFM_100_FX; if (media & TI_LNK_10MB) ifmr->ifm_active |= IFM_10_FL; } if (media & TI_LNK_FULL_DUPLEX) ifmr->ifm_active |= IFM_FDX; if (media & TI_LNK_HALF_DUPLEX) ifmr->ifm_active |= IFM_HDX; } return; } static int ti_ioctl(ifp, command, data) struct ifnet *ifp; u_long command; caddr_t data; { struct ti_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; int mask, error = 0; struct ti_cmd_desc cmd; TI_LOCK(sc); switch(command) { case SIOCSIFADDR: case SIOCGIFADDR: error = ether_ioctl(ifp, command, data); break; case SIOCSIFMTU: if (ifr->ifr_mtu > TI_JUMBO_MTU) error = EINVAL; else { ifp->if_mtu = ifr->ifr_mtu; ti_init(sc); } break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { /* * If only the state of the PROMISC flag changed, * then just use the 'set promisc mode' command * instead of reinitializing the entire NIC. Doing * a full re-init means reloading the firmware and * waiting for it to start up, which may take a * second or two. */ if (ifp->if_flags & IFF_RUNNING && ifp->if_flags & IFF_PROMISC && !(sc->ti_if_flags & IFF_PROMISC)) { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_ENB, 0); } else if (ifp->if_flags & IFF_RUNNING && !(ifp->if_flags & IFF_PROMISC) && sc->ti_if_flags & IFF_PROMISC) { TI_DO_CMD(TI_CMD_SET_PROMISC_MODE, TI_CMD_CODE_PROMISC_DIS, 0); } else ti_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { ti_stop(sc); } } sc->ti_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifp->if_flags & IFF_RUNNING) { ti_setmulti(sc); error = 0; } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); break; case SIOCSIFCAP: mask = ifr->ifr_reqcap ^ ifp->if_capenable; if (mask & IFCAP_HWCSUM) { if (IFCAP_HWCSUM & ifp->if_capenable) ifp->if_capenable &= ~IFCAP_HWCSUM; else ifp->if_capenable |= IFCAP_HWCSUM; if (ifp->if_flags & IFF_RUNNING) ti_init(sc); } error = 0; break; default: error = EINVAL; break; } TI_UNLOCK(sc); return(error); } static int ti_open(dev_t dev, int flags, int fmt, struct thread *td) { int unit; struct ti_softc *sc; unit = minor(dev) & 0xff; sc = ti_lookup_softc(unit); if (sc == NULL) return(ENODEV); TI_LOCK(sc); sc->ti_flags |= TI_FLAG_DEBUGING; TI_UNLOCK(sc); return(0); } static int ti_close(dev_t dev, int flag, int fmt, struct thread *td) { int unit; struct ti_softc *sc; unit = minor(dev) & 0xff; sc = ti_lookup_softc(unit); if (sc == NULL) return(ENODEV); TI_LOCK(sc); sc->ti_flags &= ~TI_FLAG_DEBUGING; TI_UNLOCK(sc); return(0); } /* * This ioctl routine goes along with the Tigon character device. */ static int ti_ioctl2(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) { int unit, error; struct ti_softc *sc; unit = minor(dev) & 0xff; sc = ti_lookup_softc(unit); if (sc == NULL) return(ENODEV); error = 0; switch(cmd) { case TIIOCGETSTATS: { struct ti_stats *outstats; outstats = (struct ti_stats *)addr; bcopy(&sc->ti_rdata->ti_info.ti_stats, outstats, sizeof(struct ti_stats)); break; } case TIIOCGETPARAMS: { struct ti_params *params; params = (struct ti_params *)addr; params->ti_stat_ticks = sc->ti_stat_ticks; params->ti_rx_coal_ticks = sc->ti_rx_coal_ticks; params->ti_tx_coal_ticks = sc->ti_tx_coal_ticks; params->ti_rx_max_coal_bds = sc->ti_rx_max_coal_bds; params->ti_tx_max_coal_bds = sc->ti_tx_max_coal_bds; params->ti_tx_buf_ratio = sc->ti_tx_buf_ratio; params->param_mask = TI_PARAM_ALL; error = 0; break; } case TIIOCSETPARAMS: { struct ti_params *params; params = (struct ti_params *)addr; if (params->param_mask & TI_PARAM_STAT_TICKS) { sc->ti_stat_ticks = params->ti_stat_ticks; CSR_WRITE_4(sc, TI_GCR_STAT_TICKS, sc->ti_stat_ticks); } if (params->param_mask & TI_PARAM_RX_COAL_TICKS) { sc->ti_rx_coal_ticks = params->ti_rx_coal_ticks; CSR_WRITE_4(sc, TI_GCR_RX_COAL_TICKS, sc->ti_rx_coal_ticks); } if (params->param_mask & TI_PARAM_TX_COAL_TICKS) { sc->ti_tx_coal_ticks = params->ti_tx_coal_ticks; CSR_WRITE_4(sc, TI_GCR_TX_COAL_TICKS, sc->ti_tx_coal_ticks); } if (params->param_mask & TI_PARAM_RX_COAL_BDS) { sc->ti_rx_max_coal_bds = params->ti_rx_max_coal_bds; CSR_WRITE_4(sc, TI_GCR_RX_MAX_COAL_BD, sc->ti_rx_max_coal_bds); } if (params->param_mask & TI_PARAM_TX_COAL_BDS) { sc->ti_tx_max_coal_bds = params->ti_tx_max_coal_bds; CSR_WRITE_4(sc, TI_GCR_TX_MAX_COAL_BD, sc->ti_tx_max_coal_bds); } if (params->param_mask & TI_PARAM_TX_BUF_RATIO) { sc->ti_tx_buf_ratio = params->ti_tx_buf_ratio; CSR_WRITE_4(sc, TI_GCR_TX_BUFFER_RATIO, sc->ti_tx_buf_ratio); } error = 0; break; } case TIIOCSETTRACE: { ti_trace_type trace_type; trace_type = *(ti_trace_type *)addr; /* * Set tracing to whatever the user asked for. Setting * this register to 0 should have the effect of disabling * tracing. */ CSR_WRITE_4(sc, TI_GCR_NIC_TRACING, trace_type); error = 0; break; } case TIIOCGETTRACE: { struct ti_trace_buf *trace_buf; u_int32_t trace_start, cur_trace_ptr, trace_len; trace_buf = (struct ti_trace_buf *)addr; trace_start = CSR_READ_4(sc, TI_GCR_NICTRACE_START); cur_trace_ptr = CSR_READ_4(sc, TI_GCR_NICTRACE_PTR); trace_len = CSR_READ_4(sc, TI_GCR_NICTRACE_LEN); #if 0 printf("ti%d: trace_start = %#x, cur_trace_ptr = %#x, " "trace_len = %d\n", sc->ti_unit, trace_start, cur_trace_ptr, trace_len); printf("ti%d: trace_buf->buf_len = %d\n", sc->ti_unit, trace_buf->buf_len); #endif error = ti_copy_mem(sc, trace_start, min(trace_len, trace_buf->buf_len), (caddr_t)trace_buf->buf, 1, 1); if (error == 0) { trace_buf->fill_len = min(trace_len, trace_buf->buf_len); if (cur_trace_ptr < trace_start) trace_buf->cur_trace_ptr = trace_start - cur_trace_ptr; else trace_buf->cur_trace_ptr = cur_trace_ptr - trace_start; } else trace_buf->fill_len = 0; break; } /* * For debugging, five ioctls are needed: * ALT_ATTACH * ALT_READ_TG_REG * ALT_WRITE_TG_REG * ALT_READ_TG_MEM * ALT_WRITE_TG_MEM */ case ALT_ATTACH: /* * From what I can tell, Alteon's Solaris Tigon driver * only has one character device, so you have to attach * to the Tigon board you're interested in. This seems * like a not-so-good way to do things, since unless you * subsequently specify the unit number of the device * you're interested in in every ioctl, you'll only be * able to debug one board at a time. */ error = 0; break; case ALT_READ_TG_MEM: case ALT_WRITE_TG_MEM: { struct tg_mem *mem_param; u_int32_t sram_end, scratch_end; mem_param = (struct tg_mem *)addr; if (sc->ti_hwrev == TI_HWREV_TIGON) { sram_end = TI_END_SRAM_I; scratch_end = TI_END_SCRATCH_I; } else { sram_end = TI_END_SRAM_II; scratch_end = TI_END_SCRATCH_II; } /* * For now, we'll only handle accessing regular SRAM, * nothing else. */ if ((mem_param->tgAddr >= TI_BEG_SRAM) && ((mem_param->tgAddr + mem_param->len) <= sram_end)) { /* * In this instance, we always copy to/from user * space, so the user space argument is set to 1. */ error = ti_copy_mem(sc, mem_param->tgAddr, mem_param->len, mem_param->userAddr, 1, (cmd == ALT_READ_TG_MEM) ? 1 : 0); } else if ((mem_param->tgAddr >= TI_BEG_SCRATCH) && (mem_param->tgAddr <= scratch_end)) { error = ti_copy_scratch(sc, mem_param->tgAddr, mem_param->len, mem_param->userAddr, 1, (cmd == ALT_READ_TG_MEM) ? 1 : 0, TI_PROCESSOR_A); } else if ((mem_param->tgAddr >= TI_BEG_SCRATCH_B_DEBUG) && (mem_param->tgAddr <= TI_BEG_SCRATCH_B_DEBUG)) { if (sc->ti_hwrev == TI_HWREV_TIGON) { printf("ti%d: invalid memory range for " "Tigon I\n", sc->ti_unit); error = EINVAL; break; } error = ti_copy_scratch(sc, mem_param->tgAddr - TI_SCRATCH_DEBUG_OFF, mem_param->len, mem_param->userAddr, 1, (cmd == ALT_READ_TG_MEM) ? 1 : 0, TI_PROCESSOR_B); } else { printf("ti%d: memory address %#x len %d is out of " "supported range\n", sc->ti_unit, mem_param->tgAddr, mem_param->len); error = EINVAL; } break; } case ALT_READ_TG_REG: case ALT_WRITE_TG_REG: { struct tg_reg *regs; u_int32_t tmpval; regs = (struct tg_reg *)addr; /* * Make sure the address in question isn't out of range. */ if (regs->addr > TI_REG_MAX) { error = EINVAL; break; } if (cmd == ALT_READ_TG_REG) { bus_space_read_region_4(sc->ti_btag, sc->ti_bhandle, regs->addr, &tmpval, 1); regs->data = ntohl(tmpval); #if 0 if ((regs->addr == TI_CPU_STATE) || (regs->addr == TI_CPU_CTL_B)) { printf("ti%d: register %#x = %#x\n", sc->ti_unit, regs->addr, tmpval); } #endif } else { tmpval = htonl(regs->data); bus_space_write_region_4(sc->ti_btag, sc->ti_bhandle, regs->addr, &tmpval, 1); } break; } default: error = ENOTTY; break; } return(error); } static void ti_watchdog(ifp) struct ifnet *ifp; { struct ti_softc *sc; sc = ifp->if_softc; TI_LOCK(sc); /* * When we're debugging, the chip is often stopped for long periods * of time, and that would normally cause the watchdog timer to fire. * Since that impedes debugging, we don't want to do that. */ if (sc->ti_flags & TI_FLAG_DEBUGING) { TI_UNLOCK(sc); return; } printf("ti%d: watchdog timeout -- resetting\n", sc->ti_unit); ti_stop(sc); ti_init(sc); ifp->if_oerrors++; TI_UNLOCK(sc); return; } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ static void ti_stop(sc) struct ti_softc *sc; { struct ifnet *ifp; struct ti_cmd_desc cmd; TI_LOCK(sc); ifp = &sc->arpcom.ac_if; /* Disable host interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* * Tell firmware we're shutting down. */ TI_DO_CMD(TI_CMD_HOST_STATE, TI_CMD_CODE_STACK_DOWN, 0); /* Halt and reinitialize. */ ti_chipinit(sc); ti_mem(sc, 0x2000, 0x100000 - 0x2000, NULL); ti_chipinit(sc); /* Free the RX lists. */ ti_free_rx_ring_std(sc); /* Free jumbo RX list. */ ti_free_rx_ring_jumbo(sc); /* Free mini RX list. */ ti_free_rx_ring_mini(sc); /* Free TX buffers. */ ti_free_tx_ring(sc); sc->ti_ev_prodidx.ti_idx = 0; sc->ti_return_prodidx.ti_idx = 0; sc->ti_tx_considx.ti_idx = 0; sc->ti_tx_saved_considx = TI_TXCONS_UNSET; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); TI_UNLOCK(sc); return; } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ static void ti_shutdown(dev) device_t dev; { struct ti_softc *sc; sc = device_get_softc(dev); TI_LOCK(sc); ti_chipinit(sc); TI_UNLOCK(sc); return; } Index: head/sys/sparc64/include/profile.h =================================================================== --- head/sys/sparc64/include/profile.h (revision 99012) +++ head/sys/sparc64/include/profile.h (revision 99013) @@ -1,65 +1,65 @@ /* * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * * from: NetBSD: profile.h,v 1.9 1997/04/06 08:47:37 cgd Exp * from: FreeBSD: src/sys/alpha/include/profile.h,v 1.4 1999/12/29 * $FreeBSD$ */ #ifndef _MACHINE_PROFILE_H_ #define _MACHINE_PROFILE_H_ #define _MCOUNT_DECL void mcount #define FUNCTION_ALIGNMENT 32 typedef u_long fptrdiff_t; typedef u_long uintfptr_t; #define MCOUNT \ void \ _mcount() \ { \ } #ifdef _KERNEL #define MCOUNT_ENTER(s) #define MCOUNT_EXIT(s) #define MCOUNT_DECL(s) #ifdef GUPROF struct gmonparam; -void nullfunc_loop_profiled __P((void)); -void nullfunc_profiled __P((void)); -void startguprof __P((struct gmonparam *p)); -void stopguprof __P((struct gmonparam *p)); +void nullfunc_loop_profiled(void); +void nullfunc_profiled(void); +void startguprof(struct gmonparam *p); +void stopguprof(struct gmonparam *p); #else #define startguprof(p) #define stopguprof(p) #endif /* GUPROF */ #endif #endif /* !_MACHINE_PROFILE_H_ */