diff options
Diffstat (limited to 'recipes/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch')
-rw-r--r-- | recipes/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch | 10239 |
1 files changed, 10239 insertions, 0 deletions
diff --git a/recipes/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch b/recipes/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch new file mode 100644 index 0000000000..0e37220a39 --- /dev/null +++ b/recipes/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch @@ -0,0 +1,10239 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.20/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/Makefile 2005-01-08 12:16:21.886535400 -0500 +@@ -90,11 +90,26 @@ + + CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ + -fno-strict-aliasing -fno-common ++ ++# Turn on -pg to instrument the kernel with calls to mcount(). ++# Unfortunately, gcc won't allow -pg without frame pointers. ++ifdef CONFIG_MCOUNT ++ CFLAGS += -pg ++ CFLAGS_KERNEL += -pg ++ CONFIG_FRAME_POINTER = 1 ++endif + ifndef CONFIG_FRAME_POINTER + CFLAGS += -fomit-frame-pointer + endif + AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) + ++# Broadcom HWNBU source tree ++export SRCBASE := $(TOPDIR)/../.. ++CFLAGS += -I$(SRCBASE)/include ++AFLAGS += -I$(SRCBASE)/include ++ASFLAGS += -I$(SRCBASE)/include ++ ++ + # + # ROOT_DEV specifies the default root-device when making the image. + # This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +--- linux-2.4.20/Rules.make~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/Rules.make 2005-01-07 05:39:02.000000000 -0500 +@@ -176,7 +176,14 @@ + _modinst__: dummy + ifneq "$(strip $(ALL_MOBJS))" "" + mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR) +- cp $(sort $(ALL_MOBJS)) $(MODLIB)/kernel/$(MOD_DESTDIR) ++# cp $(sort $(ALL_MOBJS)) $(MODLIB)/kernel/$(MOD_DESTDIR) ++ for f in $(ALL_MOBJS) ; do \ ++ $(OBJCOPY) -R __ksymtab -R .comment -R .note -x \ ++ `$(NM) $$f | cut -f3- -d' ' | sed -n \ ++ -e 's/__module_parm_\(.*\)/-K \1/p' \ ++ -e 's/__ks..tab_\(.*\)/-K \1/p'` \ ++ $$f $(MODLIB)/kernel/$(MOD_DESTDIR)$(MOD_TARGET)$$f ; \ ++ done + endif + + .PHONY: modules_install +--- linux-2.4.20/arch/mips/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/Makefile 2005-01-08 12:16:19.825848672 -0500 +@@ -39,10 +39,10 @@ + GCCFLAGS := -I $(TOPDIR)/include/asm/gcc + GCCFLAGS += -G 0 -mno-abicalls -fno-pic -pipe + LINKFLAGS += -G 0 -static # -N +-MODFLAGS += -mlong-calls ++MODFLAGS += -mlong-calls -fno-common + +-ifdef CONFIG_REMOTE_DEBUG +-GCCFLAGS += -g ++ifdef CONFIG_DEBUG ++GCCFLAGS += -gstabs+ + ifdef CONFIG_SB1XXX_CORELIS + GCCFLAGS += -mno-sched-prolog -fno-omit-frame-pointer + endif +@@ -499,6 +499,37 @@ + endif + + # ++# Broadcom BCM947XX variants ++# ++ifdef CONFIG_BCM947XX ++LIBS += arch/mips/brcm-boards/generic/brcm.o arch/mips/brcm-boards/bcm947xx/bcm947xx.o ++SUBDIRS += arch/mips/brcm-boards/generic arch/mips/brcm-boards/bcm947xx ++LOADADDR := 0x80001000 ++zImage: vmlinux ++ $(MAKE) -C arch/$(ARCH)/brcm-boards/bcm947xx/compressed ++export LOADADDR ++endif ++ ++# ++# Broadcom BCM933XX variants ++# ++ifdef CONFIG_BCM933XX ++LIBS += arch/mips/brcm-boards/bcm933xx/bcm933xx.o ++SUBDIRS += arch/mips/brcm-boards/bcm933xx ++LOADADDR := 0x80010000 ++ ++vmlinux.srec: vmlinux ++ $(OBJCOPY) -O srec $< $@ ++linux.srec: vmlinux.srec ++ $(OBJCOPY) --adjust-vma=0x80000000 -O srec $< $@ ++vmlinux.out: vmlinux.bin ++ $(TOPDIR)/pstore.sh ++vmlinux.bin: vmlinux ++ $(OBJCOPY) -O binary $< $@ ++export LOADADDR ++endif ++ ++# + # SNI RM200 PCI + # + ifdef CONFIG_SNI_RM200_PCI +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,23 @@ ++# ++# Makefile for Broadcom BCM947XX boards ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.7 2004/04/12 04:31:00 honor Exp $ ++# ++ ++O_TARGET := bcm947xx.o ++ ++export-objs := nvram_linux.o setup.o ++obj-y := prom.o setup.o time.o sbmips.o sbpci.o pcibios.o perfcntr.o gpio.o ++obj-y += sflash.o nvram.o nvram_linux.o ++ ++vpath %.c $(SRCBASE)/shared $(SRCBASE)/shared/nvram ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/compressed/Makefile 2004-05-30 02:30:00.000000000 -0400 +@@ -0,0 +1,100 @@ ++# ++# Makefile for Broadcom BCM947XX boards ++# ++# Copyright 2001-2003, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.6 2003/11/08 08:11:32 honor Exp $ ++# ++# Copyright 2004 Manuel Novoa III <mjn3@codepoet.org> ++# Modified to support bzip'd kernels. ++# Of course, it would be better to integrate bunzip capability into CFE. ++# ++ ++# Link at 3 MB offset in RAM ++#TEXT_START ?= 0x80300000 ++TEXT_START ?= 0x80001000 ++BZ_MEM_TOP := 0x81000000 ++BZ_TEXT_START := BZ_MEM_TOP-0x4000 ++BZ_STACK_TOP := BZ_TEXT_START-4 ++ ++OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S ++ ++SRCBASE := $(TOPDIR)/../.. ++VPATH := $(SRCBASE)/shared ++ASFLAGS += -D__ASSEMBLY__ -I$(SRCBASE)/include -DLOADADDR=$(LOADADDR) ++ASFLAGS += -DBZ_MEM_TOP=$(BZ_MEM_TOP) ++ASFLAGS += -DBZ_TEXT_START=$(BZ_TEXT_START) ++ASFLAGS += -DBZ_STACK_TOP=$(BZ_STACK_TOP) ++CFLAGS += -I$(SRCBASE)/include -DLOADADDR=$(LOADADDR) ++CFLAGS += -DBZ_MEM_TOP=$(BZ_MEM_TOP) ++CFLAGS += -DBZ_TEXT_START=$(BZ_TEXT_START) ++CFLAGS += -DBZ_STACK_TOP=$(BZ_STACK_TOP) ++ifdef CONFIG_MCOUNT ++CFLAGS := $(subst -pg,,$(CFLAGS)) ++endif ++CFLAGS += -ffunction-sections $(call check_gcc, -fvtable-gc, ) ++SEDFLAGS := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/BZ_MEM_TOP/$(BZ_MEM_TOP)/;s/TEXT_START/$(TEXT_START)/ ++ ++SYSTEM ?= $(TOPDIR)/vmlinux ++OBJECTS := head.o data.o ++ ++all: bzImage vmlinuz ++ ++# Don't build dependencies, this may die if $(CC) isn't gcc ++dep: ++ ++# Create a gzipped version named vmlinuz for compatibility ++vmlinuz: piggy ++ gzip -c9 $< > $@ ++ ++# Our bzImage is a gzip'd binary that decompresses and runs ++# the appended bzip'd kernel. ++bzImage: bzLoaderImage.gz piggz ++ cat bzLoaderImage.gz piggz > $@ ++ ++bzLoaderImage.gz: bzLoaderImage ++ gzip -nc9 $< > $@ ++ ++bzLoaderImage: bzLoader ++ $(OBJCOPY) $< $@ ++ ++bzLoader: vmlinux.lds $(OBJECTS) ++ $(LD) -static --gc-sections -no-warn-mismatch -T vmlinux.lds -o $@ $(OBJECTS) ++ ++vmlinux.lds: vmlinux.lds.in Makefile ++ @sed "$(SEDFLAGS)" < $< > $@ ++ ++piggz: piggy ++ bzip2 -c9 $< > $@ ++ ++piggy: $(SYSTEM) ++ $(OBJCOPY) $< $@ ++ ++data.o: data.lds data.image ++ $(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary data.image -b elf32-tradlittlemips ++ ++data.lds: ++ @echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@ ++ ++data.image: decompress_bunzip2.image ++ $(OBJCOPY) $< $@ ++ ++decompress_bunzip2.image: decompress_bunzip2.lds decompress_bunzip2.o ++ $(LD) -static --gc-sections -no-warn-mismatch -T decompress_bunzip2.lds -o $@ decompress_bunzip2.o ++ ++decompress_bunzip2.lds: decompress_bunzip2.lds.in Makefile ++ @sed "$(SEDFLAGS)" < $< > $@ ++ ++mrproper: clean ++ ++clean: ++ rm -f vmlinux vmlinuz piggz piggy *.lds *.o \ ++ bzLoader bzLoaderImage bzLoaderImage.gz bzImage \ ++ data.lds data.image \ ++ decompress_bunzip2.lds decompress_bunzip2.image +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/compressed/head.S 2004-05-30 02:26:40.000000000 -0400 +@@ -0,0 +1,26 @@ ++/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */ ++/* Licensed under the linux kernel's version of the GPL. */ ++ ++#include <asm/asm.h> ++#include <asm/regdef.h> ++ ++ .text ++ LEAF(startup) ++ .set noreorder ++ ++ li t1, BZ_TEXT_START ++ add a0, t1, 0 ++ la a1, code_start ++ la a2, code_stop ++$L1: ++ lw t0, 0(a1) ++ sw t0, 0(a0) ++ add a1, 4 ++ add a0, 4 ++ blt a1, a2, $L1 ++ ++ add sp, t1, -4 ++ jal t1 ++ ++ .set reorder ++ END(startup) +--- linux-2.4.20/arch/mips/brcm-boards/bcm947xx/compressed/misc.c~2.4.20_broadcom_3_37_2_1109_US.patch ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/compressed/misc.c +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/compressed/vmlinux.lds.in 2004-05-21 13:13:07.000000000 -0400 +@@ -0,0 +1,17 @@ ++OUTPUT_ARCH(mips) ++ENTRY(startup) ++SECTIONS { ++ . = TEXT_START; ++ .text : { ++ *(.text) ++ *(.rodata) ++ } ++ ++ .data : { ++ *(.data) ++ } ++ ++ .bss : { ++ *(.bss) ++ } ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/gpio.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,158 @@ ++/* ++ * GPIO char driver ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: gpio.c,v 1.1.1.7 2004/04/12 04:31:00 honor Exp $ ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <asm/uaccess.h> ++ ++#include <typedefs.h> ++#include <bcmutils.h> ++#include <sbutils.h> ++#include <bcmdevs.h> ++ ++static void *gpio_sbh; ++static int gpio_major; ++static devfs_handle_t gpio_dir; ++static struct { ++ char *name; ++ devfs_handle_t handle; ++} gpio_file[] = { ++ { "in", NULL }, ++ { "out", NULL }, ++ { "outen", NULL }, ++ { "control", NULL } ++}; ++ ++static int ++gpio_open(struct inode *inode, struct file * file) ++{ ++ if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file)) ++ return -ENODEV; ++ ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int ++gpio_release(struct inode *inode, struct file * file) ++{ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static ssize_t ++gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos) ++{ ++ u32 val; ++ ++ switch (MINOR(file->f_dentry->d_inode->i_rdev)) { ++ case 0: ++ val = sb_gpioin(gpio_sbh); ++ break; ++ case 1: ++ val = sb_gpioout(gpio_sbh, 0, 0); ++ break; ++ case 2: ++ val = sb_gpioouten(gpio_sbh, 0, 0); ++ break; ++ case 3: ++ val = sb_gpiocontrol(gpio_sbh, 0, 0); ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ if (put_user(val, (u32 *) buf)) ++ return -EFAULT; ++ ++ return sizeof(val); ++} ++ ++static ssize_t ++gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos) ++{ ++ u32 val; ++ ++ if (get_user(val, (u32 *) buf)) ++ return -EFAULT; ++ ++ switch (MINOR(file->f_dentry->d_inode->i_rdev)) { ++ case 0: ++ return -EACCES; ++ case 1: ++ sb_gpioout(gpio_sbh, ~0, val); ++ break; ++ case 2: ++ sb_gpioouten(gpio_sbh, ~0, val); ++ break; ++ case 3: ++ sb_gpiocontrol(gpio_sbh, ~0, val); ++ break; ++ default: ++ return -ENODEV; ++ } ++ ++ return sizeof(val); ++} ++ ++static struct file_operations gpio_fops = { ++ owner: THIS_MODULE, ++ open: gpio_open, ++ release: gpio_release, ++ read: gpio_read, ++ write: gpio_write, ++}; ++ ++static int __init ++gpio_init(void) ++{ ++ int i; ++ ++ if (!(gpio_sbh = sb_kattach())) ++ return -ENODEV; ++ ++ sb_gpiosetcore(gpio_sbh); ++ ++ if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0) ++ return gpio_major; ++ ++ gpio_dir = devfs_mk_dir(NULL, "gpio", NULL); ++ ++ for (i = 0; i < ARRAYSIZE(gpio_file); i++) { ++ gpio_file[i].handle = devfs_register(gpio_dir, ++ gpio_file[i].name, ++ DEVFS_FL_DEFAULT, gpio_major, i, ++ S_IFCHR | S_IRUGO | S_IWUGO, ++ &gpio_fops, NULL); ++ } ++ ++ return 0; ++} ++ ++static void __exit ++gpio_exit(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAYSIZE(gpio_file); i++) ++ devfs_unregister(gpio_file[i].handle); ++ devfs_unregister(gpio_dir); ++ devfs_unregister_chrdev(gpio_major, "gpio"); ++ sb_detach(gpio_sbh); ++} ++ ++module_init(gpio_init); ++module_exit(gpio_exit); +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/nvram_linux.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,638 @@ ++/* ++ * NVRAM variable manipulation (Linux kernel half) ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: nvram_linux.c,v 1.10 2004/04/12 06:07:56 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/interrupt.h> ++#include <linux/spinlock.h> ++#include <linux/slab.h> ++#include <linux/bootmem.h> ++#include <linux/wrapper.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/mtd/mtd.h> ++#include <asm/addrspace.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++ ++#include <typedefs.h> ++#include <bcmendian.h> ++#include <bcmnvram.h> ++#include <bcmutils.h> ++#include <sbconfig.h> ++#include <sbchipc.h> ++#include <sbutils.h> ++#include <sbmips.h> ++#include <sflash.h> ++ ++/* In BSS to minimize text size and page aligned so it can be mmap()-ed */ ++static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE))); ++ ++#ifdef MODULE ++ ++#define early_nvram_get(name) nvram_get(name) ++ ++#else /* !MODULE */ ++ ++/* Global SB handle */ ++extern void *bcm947xx_sbh; ++extern spinlock_t bcm947xx_sbh_lock; ++ ++/* Convenience */ ++#define sbh bcm947xx_sbh ++#define sbh_lock bcm947xx_sbh_lock ++#define KB * 1024 ++#define MB * 1024 * 1024 ++ ++/* Probe for NVRAM header */ ++static void __init ++early_nvram_init(void) ++{ ++ struct nvram_header *header; ++ chipcregs_t *cc; ++ struct sflash *info = NULL; ++ int i; ++ uint32 base, off, lim; ++ ++ if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) { ++ base = CC_FLASH_BASE; ++ switch (readl(&cc->capabilities) & CAP_FLASH_MASK) { ++ case PFLASH: ++ lim = CC_FLASH_MAX; ++ break; ++ ++ case SFLASH_ST: ++ case SFLASH_AT: ++ if ((info = sflash_init(cc)) == NULL) ++ return; ++ lim = info->size; ++ break; ++ ++ case FLASH_NONE: ++ default: ++ return; ++ } ++ } else { ++ /* extif assumed, Stop at 4 MB */ ++ base = FLASH_BASE; ++ lim = FLASH_MAX; ++ } ++ ++ off = FLASH_MIN; ++ while (off <= lim) { ++ /* Windowed flash access */ ++ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE); ++ if (header->magic == NVRAM_MAGIC) { ++ u32 *src = (u32 *) header; ++ u32 *dst = (u32 *) nvram_buf; ++ for (i = 0; i < sizeof(struct nvram_header); i += 4) ++ *dst++ = *src++; ++ for (; i < header->len && i < NVRAM_SPACE; i += 4) ++ *dst++ = ltoh32(*src++); ++ return; ++ } ++ ++ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ ++ if (off == 1 KB) ++ break; ++ else if (off == 4 KB) ++ off = 1 KB; ++ else if (off == lim) ++ off = 4 KB; ++ else ++ off <<= 1; ++ } ++} ++ ++/* Early (before mm or mtd) read-only access to NVRAM */ ++static char * __init ++early_nvram_get(const char *name) ++{ ++ char *var, *value, *end, *eq; ++ ++ if (!name) ++ return NULL; ++ ++ if (!nvram_buf[0]) ++ early_nvram_init(); ++ ++ /* Look for name=value and return value */ ++ var = &nvram_buf[sizeof(struct nvram_header)]; ++ end = nvram_buf + sizeof(nvram_buf) - 2; ++ end[0] = end[1] = '\0'; ++ for (; *var; var = value + strlen(value) + 1) { ++ if (!(eq = strchr(var, '='))) ++ break; ++ value = eq + 1; ++ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0) ++ return value; ++ } ++ ++ return NULL; ++} ++ ++#endif /* !MODULE */ ++ ++extern char * _nvram_get(const char *name); ++extern int _nvram_set(const char *name, const char *value); ++extern int _nvram_unset(const char *name); ++extern int _nvram_getall(char *buf, int count); ++extern int _nvram_commit(struct nvram_header *header); ++extern int _nvram_init(void); ++extern void _nvram_exit(void); ++ ++/* Globals */ ++static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED; ++static struct semaphore nvram_sem; ++static unsigned long nvram_offset = 0; ++static int nvram_major = -1; ++static devfs_handle_t nvram_handle = NULL; ++static struct mtd_info *nvram_mtd = NULL; ++ ++int ++_nvram_read(char *buf) ++{ ++ struct nvram_header *header = (struct nvram_header *) buf; ++ size_t len; ++ ++ if (!nvram_mtd || ++ MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) || ++ len != NVRAM_SPACE || ++ header->magic != NVRAM_MAGIC) { ++ /* Maybe we can recover some data from early initialization */ ++ memcpy(buf, nvram_buf, NVRAM_SPACE); ++ } ++ ++ return 0; ++} ++ ++struct nvram_tuple * ++_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value) ++{ ++ if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE) ++ return NULL; ++ ++ if (!t) { ++ if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC))) ++ return NULL; ++ ++ /* Copy name */ ++ t->name = (char *) &t[1]; ++ strcpy(t->name, name); ++ ++ t->value = NULL; ++ } ++ ++ /* Copy value */ ++ if (!t->value || strcmp(t->value, value)) { ++ t->value = &nvram_buf[nvram_offset]; ++ strcpy(t->value, value); ++ nvram_offset += strlen(value) + 1; ++ } ++ ++ return t; ++} ++ ++void ++_nvram_free(struct nvram_tuple *t) ++{ ++ if (!t) ++ nvram_offset = 0; ++ else ++ kfree(t); ++} ++ ++int ++nvram_set(const char *name, const char *value) ++{ ++ unsigned long flags; ++ int ret; ++ struct nvram_header *header; ++ ++ spin_lock_irqsave(&nvram_lock, flags); ++ if ((ret = _nvram_set(name, value))) { ++ /* Consolidate space and try again */ ++ if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) { ++ if (_nvram_commit(header) == 0) ++ ret = _nvram_set(name, value); ++ kfree(header); ++ } ++ } ++ spin_unlock_irqrestore(&nvram_lock, flags); ++ ++ return ret; ++} ++ ++char * ++real_nvram_get(const char *name) ++{ ++ unsigned long flags; ++ char *value; ++ ++ spin_lock_irqsave(&nvram_lock, flags); ++ value = _nvram_get(name); ++ spin_unlock_irqrestore(&nvram_lock, flags); ++ ++ return value; ++} ++ ++char * ++nvram_get(const char *name) ++{ ++ if (nvram_major >= 0) ++ return real_nvram_get(name); ++ else ++ return early_nvram_get(name); ++} ++ ++int ++nvram_unset(const char *name) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&nvram_lock, flags); ++ ret = _nvram_unset(name); ++ spin_unlock_irqrestore(&nvram_lock, flags); ++ ++ return ret; ++} ++ ++static void ++erase_callback(struct erase_info *done) ++{ ++ wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv; ++ wake_up(wait_q); ++} ++ ++int ++nvram_commit(void) ++{ ++ char *buf; ++ size_t erasesize, len; ++ unsigned int i; ++ int ret; ++ struct nvram_header *header; ++ unsigned long flags; ++ u_int32_t offset; ++ DECLARE_WAITQUEUE(wait, current); ++ wait_queue_head_t wait_q; ++ struct erase_info erase; ++ ++ printk("nvram_commit(): init\n"); ++ ++ if (!nvram_mtd) { ++ printk("nvram_commit: NVRAM not found\n"); ++ return -ENODEV; ++ } ++ ++ if (in_interrupt()) { ++ printk("nvram_commit: not committing in interrupt\n"); ++ return -EINVAL; ++ } ++ ++ /* Backup sector blocks to be erased */ ++ erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize); ++ if (!(buf = kmalloc(erasesize, GFP_KERNEL))) { ++ printk("nvram_commit: out of memory\n"); ++ return -ENOMEM; ++ } ++ ++ down(&nvram_sem); ++#if 0 ++ offset = nvram_mtd->size - erasesize; ++ i = erasesize - NVRAM_SPACE; ++ ret = MTD_READ(nvram_mtd, offset, i, &len, buf); ++ if (ret || len != i) { ++ printk("nvram_commit: read error\n"); ++ ret = -EIO; ++ goto done; ++#endif ++ if ((i = erasesize - NVRAM_SPACE) > 0) { ++ offset = nvram_mtd->size - erasesize; ++ len = 0; ++ ret = MTD_READ(nvram_mtd, offset, i, &len, buf); ++ if (ret || len != i) { ++ printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i); ++ ret = -EIO; ++ goto done; ++ } ++ header = (struct nvram_header *)(buf + i); ++ } else { ++ offset = nvram_mtd->size - NVRAM_SPACE; ++ header = (struct nvram_header *)buf; ++ } ++ ++ /* Regenerate NVRAM */ ++ spin_lock_irqsave(&nvram_lock, flags); ++ ret = _nvram_commit(header); ++ spin_unlock_irqrestore(&nvram_lock, flags); ++ if (ret) ++ goto done; ++ ++ /* Erase sector blocks */ ++ init_waitqueue_head(&wait_q); ++ for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) { ++ erase.mtd = nvram_mtd; ++ erase.addr = offset; ++ erase.len = nvram_mtd->erasesize; ++ erase.callback = erase_callback; ++ erase.priv = (u_long) &wait_q; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ add_wait_queue(&wait_q, &wait); ++ ++ /* Unlock sector blocks */ ++ if (nvram_mtd->unlock) ++ nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize); ++ ++ if ((ret = MTD_ERASE(nvram_mtd, &erase))) { ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&wait_q, &wait); ++ printk("nvram_commit: erase error\n"); ++ goto done; ++ } ++ ++ /* Wait for erase to finish */ ++ schedule(); ++ remove_wait_queue(&wait_q, &wait); ++ } ++ ++ /* Write partition up to end of data area */ ++ offset = nvram_mtd->size - erasesize; ++ i = erasesize - NVRAM_SPACE + header->len; ++ ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf); ++ if (ret || len != i) { ++ printk("nvram_commit: write error\n"); ++ ret = -EIO; ++ goto done; ++ } ++ /* ++ * Reading a few bytes back here will put the device ++ * back to the correct mode on certain flashes */ ++ ++ offset = nvram_mtd->size - erasesize; ++ ret = MTD_READ(nvram_mtd, offset, 4, &len, buf); ++ ++ done: ++ up(&nvram_sem); ++ kfree(buf); ++ printk("nvram_commit(): end\n"); ++ return ret; ++} ++ ++int ++nvram_getall(char *buf, int count) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&nvram_lock, flags); ++ ret = _nvram_getall(buf, count); ++ spin_unlock_irqrestore(&nvram_lock, flags); ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(nvram_get); ++EXPORT_SYMBOL(nvram_getall); ++EXPORT_SYMBOL(nvram_set); ++EXPORT_SYMBOL(nvram_unset); ++EXPORT_SYMBOL(nvram_commit); ++ ++/* User mode interface below */ ++ ++static ssize_t ++dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos) ++{ ++ char tmp[100], *name = tmp, *value; ++ ssize_t ret; ++ unsigned long off; ++ ++ if (count > sizeof(tmp)) { ++ if (!(name = kmalloc(count, GFP_KERNEL))) ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(name, buf, count)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ ++ if (*name == '\0') { ++ /* Get all variables */ ++ ret = nvram_getall(name, count); ++ if (ret == 0) { ++ if (copy_to_user(buf, name, count)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ ret = count; ++ } ++ } else { ++ if (!(value = nvram_get(name))) { ++ ret = 0; ++ goto done; ++ } ++ ++ /* Provide the offset into mmap() space */ ++ off = (unsigned long) value - (unsigned long) nvram_buf; ++ ++ if (put_user(off, (unsigned long *) buf)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ ++ ret = sizeof(unsigned long); ++ } ++ ++ flush_cache_all(); ++ ++done: ++ if (name != tmp) ++ kfree(name); ++ ++ return ret; ++} ++ ++static ssize_t ++dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos) ++{ ++ char tmp[100], *name = tmp, *value; ++ ssize_t ret; ++ ++ if (count > sizeof(tmp)) { ++ if (!(name = kmalloc(count, GFP_KERNEL))) ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(name, buf, count)) { ++ ret = -EFAULT; ++ goto done; ++ } ++ ++ value = name; ++ name = strsep(&value, "="); ++ if (value) ++ ret = nvram_set(name, value) ? : count; ++ else ++ ret = nvram_unset(name) ? : count; ++ ++ done: ++ if (name != tmp) ++ kfree(name); ++ ++ return ret; ++} ++ ++static int ++dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ if (cmd != NVRAM_MAGIC) ++ return -EINVAL; ++ return nvram_commit(); ++} ++ ++static int ++dev_nvram_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long offset = virt_to_phys(nvram_buf); ++ ++ if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, ++ vma->vm_page_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ ++static int ++dev_nvram_open(struct inode *inode, struct file * file) ++{ ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int ++dev_nvram_release(struct inode *inode, struct file * file) ++{ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static struct file_operations dev_nvram_fops = { ++ owner: THIS_MODULE, ++ open: dev_nvram_open, ++ release: dev_nvram_release, ++ read: dev_nvram_read, ++ write: dev_nvram_write, ++ ioctl: dev_nvram_ioctl, ++ mmap: dev_nvram_mmap, ++}; ++ ++static void ++dev_nvram_exit(void) ++{ ++ int order = 0; ++ struct page *page, *end; ++ ++ if (nvram_handle) ++ devfs_unregister(nvram_handle); ++ ++ if (nvram_major >= 0) ++ devfs_unregister_chrdev(nvram_major, "nvram"); ++ ++ if (nvram_mtd) ++ put_mtd_device(nvram_mtd); ++ ++ while ((PAGE_SIZE << order) < NVRAM_SPACE) ++ order++; ++ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); ++ for (page = virt_to_page(nvram_buf); page <= end; page++) ++ mem_map_unreserve(page); ++ ++ _nvram_exit(); ++} ++ ++static int __init ++dev_nvram_init(void) ++{ ++ int order = 0, ret = 0; ++ struct page *page, *end; ++ unsigned int i; ++ ++ /* Allocate and reserve memory to mmap() */ ++ while ((PAGE_SIZE << order) < NVRAM_SPACE) ++ order++; ++ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1); ++ for (page = virt_to_page(nvram_buf); page <= end; page++) ++ mem_map_reserve(page); ++ ++#ifdef CONFIG_MTD ++ /* Find associated MTD device */ ++ for (i = 0; i < MAX_MTD_DEVICES; i++) { ++ nvram_mtd = get_mtd_device(NULL, i); ++ if (nvram_mtd) { ++ if (!strcmp(nvram_mtd->name, "nvram") && ++ nvram_mtd->size >= NVRAM_SPACE) ++ break; ++ put_mtd_device(nvram_mtd); ++ } ++ } ++ if (i >= MAX_MTD_DEVICES) ++ nvram_mtd = NULL; ++#endif ++ ++ /* Initialize hash table lock */ ++ spin_lock_init(&nvram_lock); ++ ++ /* Initialize commit semaphore */ ++ init_MUTEX(&nvram_sem); ++ ++ /* Register char device */ ++ if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) { ++ ret = nvram_major; ++ goto err; ++ } ++ ++ /* Initialize hash table */ ++ _nvram_init(); ++ ++ /* Create /dev/nvram handle */ ++ nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0, ++ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL); ++ ++ /* Set the SDRAM NCDL value into NVRAM if not already done */ ++ if (getintvar(NULL, "sdram_ncdl") == 0) { ++ unsigned int ncdl; ++ char buf[] = "0x00000000"; ++ ++ if ((ncdl = sb_memc_get_ncdl(sbh))) { ++ sprintf(buf, "0x%08x", ncdl); ++ nvram_set("sdram_ncdl", buf); ++ nvram_commit(); ++ } ++ } ++ ++ return 0; ++ ++ err: ++ dev_nvram_exit(); ++ return ret; ++} ++ ++module_init(dev_nvram_init); ++module_exit(dev_nvram_exit); +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/pcibios.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,332 @@ ++/* ++ * Low-Level PCI and SB support for BCM47xx (Linux support code) ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: pcibios.c,v 1.1.1.6 2004/04/12 04:31:00 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/pci.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/paccess.h> ++ ++#include <typedefs.h> ++#include <bcmutils.h> ++#include <sbconfig.h> ++#include <sbpci.h> ++#include <pcicfg.h> ++#include <sbutils.h> ++#include <bcmdevs.h> ++#include <bcmnvram.h> ++ ++/* Global SB handle */ ++extern void *bcm947xx_sbh; ++extern spinlock_t bcm947xx_sbh_lock; ++ ++/* Convenience */ ++#define sbh bcm947xx_sbh ++#define sbh_lock bcm947xx_sbh_lock ++ ++static int ++sbpci_read_config_byte(struct pci_dev *dev, int where, u8 *value) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value)); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++sbpci_read_config_word(struct pci_dev *dev, int where, u16 *value) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value)); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++sbpci_read_config_dword(struct pci_dev *dev, int where, u32 *value) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, value, sizeof(*value)); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++sbpci_write_config_byte(struct pci_dev *dev, int where, u8 value) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value)); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++sbpci_write_config_word(struct pci_dev *dev, int where, u16 value) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value)); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; ++} ++ ++static int ++sbpci_write_config_dword(struct pci_dev *dev, int where, u32 value) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, &value, sizeof(value)); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops pcibios_ops = { ++ sbpci_read_config_byte, ++ sbpci_read_config_word, ++ sbpci_read_config_dword, ++ sbpci_write_config_byte, ++ sbpci_write_config_word, ++ sbpci_write_config_dword ++}; ++ ++ ++void __init ++pcibios_init(void) ++{ ++ ulong flags; ++ ++ if (!(sbh = sb_kattach())) ++ panic("sb_kattach failed"); ++ spin_lock_init(&sbh_lock); ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ sbpci_init(sbh); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ ++ set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000)); ++ ++ /* Scan the SB bus */ ++ pci_scan_bus(0, &pcibios_ops, NULL); ++ ++} ++ ++char * __init ++pcibios_setup(char *str) ++{ ++ if (!strncmp(str, "ban=", 4)) { ++ sbpci_ban(simple_strtoul(str + 4, NULL, 0)); ++ return NULL; ++ } ++ ++ return (str); ++} ++ ++static u32 pci_iobase = 0x100; ++static u32 pci_membase = SB_PCI_DMA; ++ ++void __init ++pcibios_fixup_bus(struct pci_bus *b) ++{ ++ struct list_head *ln; ++ struct pci_dev *d; ++ struct resource *res; ++ int pos, size; ++ u32 *base; ++ u8 irq; ++ ++ printk("PCI: Fixing up bus %d\n", b->number); ++ ++ /* Fix up SB */ ++ if (b->number == 0) { ++ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { ++ d = pci_dev_b(ln); ++ /* Fix up interrupt lines */ ++ pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq); ++ d->irq = irq + 2; ++ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); ++ } ++ } ++ ++ /* Fix up external PCI */ ++ else { ++ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { ++ d = pci_dev_b(ln); ++ /* Fix up resource bases */ ++ for (pos = 0; pos < 6; pos++) { ++ res = &d->resource[pos]; ++ base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase; ++ if (res->end) { ++ size = res->end - res->start + 1; ++ if (*base & (size - 1)) ++ *base = (*base + size) & ~(size - 1); ++ res->start = *base; ++ res->end = res->start + size - 1; ++ *base += size; ++ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); ++ } ++ /* Fix up PCI bridge BAR0 only */ ++ if (b->number == 1 && PCI_SLOT(d->devfn) == 0) ++ break; ++ } ++ /* Fix up interrupt lines */ ++ if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL)) ++ d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq; ++ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); ++ } ++ } ++} ++ ++unsigned int ++pcibios_assign_all_busses(void) ++{ ++ return 1; ++} ++ ++void ++pcibios_align_resource(void *data, struct resource *res, ++ unsigned long size, unsigned long align) ++{ ++} ++ ++int ++pcibios_enable_resources(struct pci_dev *dev) ++{ ++ u16 cmd, old_cmd; ++ int idx; ++ struct resource *r; ++ ++ /* External PCI only */ ++ if (dev->bus->number == 0) ++ return 0; ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ old_cmd = cmd; ++ for(idx=0; idx<6; idx++) { ++ r = &dev->resource[idx]; ++ if (r->flags & IORESOURCE_IO) ++ cmd |= PCI_COMMAND_IO; ++ if (r->flags & IORESOURCE_MEM) ++ cmd |= PCI_COMMAND_MEMORY; ++ } ++ if (dev->resource[PCI_ROM_RESOURCE].start) ++ cmd |= PCI_COMMAND_MEMORY; ++ if (cmd != old_cmd) { ++ printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ } ++ return 0; ++} ++ ++int ++pcibios_enable_device(struct pci_dev *dev, int mask) ++{ ++ ulong flags; ++ uint coreidx; ++ ++ /* External PCI device enable */ ++ if (dev->bus->number != 0) ++ return pcibios_enable_resources(dev); ++ ++ /* These cores come out of reset enabled */ ++ if (dev->device == SB_MIPS || ++ dev->device == SB_MIPS33 || ++ dev->device == SB_EXTIF || ++ dev->device == SB_CC) ++ return 0; ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ coreidx = sb_coreidx(sbh); ++ if (!sb_setcoreidx(sbh, PCI_SLOT(dev->devfn))) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ /* ++ * The USB core requires a special bit to be set during core ++ * reset to enable host (OHCI) mode. Resetting the SB core in ++ * pcibios_enable_device() is a hack for compatibility with ++ * vanilla usb-ohci so that it does not have to know about ++ * SB. A driver that wants to use the USB core in device mode ++ * should know about SB and should reset the bit back to 0 ++ * after calling pcibios_enable_device(). ++ */ ++ if (sb_coreid(sbh) == SB_USB) { ++ sb_core_disable(sbh, sb_coreflags(sbh, 0, 0)); ++ sb_core_reset(sbh, 1 << 29); ++ } else ++ sb_core_reset(sbh, 0); ++ ++ sb_setcoreidx(sbh, coreidx); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ ++ return 0; ++} ++ ++void ++pcibios_update_resource(struct pci_dev *dev, struct resource *root, ++ struct resource *res, int resource) ++{ ++ unsigned long where, size; ++ u32 reg; ++ ++ /* External PCI only */ ++ if (dev->bus->number == 0) ++ return; ++ ++ where = PCI_BASE_ADDRESS_0 + (resource * 4); ++ size = res->end - res->start; ++ pci_read_config_dword(dev, where, ®); ++ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); ++ pci_write_config_dword(dev, where, reg); ++} ++ ++static void __init ++quirk_sbpci_bridge(struct pci_dev *dev) ++{ ++ if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0) ++ return; ++ ++ printk("PCI: Fixing up bridge\n"); ++ ++ /* Enable PCI bridge bus mastering and memory space */ ++ pci_set_master(dev); ++ pcibios_enable_resources(dev); ++ ++ /* Enable PCI bridge BAR1 prefetch and burst */ ++ pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3); ++} ++ ++struct pci_fixup pcibios_fixups[] = { ++ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge }, ++ { 0 } ++}; +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/perfcntr.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,67 @@ ++/* ++ * Broadcom BCM47xx Performance Counter /proc/cpuinfo support ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: perfcntr.c,v 1.1.1.3 2004/04/12 04:31:00 honor Exp $ ++ */ ++ ++#include <asm/mipsregs.h> ++ ++/* ++ * BCM4710 performance counter register select values ++ * No even-odd control-counter mapping, just counters ++ */ ++#define PERF_DCACHE_HIT 0 ++#define PERF_DCACHE_MISS 1 ++#define PERF_ICACHE_HIT 2 ++#define PERF_ICACHE_MISS 3 ++#define PERF_ICOUNT 4 ++ ++/* ++ * Move from Coprocessor 0 Register 25 Select n ++ * data <- CPR[0,25,n] ++ * GPR[1] <- data ++ */ ++#define read_bcm4710_perf_cntr(n) \ ++({ int __res; \ ++ __asm__ __volatile__( \ ++ ".set\tnoreorder\n\t" \ ++ ".set\tnoat\n\t" \ ++ ".word\t"STR(0x4001c800|(n))"\n\t" \ ++ "move\t%0,$1\n\t" \ ++ ".set\tat\n\t" \ ++ ".set\treorder" \ ++ :"=r" (__res)); \ ++ __res;}) ++ ++asmlinkage unsigned int read_perf_cntr(unsigned int counter) ++{ ++ switch (counter) { ++ case PERF_DCACHE_HIT: return read_bcm4710_perf_cntr(PERF_DCACHE_HIT); ++ case PERF_DCACHE_MISS: return read_bcm4710_perf_cntr(PERF_DCACHE_MISS); ++ case PERF_ICACHE_HIT: return read_bcm4710_perf_cntr(PERF_ICACHE_HIT); ++ case PERF_ICACHE_MISS: return read_bcm4710_perf_cntr(PERF_ICACHE_MISS); ++ case PERF_ICOUNT: return read_bcm4710_perf_cntr(PERF_ICOUNT); ++ } ++ return 0; ++} ++ ++asmlinkage void write_perf_cntr(unsigned int counter, unsigned int val) ++{ ++} ++ ++asmlinkage unsigned int read_perf_cntl(unsigned int counter) ++{ ++ return 0; ++} ++ ++asmlinkage void write_perf_cntl(unsigned int counter, unsigned int val) ++{ ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/prom.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,41 @@ ++/* ++ * Early initialization code for BCM94710 boards ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: prom.c,v 1.1.1.6 2004/04/12 04:31:00 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <asm/bootinfo.h> ++ ++void __init ++prom_init(int argc, const char **argv) ++{ ++ unsigned long mem; ++ ++ mips_machgroup = MACH_GROUP_BRCM; ++ mips_machtype = MACH_BCM947XX; ++ ++ /* Figure out memory size by finding aliases */ ++ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { ++ if (*(unsigned long *)((unsigned long)(prom_init) + mem) == ++ *(unsigned long *)(prom_init)) ++ break; ++ } ++ add_memory_region(0, mem, BOOT_MEM_RAM); ++} ++ ++void __init ++prom_free_prom_memory(void) ++{ ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,284 @@ ++/* ++ * Generic setup routines for Broadcom MIPS boards ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: setup.c,v 1.3 2004/04/12 05:42:38 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/serialP.h> ++#include <linux/ide.h> ++#include <asm/bootinfo.h> ++#include <asm/time.h> ++#include <asm/reboot.h> ++ ++#ifdef CONFIG_MTD_PARTITIONS ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/minix_fs.h> ++#include <linux/ext2_fs.h> ++#include <linux/romfs_fs.h> ++#include <linux/cramfs_fs.h> ++#endif ++ ++#include <typedefs.h> ++#include <bcmutils.h> ++#include <bcmnvram.h> ++#include <sbmips.h> ++#include <sbutils.h> ++#include <trxhdr.h> ++ ++extern void bcm947xx_time_init(void); ++extern void bcm947xx_timer_setup(struct irqaction *irq); ++ ++#ifdef CONFIG_REMOTE_DEBUG ++extern void set_debug_traps(void); ++extern void rs_kgdb_hook(struct serial_state *); ++extern void breakpoint(void); ++#endif ++ ++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ++extern struct ide_ops std_ide_ops; ++#endif ++ ++/* Global SB handle */ ++void *bcm947xx_sbh = NULL; ++spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED; ++EXPORT_SYMBOL(bcm947xx_sbh); ++EXPORT_SYMBOL(bcm947xx_sbh_lock); ++ ++/* Convenience */ ++#define sbh bcm947xx_sbh ++#define sbh_lock bcm947xx_sbh_lock ++ ++/* Kernel command line */ ++char arcs_cmdline[CL_SIZE] __initdata = CONFIG_CMDLINE; ++ ++void ++bcm947xx_machine_restart(char *command) ++{ ++ printk("Please stand by while rebooting the system...\n"); ++ ++ /* Set the watchdog timer to reset immediately */ ++ __cli(); ++ sb_watchdog(sbh, 1); ++ while (1); ++} ++ ++void ++bcm947xx_machine_halt(void) ++{ ++ printk("System halted\n"); ++ ++ /* Disable interrupts and watchdog and spin forever */ ++ __cli(); ++ sb_watchdog(sbh, 0); ++ while (1); ++} ++ ++#ifdef CONFIG_SERIAL ++ ++static struct serial_struct rs = { ++ line: 0, ++ flags: ASYNC_BOOT_AUTOCONF, ++ io_type: SERIAL_IO_MEM, ++}; ++ ++static void __init ++serial_add(void *regs, uint irq, uint baud_base, uint reg_shift) ++{ ++ rs.iomem_base = regs; ++ rs.irq = irq + 2; ++ rs.baud_base = baud_base / 16; ++ rs.iomem_reg_shift = reg_shift; ++ ++ early_serial_setup(&rs); ++ ++ rs.line++; ++} ++ ++static void __init ++serial_setup(void *sbh) ++{ ++ sb_serial_init(sbh, serial_add); ++ ++#ifdef CONFIG_REMOTE_DEBUG ++ /* Use the last port for kernel debugging */ ++ if (rs.iomem_base) ++ rs_kgdb_hook(&rs); ++#endif ++} ++ ++#endif /* CONFIG_SERIAL */ ++ ++void __init ++brcm_setup(void) ++{ ++ char *value; ++ ++ /* Get global SB handle */ ++ sbh = sb_kattach(); ++ ++ /* Initialize clocks and interrupts */ ++ sb_mips_init(sbh); ++ ++#ifdef CONFIG_SERIAL ++ /* Initialize UARTs */ ++ serial_setup(sbh); ++#endif ++ ++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ++ ide_ops = &std_ide_ops; ++#endif ++ ++ /* Override default command line arguments */ ++ value = nvram_get("kernel_args"); ++ if (value && strlen(value) && strncmp(value, "empty", 5)) ++ strncpy(arcs_cmdline, value, sizeof(arcs_cmdline)); ++ ++ ++ /* Generic setup */ ++ _machine_restart = bcm947xx_machine_restart; ++ _machine_halt = bcm947xx_machine_halt; ++ _machine_power_off = bcm947xx_machine_halt; ++ ++ board_time_init = bcm947xx_time_init; ++ board_timer_setup = bcm947xx_timer_setup; ++} ++ ++const char * ++get_system_type(void) ++{ ++ return "Broadcom BCM947XX"; ++} ++ ++void __init ++bus_error_init(void) ++{ ++} ++ ++#ifdef CONFIG_MTD_PARTITIONS ++ ++static struct mtd_partition bcm947xx_parts[] = { ++ { name: "pmon", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, ++ { name: "linux", offset: 0, size: 0, }, ++ { name: "rootfs", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, ++ { name: "nvram", offset: 0, size: 0, }, ++ { name: NULL, }, ++}; ++ ++struct mtd_partition * __init ++init_mtd_partitions(struct mtd_info *mtd, size_t size) ++{ ++ struct minix_super_block *minixsb; ++ struct ext2_super_block *ext2sb; ++ struct romfs_super_block *romfsb; ++ struct cramfs_super *cramfsb; ++ struct trx_header *trx; ++ unsigned char buf[512]; ++ int off; ++ size_t len; ++ ++ minixsb = (struct minix_super_block *) buf; ++ ext2sb = (struct ext2_super_block *) buf; ++ romfsb = (struct romfs_super_block *) buf; ++ cramfsb = (struct cramfs_super *) buf; ++ trx = (struct trx_header *) buf; ++ ++ /* Look at every 64 KB boundary */ ++ for (off = 0; off < size; off += (64 * 1024)) { ++ memset(buf, 0xe5, sizeof(buf)); ++ ++ /* ++ * Read block 0 to test for romfs and cramfs superblock ++ */ ++ if (MTD_READ(mtd, off, sizeof(buf), &len, buf) || ++ len != sizeof(buf)) ++ continue; ++ ++ /* Try looking at TRX header for rootfs offset */ ++ if (le32_to_cpu(trx->magic) == TRX_MAGIC) { ++ bcm947xx_parts[1].offset = off; ++ if (le32_to_cpu(trx->offsets[1]) > off) ++ off = le32_to_cpu(trx->offsets[1]); ++ continue; ++ } ++ ++ /* romfs is at block zero too */ ++ if (romfsb->word0 == ROMSB_WORD0 && ++ romfsb->word1 == ROMSB_WORD1) { ++ printk(KERN_NOTICE ++ "%s: romfs filesystem found at block %d\n", ++ mtd->name, off / BLOCK_SIZE); ++ goto done; ++ } ++ ++ /* so is cramfs */ ++ if (cramfsb->magic == CRAMFS_MAGIC) { ++ printk(KERN_NOTICE ++ "%s: cramfs filesystem found at block %d\n", ++ mtd->name, off / BLOCK_SIZE); ++ goto done; ++ } ++ ++ /* ++ * Read block 1 to test for minix and ext2 superblock ++ */ ++ if (MTD_READ(mtd, off + BLOCK_SIZE, sizeof(buf), &len, buf) || ++ len != sizeof(buf)) ++ continue; ++ ++ /* Try minix */ ++ if (minixsb->s_magic == MINIX_SUPER_MAGIC || ++ minixsb->s_magic == MINIX_SUPER_MAGIC2) { ++ printk(KERN_NOTICE ++ "%s: Minix filesystem found at block %d\n", ++ mtd->name, off / BLOCK_SIZE); ++ goto done; ++ } ++ ++ /* Try ext2 */ ++ if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { ++ printk(KERN_NOTICE ++ "%s: ext2 filesystem found at block %d\n", ++ mtd->name, off / BLOCK_SIZE); ++ goto done; ++ } ++ } ++ ++ printk(KERN_NOTICE ++ "%s: Couldn't find valid ROM disk image\n", ++ mtd->name); ++ ++ done: ++ /* Find and size nvram */ ++ bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); ++ bcm947xx_parts[3].size = size - bcm947xx_parts[3].offset; ++ ++ /* Find and size rootfs */ ++ if (off < size) { ++ bcm947xx_parts[2].offset = off; ++ bcm947xx_parts[2].size = bcm947xx_parts[3].offset - bcm947xx_parts[2].offset; ++ } ++ ++ /* Size linux (kernel and rootfs) */ ++ bcm947xx_parts[1].size = bcm947xx_parts[3].offset - bcm947xx_parts[1].offset; ++ ++ /* Size pmon */ ++ bcm947xx_parts[0].size = bcm947xx_parts[1].offset - bcm947xx_parts[0].offset; ++ ++ return bcm947xx_parts; ++} ++ ++EXPORT_SYMBOL(init_mtd_partitions); ++ ++#endif +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/bcm947xx/time.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,117 @@ ++/* ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: time.c,v 1.1.1.6 2004/04/12 04:31:00 honor Exp $ ++ */ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/serial_reg.h> ++#include <linux/interrupt.h> ++#include <asm/addrspace.h> ++#include <asm/io.h> ++#include <asm/time.h> ++ ++#include <typedefs.h> ++#include <bcmnvram.h> ++#include <sbconfig.h> ++#include <sbextif.h> ++#include <sbutils.h> ++#include <sbmips.h> ++ ++/* Global SB handle */ ++extern void *bcm947xx_sbh; ++extern spinlock_t bcm947xx_sbh_lock; ++ ++/* Convenience */ ++#define sbh bcm947xx_sbh ++#define sbh_lock bcm947xx_sbh_lock ++ ++extern int panic_timeout; ++static int watchdog = 0; ++static u8 *mcr = NULL; ++ ++void __init ++bcm947xx_time_init(void) ++{ ++ unsigned int hz; ++ extifregs_t *eir; ++ ++ /* ++ * Use deterministic values for initial counter interrupt ++ * so that calibrate delay avoids encountering a counter wrap. ++ */ ++ write_c0_count(0); ++ write_c0_compare(0xffff); ++ ++ if (!(hz = sb_mips_clock(sbh))) ++ hz = 100000000; ++ ++ printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh), ++ (hz + 500000) / 1000000); ++ ++ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */ ++ mips_counter_frequency = hz / 2; ++ ++ /* Set watchdog interval in ms */ ++ watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0); ++ ++ /* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */ ++ if (watchdog > 0) { ++ if (watchdog < 3000) ++ watchdog = 3000; ++ } ++ ++ ++ /* Set panic timeout in seconds */ ++ panic_timeout = watchdog / 1000; ++ ++ /* Setup blink */ ++ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) { ++ sbconfig_t *sb = (sbconfig_t *)((unsigned int) eir + SBCONFIGOFF); ++ unsigned long base = EXTIF_CFGIF_BASE(sb_base(readl(&sb->sbadmatch1))); ++ mcr = (u8 *) ioremap_nocache(base + UART_MCR, 1); ++ } ++} ++ ++static void ++bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ /* Generic MIPS timer code */ ++ timer_interrupt(irq, dev_id, regs); ++ ++ /* Set the watchdog timer to reset after the specified number of ms */ ++ if (watchdog > 0) ++ sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog); ++ ++#ifdef CONFIG_HWSIM ++ (*((int *)0xa0000f1c))++; ++#else ++ /* Blink one of the LEDs in the external UART */ ++ if (mcr && !(jiffies % (HZ/2))) ++ writeb(readb(mcr) ^ UART_MCR_OUT2, mcr); ++#endif ++} ++ ++static struct irqaction bcm947xx_timer_irqaction = { ++ bcm947xx_timer_interrupt, ++ SA_INTERRUPT, ++ 0, ++ "timer", ++ NULL, ++ NULL ++}; ++ ++void __init ++bcm947xx_timer_setup(struct irqaction *irq) ++{ ++ /* Enable the timer interrupt */ ++ setup_irq(7, &bcm947xx_timer_irqaction); ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/generic/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,26 @@ ++# ++# Makefile for generic Broadcom MIPS boards ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.6 2004/04/12 04:31:00 honor Exp $ ++# ++ ++.S.s: ++ $(CPP) $(AFLAGS) $< -o $*.s ++.S.o: ++ $(CC) $(AFLAGS) -c $< -o $*.o ++ ++O_TARGET := brcm.o ++ ++obj-y := int-handler.o irq.o ++ ++obj-$(CONFIG_REMOTE_DEBUG) += gdb_hook.o ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/generic/gdb_hook.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,120 @@ ++/* ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * ######################################################################## ++ * ++ * This is the interface to the remote debugger stub. ++ * ++ */ ++ ++#include <linux/serialP.h> ++#include <linux/serial_reg.h> ++ ++#include <asm/serial.h> ++#include <asm/io.h> ++ ++static struct async_struct kdb_port_info = {0}; ++ ++static __inline__ unsigned int serial_in(struct async_struct *info, int offset) ++{ ++ return readb((unsigned long) info->iomem_base + ++ (offset<<info->iomem_reg_shift)); ++} ++ ++static __inline__ void serial_out(struct async_struct *info, int offset, ++ int value) ++{ ++ writeb(value, (unsigned long) info->iomem_base + ++ (offset<<info->iomem_reg_shift)); ++} ++ ++void rs_kgdb_hook(struct serial_state *ser) { ++ int t; ++ ++ kdb_port_info.state = ser; ++ kdb_port_info.magic = SERIAL_MAGIC; ++ kdb_port_info.port = ser->port; ++ kdb_port_info.flags = ser->flags; ++ kdb_port_info.iomem_base = ser->iomem_base; ++ kdb_port_info.iomem_reg_shift = ser->iomem_reg_shift; ++ kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS; ++ ++ /* ++ * Clear all interrupts ++ */ ++ serial_in(&kdb_port_info, UART_LSR); ++ serial_in(&kdb_port_info, UART_RX); ++ serial_in(&kdb_port_info, UART_IIR); ++ serial_in(&kdb_port_info, UART_MSR); ++ ++ /* ++ * Now, initialize the UART ++ */ ++ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ ++ serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR); ++ ++ /* ++ * and set the speed of the serial port ++ * (currently hardwired to 115200 8N1 ++ */ ++ ++ /* baud rate is fixed to 115200 (is this sufficient?)*/ ++ t = kdb_port_info.state->baud_base / 115200; ++ /* set DLAB */ ++ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); ++ serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */ ++ serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */ ++ /* reset DLAB */ ++ serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); ++} ++ ++int putDebugChar(char c) ++{ ++ ++ if (!kdb_port_info.state) { /* need to init device first */ ++ return 0; ++ } ++ ++ while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0) ++ ; ++ ++ serial_out(&kdb_port_info, UART_TX, c); ++ ++ return 1; ++} ++ ++char getDebugChar(void) ++{ ++ if (!kdb_port_info.state) { /* need to init device first */ ++ return 0; ++ } ++ ++ while (!(serial_in(&kdb_port_info, UART_LSR) & 1)) ++ ; ++ ++ return(serial_in(&kdb_port_info, UART_RX)); ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/generic/int-handler.S 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,51 @@ ++/* ++ * Generic interrupt handler for Broadcom MIPS boards ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: int-handler.S,v 1.1.1.6 2004/04/12 04:31:00 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++ ++#include <asm/asm.h> ++#include <asm/mipsregs.h> ++#include <asm/regdef.h> ++#include <asm/stackframe.h> ++ ++/* ++ * MIPS IRQ Source ++ * -------- ------ ++ * 0 Software (ignored) ++ * 1 Software (ignored) ++ * 2 Combined hardware interrupt (hw0) ++ * 3 Hardware ++ * 4 Hardware ++ * 5 Hardware ++ * 6 Hardware ++ * 7 R4k timer ++ */ ++ ++ .text ++ .set noreorder ++ .set noat ++ .align 5 ++ NESTED(brcmIRQ, PT_SIZE, sp) ++ SAVE_ALL ++ CLI ++ .set at ++ .set noreorder ++ ++ jal brcm_irq_dispatch ++ move a0, sp ++ ++ j ret_from_irq ++ nop ++ ++ END(brcmIRQ) +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/brcm-boards/generic/irq.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,130 @@ ++/* ++ * Generic interrupt control functions for Broadcom MIPS boards ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: irq.c,v 1.1.1.6 2004/04/12 04:31:00 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++ ++#include <asm/irq.h> ++#include <asm/mipsregs.h> ++#include <asm/gdb-stub.h> ++ ++#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) ++ ++extern asmlinkage void brcmIRQ(void); ++extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs); ++ ++void ++brcm_irq_dispatch(struct pt_regs *regs) ++{ ++ u32 cause; ++ ++ cause = read_c0_cause() & ++ read_c0_status() & ++ CAUSEF_IP; ++ ++#ifdef CONFIG_KERNPROF ++ change_c0_status(cause | 1, 1); ++#else ++ clear_c0_status(cause); ++#endif ++ ++ if (cause & CAUSEF_IP7) ++ do_IRQ(7, regs); ++ if (cause & CAUSEF_IP2) ++ do_IRQ(2, regs); ++ if (cause & CAUSEF_IP3) ++ do_IRQ(3, regs); ++ if (cause & CAUSEF_IP4) ++ do_IRQ(4, regs); ++ if (cause & CAUSEF_IP5) ++ do_IRQ(5, regs); ++ if (cause & CAUSEF_IP6) ++ do_IRQ(6, regs); ++} ++ ++static void ++enable_brcm_irq(unsigned int irq) ++{ ++ if (irq < 8) ++ set_c0_status(1 << (irq + 8)); ++ else ++ set_c0_status(IE_IRQ0); ++} ++ ++static void ++disable_brcm_irq(unsigned int irq) ++{ ++ if (irq < 8) ++ clear_c0_status(1 << (irq + 8)); ++ else ++ clear_c0_status(IE_IRQ0); ++} ++ ++static void ++ack_brcm_irq(unsigned int irq) ++{ ++ /* Already done in brcm_irq_dispatch */ ++} ++ ++static unsigned int ++startup_brcm_irq(unsigned int irq) ++{ ++ enable_brcm_irq(irq); ++ ++ return 0; /* never anything pending */ ++} ++ ++static void ++end_brcm_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) ++ enable_brcm_irq(irq); ++} ++ ++static struct hw_interrupt_type brcm_irq_type = { ++ typename: "MIPS", ++ startup: startup_brcm_irq, ++ shutdown: disable_brcm_irq, ++ enable: enable_brcm_irq, ++ disable: disable_brcm_irq, ++ ack: ack_brcm_irq, ++ end: end_brcm_irq, ++ NULL ++}; ++ ++void __init ++init_IRQ(void) ++{ ++ int i; ++ ++ for (i = 0; i < NR_IRQS; i++) { ++ irq_desc[i].status = IRQ_DISABLED; ++ irq_desc[i].action = 0; ++ irq_desc[i].depth = 1; ++ irq_desc[i].handler = &brcm_irq_type; ++ } ++ ++ set_except_vector(0, brcmIRQ); ++ change_c0_status(ST0_IM, ALLINTS); ++ ++#ifdef CONFIG_REMOTE_DEBUG ++ printk("Breaking into debugger...\n"); ++ set_debug_traps(); ++ breakpoint(); ++#endif ++} +--- linux-2.4.20/arch/mips/config-shared.in~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/config-shared.in 2005-01-08 12:16:20.335771152 -0500 +@@ -191,8 +191,15 @@ + fi + fi + fi ++dep_bool 'Support for Broadcom MIPS-based boards' CONFIG_MIPS_BRCM $CONFIG_EXPERIMENTAL ++dep_bool 'Support for Broadcom BCM947XX' CONFIG_BCM947XX $CONFIG_MIPS_BRCM ++if [ "$CONFIG_BCM947XX" = "y" ] ; then ++ bool ' Support for Broadcom BCM4710' CONFIG_BCM4710 ++ bool ' Support for Broadcom BCM4310' CONFIG_BCM4310 ++ bool ' Support for Broadcom BCM4704' CONFIG_BCM4704 ++ bool ' Support for Broadcom BCM5365' CONFIG_BCM5365 ++fi + bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI +-bool 'Support for TANBAC TB0226 (Mbase)' CONFIG_TANBAC_TB0226 + dep_bool 'Support for Toshiba JMR-TX3927 board' CONFIG_TOSHIBA_JMR3927 $CONFIG_MIPS32 + bool 'Support for Victor MP-C303/304' CONFIG_VICTOR_MPC30X + if [ "$CONFIG_VICTOR_MPC30X" = "y" ]; then +@@ -206,6 +213,11 @@ + define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n + + # ++# Provide an option for a default kernel command line ++# ++string 'Default kernel command string' CONFIG_CMDLINE "" ++ ++# + # Select some configuration options automatically based on user selections. + # + +@@ -526,6 +538,13 @@ + define_bool CONFIG_SWAP_IO_SPACE_L y + define_bool CONFIG_BOOT_ELF32 y + fi ++if [ "$CONFIG_BCM947XX" = "y" ] ; then ++ define_bool CONFIG_PCI y ++ define_bool CONFIG_NONCOHERENT_IO y ++ define_bool CONFIG_NEW_TIME_C y ++ define_bool CONFIG_NEW_IRQ y ++ define_bool CONFIG_HND y ++fi + if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then + define_bool CONFIG_ARC32 y + define_bool CONFIG_ARC_MEMORY y +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/defconfig-bcm947xx 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,769 @@ ++# ++# Automatically generated make config: don't edit ++# ++CONFIG_MIPS=y ++CONFIG_MIPS32=y ++# CONFIG_MIPS64 is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++# CONFIG_KMOD is not set ++ ++# ++# Machine selection ++# ++# CONFIG_ACER_PICA_61 is not set ++# CONFIG_MIPS_DB1000 is not set ++# CONFIG_MIPS_DB1100 is not set ++# CONFIG_MIPS_DB1500 is not set ++# CONFIG_MIPS_PB1000 is not set ++# CONFIG_MIPS_PB1100 is not set ++# CONFIG_MIPS_PB1500 is not set ++# CONFIG_BAGET_MIPS is not set ++# CONFIG_CASIO_E55 is not set ++# CONFIG_MIPS_COBALT is not set ++# CONFIG_DECSTATION is not set ++# CONFIG_MIPS_EV64120 is not set ++# CONFIG_MIPS_EV96100 is not set ++# CONFIG_MIPS_IVR is not set ++# CONFIG_HP_LASERJET is not set ++# CONFIG_IBM_WORKPAD is not set ++# CONFIG_LASAT is not set ++# CONFIG_MIPS_ITE8172 is not set ++# CONFIG_MIPS_ATLAS is not set ++# CONFIG_MIPS_MAGNUM_4000 is not set ++# CONFIG_MIPS_MALTA is not set ++# CONFIG_MIPS_SEAD is not set ++# CONFIG_MOMENCO_OCELOT is not set ++# CONFIG_MOMENCO_OCELOT_G is not set ++# CONFIG_DDB5074 is not set ++# CONFIG_DDB5476 is not set ++# CONFIG_DDB5477 is not set ++# CONFIG_NEC_OSPREY is not set ++# CONFIG_NEC_EAGLE is not set ++# CONFIG_OLIVETTI_M700 is not set ++# CONFIG_NINO is not set ++# CONFIG_SGI_IP22 is not set ++# CONFIG_SGI_IP27 is not set ++# CONFIG_SGI_IP32 is not set ++# CONFIG_SIBYTE_SB1xxx_SOC is not set ++CONFIG_MIPS_BRCM=y ++CONFIG_BCM947XX=y ++CONFIG_BCM4710=y ++CONFIG_BCM4310=y ++CONFIG_BCM4704=y ++# CONFIG_BCM5365 is not set ++# CONFIG_SNI_RM200_PCI is not set ++# CONFIG_TOSHIBA_JMR3927 is not set ++# CONFIG_VICTOR_MPC30X is not set ++# CONFIG_ZAO_CAPCELLA is not set ++# CONFIG_HIGHMEM is not set ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++CONFIG_CMDLINE="root=/dev/mtdblock2 noinitrd console=ttyS0,115200" ++CONFIG_PCI=y ++CONFIG_NONCOHERENT_IO=y ++CONFIG_NEW_TIME_C=y ++CONFIG_NEW_IRQ=y ++CONFIG_HND=y ++# CONFIG_MIPS_AU1000 is not set ++ ++# ++# CPU selection ++# ++CONFIG_CPU_MIPS32=y ++# CONFIG_CPU_MIPS64 is not set ++# CONFIG_CPU_R3000 is not set ++# CONFIG_CPU_TX39XX is not set ++# CONFIG_CPU_VR41XX is not set ++# CONFIG_CPU_R4300 is not set ++# CONFIG_CPU_R4X00 is not set ++# CONFIG_CPU_TX49XX is not set ++# CONFIG_CPU_R5000 is not set ++# CONFIG_CPU_R5432 is not set ++# CONFIG_CPU_R6000 is not set ++# CONFIG_CPU_NEVADA is not set ++# CONFIG_CPU_R8000 is not set ++# CONFIG_CPU_R10000 is not set ++# CONFIG_CPU_RM7000 is not set ++# CONFIG_CPU_SB1 is not set ++CONFIG_CPU_HAS_PREFETCH=y ++# CONFIG_VTAG_ICACHE is not set ++# CONFIG_64BIT_PHYS_ADDR is not set ++# CONFIG_CPU_ADVANCED is not set ++CONFIG_CPU_HAS_LLSC=y ++# CONFIG_CPU_HAS_LLDSCD is not set ++# CONFIG_CPU_HAS_WB is not set ++CONFIG_CPU_HAS_SYNC=y ++ ++# ++# General setup ++# ++CONFIG_CPU_LITTLE_ENDIAN=y ++CONFIG_NET=y ++# CONFIG_PCI_NAMES is not set ++# CONFIG_ISA is not set ++# CONFIG_EISA is not set ++# CONFIG_TC is not set ++# CONFIG_MCA is not set ++# CONFIG_SBUS is not set ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++# CONFIG_PCMCIA is not set ++ ++# ++# PCI Hotplug Support ++# ++# CONFIG_HOTPLUG_PCI is not set ++# CONFIG_HOTPLUG_PCI_COMPAQ is not set ++# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set ++# CONFIG_HOTPLUG_PCI_ACPI is not set ++# CONFIG_SYSVIPC is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_PRINT_SYSCALLS is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_MIPS32_COMPAT is not set ++# CONFIG_MIPS32_O32 is not set ++# CONFIG_MIPS32_N32 is not set ++# CONFIG_BINFMT_ELF32 is not set ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_PM is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++# CONFIG_MTD_BLOCK is not set ++CONFIG_MTD_BLOCK_RO=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++# CONFIG_MTD_CFI_B4 is not set ++CONFIG_MTD_CFI_I1=y ++# CONFIG_MTD_CFI_I2 is not set ++# CONFIG_MTD_CFI_I4 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_CFI_SSTSTD=y ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++CONFIG_MTD_BCM947XX=y ++# CONFIG_MTD_PB1000 is not set ++# CONFIG_MTD_PB1500 is not set ++# CONFIG_MTD_PB1100 is not set ++# CONFIG_MTD_CSTM_MIPS_IXX is not set ++# CONFIG_MTD_OCELOT is not set ++# CONFIG_MTD_LASAT is not set ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++CONFIG_MTD_SFLASH=y ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_MSYS is not set ++# CONFIG_NOROOT is not set ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BLK_STATS is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++# CONFIG_NETLINK_DEV is not set ++CONFIG_NETFILTER=y ++# CONFIG_NETFILTER_DEBUG is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++CONFIG_IP_MROUTE=y ++# CONFIG_IP_PIMSM_V1 is not set ++# CONFIG_IP_PIMSM_V2 is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++ ++# ++# IP: Netfilter Configuration ++# ++CONFIG_IP_NF_CONNTRACK=y ++CONFIG_IP_NF_FTP=y ++CONFIG_IP_NF_TFTP=y ++CONFIG_IP_NF_H323=y ++# CONFIG_IP_NF_IRC is not set ++# CONFIG_IP_NF_MMS is not set ++CONFIG_IP_NF_CT_PROTO_GRE=y ++CONFIG_IP_NF_PPTP=y ++# CONFIG_IP_NF_SIP is not set ++# CONFIG_IP_NF_QUEUE is not set ++CONFIG_IP_NF_IPTABLES=y ++# CONFIG_IP_NF_MATCH_LIMIT is not set ++# CONFIG_IP_NF_POOL is not set ++CONFIG_IP_NF_MATCH_MAC=y ++# CONFIG_IP_NF_MATCH_PKTTYPE is not set ++CONFIG_IP_NF_MATCH_MARK=y ++# CONFIG_IP_NF_MATCH_MULTIPORT is not set ++# CONFIG_IP_NF_MATCH_MPORT is not set ++CONFIG_IP_NF_MATCH_TOS=y ++CONFIG_IP_NF_MATCH_TIME=y ++# CONFIG_IP_NF_MATCH_ECN is not set ++# CONFIG_IP_NF_MATCH_DSCP is not set ++# CONFIG_IP_NF_MATCH_AH_ESP is not set ++# CONFIG_IP_NF_MATCH_LENGTH is not set ++# CONFIG_IP_NF_MATCH_TTL is not set ++CONFIG_IP_NF_MATCH_TCPMSS=y ++# CONFIG_IP_NF_MATCH_HELPER is not set ++CONFIG_IP_NF_MATCH_STATE=y ++# CONFIG_IP_NF_MATCH_CONNTRACK is not set ++# CONFIG_IP_NF_MATCH_UNCLEAN is not set ++CONFIG_IP_NF_MATCH_WEBSTR=y ++# CONFIG_IP_NF_MATCH_OWNER is not set ++CONFIG_IP_NF_FILTER=y ++CONFIG_IP_NF_TARGET_REJECT=y ++# CONFIG_IP_NF_TARGET_MIRROR is not set ++CONFIG_IP_NF_NAT=y ++CONFIG_IP_NF_NAT_NEEDED=y ++CONFIG_IP_NF_TARGET_MASQUERADE=y ++CONFIG_IP_NF_TARGET_REDIRECT=y ++CONFIG_IP_NF_AUTOFW=y ++CONFIG_IP_NF_TARGET_TRIGGER=y ++CONFIG_IP_NF_NAT_H323=y ++CONFIG_IP_NF_NAT_PPTP=y ++# CONFIG_IP_NF_NAT_SIP is not set ++CONFIG_IP_NF_NAT_PROTO_GRE=y ++# CONFIG_IP_NF_NAT_LOCAL is not set ++# CONFIG_IP_NF_NAT_SNMP_BASIC is not set ++CONFIG_IP_NF_NAT_FTP=y ++CONFIG_IP_NF_NAT_TFTP=y ++CONFIG_IP_NF_MANGLE=y ++CONFIG_IP_NF_TARGET_TOS=y ++# CONFIG_IP_NF_TARGET_ECN is not set ++# CONFIG_IP_NF_TARGET_DSCP is not set ++CONFIG_IP_NF_TARGET_LOG=y ++CONFIG_IP_NF_TARGET_MARK=y ++# CONFIG_IP_NF_TARGET_ULOG is not set ++CONFIG_IP_NF_TARGET_TCPMSS=y ++# CONFIG_IP_NF_ARPTABLES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++CONFIG_VLAN_8021Q=y ++ ++# ++# ++# ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++CONFIG_BRIDGE=y ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++CONFIG_NET_SCHED=y ++CONFIG_NET_SCH_CBQ=y ++CONFIG_NET_SCH_HTB=y ++# CONFIG_NET_SCH_CSZ is not set ++CONFIG_NET_SCH_PRIO=y ++# CONFIG_NET_SCH_RED is not set ++CONFIG_NET_SCH_SFQ=y ++# CONFIG_NET_SCH_TEQL is not set ++# CONFIG_NET_SCH_TBF is not set ++# CONFIG_NET_SCH_GRED is not set ++# CONFIG_NET_SCH_DSMARK is not set ++# CONFIG_NET_SCH_INGRESS is not set ++CONFIG_NET_QOS=y ++CONFIG_NET_ESTIMATOR=y ++CONFIG_NET_CLS=y ++# CONFIG_NET_CLS_TCINDEX is not set ++# CONFIG_NET_CLS_ROUTE4 is not set ++# CONFIG_NET_CLS_FW is not set ++CONFIG_NET_CLS_U32=y ++# CONFIG_NET_CLS_RSVP is not set ++# CONFIG_NET_CLS_RSVP6 is not set ++# CONFIG_NET_CLS_POLICE is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Telephony Support ++# ++# CONFIG_PHONE is not set ++# CONFIG_PHONE_IXJ is not set ++# CONFIG_PHONE_IXJ_PCMCIA is not set ++ ++# ++# ATA/IDE/MFM/RLL support ++# ++# CONFIG_IDE is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_HD is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_PCI is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# Broadcom HND network devices ++# ++CONFIG_HND=y ++# CONFIG_IL is not set ++# CONFIG_IL_42XX is not set ++# CONFIG_IL_47XX is not set ++CONFIG_LARQ_BUF=0 ++CONFIG_ET=m ++# CONFIG_ET_4413 is not set ++CONFIG_ET_47XX=y ++CONFIG_WL=m ++CONFIG_WL_AP=y ++CONFIG_WL_STA=y ++# CONFIG_WL_OID is not set ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_SUNLANCE is not set ++# CONFIG_HAPPYMEAL is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++# CONFIG_NET_VENDOR_SMC is not set ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_HP100 is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_E1000 is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=y ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=y ++CONFIG_PPP_SYNC_TTY=y ++# CONFIG_PPP_DEFLATE is not set ++# CONFIG_PPP_BSDCOMP is not set ++CONFIG_PPPOE=y ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++# CONFIG_INPUT is not set ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++ ++# ++# Character devices ++# ++# CONFIG_VT is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++CONFIG_SERIAL_NONSTANDARD=y ++# CONFIG_COMPUTONE is not set ++# CONFIG_ROCKETPORT is not set ++# CONFIG_CYCLADES is not set ++# CONFIG_DIGIEPCA is not set ++# CONFIG_DIGI is not set ++# CONFIG_ESPSERIAL is not set ++# CONFIG_MOXA_INTELLIO is not set ++# CONFIG_MOXA_SMARTIO is not set ++# CONFIG_ISI is not set ++# CONFIG_SYNCLINK is not set ++# CONFIG_SYNCLINKMP is not set ++CONFIG_N_HDLC=y ++# CONFIG_RISCOM8 is not set ++# CONFIG_SPECIALIX is not set ++# CONFIG_SX is not set ++# CONFIG_RIO is not set ++# CONFIG_STALDRV is not set ++# CONFIG_SERIAL_TX3912 is not set ++# CONFIG_SERIAL_TX3912_CONSOLE is not set ++# CONFIG_TXX927_SERIAL is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=16 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++ ++# ++# Input core support is needed for gameports ++# ++ ++# ++# Input core support is needed for joysticks ++# ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_AMD_PM768 is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++# CONFIG_FAT_FS is not set ++# CONFIG_MSDOS_FS is not set ++# CONFIG_UMSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++CONFIG_CRAMFS=y ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++CONFIG_DEVFS_FS=y ++CONFIG_DEVFS_MOUNT=y ++# CONFIG_DEVFS_DEBUG is not set ++# CONFIG_DEVPTS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++# CONFIG_NFS_FS is not set ++# CONFIG_NFS_V3 is not set ++# CONFIG_ROOT_NFS is not set ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++# CONFIG_SUNRPC is not set ++# CONFIG_LOCKD is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++# CONFIG_MSDOS_PARTITION is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_EFI_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++# CONFIG_NLS is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND is not set ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Support for USB gadgets ++# ++# CONFIG_USB_GADGET is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_CROSSCOMPILE=y ++# CONFIG_KERNPROF is not set ++# CONFIG_MCOUNT is not set ++# CONFIG_DEBUG is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_MIPS_UNCACHED is not set ++# CONFIG_KTRACE is not set ++# CONFIG_HWSIM is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++# CONFIG_ZLIB_DEFLATE is not set +--- linux-2.4.20/arch/mips/kernel/cpu-probe.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/cpu-probe.c 2005-01-07 05:39:02.000000000 -0500 +@@ -158,6 +158,16 @@ + unsigned long config0 = read_c0_config(); + unsigned long config1; + ++ if ((config0 & CONF_BE) != ++#ifdef CONFIG_CPU_LITTLE_ENDIAN ++ 0 ++#else ++ CONF_BE ++#endif ++ ) { ++ panic("Kernel compiled little-endian, but running on a big-endian cpu"); ++ } ++ + if (config0 & (1 << 31)) { + /* MIPS32 or MIPS64 compliant CPU. Read Config 1 register. */ + mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | +@@ -179,9 +189,9 @@ + } + #endif + mips_cpu.processor_id = read_c0_prid(); +- switch (mips_cpu.processor_id & 0xff0000) { ++ switch (mips_cpu.processor_id & PRID_COMP_MASK) { + case PRID_COMP_LEGACY: +- switch (mips_cpu.processor_id & 0xff00) { ++ switch (mips_cpu.processor_id & PRID_IMP_MASK) { + case PRID_IMP_R2000: + mips_cpu.cputype = CPU_R2000; + mips_cpu.isa_level = MIPS_CPU_ISA_I; +@@ -191,7 +201,7 @@ + mips_cpu.tlbsize = 64; + break; + case PRID_IMP_R3000: +- if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A) ++ if ((mips_cpu.processor_id & PRID_REV_MASK) == PRID_REV_R3000A) + if (cpu_has_confreg()) + mips_cpu.cputype = CPU_R3081E; + else +@@ -205,7 +215,7 @@ + mips_cpu.tlbsize = 64; + break; + case PRID_IMP_R4000: +- if ((mips_cpu.processor_id & 0xff) >= PRID_REV_R4400) ++ if ((mips_cpu.processor_id & PRID_REV_MASK) >= PRID_REV_R4400) + mips_cpu.cputype = CPU_R4400SC; + else + mips_cpu.cputype = CPU_R4000SC; +@@ -287,7 +297,7 @@ + mips_cpu.icache.ways = 2; + mips_cpu.dcache.ways = 2; + } else { +- switch (mips_cpu.processor_id & 0xff) { ++ switch (mips_cpu.processor_id & PRID_REV_MASK) { + case PRID_REV_TX3912: + mips_cpu.cputype = CPU_TX3912; + mips_cpu.tlbsize = 32; +@@ -405,7 +415,7 @@ + break; + #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) + case PRID_COMP_MIPS: +- switch (mips_cpu.processor_id & 0xff00) { ++ switch (mips_cpu.processor_id & PRID_IMP_MASK) { + case PRID_IMP_4KC: + mips_cpu.cputype = CPU_4KC; + mips_cpu.isa_level = MIPS_CPU_ISA_M32; +@@ -432,10 +442,10 @@ + } + break; + case PRID_COMP_ALCHEMY: +- switch (mips_cpu.processor_id & 0xff00) { ++ switch (mips_cpu.processor_id & PRID_IMP_MASK) { + case PRID_IMP_AU1_REV1: + case PRID_IMP_AU1_REV2: +- switch ((mips_cpu.processor_id >> 24) & 0xff) { ++ switch ((mips_cpu.processor_id >> 24) & PRID_REV_MASK) { + case 0: + mips_cpu.cputype = CPU_AU1000; + break; +@@ -456,9 +466,43 @@ + break; + } + break; ++ case PRID_COMP_BROADCOM: ++ switch (mips_cpu.processor_id & PRID_IMP_MASK) { ++ case PRID_IMP_BCM4710: ++ mips_cpu.cputype = CPU_BCM4710; ++ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | ++ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER; ++ config1 = read_c0_config1(); ++ if (config1 & (1 << 3)) ++ mips_cpu.options |= MIPS_CPU_WATCH; ++ if (config1 & (1 << 2)) ++ mips_cpu.options |= MIPS_CPU_MIPS16; ++ if (config1 & 1) ++ mips_cpu.options |= MIPS_CPU_FPU; ++ mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; ++ break; ++ case PRID_IMP_4KC: ++ case PRID_IMP_BCM3302: ++ mips_cpu.cputype = CPU_BCM3302; ++ mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX | ++ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER; ++ config1 = read_c0_config1(); ++ if (config1 & (1 << 3)) ++ mips_cpu.options |= MIPS_CPU_WATCH; ++ if (config1 & (1 << 2)) ++ mips_cpu.options |= MIPS_CPU_MIPS16; ++ if (config1 & 1) ++ mips_cpu.options |= MIPS_CPU_FPU; ++ mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT; ++ break; ++ default: ++ mips_cpu.cputype = CPU_UNKNOWN; ++ break; ++ } ++ break; + #endif /* CONFIG_CPU_MIPS32 */ + case PRID_COMP_SIBYTE: +- switch (mips_cpu.processor_id & 0xff00) { ++ switch (mips_cpu.processor_id & PRID_IMP_MASK) { + case PRID_IMP_SB1: + mips_cpu.cputype = CPU_SB1; + mips_cpu.isa_level = MIPS_CPU_ISA_M64; +--- linux-2.4.20/arch/mips/kernel/entry.S~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/entry.S 2005-01-07 05:39:02.000000000 -0500 +@@ -100,6 +100,10 @@ + * and R4400 SC and MC versions. + */ + NESTED(except_vec3_generic, 0, sp) ++#ifdef CONFIG_BCM4710 ++ nop ++ nop ++#endif + mfc0 k1, CP0_CAUSE + la k0, exception_handlers + andi k1, k1, 0x7c +--- linux-2.4.20/arch/mips/kernel/head.S~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/head.S 2005-01-07 05:39:02.000000000 -0500 +@@ -28,12 +28,20 @@ + #include <asm/mipsregs.h> + #include <asm/stackframe.h> + ++#ifdef CONFIG_BCM4710 ++#undef eret ++#define eret nop; nop; eret ++#endif ++ + .text ++ j kernel_entry ++ nop ++ + /* + * Reserved space for exception handlers. + * Necessary for machines which link their kernels at KSEG0. + */ +- .fill 0x400 ++ .fill 0x3f4 + + /* The following two symbols are used for kernel profiling. */ + EXPORT(stext) +--- linux-2.4.20/arch/mips/kernel/proc.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/proc.c 2005-01-07 05:39:02.000000000 -0500 +@@ -73,9 +73,12 @@ + [CPU_VR4122] "NEC VR4122", + [CPU_VR4131] "NEC VR4131", + [CPU_VR4181] "NEC VR4181", +- [CPU_VR4181A] "NEC VR4181A" ++ [CPU_VR4181A] "NEC VR4181A", ++ [CPU_BCM4710] "BCM4710", ++ [CPU_BCM3302] "BCM3302", + }; + ++extern unsigned long unaligned_instructions; + + static int show_cpuinfo(struct seq_file *m, void *v) + { +@@ -124,6 +127,21 @@ + seq_printf(m, "sc emulations\t\t: %lu\n", sc_ops); + #endif + ++ seq_printf(m, "unaligned_instructions\t: %u\n", unaligned_instructions); ++ ++#if defined(CONFIG_BCM4710) || defined(CONFIG_BCM4310) ++ seq_printf(m, "dcache hits\t\t: %u\n", ++ read_perf_cntr(0)); ++ seq_printf(m, "dcache misses\t\t: %u\n", ++ read_perf_cntr(1)); ++ seq_printf(m, "icache hits\t\t: %u\n", ++ read_perf_cntr(2)); ++ seq_printf(m, "icache misses\t\t: %u\n", ++ read_perf_cntr(3)); ++ seq_printf(m, "instructions\t\t: %u\n", ++ read_perf_cntr(4)); ++#endif ++ + return 0; + } + +--- linux-2.4.20/arch/mips/kernel/setup.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/setup.c 2005-01-07 05:39:02.000000000 -0500 +@@ -490,12 +490,12 @@ + void victor_mpc30x_setup(void); + void ibm_workpad_setup(void); + void casio_e55_setup(void); +- void tanbac_tb0226_setup(void); + void jmr3927_setup(void); + void it8172_setup(void); + void swarm_setup(void); + void hp_setup(void); + void au1x00_setup(void); ++ void brcm_setup(void); + + #ifdef CONFIG_BLK_DEV_FD + fd_ops = &no_fd_ops; +@@ -671,6 +671,9 @@ + hp_setup(); + break; + #endif ++ case MACH_GROUP_BRCM: ++ brcm_setup(); ++ break; + default: + panic("Unsupported architecture"); + } +--- linux-2.4.20/arch/mips/kernel/traps.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/traps.c 2005-01-07 05:39:02.000000000 -0500 +@@ -405,17 +405,12 @@ + unsigned long value) + { + const struct exception_table_entry *mid; +- long diff; + +- while (first < last) { +- mid = (last - first) / 2 + first; +- diff = mid->insn - value; +- if (diff < 0) +- first = mid + 1; +- else +- last = mid; ++ for (mid = first; mid <= last; mid++) { ++ if (mid->insn == value) ++ return mid->nextinsn; + } +- return (first == last && first->insn == value) ? first->nextinsn : 0; ++ return 0; + } + + extern spinlock_t modlist_lock; +@@ -918,7 +913,7 @@ + + void __init trap_init(void) + { +- extern char except_vec1_generic; ++ extern char except_vec1_generic, except_vec2_generic; + extern char except_vec3_generic, except_vec3_r4000; + extern char except_vec_ejtag_debug; + extern char except_vec4; +@@ -928,6 +923,7 @@ + + /* Copy the generic exception handler code to it's final destination. */ + memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80); ++ memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80); + + /* + * Setup default vectors +@@ -1014,6 +1010,12 @@ + //set_except_vector(15, handle_ndc); + } + ++ if (mips_cpu.cputype == CPU_SB1) { ++ /* Enable timer interrupt and scd mapped interrupt */ ++ clear_c0_status(0xf000); ++ set_c0_status(0xc00); ++ } ++ + if (mips_cpu.options & MIPS_CPU_FPU) { + save_fp_context = _save_fp_context; + restore_fp_context = _restore_fp_context; +--- linux-2.4.20/arch/mips/kernel/unaligned.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/kernel/unaligned.c 2005-01-07 05:39:02.000000000 -0500 +@@ -145,7 +145,7 @@ + if (verify_area(VERIFY_READ, addr, 2)) + goto sigbus; + +- __asm__ __volatile__ (".set\tnoat\n" ++ __asm__(".set\tnoat\n" + #ifdef __BIG_ENDIAN + "1:\tlb\t%0, 0(%2)\n" + "2:\tlbu\t$1, 1(%2)\n\t" +@@ -178,7 +178,7 @@ + if (verify_area(VERIFY_READ, addr, 4)) + goto sigbus; + +- __asm__ __volatile__ ( ++ __asm__( + #ifdef __BIG_ENDIAN + "1:\tlwl\t%0, (%2)\n" + "2:\tlwr\t%0, 3(%2)\n\t" +@@ -208,7 +208,7 @@ + if (verify_area(VERIFY_READ, addr, 2)) + goto sigbus; + +- __asm__ __volatile__ ( ++ __asm__( + ".set\tnoat\n" + #ifdef __BIG_ENDIAN + "1:\tlbu\t%0, 0(%2)\n" +@@ -250,7 +250,7 @@ + if (verify_area(VERIFY_READ, addr, 4)) + goto sigbus; + +- __asm__ __volatile__ ( ++ __asm__( + #ifdef __BIG_ENDIAN + "1:\tlwl\t%0, (%2)\n" + "2:\tlwr\t%0, 3(%2)\n\t" +@@ -294,7 +294,7 @@ + if (verify_area(VERIFY_READ, addr, 8)) + goto sigbus; + +- __asm__ __volatile__ ( ++ __asm__( + #ifdef __BIG_ENDIAN + "1:\tldl\t%0, (%2)\n" + "2:\tldr\t%0, 7(%2)\n\t" +@@ -329,7 +329,7 @@ + goto sigbus; + + value = regs->regs[insn.i_format.rt]; +- __asm__ __volatile__ ( ++ __asm__( + #ifdef __BIG_ENDIAN + ".set\tnoat\n" + "1:\tsb\t%1, 1(%2)\n\t" +@@ -365,7 +365,7 @@ + goto sigbus; + + value = regs->regs[insn.i_format.rt]; +- __asm__ __volatile__ ( ++ __asm__( + #ifdef __BIG_ENDIAN + "1:\tswl\t%1,(%2)\n" + "2:\tswr\t%1, 3(%2)\n\t" +@@ -403,7 +403,7 @@ + goto sigbus; + + value = regs->regs[insn.i_format.rt]; +- __asm__ __volatile__ ( ++ __asm__( + #ifdef __BIG_ENDIAN + "1:\tsdl\t%1,(%2)\n" + "2:\tsdr\t%1, 7(%2)\n\t" +--- linux-2.4.20/arch/mips/mm/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/mm/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -28,6 +28,7 @@ + obj-$(CONFIG_CPU_MIPS32) += pg-mips32.o c-mips32.o tlb-r4k.o tlbex-r4k.o + obj-$(CONFIG_CPU_MIPS64) += pg-mips32.o c-mips32.o tlb-r4k.o tlbex-r4k.o + obj-$(CONFIG_CPU_SB1) += pg-sb1.o c-sb1.o tlb-sb1.o tlbex-r4k.o cex-sb1.o cerr-sb1.o ++obj-$(CONFIG_BCM4710) += c-bcm4710.o + + obj-$(CONFIG_R5000_CPU_SCACHE) += r5k-sc.o + +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/arch/mips/mm/c-bcm4710.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,392 @@ ++/* ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++ * ++ * MIPS32 CPU variant specific MMU/Cache routines. ++ */ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/mm.h> ++ ++#include <asm/bootinfo.h> ++#include <asm/cpu.h> ++#include <asm/bcache.h> ++#include <asm/io.h> ++#include <asm/page.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/mmu_context.h> ++ ++/* CP0 hazard avoidance. */ ++#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ ++ "nop; nop; nop; nop; nop; nop;\n\t" \ ++ ".set reorder\n\t") ++ ++/* Primary cache parameters. */ ++extern int icache_size, dcache_size; /* Size in bytes */ ++extern int ic_lsize, dc_lsize; /* LineSize in bytes */ ++ ++#include <asm/cacheops.h> ++#include <asm/bcm4710_cache.h> ++ ++#undef DEBUG_CACHE ++ ++static inline void mips32_flush_cache_all_pc(void) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ blast_dcache(); blast_icache(); ++ local_irq_restore(flags); ++} ++ ++static void mips32_flush_cache_range_pc(struct mm_struct *mm, ++ unsigned long start, ++ unsigned long end) ++{ ++ if(mm->context != 0) { ++ unsigned long flags; ++ ++#ifdef DEBUG_CACHE ++ printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); ++#endif ++ local_irq_save(flags); ++ blast_dcache(); blast_icache(); ++ local_irq_restore(flags); ++ } ++} ++ ++/* ++ * On architectures like the Sparc, we could get rid of lines in ++ * the cache created only by a certain context, but on the MIPS ++ * (and actually certain Sparc's) we cannot. ++ */ ++static void mips32_flush_cache_mm_pc(struct mm_struct *mm) ++{ ++ if(mm->context != 0) { ++#ifdef DEBUG_CACHE ++ printk("cmm[%d]", (int)mm->context); ++#endif ++ mips32_flush_cache_all_pc(); ++ } ++} ++ ++static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, ++ unsigned long page) ++{ ++ struct mm_struct *mm = vma->vm_mm; ++ pgd_t *pgdp; ++ pmd_t *pmdp; ++ pte_t *ptep; ++ ++ /* ++ * If ownes no valid ASID yet, cannot possibly have gotten ++ * this page into the cache. ++ */ ++ if (mm->context == 0) ++ return; ++ ++#ifdef DEBUG_CACHE ++ printk("cpage[%d,%08lx]", (int)mm->context, page); ++#endif ++ page &= PAGE_MASK; ++ pgdp = pgd_offset(mm, page); ++ pmdp = pmd_offset(pgdp, page); ++ ptep = pte_offset(pmdp, page); ++ ++ /* ++ * If the page isn't marked valid, the page cannot possibly be ++ * in the cache. ++ */ ++ if (!(pte_val(*ptep) & _PAGE_VALID)) ++ return; ++ ++ /* ++ * Doing flushes for another ASID than the current one is ++ * too difficult since Mips32 caches do a TLB translation ++ * for every cache flush operation. So we do indexed flushes ++ * in that case, which doesn't overly flush the cache too much. ++ */ ++ if (mm == current->active_mm) { ++ blast_dcache_page(page); ++ } else { ++ /* Do indexed flush, too much work to get the (possible) ++ * tlb refills to work correctly. ++ */ ++ page = (KSEG0 + (page & (dcache_size - 1))); ++ blast_dcache_page_indexed(page); ++ } ++} ++ ++/* If the addresses passed to these routines are valid, they are ++ * either: ++ * ++ * 1) In KSEG0, so we can do a direct flush of the page. ++ * 2) In KSEG2, and since every process can translate those ++ * addresses all the time in kernel mode we can do a direct ++ * flush. ++ * 3) In KSEG1, no flush necessary. ++ */ ++static void mips32_flush_page_to_ram_pc(struct page *page) ++{ ++ blast_dcache_page((unsigned long)page_address(page)); ++} ++ ++static void ++mips32_flush_icache_range(unsigned long start, unsigned long end) ++{ ++ flush_cache_all(); ++} ++ ++static void ++mips32_flush_icache_page(struct vm_area_struct *vma, struct page *page) ++{ ++ /* ++ * If there's no context yet, or the page isn't executable, no icache ++ * flush is needed. ++ */ ++ if (!(vma->vm_flags & VM_EXEC)) ++ return; ++ ++ /* ++ * We're not sure of the virtual address(es) involved here, so ++ * conservatively flush the entire caches. ++ */ ++ flush_cache_all(); ++} ++ ++/* ++ * Writeback and invalidate the primary cache dcache before DMA. ++ */ ++static void ++mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) ++{ ++ unsigned long end, a; ++ unsigned long flags; ++ ++ if (size >= dcache_size) { ++ blast_dcache(); ++ } else if (size) { ++ local_irq_save(flags); ++ a = addr & ~(dc_lsize - 1); ++ end = (addr + size - 1) & ~(dc_lsize - 1); ++ BCM4710_FILL_TLB(a); ++ BCM4710_FILL_TLB(end); ++ while (1) { ++ flush_dcache_line(a); /* Hit_Writeback_Inv_D */ ++ if (a == end) break; ++ a += dc_lsize; ++ } ++ local_irq_restore(flags); ++ } ++ bc_wback_inv(addr, size); ++} ++ ++static void ++mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) ++{ ++ unsigned long end, a; ++ unsigned long flags; ++ ++ if (size >= dcache_size) { ++ blast_dcache(); ++ } else if (size) { ++ local_irq_save(flags); ++ a = addr & ~(dc_lsize - 1); ++ end = (addr + size - 1) & ~(dc_lsize - 1); ++ BCM4710_FILL_TLB(a); ++ BCM4710_FILL_TLB(end); ++ while (1) { ++ invalidate_dcache_line(a); /* Hit_Inv_D */ ++ if (a == end) break; ++ a += dc_lsize; ++ } ++ local_irq_restore(flags); ++ } ++ ++ bc_inv(addr, size); ++} ++ ++static void ++mips32_dma_cache_wback(unsigned long addr, unsigned long size) ++{ ++ panic("mips32_dma_cache called - should not happen."); ++} ++ ++/* ++ * While we're protected against bad userland addresses we don't care ++ * very much about what happens in that case. Usually a segmentation ++ * fault will dump the process later on anyway ... ++ */ ++static void mips32_flush_cache_sigtramp(unsigned long addr) ++{ ++ BCM4710_PROTECTED_FILL_TLB(addr); ++ BCM4710_PROTECTED_FILL_TLB(addr + 4); ++ protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); ++ protected_flush_icache_line(addr & ~(ic_lsize - 1)); ++} ++ ++static void mips32_flush_icache_all(void) ++{ ++ if (mips_cpu.icache.flags | MIPS_CACHE_VTAG_CACHE) { ++ blast_icache(); ++ } ++} ++ ++/* Detect and size the various caches. */ ++static void __init probe_icache(unsigned long config) ++{ ++ unsigned long config1; ++ unsigned int lsize; ++ ++ mips_cpu.icache.flags = 0; ++ if (!(config & (1 << 31))) { ++ /* ++ * Not a MIPS32 complainant CPU. ++ * Config 1 register not supported, we assume R4k style. ++ */ ++ icache_size = 1 << (12 + ((config >> 9) & 7)); ++ ic_lsize = 16 << ((config >> 5) & 1); ++ mips_cpu.icache.linesz = ic_lsize; ++ ++ /* ++ * We cannot infer associativity - assume direct map ++ * unless probe template indicates otherwise ++ */ ++ if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1; ++ mips_cpu.icache.sets = ++ (icache_size / ic_lsize) / mips_cpu.icache.ways; ++ } else { ++ config1 = read_c0_config1(); ++ ++ if ((lsize = ((config1 >> 19) & 7))) ++ mips_cpu.icache.linesz = 2 << lsize; ++ else ++ mips_cpu.icache.linesz = lsize; ++ mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7); ++ mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7); ++ ++ ic_lsize = mips_cpu.icache.linesz; ++ icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * ++ ic_lsize; ++ ++ if ((config & 0x8) || (mips_cpu.cputype == CPU_20KC)) { ++ /* ++ * The CPU has a virtually tagged I-cache. ++ * Some older 20Kc chips doesn't have the 'VI' bit in ++ * the config register, so we also check for 20Kc. ++ */ ++ mips_cpu.icache.flags = MIPS_CACHE_VTAG_CACHE; ++ printk("Virtually tagged I-cache detected\n"); ++ } ++ } ++ printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n", ++ icache_size >> 10, ic_lsize, mips_cpu.icache.ways); ++} ++ ++static void __init probe_dcache(unsigned long config) ++{ ++ unsigned long config1; ++ unsigned int lsize; ++ ++ mips_cpu.dcache.flags = 0; ++ if (!(config & (1 << 31))) { ++ /* ++ * Not a MIPS32 complainant CPU. ++ * Config 1 register not supported, we assume R4k style. ++ */ ++ dcache_size = 1 << (12 + ((config >> 6) & 7)); ++ dc_lsize = 16 << ((config >> 4) & 1); ++ mips_cpu.dcache.linesz = dc_lsize; ++ /* ++ * We cannot infer associativity - assume direct map ++ * unless probe template indicates otherwise ++ */ ++ if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1; ++ mips_cpu.dcache.sets = ++ (dcache_size / dc_lsize) / mips_cpu.dcache.ways; ++ } else { ++ config1 = read_c0_config1(); ++ ++ if ((lsize = ((config1 >> 10) & 7))) ++ mips_cpu.dcache.linesz = 2 << lsize; ++ else ++ mips_cpu.dcache.linesz= lsize; ++ mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7); ++ mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7); ++ ++ dc_lsize = mips_cpu.dcache.linesz; ++ dcache_size = ++ mips_cpu.dcache.sets * mips_cpu.dcache.ways ++ * dc_lsize; ++ } ++ printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n", ++ dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways); ++} ++ ++static void __init setup_noscache_funcs(void) ++{ ++ _clear_page = (void *)mips32_clear_page_dc; ++ _copy_page = (void *)mips32_copy_page_dc; ++ _flush_cache_all = mips32_flush_cache_all_pc; ++ ___flush_cache_all = mips32_flush_cache_all_pc; ++ _flush_cache_mm = mips32_flush_cache_mm_pc; ++ _flush_cache_range = mips32_flush_cache_range_pc; ++ _flush_cache_page = mips32_flush_cache_page_pc; ++ _flush_page_to_ram = mips32_flush_page_to_ram_pc; ++ ++ _flush_icache_page = mips32_flush_icache_page; ++ ++ _dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc; ++ _dma_cache_wback = mips32_dma_cache_wback; ++ _dma_cache_inv = mips32_dma_cache_inv_pc; ++} ++ ++static void __init _change_cachability(u32 cm) ++{ ++ change_c0_config(CONF_CM_CMASK, cm); ++ ++ if ((mips_cpu.processor_id & (PRID_COMP_MASK | PRID_IMP_MASK)) == ++ (PRID_COMP_BROADCOM | PRID_IMP_BCM3302)) { ++ cm = read_c0_diag(); ++ /* Enable icache */ ++ cm |= (1 << 31); ++ /* Enable dcache */ ++ cm |= (1 << 30); ++ write_c0_diag(cm); ++ } ++} ++static void (*change_cachability)(u32); ++ ++void __init ld_mmu_bcm4710(void) ++{ ++ unsigned long config = read_c0_config(); ++ ++ change_cachability = (void (*)(u32)) KSEG1ADDR((unsigned long)(_change_cachability)); ++ change_cachability(CONF_CM_DEFAULT); ++ ++ probe_icache(config); ++ probe_dcache(config); ++ setup_noscache_funcs(); ++ ++ _flush_cache_sigtramp = mips32_flush_cache_sigtramp; ++ _flush_icache_range = mips32_flush_icache_range; /* Ouch */ ++ _flush_icache_all = mips32_flush_icache_all; ++ ++ __flush_cache_all(); ++} +--- linux-2.4.20/arch/mips/mm/c-mips32.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/mm/c-mips32.c 2005-01-07 05:39:02.000000000 -0500 +@@ -163,7 +163,6 @@ + unsigned long page) + { + struct mm_struct *mm = vma->vm_mm; +- unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; +@@ -212,7 +211,6 @@ + unsigned long page) + { + struct mm_struct *mm = vma->vm_mm; +- unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; +@@ -313,11 +311,11 @@ + mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) + { + unsigned long end, a; +- unsigned int flags; ++ unsigned long flags; + + if (size >= dcache_size) { + blast_dcache(); +- } else { ++ } else if (size) { + local_irq_save(flags); + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); +@@ -338,9 +336,7 @@ + + if (size >= scache_size) { + blast_scache(); +- return; +- } +- ++ } else if (size) { + a = addr & ~(sc_lsize - 1); + end = (addr + size - 1) & ~(sc_lsize - 1); + while (1) { +@@ -348,17 +344,18 @@ + if (a == end) break; + a += sc_lsize; + } ++ } + } + + static void + mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) + { + unsigned long end, a; +- unsigned int flags; ++ unsigned long flags; + + if (size >= dcache_size) { + blast_dcache(); +- } else { ++ } else if (size) { + local_irq_save(flags); + a = addr & ~(dc_lsize - 1); + end = (addr + size - 1) & ~(dc_lsize - 1); +@@ -380,9 +377,7 @@ + + if (size >= scache_size) { + blast_scache(); +- return; +- } +- ++ } else if (size) { + a = addr & ~(sc_lsize - 1); + end = (addr + size - 1) & ~(sc_lsize - 1); + while (1) { +@@ -390,6 +385,7 @@ + if (a == end) break; + a += sc_lsize; + } ++ } + } + + static void +@@ -664,16 +660,51 @@ + setup_noscache_funcs(); + } + +-void __init ld_mmu_mips32(void) ++#if defined(CONFIG_BCM4310) || defined(CONFIG_BCM4704) || defined(CONFIG_BCM5365) ++static void __init _change_cachability(u32 cm) + { +- unsigned long config = read_c0_config(); +- extern char except_vec2_generic; ++ change_c0_config(CONF_CM_CMASK, cm); + +- /* Default cache error handler for MIPS32 */ +- memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80); +- memcpy((void *)(KSEG1 + 0x100), &except_vec2_generic, 0x80); ++ if (BCM330X(mips_cpu.processor_id)) { ++ cm = read_c0_diag(); ++ /* Enable icache */ ++ cm |= (1 << 31); ++ /* Enable dcache */ ++ cm |= (1 << 30); ++ write_c0_diag(cm); ++ } ++} ++static void (*change_cachability)(u32); ++#endif + +- change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); ++#ifdef CONFIG_BCM4704 ++static void __init mips32_icache_fill(unsigned long addr, uint nbytes) ++{ ++ int i; ++ for (i = 0; i < nbytes; i += ic_lsize) ++ fill_icache_line((addr + i)); ++ } ++ ++/* ++ * This must be run from the cache on 4704A0 ++ * so there are no mips core BIU ops in progress ++ * when the PFC is enabled. ++ */ ++#define PFC_CR0 0xff400000 /* control reg 0 */ ++#define PFC_CR1 0xff400004 /* control reg 1 */ ++static void __init enable_pfc(u32 mode) ++{ ++ /* write range */ ++ *(volatile u32 *)PFC_CR1 = 0xffff0000; ++ ++ /* enable */ ++ *(volatile u32 *)PFC_CR0 = mode; ++} ++#endif ++ ++void __init ld_mmu_mips32(void) ++{ ++ unsigned long config = read_c0_config(); + + probe_icache(config); + probe_dcache(config); +@@ -684,4 +715,20 @@ + _flush_icache_all = mips32_flush_icache_all; + + __flush_cache_all(); ++ ++#if defined(CONFIG_BCM4310) || defined(CONFIG_BCM4704) || defined(CONFIG_BCM5365) ++ change_cachability = (void (*)(u32)) KSEG1ADDR((unsigned long)(_change_cachability)); ++ change_cachability(CONF_CM_DEFAULT); ++#else ++ change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT); ++#endif ++ ++#ifdef CONFIG_BCM4704 ++ /* enable prefetch cache */ ++ if (BCM330X(mips_cpu.processor_id) && ++ (read_c0_diag() & (1 << 29))) { ++ mips32_icache_fill((unsigned long) &enable_pfc, 64); ++ enable_pfc(0x15); ++ } ++#endif + } +--- linux-2.4.20/arch/mips/mm/loadmmu.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/arch/mips/mm/loadmmu.c 2005-01-07 05:39:02.000000000 -0500 +@@ -61,12 +61,21 @@ + extern void ld_mmu_andes(void); + extern void ld_mmu_sb1(void); + extern void ld_mmu_mips32(void); ++extern void ld_mmu_bcm4710(void); + extern void r3k_tlb_init(void); + extern void r4k_tlb_init(void); + extern void sb1_tlb_init(void); + + void __init loadmmu(void) + { ++#ifdef CONFIG_BCM4710 ++ if (mips_cpu.cputype == CPU_BCM4710 && ++ (mips_cpu.processor_id & PRID_REV_MASK) == 0) { ++ printk("Loading BCM4710 MMU routines.\n"); ++ ld_mmu_bcm4710(); ++ r4k_tlb_init(); ++ } else ++#endif + if (mips_cpu.options & MIPS_CPU_4KTLB) { + #if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_VR41XX) || \ + defined(CONFIG_CPU_R4300) || defined(CONFIG_CPU_R5000) || \ +--- linux-2.4.20/arch/mips/mm/tlbex-r4k.S~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/mm/tlbex-r4k.S 2005-01-07 05:39:02.000000000 -0500 +@@ -162,6 +162,9 @@ + .set noat + LEAF(except_vec0_r4000) + .set mips3 ++#ifdef CONFIG_BCM4704 ++ nop ++#endif + GET_PGD(k0, k1) # get pgd pointer + mfc0 k0, CP0_BADVADDR # Get faulting address + srl k0, k0, _PGDIR_SHIFT # get pgd only bits +@@ -248,15 +251,16 @@ + eret # return from trap + END(except_vec0_nevada) + +- /* TLB refill, EXL == 0, SB1 with M3 errata handling version */ +- LEAF(except_vec0_sb1) + #ifdef BCM1250_M3_WAR ++ ++ /* TLB refill, EXL == 0, SB1 with M3 errata handling version */ ++ LEAF(except_vec0_sb1_m3) + mfc0 k0, CP0_BADVADDR + mfc0 k1, CP0_ENTRYHI + xor k0, k1 +- srl k0, k0, PAGE_SHIFT+1 +- bnez k0, 1f +-#endif ++ srl k0, k0, 13 # PAGE_SHIFT + 1 ++ bnez k0, 2f ++ + GET_PGD(k0, k1) # get pgd pointer + mfc0 k0, CP0_BADVADDR # Get faulting address + srl k0, k0, _PGDIR_SHIFT # get pgd only bits +@@ -273,9 +277,12 @@ + P_MTC0 k0, CP0_ENTRYLO0 # load it + PTE_SRL k1, k1, 6 # convert to entrylo1 + P_MTC0 k1, CP0_ENTRYLO1 # load it ++ b 1f + tlbwr # write random tlb entry +-1: eret # return from trap +- END(except_vec0_sb1) ++1: nop ++2: eret # return from trap ++ END(except_vec0_sb1_m3) ++#endif /* BCM1250_M3_WAR */ + + /* TLB refill, EXL == 0, R4[40]00/R5000 badvaddr hwbug version */ + LEAF(except_vec0_r45k_bvahwbug) +--- linux-2.4.20/arch/mips/ramdisk/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/arch/mips/ramdisk/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -5,10 +5,10 @@ + # removes any old dependencies. DON'T put your own dependencies here + # unless it's something special (ie not a .c file). + # +- + O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) +-img = $(CONFIG_EMBEDDED_RAMDISK_IMAGE) +-ramdisk.o: ramdisk.gz ld.script ++img = $(subst ",,$(CONFIG_EMBEDDED_RAMDISK_IMAGE)) ++ ++ramdisk.o: $(img) ld.script + echo "O_FORMAT: " $(O_FORMAT) + $(LD) -T ld.script -b binary --oformat $(O_FORMAT) -o $@ $(img) + +--- linux-2.4.20/drivers/block/Config.in~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/block/Config.in 2005-01-07 05:39:02.000000000 -0500 +@@ -4,6 +4,10 @@ + mainmenu_option next_comment + comment 'Block devices' + ++tristate 'M-Systems DiskOnChip Block Device support' CONFIG_BLK_DEV_MSYS ++ ++tristate 'No-root support' CONFIG_NOROOT ++ + tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD + if [ "$CONFIG_AMIGA" = "y" ]; then + tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY +--- linux-2.4.20/drivers/block/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/block/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -34,4 +34,9 @@ + + subdir-$(CONFIG_PARIDE) += paride + ++ifdef CONFIG_BLK_DEV_MSYS ++obj-$(CONFIG_BLK_DEV_MSYS) += ../../../../router/trueffs/linux/doc.o ++subdir-$(CONFIG_BLK_DEV_MSYS) += ../../../../router/trueffs/linux ++endif ++ + include $(TOPDIR)/Rules.make +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/block/dummy.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,70 @@ ++/* ++ * dummyfs: a placeholder filesystem that sleeps forever when mounted ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: dummy.c,v 1.1.1.6 2004/04/12 04:31:22 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/sched.h> ++#include <linux/fs.h> ++#include <linux/file.h> ++#include <linux/stat.h> ++#include <linux/errno.h> ++#include <linux/major.h> ++#include <linux/wait.h> ++#include <linux/blk.h> ++#include <linux/init.h> ++#include <linux/devfs_fs_kernel.h> ++#include <linux/smp_lock.h> ++#include <linux/swap.h> ++#include <linux/slab.h> ++ ++#include <asm/uaccess.h> ++ ++/* I don't thik anyone would mind if we stole CM206_CDROM_MAJOR */ ++#define DUMMY_MAJOR 0x20 ++ ++static int dummy_open(struct inode *inode, struct file *file) ++{ ++ DECLARE_WAIT_QUEUE_HEAD(wait); ++ ++ for (;;) ++ sleep_on(&wait); ++ ++ return 0; ++} ++ ++static struct block_device_operations dummy_fops = { ++ open: dummy_open, ++}; ++ ++int __init dummy_init(void) ++{ ++ if (devfs_register_blkdev(DUMMY_MAJOR, "dummy", &dummy_fops)) { ++ printk(KERN_WARNING "Unable to get major number for dummy device\n"); ++ return -EIO; ++ } ++ ++ register_disk(NULL, MKDEV(DUMMY_MAJOR, 0), 1, &dummy_fops, 0); ++ ++ return 0; ++} ++ ++void dummy_exit(void) ++{ ++ if (devfs_unregister_blkdev(0, "dummy")) ++ printk(KERN_WARNING "dummy: cannot unregister blkdev\n"); ++} ++ ++module_init(dummy_init); ++module_exit(dummy_exit); +--- linux-2.4.20/drivers/char/mem.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/char/mem.c 2005-01-07 05:39:02.000000000 -0500 +@@ -621,7 +621,8 @@ + {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, + {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, + {3, "null", S_IRUGO | S_IWUGO, &null_fops}, +-#if defined(CONFIG_ISA) || !defined(__mc68000__) ++#if defined(CONFIG_ISA) || !defined(__mc68000__) || \ ++ defined(CONFIG_BCM94702_CPCI) + {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, + #endif + {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, +--- linux-2.4.20/drivers/char/serial.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/char/serial.c 2005-01-07 05:39:02.000000000 -0500 +@@ -444,6 +444,10 @@ + return inb(info->port+1); + #endif + case SERIAL_IO_MEM: ++#ifdef CONFIG_BCM4310 ++ readb((unsigned long) info->iomem_base + ++ (UART_SCR<<info->iomem_reg_shift)); ++#endif + return readb((unsigned long) info->iomem_base + + (offset<<info->iomem_reg_shift)); + default: +@@ -464,6 +468,9 @@ + case SERIAL_IO_MEM: + writeb(value, (unsigned long) info->iomem_base + + (offset<<info->iomem_reg_shift)); ++#ifdef CONFIG_BCM4704 ++ *((volatile unsigned int *) KSEG1ADDR(0x18000000)); ++#endif + break; + default: + outb(value, info->port+offset); +@@ -5970,6 +5977,13 @@ + * Divisor, bytesize and parity + */ + state = rs_table + co->index; ++ /* ++ * Safe guard: state structure must have been initialized ++ */ ++ if (state->iomem_base == NULL) { ++ printk("!unable to setup serial console!\n"); ++ return -1; ++ } + if (doflow) + state->flags |= ASYNC_CONS_FLOW; + info = &async_sercons; +--- linux-2.4.20/drivers/ide/ide-pci.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/ide/ide-pci.c 2005-01-07 05:39:02.000000000 -0500 +@@ -793,11 +793,6 @@ + goto bypass_piix_dma; + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA)) + goto bypass_legacy_dma; +- if (hwif->udma_four) { +- printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name); +- } else { +- hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; +- } + #ifdef CONFIG_BLK_DEV_IDEDMA + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) || +@@ -855,6 +850,11 @@ + printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name); + } + } ++ if (hwif->udma_four) { ++ printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name); ++ } else { ++ hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0; ++ } + #endif /* CONFIG_BLK_DEV_IDEDMA */ + bypass_legacy_dma: + bypass_piix_dma: +--- linux-2.4.20/drivers/mtd/chips/Config.in~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/chips/Config.in 2005-01-07 05:39:02.000000000 -0500 +@@ -43,6 +43,7 @@ + fi + dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE + dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE ++dep_tristate ' Support for SST flash chips' CONFIG_MTD_CFI_SSTSTD $CONFIG_MTD_GEN_PROBE + + dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD + dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD +--- linux-2.4.20/drivers/mtd/chips/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/chips/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -17,6 +17,7 @@ + obj-$(CONFIG_MTD) += chipreg.o + obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o + obj-$(CONFIG_MTD_CFI) += cfi_probe.o ++obj-$(CONFIG_MTD_CFI_SSTSTD) += cfi_cmdset_0701.o + obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o + obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o + obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o +--- linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0001.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0001.c 2005-01-07 05:39:02.000000000 -0500 +@@ -59,6 +59,8 @@ + #ifdef DEBUG_CFI_FEATURES + static void cfi_tell_features(struct cfi_pri_intelext *extp) + { ++ int i; ++ + printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); + printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); + printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); +@@ -184,7 +186,7 @@ + unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; + + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); +- //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips); ++ printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips); + + if (!mtd) { + printk(KERN_ERR "Failed to allocate memory for MTD device\n"); +@@ -1226,6 +1228,9 @@ + chip->state = chip->oldstate; + wake_up(&chip->wq); + } ++ ++ /* make absolutely sure that chip is out of lock/suspend state */ ++ cfi_write(map, CMD(0xFF), 0); + spin_unlock_bh(chip->mutex); + } + } +@@ -1319,6 +1324,7 @@ + } + + /* Done and happy. */ ++ cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + DISABLE_VPP(map); + wake_up(&chip->wq); +@@ -1468,6 +1474,7 @@ + } + + /* Done and happy. */ ++ cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + DISABLE_VPP(map); + wake_up(&chip->wq); +@@ -1483,34 +1490,96 @@ + #ifdef DEBUG_LOCK_BITS + int ofs_factor = cfi->interleave * cfi->device_type; + #endif ++ int i, first; ++ struct mtd_erase_region_info *regions = mtd->eraseregions; ++ ++ if (ofs > mtd->size) ++ return -EINVAL; ++ ++ if ((len + ofs) > mtd->size) ++ return -EINVAL; ++ ++ /* Check that both start and end of the requested erase are ++ * aligned with the erasesize at the appropriate addresses. ++ */ ++ ++ i = 0; ++ ++ /* Skip all erase regions which are ended before the start of ++ the requested erase. Actually, to save on the calculations, ++ we skip to the first erase region which starts after the ++ start of the requested erase, and then go back one. ++ */ ++ ++ while (i < mtd->numeraseregions && ofs >= regions[i].offset) ++ i++; ++ i--; ++ ++ /* OK, now i is pointing at the erase region in which this ++ erase request starts. Check the start of the requested ++ erase range is aligned with the erase size which is in ++ effect here. ++ */ ++ ++ if (ofs & (regions[i].erasesize-1)) ++ return -EINVAL; ++ ++ /* Remember the erase region we start on */ ++ first = i; ++ ++ /* Next, check that the end of the requested erase is aligned ++ * with the erase region at that address. ++ */ ++ ++ while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset) ++ i++; ++ ++ /* As before, drop back one to point at the region in which ++ the address actually falls ++ */ ++ i--; ++ ++ if ((ofs + len) & (regions[i].erasesize-1)) ++ return -EINVAL; + + chipnum = ofs >> cfi->chipshift; + adr = ofs - (chipnum << cfi->chipshift); ++ i = first; + +-#ifdef DEBUG_LOCK_BITS +- { +- unsigned long temp_adr = adr; +- unsigned long temp_len = len; ++ while(len) { + ++#ifdef DEBUG_LOCK_BITS + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); +- while (temp_len) { +- printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); +- temp_adr += mtd->erasesize; +- temp_len -= mtd->erasesize; +- } ++ printk("before unlock %x: block status register is %x\n",adr,cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); +- } + #endif + + ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr); + + #ifdef DEBUG_LOCK_BITS + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); +- printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); ++ printk("after unlock %x: block status register is %x\n",adr,cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); + #endif + ++ if (ret) + return ret; ++ ++ adr += regions[i].erasesize; ++ len -= regions[i].erasesize; ++ ++ if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) ++ i++; ++ ++ if (adr >> cfi->chipshift) { ++ adr = 0; ++ chipnum++; ++ ++ if (chipnum >= cfi->numchips) ++ break; ++ } ++ } ++ return 0; + } + + static int cfi_intelext_suspend(struct mtd_info *mtd) +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0701.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,855 @@ ++/* ++ * Common Flash Interface support: ++ * SST Standard Vendor Command Set (ID 0x0701) ++ * ++ * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp> ++ * ++ * 2_by_8 routines added by Simon Munton ++ * ++ * This code is GPL ++ * ++ * $Id: cfi_cmdset_0701.c,v 1.1.1.4 2003/10/14 08:08:17 sparq Exp $ ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <asm/io.h> ++#include <asm/byteorder.h> ++ ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/cfi.h> ++ ++static int cfi_sststd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); ++static int cfi_sststd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); ++static int cfi_sststd_erase_onesize(struct mtd_info *, struct erase_info *); ++static int cfi_sststd_erase_varsize(struct mtd_info *, struct erase_info *); ++static void cfi_sststd_sync (struct mtd_info *); ++static int cfi_sststd_suspend (struct mtd_info *); ++static void cfi_sststd_resume (struct mtd_info *); ++ ++static void cfi_sststd_destroy(struct mtd_info *); ++ ++struct mtd_info *cfi_cmdset_0701(struct map_info *, int); ++static struct mtd_info *cfi_sststd_setup (struct map_info *); ++ ++ ++static struct mtd_chip_driver cfi_sststd_chipdrv = { ++ probe: NULL, /* Not usable directly */ ++ destroy: cfi_sststd_destroy, ++ name: "cfi_cmdset_0701", ++ module: THIS_MODULE ++}; ++ ++struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary) ++{ ++ struct cfi_private *cfi = map->fldrv_priv; ++ int ofs_factor = cfi->interleave * cfi->device_type; ++ int i; ++ __u8 major, minor; ++ __u32 base = cfi->chips[0].start; ++ ++ if (cfi->cfi_mode==1){ ++ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; ++ ++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ ++ major = cfi_read_query(map, base + (adr+3)*ofs_factor); ++ minor = cfi_read_query(map, base + (adr+4)*ofs_factor); ++ ++ printk(" SST Query Table v%c.%c at 0x%4.4X\n", ++ major, minor, adr); ++ cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ ++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ cfi->mfr = cfi_read_query(map, base); ++ cfi->id = cfi_read_query(map, base + ofs_factor); ++ ++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ ++ switch (cfi->device_type) { ++ case CFI_DEVICETYPE_X16: ++ cfi->addr_unlock1 = 0x5555; ++ cfi->addr_unlock2 = 0x2AAA; ++ break; ++ default: ++ printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0701 device type %d\n", cfi->device_type); ++ return NULL; ++ } ++ } /* CFI mode */ ++ ++ for (i=0; i< cfi->numchips; i++) { ++ cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; ++ cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; ++ cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; ++ } ++ ++ map->fldrv = &cfi_sststd_chipdrv; ++ MOD_INC_USE_COUNT; ++ ++ cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ return cfi_sststd_setup(map); ++} ++ ++static struct mtd_info *cfi_sststd_setup(struct map_info *map) ++{ ++ struct cfi_private *cfi = map->fldrv_priv; ++ struct mtd_info *mtd; ++ unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; ++ ++ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); ++ printk("number of %s chips: %d\n", (cfi->cfi_mode)?"JEDEC":"CFI",cfi->numchips); ++ ++ if (!mtd) { ++ printk("Failed to allocate memory for MTD device\n"); ++ kfree(cfi->cmdset_priv); ++ return NULL; ++ } ++ ++ memset(mtd, 0, sizeof(*mtd)); ++ mtd->priv = map; ++ mtd->type = MTD_NORFLASH; ++ /* Also select the correct geometry setup too */ ++ mtd->size = devsize * cfi->numchips; ++ ++ if (cfi->cfiq->NumEraseRegions == 1) { ++ /* No need to muck about with multiple erase sizes */ ++ mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave; ++ } else { ++ unsigned long offset = 0; ++ int i,j; ++ ++ mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; ++ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); ++ if (!mtd->eraseregions) { ++ printk("Failed to allocate memory for MTD erase region info\n"); ++ kfree(cfi->cmdset_priv); ++ return NULL; ++ } ++ ++ for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { ++ unsigned long ernum, ersize; ++ ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; ++ ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; ++ ++ if (mtd->erasesize < ersize) { ++ mtd->erasesize = ersize; ++ } ++ for (j=0; j<cfi->numchips; j++) { ++ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; ++ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; ++ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; ++ } ++ offset += (ersize * ernum); ++ } ++ ++ // debug ++ for (i=0; i<mtd->numeraseregions;i++){ ++ printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", ++ i,mtd->eraseregions[i].offset, ++ mtd->eraseregions[i].erasesize, ++ mtd->eraseregions[i].numblocks); ++ } ++ } ++ ++ switch (CFIDEV_BUSWIDTH) ++ { ++ case 1: ++ case 2: ++ case 4: ++ if (mtd->numeraseregions > 1) ++ mtd->erase = cfi_sststd_erase_varsize; ++ else ++ mtd->erase = cfi_sststd_erase_onesize; ++ mtd->read = cfi_sststd_read; ++ mtd->write = cfi_sststd_write; ++ break; ++ ++ default: ++ printk("Unsupported buswidth\n"); ++ kfree(mtd); ++ kfree(cfi->cmdset_priv); ++ return NULL; ++ break; ++ } ++ mtd->sync = cfi_sststd_sync; ++ mtd->suspend = cfi_sststd_suspend; ++ mtd->resume = cfi_sststd_resume; ++ mtd->flags = MTD_CAP_NORFLASH; ++ map->fldrv = &cfi_sststd_chipdrv; ++ mtd->name = map->name; ++ MOD_INC_USE_COUNT; ++ return mtd; ++} ++ ++static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long timeo = jiffies + HZ; ++ ++ retry: ++ cfi_spin_lock(chip->mutex); ++ ++ if (chip->state != FL_READY){ ++ printk("Waiting for chip to read, status = %d\n", chip->state); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&chip->wq, &wait); ++ ++ cfi_spin_unlock(chip->mutex); ++ ++ schedule(); ++ remove_wait_queue(&chip->wq, &wait); ++ timeo = jiffies + HZ; ++ ++ goto retry; ++ } ++ ++ adr += chip->start; ++ ++ chip->state = FL_READY; ++ ++ map->copy_from(map, buf, adr, len); ++ ++ wake_up(&chip->wq); ++ cfi_spin_unlock(chip->mutex); ++ ++ return 0; ++} ++ ++static int cfi_sststd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ unsigned long ofs; ++ int chipnum; ++ int ret = 0; ++ ++ /* ofs: offset within the first chip that the first read should start */ ++ ++ chipnum = (from >> cfi->chipshift); ++ ofs = from - (chipnum << cfi->chipshift); ++ ++ ++ *retlen = 0; ++ ++ while (len) { ++ unsigned long thislen; ++ ++ if (chipnum >= cfi->numchips) ++ break; ++ ++ if ((len + ofs -1) >> cfi->chipshift) ++ thislen = (1<<cfi->chipshift) - ofs; ++ else ++ thislen = len; ++ ++ ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); ++ if (ret) ++ break; ++ ++ *retlen += thislen; ++ len -= thislen; ++ buf += thislen; ++ ++ ofs = 0; ++ chipnum++; ++ } ++ return ret; ++} ++ ++static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast) ++{ ++ unsigned long timeo = jiffies + HZ; ++ unsigned int Last[4]; ++ unsigned long Count = 0; ++ struct cfi_private *cfi = map->fldrv_priv; ++ DECLARE_WAITQUEUE(wait, current); ++ int ret = 0; ++ ++ retry: ++ cfi_spin_lock(chip->mutex); ++ ++ if (chip->state != FL_READY){ ++ printk("Waiting for chip to write, status = %d\n", chip->state); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&chip->wq, &wait); ++ ++ cfi_spin_unlock(chip->mutex); ++ ++ schedule(); ++ remove_wait_queue(&chip->wq, &wait); ++ printk("Wake up to write:\n"); ++ timeo = jiffies + HZ; ++ ++ goto retry; ++ } ++ ++ chip->state = FL_WRITING; ++ ++ adr += chip->start; ++ ENABLE_VPP(map); ++ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ ++ cfi_write(map, datum, adr); ++ ++ cfi_spin_unlock(chip->mutex); ++ cfi_udelay(chip->word_write_time); ++ cfi_spin_lock(chip->mutex); ++ ++ Last[0] = cfi_read(map, adr); ++ // printk("Last[0] is %x\n", Last[0]); ++ Last[1] = cfi_read(map, adr); ++ // printk("Last[1] is %x\n", Last[1]); ++ Last[2] = cfi_read(map, adr); ++ // printk("Last[2] is %x\n", Last[2]); ++ ++ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){ ++ cfi_spin_unlock(chip->mutex); ++ cfi_udelay(10); ++ cfi_spin_lock(chip->mutex); ++ ++ Last[Count % 4] = cfi_read(map, adr); ++ // printk("Last[%d%%4] is %x\n", Count, Last[Count%4]); ++ } ++ ++ if (Last[(Count - 1) % 4] != datum){ ++ printk("Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum); ++ cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL); ++ DISABLE_VPP(map); ++ ret = -EIO; ++ } ++ DISABLE_VPP(map); ++ chip->state = FL_READY; ++ wake_up(&chip->wq); ++ cfi_spin_unlock(chip->mutex); ++ ++ return ret; ++} ++ ++static int cfi_sststd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ int ret = 0; ++ int chipnum; ++ unsigned long ofs, chipstart; ++ ++ *retlen = 0; ++ if (!len) ++ return 0; ++ ++ chipnum = to >> cfi->chipshift; ++ ofs = to - (chipnum << cfi->chipshift); ++ chipstart = cfi->chips[chipnum].start; ++ ++ /* If it's not bus-aligned, do the first byte write */ ++ if (ofs & (CFIDEV_BUSWIDTH-1)) { ++ unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); ++ int i = ofs - bus_ofs; ++ int n = 0; ++ u_char tmp_buf[4]; ++ __u32 datum; ++ ++ map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); ++ while (len && i < CFIDEV_BUSWIDTH) ++ tmp_buf[i++] = buf[n++], len--; ++ ++ if (cfi_buswidth_is_2()) { ++ datum = *(__u16*)tmp_buf; ++ } else if (cfi_buswidth_is_4()) { ++ datum = *(__u32*)tmp_buf; ++ } else { ++ return -EINVAL; /* should never happen, but be safe */ ++ } ++ ++ ret = do_write_oneword(map, &cfi->chips[chipnum], ++ bus_ofs, datum, 0); ++ if (ret) ++ return ret; ++ ++ ofs += n; ++ buf += n; ++ (*retlen) += n; ++ ++ if (ofs >> cfi->chipshift) { ++ chipnum ++; ++ ofs = 0; ++ if (chipnum == cfi->numchips) ++ return 0; ++ } ++ } ++ ++ /* We are now aligned, write as much as possible */ ++ while(len >= CFIDEV_BUSWIDTH) { ++ __u32 datum; ++ ++ if (cfi_buswidth_is_1()) { ++ datum = *(__u8*)buf; ++ } else if (cfi_buswidth_is_2()) { ++ datum = *(__u16*)buf; ++ } else if (cfi_buswidth_is_4()) { ++ datum = *(__u32*)buf; ++ } else { ++ return -EINVAL; ++ } ++ ret = do_write_oneword(map, &cfi->chips[chipnum], ++ ofs, datum, cfi->fast_prog); ++ if (ret) { ++ return ret; ++ } ++ ++ ofs += CFIDEV_BUSWIDTH; ++ buf += CFIDEV_BUSWIDTH; ++ (*retlen) += CFIDEV_BUSWIDTH; ++ len -= CFIDEV_BUSWIDTH; ++ ++ if (ofs >> cfi->chipshift) { ++ chipnum ++; ++ ofs = 0; ++ if (chipnum == cfi->numchips) ++ return 0; ++ chipstart = cfi->chips[chipnum].start; ++ } ++ } ++ ++ if (len & (CFIDEV_BUSWIDTH-1)) { ++ int i = 0, n = 0; ++ u_char tmp_buf[4]; ++ __u32 datum; ++ ++ map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); ++ while (len--) ++ tmp_buf[i++] = buf[n++]; ++ ++ if (cfi_buswidth_is_2()) { ++ datum = *(__u16*)tmp_buf; ++ } else if (cfi_buswidth_is_4()) { ++ datum = *(__u32*)tmp_buf; ++ } else { ++ return -EINVAL; /* should never happen, but be safe */ ++ } ++ ++ ret = do_write_oneword(map, &cfi->chips[chipnum], ++ ofs, datum, 0); ++ if (ret) ++ return ret; ++ ++ (*retlen) += n; ++ } ++ ++ return 0; ++} ++ ++static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) ++{ ++ unsigned int status; ++ unsigned long timeo = jiffies + HZ; ++ struct cfi_private *cfi = map->fldrv_priv; ++ unsigned int rdy_mask; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ retry: ++ cfi_spin_lock(chip->mutex); ++ ++ if (chip->state != FL_READY){ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&chip->wq, &wait); ++ ++ cfi_spin_unlock(chip->mutex); ++ ++ schedule(); ++ remove_wait_queue(&chip->wq, &wait); ++ timeo = jiffies + HZ; ++ ++ goto retry; ++ } ++ ++ chip->state = FL_ERASING; ++ ++ adr += chip->start; ++ ENABLE_VPP(map); ++ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); ++ cfi_write(map, CMD(0x30), adr); ++ ++ timeo = jiffies + (HZ*20); ++ ++ cfi_spin_unlock(chip->mutex); ++ schedule_timeout(HZ); ++ cfi_spin_lock(chip->mutex); ++ ++ rdy_mask = CMD(0x80); ++ ++ /* Once the state machine's known to be working I'll do that */ ++ ++ while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) { ++ static int z=0; ++ ++ if (chip->state != FL_ERASING) { ++ /* Someone's suspended the erase. Sleep */ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&chip->wq, &wait); ++ ++ cfi_spin_unlock(chip->mutex); ++ printk("erase suspended. Sleeping\n"); ++ ++ schedule(); ++ remove_wait_queue(&chip->wq, &wait); ++ timeo = jiffies + (HZ*2); ++ cfi_spin_lock(chip->mutex); ++ continue; ++ } ++ ++ /* OK Still waiting */ ++ if (time_after(jiffies, timeo)) { ++ chip->state = FL_READY; ++ cfi_spin_unlock(chip->mutex); ++ printk("waiting for erase to complete timed out."); ++ DISABLE_VPP(map); ++ return -EIO; ++ } ++ ++ /* Latency issues. Drop the lock, wait a while and retry */ ++ cfi_spin_unlock(chip->mutex); ++ ++ z++; ++ if ( 0 && !(z % 100 )) ++ printk("chip not ready yet after erase. looping\n"); ++ ++ cfi_udelay(1); ++ ++ cfi_spin_lock(chip->mutex); ++ continue; ++ } ++ ++ /* Done and happy. */ ++ DISABLE_VPP(map); ++ chip->state = FL_READY; ++ wake_up(&chip->wq); ++ cfi_spin_unlock(chip->mutex); ++ return 0; ++} ++ ++static int cfi_sststd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ unsigned long adr, len; ++ int chipnum, ret = 0; ++ int i, first; ++ struct mtd_erase_region_info *regions = mtd->eraseregions; ++ ++ if (instr->addr > mtd->size) ++ return -EINVAL; ++ ++ if ((instr->len + instr->addr) > mtd->size) ++ return -EINVAL; ++ ++ /* Check that both start and end of the requested erase are ++ * aligned with the erasesize at the appropriate addresses. ++ */ ++ ++ i = 0; ++ ++ /* Skip all erase regions which are ended before the start of ++ the requested erase. Actually, to save on the calculations, ++ we skip to the first erase region which starts after the ++ start of the requested erase, and then go back one. ++ */ ++ ++ while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) ++ i++; ++ i--; ++ ++ /* OK, now i is pointing at the erase region in which this ++ erase request starts. Check the start of the requested ++ erase range is aligned with the erase size which is in ++ effect here. ++ */ ++ ++ if (instr->addr & (regions[i].erasesize-1)) ++ return -EINVAL; ++ ++ /* Remember the erase region we start on */ ++ first = i; ++ ++ /* Next, check that the end of the requested erase is aligned ++ * with the erase region at that address. ++ */ ++ ++ while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset) ++ i++; ++ ++ /* As before, drop back one to point at the region in which ++ the address actually falls ++ */ ++ i--; ++ ++ if ((instr->addr + instr->len) & (regions[i].erasesize-1)) ++ return -EINVAL; ++ ++ chipnum = instr->addr >> cfi->chipshift; ++ adr = instr->addr - (chipnum << cfi->chipshift); ++ len = instr->len; ++ ++ i=first; ++ ++ while(len) { ++ ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); ++ ++ if (ret) ++ return ret; ++ ++ adr += regions[i].erasesize; ++ len -= regions[i].erasesize; ++ ++ if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) ++ i++; ++ ++ if (adr >> cfi->chipshift) { ++ adr = 0; ++ chipnum++; ++ ++ if (chipnum >= cfi->numchips) ++ break; ++ } ++ } ++ ++ instr->state = MTD_ERASE_DONE; ++ if (instr->callback) ++ instr->callback(instr); ++ ++ return 0; ++} ++ ++static int cfi_sststd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ unsigned long adr, len; ++ int chipnum, ret = 0; ++ ++ if (instr->addr & (mtd->erasesize - 1)) ++ return -EINVAL; ++ ++ if (instr->len & (mtd->erasesize -1)) ++ return -EINVAL; ++ ++ if ((instr->len + instr->addr) > mtd->size) ++ return -EINVAL; ++ ++ chipnum = instr->addr >> cfi->chipshift; ++ adr = instr->addr - (chipnum << cfi->chipshift); ++ len = instr->len; ++ ++ while(len) { ++ ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); ++ ++ if (ret) ++ return ret; ++ ++ adr += mtd->erasesize; ++ len -= mtd->erasesize; ++ ++ if (adr >> cfi->chipshift) { ++ adr = 0; ++ chipnum++; ++ ++ if (chipnum >= cfi->numchips) ++ break; ++ } ++ } ++ ++ instr->state = MTD_ERASE_DONE; ++ if (instr->callback) ++ instr->callback(instr); ++ ++ return 0; ++} ++ ++static void cfi_sststd_sync (struct mtd_info *mtd) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ int i; ++ struct flchip *chip; ++ int ret = 0; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ for (i=0; !ret && i<cfi->numchips; i++) { ++ chip = &cfi->chips[i]; ++ ++ retry: ++ cfi_spin_lock(chip->mutex); ++ ++ switch(chip->state) { ++ case FL_READY: ++ case FL_STATUS: ++ case FL_CFI_QUERY: ++ case FL_JEDEC_QUERY: ++ chip->oldstate = chip->state; ++ chip->state = FL_SYNCING; ++ /* No need to wake_up() on this state change - ++ * as the whole point is that nobody can do anything ++ * with the chip now anyway. ++ */ ++ case FL_SYNCING: ++ cfi_spin_unlock(chip->mutex); ++ break; ++ ++ default: ++ /* Not an idle state */ ++ add_wait_queue(&chip->wq, &wait); ++ ++ cfi_spin_unlock(chip->mutex); ++ ++ schedule(); ++ ++ remove_wait_queue(&chip->wq, &wait); ++ ++ goto retry; ++ } ++ } ++ ++ /* Unlock the chips again */ ++ ++ for (i--; i >=0; i--) { ++ chip = &cfi->chips[i]; ++ ++ cfi_spin_lock(chip->mutex); ++ ++ if (chip->state == FL_SYNCING) { ++ chip->state = chip->oldstate; ++ wake_up(&chip->wq); ++ } ++ cfi_spin_unlock(chip->mutex); ++ } ++} ++ ++ ++static int cfi_sststd_suspend(struct mtd_info *mtd) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ int i; ++ struct flchip *chip; ++ int ret = 0; ++//printk("suspend\n"); ++ ++ for (i=0; !ret && i<cfi->numchips; i++) { ++ chip = &cfi->chips[i]; ++ ++ cfi_spin_lock(chip->mutex); ++ ++ switch(chip->state) { ++ case FL_READY: ++ case FL_STATUS: ++ case FL_CFI_QUERY: ++ case FL_JEDEC_QUERY: ++ chip->oldstate = chip->state; ++ chip->state = FL_PM_SUSPENDED; ++ /* No need to wake_up() on this state change - ++ * as the whole point is that nobody can do anything ++ * with the chip now anyway. ++ */ ++ case FL_PM_SUSPENDED: ++ break; ++ ++ default: ++ ret = -EAGAIN; ++ break; ++ } ++ cfi_spin_unlock(chip->mutex); ++ } ++ ++ /* Unlock the chips again */ ++ ++ if (ret) { ++ for (i--; i >=0; i--) { ++ chip = &cfi->chips[i]; ++ ++ cfi_spin_lock(chip->mutex); ++ ++ if (chip->state == FL_PM_SUSPENDED) { ++ chip->state = chip->oldstate; ++ wake_up(&chip->wq); ++ } ++ cfi_spin_unlock(chip->mutex); ++ } ++ } ++ ++ return ret; ++} ++ ++static void cfi_sststd_resume(struct mtd_info *mtd) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ int i; ++ struct flchip *chip; ++//printk("resume\n"); ++ ++ for (i=0; i<cfi->numchips; i++) { ++ ++ chip = &cfi->chips[i]; ++ ++ cfi_spin_lock(chip->mutex); ++ ++ if (chip->state == FL_PM_SUSPENDED) { ++ chip->state = FL_READY; ++ cfi_write(map, CMD(0xF0), chip->start); ++ wake_up(&chip->wq); ++ } ++ else ++ printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n"); ++ ++ cfi_spin_unlock(chip->mutex); ++ } ++} ++ ++static void cfi_sststd_destroy(struct mtd_info *mtd) ++{ ++ struct map_info *map = mtd->priv; ++ struct cfi_private *cfi = map->fldrv_priv; ++ kfree(cfi->cmdset_priv); ++ kfree(cfi); ++} ++ ++#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) ++#define cfi_sststd_init init_module ++#define cfi_sststd_exit cleanup_module ++#endif ++ ++static char im_name[]="cfi_cmdset_0701"; ++ ++mod_init_t cfi_sststd_init(void) ++{ ++ inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0701); ++ return 0; ++} ++ ++mod_exit_t cfi_sststd_exit(void) ++{ ++ inter_module_unregister(im_name); ++} ++ ++module_init(cfi_sststd_init); ++module_exit(cfi_sststd_exit); ++ +--- linux-2.4.20/drivers/mtd/chips/cfi_probe.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/chips/cfi_probe.c 2005-01-07 05:39:02.000000000 -0500 +@@ -58,8 +58,15 @@ + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); + ++ if (!qry_present(map,base,cfi)) { ++ /* rather broken SST cfi probe (requires SST unlock) */ ++ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); ++ cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); + if (!qry_present(map,base,cfi)) + return 0; ++ } + + if (!cfi->numchips) { + /* This is the first time we're called. Set up the CFI +--- linux-2.4.20/drivers/mtd/chips/gen_probe.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/chips/gen_probe.c 2005-01-07 05:39:02.000000000 -0500 +@@ -289,6 +289,10 @@ + case 0x0002: + return cfi_cmdset_0002(map, primary); + #endif ++#ifdef CONFIG_MTD_CFI_SSTSTD ++ case 0x0701: ++ return cfi_cmdset_0701(map, primary); ++#endif + } + + return cfi_cmdset_unknown(map, primary); +--- linux-2.4.20/drivers/mtd/devices/Config.in~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/devices/Config.in 2005-01-07 05:39:02.000000000 -0500 +@@ -5,6 +5,7 @@ + mainmenu_option next_comment + + comment 'Self-contained MTD device drivers' ++bool ' Broadcom Chipcommon Serial Flash support' CONFIG_MTD_SFLASH + dep_tristate ' Ramix PMC551 PCI Mezzanine RAM card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI + if [ "$CONFIG_MTD_PMC551" = "y" -o "$CONFIG_MTD_PMC551" = "m" ]; then + bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX +--- linux-2.4.20/drivers/mtd/devices/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/devices/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -12,6 +12,7 @@ + # here where previously there was none. We now have to ensure that + # doc200[01].o are linked before docprobe.o + ++obj-$(CONFIG_MTD_SFLASH) += sflash.o + obj-$(CONFIG_MTD_DOC1000) += doc1000.o + obj-$(CONFIG_MTD_DOC2000) += doc2000.o + obj-$(CONFIG_MTD_DOC2001) += doc2001.o +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/mtd/devices/sflash.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,283 @@ ++/* ++ * Broadcom SiliconBackplane chipcommon serial flash interface ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: sflash.c,v 1.1.1.7 2004/04/12 04:31:46 honor Exp $ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/ioport.h> ++#include <linux/mtd/compatmac.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/errno.h> ++#include <linux/pci.h> ++#include <asm/io.h> ++ ++#include <typedefs.h> ++#include <bcmdevs.h> ++#include <bcmutils.h> ++#include <osl.h> ++#include <bcmutils.h> ++#include <bcmnvram.h> ++#include <sbconfig.h> ++#include <sbchipc.h> ++#include <sflash.h> ++ ++#ifdef CONFIG_MTD_PARTITIONS ++extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size); ++#endif ++ ++struct sflash_mtd { ++ chipcregs_t *cc; ++ struct semaphore lock; ++ struct mtd_info mtd; ++ struct mtd_erase_region_info region; ++}; ++ ++/* Private global state */ ++static struct sflash_mtd sflash; ++ ++static int ++sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout) ++{ ++ int now = jiffies; ++ int ret = 0; ++ ++ for (;;) { ++ if (!sflash_poll(sflash->cc, offset)) { ++ ret = 0; ++ break; ++ } ++ if (time_after(jiffies, now + timeout)) { ++ printk(KERN_ERR "sflash: timeout\n"); ++ ret = -ETIMEDOUT; ++ break; ++ } ++ if (current->need_resched) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(timeout / 10); ++ } else ++ udelay(1); ++ } ++ ++ return ret; ++} ++ ++static int ++sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; ++ int bytes, ret = 0; ++ ++ /* Check address range */ ++ if (!len) ++ return 0; ++ if ((from + len) > mtd->size) ++ return -EINVAL; ++ ++ down(&sflash->lock); ++ ++ *retlen = 0; ++ while (len) { ++ if ((bytes = sflash_read(sflash->cc, (uint) from, len, buf)) < 0) { ++ ret = bytes; ++ break; ++ } ++ from += (loff_t) bytes; ++ len -= bytes; ++ buf += bytes; ++ *retlen += bytes; ++ } ++ ++ up(&sflash->lock); ++ ++ return ret; ++} ++ ++static int ++sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) ++{ ++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; ++ int bytes, ret = 0; ++ ++ /* Check address range */ ++ if (!len) ++ return 0; ++ if ((to + len) > mtd->size) ++ return -EINVAL; ++ ++ down(&sflash->lock); ++ ++ *retlen = 0; ++ while (len) { ++ if ((bytes = sflash_write(sflash->cc, (uint) to, len, buf)) < 0) { ++ ret = bytes; ++ break; ++ } ++ if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10))) ++ break; ++ to += (loff_t) bytes; ++ len -= bytes; ++ buf += bytes; ++ *retlen += bytes; ++ } ++ ++ up(&sflash->lock); ++ ++ return ret; ++} ++ ++static int ++sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) ++{ ++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv; ++ int i, j, ret = 0; ++ unsigned int addr, len; ++ ++ /* Check address range */ ++ if (!erase->len) ++ return 0; ++ if ((erase->addr + erase->len) > mtd->size) ++ return -EINVAL; ++ ++ addr = erase->addr; ++ len = erase->len; ++ ++ down(&sflash->lock); ++ ++ /* Ensure that requested region is aligned */ ++ for (i = 0; i < mtd->numeraseregions; i++) { ++ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { ++ if (addr == mtd->eraseregions[i].offset + mtd->eraseregions[i].erasesize * j && ++ len >= mtd->eraseregions[i].erasesize) { ++ if ((ret = sflash_erase(sflash->cc, addr)) < 0) ++ break; ++ if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ))) ++ break; ++ addr += mtd->eraseregions[i].erasesize; ++ len -= mtd->eraseregions[i].erasesize; ++ } ++ } ++ if (ret) ++ break; ++ } ++ ++ up(&sflash->lock); ++ ++ /* Set erase status */ ++ if (ret) ++ erase->state = MTD_ERASE_FAILED; ++ else ++ erase->state = MTD_ERASE_DONE; ++ ++ /* Call erase callback */ ++ if (erase->callback) ++ erase->callback(erase); ++ ++ return ret; ++} ++ ++#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) ++#define sflash_mtd_init init_module ++#define sflash_mtd_exit cleanup_module ++#endif ++ ++mod_init_t ++sflash_mtd_init(void) ++{ ++ struct pci_dev *pdev; ++ int ret = 0; ++ struct sflash *info; ++ uint i; ++#ifdef CONFIG_MTD_PARTITIONS ++ struct mtd_partition *parts; ++#endif ++ ++ if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) { ++ printk(KERN_ERR "sflash: chipcommon not found\n"); ++ return -ENODEV; ++ } ++ ++ memset(&sflash, 0, sizeof(struct sflash_mtd)); ++ init_MUTEX(&sflash.lock); ++ ++ /* Map registers and flash base */ ++ if (!(sflash.cc = ioremap_nocache(pci_resource_start(pdev, 0), ++ pci_resource_len(pdev, 0)))) { ++ printk(KERN_ERR "sflash: error mapping registers\n"); ++ ret = -EIO; ++ goto fail; ++ } ++ ++ /* Initialize serial flash access */ ++ info = sflash_init(sflash.cc); ++ ++ if (!info) { ++ printk(KERN_ERR "sflash: found no supported devices\n"); ++ ret = -ENODEV; ++ goto fail; ++ } ++ ++ /* Setup region info */ ++ sflash.region.offset = 0; ++ sflash.region.erasesize = info->blocksize; ++ sflash.region.numblocks = info->numblocks; ++ if (sflash.region.erasesize > sflash.mtd.erasesize) ++ sflash.mtd.erasesize = sflash.region.erasesize; ++ sflash.mtd.size = info->size; ++ sflash.mtd.numeraseregions = 1; ++ ++ /* Register with MTD */ ++ sflash.mtd.name = "sflash"; ++ sflash.mtd.type = MTD_NORFLASH; ++ sflash.mtd.flags = MTD_CAP_NORFLASH; ++ sflash.mtd.eraseregions = &sflash.region; ++ sflash.mtd.module = THIS_MODULE; ++ sflash.mtd.erase = sflash_mtd_erase; ++ sflash.mtd.read = sflash_mtd_read; ++ sflash.mtd.write = sflash_mtd_write; ++ sflash.mtd.priv = &sflash; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++ parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size); ++ for (i = 0; parts[i].name; i++); ++ ret = add_mtd_partitions(&sflash.mtd, parts, i); ++#else ++ ret = add_mtd_device(&sflash.mtd); ++#endif ++ if (ret) { ++ printk(KERN_ERR "sflash: add_mtd failed\n"); ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ if (sflash.cc) ++ iounmap((void *) sflash.cc); ++ return ret; ++} ++ ++mod_exit_t ++sflash_mtd_exit(void) ++{ ++#ifdef CONFIG_MTD_PARTITIONS ++ del_mtd_partitions(&sflash.mtd); ++#else ++ del_mtd_device(&sflash.mtd); ++#endif ++ iounmap((void *) sflash.cc); ++} ++ ++module_init(sflash_mtd_init); ++module_exit(sflash_mtd_exit); +--- linux-2.4.20/drivers/mtd/maps/Config.in~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/maps/Config.in 2005-01-07 05:39:02.000000000 -0500 +@@ -44,6 +44,7 @@ + fi + + if [ "$CONFIG_MIPS" = "y" ]; then ++ dep_tristate ' CFI Flash device mapped on Broadcom BCM947XX boards' CONFIG_MTD_BCM947XX $CONFIG_MTD_CFI + dep_tristate ' Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000 + dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500 + dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100 +--- linux-2.4.20/drivers/mtd/maps/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/maps/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -6,6 +6,7 @@ + O_TARGET := mapslink.o + + # Chip mappings ++obj-$(CONFIG_MTD_BCM947XX) += bcm947xx-flash.o + obj-$(CONFIG_MTD_CDB89712) += cdb89712.o + obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o + obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/mtd/maps/bcm947xx-flash.c 2005-01-08 12:16:21.889534944 -0500 +@@ -0,0 +1,225 @@ ++/* ++ * Flash mapping for BCM947XX boards ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: bcm947xx-flash.c,v 1.8 2004/04/12 05:42:38 honor Exp $ ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++#include <linux/config.h> ++ ++#include <typedefs.h> ++#include <bcmnvram.h> ++#include <bcmutils.h> ++#include <sbconfig.h> ++#include <sbchipc.h> ++#include <sbutils.h> ++#include <trxhdr.h> ++ ++/* Global SB handle */ ++extern void *bcm947xx_sbh; ++extern spinlock_t bcm947xx_sbh_lock; ++ ++/* Convenience */ ++#define sbh bcm947xx_sbh ++#define sbh_lock bcm947xx_sbh_lock ++ ++#ifdef CONFIG_MTD_PARTITIONS ++extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size); ++#endif ++ ++#define WINDOW_ADDR 0x1fc00000 ++#define WINDOW_SIZE 0x400000 ++#define BUSWIDTH 2 ++ ++/* e.g., flash=2M or flash=4M */ ++static int flash = 0; ++MODULE_PARM(flash, "i"); ++static int __init ++bcm947xx_setup(char *str) ++{ ++ flash = memparse(str, &str); ++ return 1; ++} ++__setup("flash=", bcm947xx_setup); ++ ++static struct mtd_info *bcm947xx_mtd; ++ ++__u8 bcm947xx_map_read8(struct map_info *map, unsigned long ofs) ++{ ++ if (map->map_priv_2 == 1) ++ return __raw_readb(map->map_priv_1 + ofs); ++ ++ u16 val = __raw_readw(map->map_priv_1 + (ofs & ~1)); ++ if (ofs & 1) ++ return ((val >> 8) & 0xff); ++ else ++ return (val & 0xff); ++} ++ ++__u16 bcm947xx_map_read16(struct map_info *map, unsigned long ofs) ++{ ++ return __raw_readw(map->map_priv_1 + ofs); ++} ++ ++__u32 bcm947xx_map_read32(struct map_info *map, unsigned long ofs) ++{ ++ return __raw_readl(map->map_priv_1 + ofs); ++} ++ ++void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) ++{ ++ memcpy_fromio(to, map->map_priv_1 + from, len); ++} ++ ++void bcm947xx_map_write8(struct map_info *map, __u8 d, unsigned long adr) ++{ ++ __raw_writeb(d, map->map_priv_1 + adr); ++ mb(); ++} ++ ++void bcm947xx_map_write16(struct map_info *map, __u16 d, unsigned long adr) ++{ ++ __raw_writew(d, map->map_priv_1 + adr); ++ mb(); ++} ++ ++void bcm947xx_map_write32(struct map_info *map, __u32 d, unsigned long adr) ++{ ++ __raw_writel(d, map->map_priv_1 + adr); ++ mb(); ++} ++ ++void bcm947xx_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) ++{ ++ memcpy_toio(map->map_priv_1 + to, from, len); ++} ++ ++struct map_info bcm947xx_map = { ++ name: "Physically mapped flash", ++ size: WINDOW_SIZE, ++ buswidth: BUSWIDTH, ++ read8: bcm947xx_map_read8, ++ read16: bcm947xx_map_read16, ++ read32: bcm947xx_map_read32, ++ copy_from: bcm947xx_map_copy_from, ++ write8: bcm947xx_map_write8, ++ write16: bcm947xx_map_write16, ++ write32: bcm947xx_map_write32, ++ copy_to: bcm947xx_map_copy_to ++}; ++ ++#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) ++#define init_bcm947xx_map init_module ++#define cleanup_bcm947xx_map cleanup_module ++#endif ++ ++mod_init_t init_bcm947xx_map(void) ++{ ++ ulong flags; ++ uint coreidx; ++ chipcregs_t *cc; ++ uint32 fltype; ++ uint window_addr = 0, window_size = 0; ++ size_t size; ++ int ret = 0; ++#ifdef CONFIG_MTD_PARTITIONS ++ struct mtd_partition *parts; ++ int i; ++#endif ++ ++ spin_lock_irqsave(&sbh_lock, flags); ++ coreidx = sb_coreidx(sbh); ++ ++ /* Check strapping option if chipcommon exists */ ++ if ((cc = sb_setcore(sbh, SB_CC, 0))) { ++ fltype = readl(&cc->capabilities) & CAP_FLASH_MASK; ++ if (fltype == PFLASH) { ++ bcm947xx_map.map_priv_2 = 1; ++ window_addr = 0x1c000000; ++ bcm947xx_map.size = window_size = 32 * 1024 * 1024; ++ if ((readl(&cc->flash_config) & CC_CFG_DS) == 0) ++ bcm947xx_map.buswidth = 1; ++ } ++ } else { ++ fltype = PFLASH; ++ bcm947xx_map.map_priv_2 = 0; ++ window_addr = WINDOW_ADDR; ++ window_size = WINDOW_SIZE; ++ } ++ ++ sb_setcoreidx(sbh, coreidx); ++ spin_unlock_irqrestore(&sbh_lock, flags); ++ ++ if (fltype != PFLASH) { ++ printk(KERN_ERR "pflash: found no supported devices\n"); ++ ret = -ENODEV; ++ goto fail; ++ } ++ ++ bcm947xx_map.map_priv_1 = (unsigned long) ioremap(window_addr, window_size); ++ if (!bcm947xx_map.map_priv_1) { ++ printk(KERN_ERR "pflash: ioremap failed\n"); ++ ret = -EIO; ++ goto fail; ++ } ++ ++ if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) { ++ printk(KERN_ERR "pflash: cfi_probe failed\n"); ++ ret = -ENXIO; ++ goto fail; ++ } ++ ++ bcm947xx_mtd->module = THIS_MODULE; ++ ++ /* Allow size override for testing */ ++ size = flash ? : bcm947xx_mtd->size; ++ ++ printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr); ++ ++#ifdef CONFIG_MTD_PARTITIONS ++ parts = init_mtd_partitions(bcm947xx_mtd, size); ++ for (i = 0; parts[i].name; i++); ++ ret = add_mtd_partitions(bcm947xx_mtd, parts, i); ++ if (ret) { ++ printk(KERN_ERR "pflash: add_mtd_partitions failed\n"); ++ goto fail; ++ } ++#endif ++ ++ return 0; ++ ++ fail: ++ if (bcm947xx_mtd) ++ map_destroy(bcm947xx_mtd); ++ if (bcm947xx_map.map_priv_1) ++ iounmap((void *) bcm947xx_map.map_priv_1); ++ bcm947xx_map.map_priv_1 = 0; ++ return ret; ++} ++ ++mod_exit_t cleanup_bcm947xx_map(void) ++{ ++#ifdef CONFIG_MTD_PARTITIONS ++ del_mtd_partitions(bcm947xx_mtd); ++#endif ++ map_destroy(bcm947xx_mtd); ++ iounmap((void *) bcm947xx_map.map_priv_1); ++ bcm947xx_map.map_priv_1 = 0; ++} ++ ++module_init(init_bcm947xx_map); ++module_exit(cleanup_bcm947xx_map); +--- linux-2.4.20/drivers/mtd/mtdblock_ro.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/drivers/mtd/mtdblock_ro.c 2005-01-08 12:16:19.492899288 -0500 +@@ -1,18 +1,16 @@ + /* +- * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $ ++ * Direct MTD block device access + * +- * Read-only version of the mtdblock device, without the +- * read/erase/modify/writeback stuff ++ * $Id: mtdblock_ro.c,v 1.1.1.4 2003/10/14 08:08:16 sparq Exp $ ++ * ++ * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache + */ + +-#ifdef MTDBLOCK_DEBUG +-#define DEBUGLVL debug +-#endif +- +- +-#include <linux/module.h> ++#include <linux/config.h> + #include <linux/types.h> +- ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> + #include <linux/mtd/mtd.h> + #include <linux/mtd/compatmac.h> + +@@ -24,56 +22,106 @@ + #define DEVICE_OFF(device) + #define DEVICE_NO_RANDOM + #include <linux/blk.h> +- ++/* for old kernels... */ ++#ifndef QUEUE_EMPTY ++#define QUEUE_EMPTY (!CURRENT) ++#endif + #if LINUX_VERSION_CODE < 0x20300 +-#define RQFUNC_ARG void +-#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) ++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) + #else +-#define RQFUNC_ARG request_queue_t *q ++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) + #endif + +-#ifdef MTDBLOCK_DEBUG +-static int debug = MTDBLOCK_DEBUG; +-MODULE_PARM(debug, "i"); ++#ifdef CONFIG_DEVFS_FS ++#include <linux/devfs_fs_kernel.h> ++static void mtd_notify_add(struct mtd_info* mtd); ++static void mtd_notify_remove(struct mtd_info* mtd); ++static struct mtd_notifier notifier = { ++ mtd_notify_add, ++ mtd_notify_remove, ++ NULL ++}; ++static devfs_handle_t devfs_dir_handle = NULL; ++static devfs_handle_t devfs_ro_handle[MAX_MTD_DEVICES]; + #endif + +-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) +-#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT +-#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT +-#else +-#define BLK_INC_USE_COUNT do {} while(0) +-#define BLK_DEC_USE_COUNT do {} while(0) +-#endif ++static struct mtdblk_dev { ++ struct mtd_info *mtd; /* Locked */ ++ int count; ++} *mtdblks[MAX_MTD_DEVICES]; + +-static int mtd_sizes[MAX_MTD_DEVICES]; ++static spinlock_t mtdblks_lock; + ++static int mtd_sizes[MAX_MTD_DEVICES]; + + static int mtdblock_open(struct inode *inode, struct file *file) + { +- struct mtd_info *mtd = NULL; +- ++ struct mtdblk_dev *mtdblk; ++ struct mtd_info *mtd; + int dev; + +- DEBUG(1,"mtdblock_open\n"); ++ DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); + +- if (inode == 0) ++ if (!inode) + return -EINVAL; + + dev = MINOR(inode->i_rdev); ++ if (dev >= MAX_MTD_DEVICES) ++ return -EINVAL; + + mtd = get_mtd_device(NULL, dev); + if (!mtd) +- return -EINVAL; ++ return -ENODEV; + if (MTD_ABSENT == mtd->type) { + put_mtd_device(mtd); +- return -EINVAL; ++ return -ENODEV; + } + +- BLK_INC_USE_COUNT; ++ spin_lock(&mtdblks_lock); + +- mtd_sizes[dev] = mtd->size>>9; ++ /* If it's already open, no need to piss about. */ ++ if (mtdblks[dev]) { ++ mtdblks[dev]->count++; ++ spin_unlock(&mtdblks_lock); ++ return 0; ++ } + +- DEBUG(1, "ok\n"); ++ /* OK, it's not open. Try to find it */ ++ ++ /* First we have to drop the lock, because we have to ++ to things which might sleep. ++ */ ++ spin_unlock(&mtdblks_lock); ++ ++ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); ++ if (!mtdblk) { ++ put_mtd_device(mtd); ++ return -ENOMEM; ++ } ++ memset(mtdblk, 0, sizeof(*mtdblk)); ++ mtdblk->count = 1; ++ mtdblk->mtd = mtd; ++ ++ /* OK, we've created a new one. Add it to the list. */ ++ ++ spin_lock(&mtdblks_lock); ++ ++ if (mtdblks[dev]) { ++ /* Another CPU made one at the same time as us. */ ++ mtdblks[dev]->count++; ++ spin_unlock(&mtdblks_lock); ++ put_mtd_device(mtdblk->mtd); ++ kfree(mtdblk); ++ return 0; ++ } ++ ++ mtdblks[dev] = mtdblk; ++ mtd_sizes[dev] = mtdblk->mtd->size/1024; ++ set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE)); ++ ++ spin_unlock(&mtdblks_lock); ++ ++ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + + return 0; + } +@@ -81,162 +129,169 @@ + static release_t mtdblock_release(struct inode *inode, struct file *file) + { + int dev; +- struct mtd_info *mtd; +- +- DEBUG(1, "mtdblock_release\n"); ++ struct mtdblk_dev *mtdblk; ++ DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); + + if (inode == NULL) + release_return(-ENODEV); + + dev = MINOR(inode->i_rdev); +- mtd = __get_mtd_device(NULL, dev); ++ mtdblk = mtdblks[dev]; + +- if (!mtd) { +- printk(KERN_WARNING "MTD device is absent on mtd_release!\n"); +- BLK_DEC_USE_COUNT; +- release_return(-ENODEV); ++ spin_lock(&mtdblks_lock); ++ if (!--mtdblk->count) { ++ /* It was the last usage. Free the device */ ++ mtdblks[dev] = NULL; ++ spin_unlock(&mtdblks_lock); ++ if (mtdblk->mtd->sync) ++ mtdblk->mtd->sync(mtdblk->mtd); ++ put_mtd_device(mtdblk->mtd); ++ kfree(mtdblk); ++ } else { ++ spin_unlock(&mtdblks_lock); + } + +- if (mtd->sync) +- mtd->sync(mtd); +- +- put_mtd_device(mtd); +- +- DEBUG(1, "ok\n"); ++ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + +- BLK_DEC_USE_COUNT; + release_return(0); + } + + +-static void mtdblock_request(RQFUNC_ARG) ++/* ++ * This is a special request_fn because it is executed in a process context ++ * to be able to sleep independently of the caller. The io_request_lock ++ * is held upon entry and exit. ++ * The head of our request queue is considered active so there is no need ++ * to dequeue requests before we are done. ++ */ ++static void handle_mtdblock_request(void) + { +- struct request *current_request; +- unsigned int res = 0; +- struct mtd_info *mtd; ++ struct request *req; ++ struct mtdblk_dev *mtdblk; ++ unsigned int res; + +- while (1) +- { +- /* Grab the Request and unlink it from the request list, INIT_REQUEST +- will execute a return if we are done. */ ++ for (;;) { + INIT_REQUEST; +- current_request = CURRENT; +- +- if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES) +- { +- printk("mtd: Unsupported device!\n"); +- end_request(0); +- continue; +- } +- +- // Grab our MTD structure +- +- mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev)); +- if (!mtd) { +- printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV); +- end_request(0); +- } ++ req = CURRENT; ++ spin_unlock_irq(&io_request_lock); ++ mtdblk = mtdblks[MINOR(req->rq_dev)]; ++ res = 0; + +- if (current_request->sector << 9 > mtd->size || +- (current_request->sector + current_request->nr_sectors) << 9 > mtd->size) +- { +- printk("mtd: Attempt to read past end of device!\n"); +- printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors); +- end_request(0); +- continue; +- } ++ if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES) ++ panic(__FUNCTION__": minor out of bound"); + +- /* Remove the request we are handling from the request list so nobody messes +- with it */ +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) +- /* Now drop the lock that the ll_rw_blk functions grabbed for us +- and process the request. This is necessary due to the extreme time +- we spend processing it. */ +- spin_unlock_irq(&io_request_lock); +-#endif ++ if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) ++ goto end_req; + + // Handle the request +- switch (current_request->cmd) ++ switch (req->cmd) + { ++ int err; + size_t retlen; + + case READ: +- if (MTD_READ(mtd,current_request->sector<<9, +- current_request->nr_sectors << 9, +- &retlen, current_request->buffer) == 0) ++ err = MTD_READ (mtdblk->mtd, req->sector << 9, ++ req->current_nr_sectors << 9, ++ &retlen, req->buffer); ++ if (!err) + res = 1; +- else +- res = 0; + break; ++ } + +- case WRITE: +- +- /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector, +- current_request->nr_sectors); +- */ +- +- // Read only device +- if ((mtd->flags & MTD_CAP_RAM) == 0) +- { +- res = 0; +- break; ++end_req: ++ spin_lock_irq(&io_request_lock); ++ end_request(res); + } ++} + +- // Do the write +- if (MTD_WRITE(mtd,current_request->sector<<9, +- current_request->nr_sectors << 9, +- &retlen, current_request->buffer) == 0) +- res = 1; +- else +- res = 0; +- break; ++static volatile int leaving = 0; ++static DECLARE_MUTEX_LOCKED(thread_sem); ++static DECLARE_WAIT_QUEUE_HEAD(thr_wq); + +- // Shouldn't happen +- default: +- printk("mtd: unknown request\n"); +- break; +- } ++int mtdblock_thread(void *dummy) ++{ ++ struct task_struct *tsk = current; ++ DECLARE_WAITQUEUE(wait, tsk); + +- // Grab the lock and re-thread the item onto the linked list +-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) ++ tsk->session = 1; ++ tsk->pgrp = 1; ++ /* we might get involved when memory gets low, so use PF_MEMALLOC */ ++ tsk->flags |= PF_MEMALLOC; ++ strcpy(tsk->comm, "mtdblockd"); ++ tsk->tty = NULL; ++ spin_lock_irq(&tsk->sigmask_lock); ++ sigfillset(&tsk->blocked); ++ recalc_sigpending(tsk); ++ spin_unlock_irq(&tsk->sigmask_lock); ++ exit_mm(tsk); ++ exit_files(tsk); ++ exit_sighand(tsk); ++ exit_fs(tsk); ++ ++ while (!leaving) { ++ add_wait_queue(&thr_wq, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irq(&io_request_lock); +-#endif +- end_request(res); ++ if (QUEUE_EMPTY || QUEUE_PLUGGED) { ++ spin_unlock_irq(&io_request_lock); ++ schedule(); ++ remove_wait_queue(&thr_wq, &wait); ++ } else { ++ remove_wait_queue(&thr_wq, &wait); ++ set_current_state(TASK_RUNNING); ++ handle_mtdblock_request(); ++ spin_unlock_irq(&io_request_lock); ++ } + } ++ ++ up(&thread_sem); ++ return 0; + } + ++#if LINUX_VERSION_CODE < 0x20300 ++#define RQFUNC_ARG void ++#else ++#define RQFUNC_ARG request_queue_t *q ++#endif ++ ++static void mtdblock_request(RQFUNC_ARG) ++{ ++ /* Don't do anything, except wake the thread if necessary */ ++ wake_up(&thr_wq); ++} + + + static int mtdblock_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) + { +- struct mtd_info *mtd; ++ struct mtdblk_dev *mtdblk; + +- mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev)); ++ mtdblk = mtdblks[MINOR(inode->i_rdev)]; + +- if (!mtd) return -EINVAL; ++#ifdef PARANOIA ++ if (!mtdblk) ++ BUG(); ++#endif + + switch (cmd) { + case BLKGETSIZE: /* Return device size */ +- return put_user((mtd->size >> 9), (unsigned long *) arg); +- +-#ifdef BLKGETSIZE64 ++ return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg); + case BLKGETSIZE64: +- return put_user((u64)mtd->size, (u64 *)arg); +-#endif ++ return put_user((u64)mtdblk->mtd->size, (u64 *)arg); + + case BLKFLSBUF: + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) +- if(!capable(CAP_SYS_ADMIN)) return -EACCES; ++ if(!capable(CAP_SYS_ADMIN)) ++ return -EACCES; + #endif + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); +- if (mtd->sync) +- mtd->sync(mtd); ++ if (mtdblk->mtd->sync) ++ mtdblk->mtd->sync(mtdblk->mtd); + return 0; + + default: +- return -ENOTTY; ++ return -EINVAL; + } + } + +@@ -261,34 +316,85 @@ + }; + #endif + ++#ifdef CONFIG_DEVFS_FS ++/* Notification that a new device has been added. Create the devfs entry for ++ * it. */ ++ ++static void mtd_notify_add(struct mtd_info* mtd) ++{ ++ char name[8]; ++ ++ if (!mtd || mtd->type == MTD_ABSENT) ++ return; ++ ++ sprintf(name, "%d", mtd->index); ++ devfs_ro_handle[mtd->index] = devfs_register(devfs_dir_handle, name, ++ DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index, ++ S_IFBLK | S_IRUGO | S_IWUGO, ++ &mtd_fops, NULL); ++} ++ ++static void mtd_notify_remove(struct mtd_info* mtd) ++{ ++ if (!mtd || mtd->type == MTD_ABSENT) ++ return; ++ ++ devfs_unregister(devfs_ro_handle[mtd->index]); ++} ++#endif ++ + int __init init_mtdblock(void) + { + int i; + ++ spin_lock_init(&mtdblks_lock); ++#ifdef CONFIG_DEVFS_FS ++ if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops)) ++ { ++ printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", ++ MTD_BLOCK_MAJOR); ++ return -EAGAIN; ++ } ++ ++ devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL); ++ register_mtd_user(¬ifier); ++#else + if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) { + printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", + MTD_BLOCK_MAJOR); + return -EAGAIN; + } ++#endif + + /* We fill it in at open() time. */ + for (i=0; i< MAX_MTD_DEVICES; i++) { + mtd_sizes[i] = 0; + } +- ++ init_waitqueue_head(&thr_wq); + /* Allow the block size to default to BLOCK_SIZE. */ + blksize_size[MAJOR_NR] = NULL; + blk_size[MAJOR_NR] = mtd_sizes; + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request); ++ kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); + return 0; + } + + static void __exit cleanup_mtdblock(void) + { ++ leaving = 1; ++ wake_up(&thr_wq); ++ down(&thread_sem); ++#ifdef CONFIG_DEVFS_FS ++ unregister_mtd_user(¬ifier); ++ devfs_unregister(devfs_dir_handle); ++ devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME); ++#else + unregister_blkdev(MAJOR_NR,DEVICE_NAME); +- blksize_size[MAJOR_NR] = NULL; ++#endif + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); ++ blksize_size[MAJOR_NR] = NULL; ++ blk_size[MAJOR_NR] = NULL; + } + + module_init(init_mtdblock); +@@ -296,5 +402,5 @@ + + + MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al."); +-MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices"); ++MODULE_AUTHOR("Nicolas Pitre <nico@cam.org> et al."); ++MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to MTD devices"); +--- linux-2.4.20/drivers/net/Config.in~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/net/Config.in 2005-01-08 12:16:21.077658368 -0500 +@@ -2,6 +2,7 @@ + # Network device configuration + # + ++source drivers/net/hnd/Config.in + source drivers/net/arcnet/Config.in + + tristate 'Dummy net driver support' CONFIG_DUMMY +--- linux-2.4.20/drivers/net/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/net/Makefile 2005-01-08 12:16:21.891534640 -0500 +@@ -21,6 +21,17 @@ + list-multi := rcpci.o + rcpci-objs := rcpci45.o rclanmtl.o + ++subdir-m += mac ++subdir-m += diag ++ ++ifeq ($(CONFIG_HW_QOS),y) ++subdir-m += port_based_qos ++else ++ ifeq ($(CONFIG_PERFORMANCE),y) ++ subdir-m += port_based_qos ++ endif ++endif ++ + ifeq ($(CONFIG_TULIP),y) + obj-y += tulip/tulip.o + endif +@@ -242,6 +253,36 @@ + endif + endif + ++# ++# Broadcom HND devices ++# ++ ++ifdef CONFIG_HND ++subdir-$(CONFIG_HND) += hnd ++endif ++ifdef CONFIG_ET ++subdir-$(CONFIG_ET) += et.4702 ++subdir-$(CONFIG_ET) += et ++endif ++ifdef CONFIG_IL ++subdir-$(CONFIG_IL) += il ++endif ++ifdef CONFIG_WL ++subdir-$(CONFIG_WL) += wl ++endif ++ifeq ($(CONFIG_HND),y) ++ obj-y += hnd/hnd.o ++endif ++ifeq ($(CONFIG_ET),y) ++ obj-y += et/et.o ++endif ++ifeq ($(CONFIG_IL),y) ++ obj-y += il/il.o ++endif ++ifeq ($(CONFIG_WL),y) ++ obj-y += wl/wl.o ++endif ++ + include $(TOPDIR)/Rules.make + + clean: +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/diag/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,27 @@ ++# Copyright 2001, Cybertan Corporation ++# All Rights Reserved. ++# ++# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Cybertan Corporation; ++# the contents of this file may not be disclosed to third parties, copied or ++# duplicated in any form, in whole or in part, without the prior written ++# permission of Cybertan Corporation. ++# ++# ++# $Id: Makefile,v 1.1 2003/07/09 14:09:58 honor Exp $ ++# ++ ++O_TARGET := diag.o ++ ++MAC_OBJS := diag_led.o ++ ++export-objs := ++obj-y := $(MAC_OBJS) ++obj-m := $(O_TARGET) ++ ++SRCBASE := $(TOPDIR)/../.. ++EXTRA_CFLAGS += -I$(SRCBASE)/include ++ ++vpath %.c $(SRCBASE)/shared ++ ++include $(TOPDIR)/Rules.make ++ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/et/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,42 @@ ++# ++# Makefile for the Broadcom et driver ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.6 2004/04/12 04:31:57 honor Exp $ ++# ++ ++O_TARGET := et.o ++ ++ET_OBJS := et_linux.o etc.o ++ ++ifeq ($(CONFIG_ET_47XX),y) ++ET_OBJS += etc47xx.o etc_robo.o etc_adm.o ++EXTRA_CFLAGS += -DBCM47XX_CHOPS ++endif ++ifeq ($(CONFIG_ET_4413),y) ++ET_OBJS += etc4413.o ++EXTRA_CFLAGS += -DBCM4413_CHOPS ++endif ++ ++export-objs := ++obj-y := $(ET_OBJS) ++obj-m := $(O_TARGET) ++ ++EXTRA_CFLAGS += -DDMA ++ ++# Search for sources under src/et/sys or objects under src/et/linux ++ifneq ($(wildcard $(SRCBASE)/et/sys),) ++EXTRA_CFLAGS += -I$(SRCBASE)/et/sys ++vpath %.c $(SRCBASE)/et/sys $(SRCBASE)/shared ++else ++obj-y := $(foreach obj,$(ET_OBJS),$(SRCBASE)/et/linux/$(obj)) ++endif ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/et.4702/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,43 @@ ++# Copyright 2001, Broadcom Corporation ++# All Rights Reserved. ++# ++# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; ++# the contents of this file may not be disclosed to third parties, copied or ++# duplicated in any form, in whole or in part, without the prior written ++# permission of Broadcom Corporation. ++# ++# Makefile for the Broadcom et driver ++# ++# $Id: Makefile,v 1.2 2003/11/13 13:04:22 honor Exp $ ++# ++ ++O_TARGET := 4702et.o ++ ++ET_OBJS := et_linux.o etc.o ++ ++ifeq ($(CONFIG_ET_47XX),y) ++ET_OBJS += etc47xx.o etc_robo.o ++EXTRA_CFLAGS += -DBCM47XX_CHOPS ++endif ++ifeq ($(CONFIG_ET_4413),y) ++ET_OBJS += etc4413.o ++EXTRA_CFLAGS += -DBCM4413_CHOPS ++endif ++ ++export-objs := ++obj-y := $(ET_OBJS) ++obj-m := $(O_TARGET) ++ ++SRCBASE := $(TOPDIR)/../.. ++EXTRA_CFLAGS += -I$(SRCBASE)/include ++EXTRA_CFLAGS += -DDMA ++ ++# Search for sources under src/et/sys or objects under src/et/linux ++ifneq ($(wildcard $(SRCBASE)/et.4702/sys),) ++EXTRA_CFLAGS += -I$(SRCBASE)/et.4702/sys ++vpath %.c $(SRCBASE)/et.4702/sys $(SRCBASE)/shared ++else ++obj-y := $(foreach obj,$(ET_OBJS),$(SRCBASE)/et.4702/linux/$(obj)) ++endif ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/hnd/Config.in 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,35 @@ ++# ++# Broadcom Home Networking Division (HND) driver configuration ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++ ++mainmenu_option next_comment ++comment 'Broadcom HND network devices' ++ tristate 'Broadcom HND network device support' CONFIG_HND $CONFIG_PCI ++ if [ "$CONFIG_HND" != "n" ]; then ++ dep_tristate ' Broadcom InsideLine HPNA support' CONFIG_IL $CONFIG_HND ++ if [ "$CONFIG_IL" != "n" ]; then ++ bool ' Broadcom BCM42xx support' CONFIG_IL_42XX ++ bool ' Broadcom BCM47xx support' CONFIG_IL_47XX ++ int ' LARQ buffer allocation (0 = tiny, 2 = huge)' CONFIG_LARQ_BUF 0 ++ fi ++ dep_tristate ' Broadcom 10/100 Ethernet support' CONFIG_ET $CONFIG_HND ++ if [ "$CONFIG_ET" != "n" ]; then ++ bool ' Broadcom BCM4413 support' CONFIG_ET_4413 ++ bool ' Broadcom BCM47xx support' CONFIG_ET_47XX ++ fi ++ dep_tristate ' Broadcom BCM43xx 802.11 Wireless support' CONFIG_WL $CONFIG_HND ++ if [ "$CONFIG_WL" != "n" ]; then ++ bool ' Access Point Mode Supported' CONFIG_WL_AP ++ bool ' STA Mode Supported' CONFIG_WL_STA ++ bool ' OID Interface Supported' CONFIG_WL_OID ++ fi ++ fi ++endmenu +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/hnd/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,67 @@ ++# ++# Makefile for Broadcom Home Networking Division (HND) shared driver code ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.7 2004/04/12 04:31:58 honor Exp $ ++# ++ ++O_TARGET := hnd.o ++ ++HND_OBJS := bcmutils.o hnddma.o linux_osl.o sbutils.o bcmsrom.o ++ ++ifneq ($(CONFIG_BCM947XX),y) ++HND_OBJS += nvramstubs.o ++endif ++ ++export-objs := shared_ksyms.o ++obj-y := shared_ksyms.o $(HND_OBJS) ++obj-m := $(O_TARGET) ++ ++vpath %.c $(SRCBASE)/shared $(SRCBASE)/shared/nvram ++ ++include $(TOPDIR)/Rules.make ++ ++ifeq ($(wildcard $(SRCBASE)/shared/bcmutils.c),) ++bcmutils.o: $(SRCBASE)/shared/linux/bcmutils.o ++ cp $< $@ ++endif ++ ++ifeq ($(wildcard $(SRCBASE)/shared/hnddma.c),) ++hnddma.o: $(SRCBASE)/shared/linux/hnddma.o ++ cp $< $@ ++endif ++ ++ifeq ($(wildcard $(SRCBASE)/shared/linux_osl.c),) ++linux_osl.o: $(SRCBASE)/shared/linux/linux_osl.o ++ cp $< $@ ++endif ++ ++ifeq ($(wildcard $(SRCBASE)/shared/sbutils.c),) ++sbutils.o: $(SRCBASE)/shared/linux/sbutils.o ++ cp $< $@ ++endif ++ ++ifeq ($(wildcard $(SRCBASE)/shared/bcmsrom.c),) ++bcmsrom.o: $(SRCBASE)/shared/linux/bcmsrom.o ++ cp $< $@ ++endif ++ ++ifeq ($(wildcard $(SRCBASE)/shared/nvramstubs.c),) ++nvramstubs.o: $(SRCBASE)/shared/linux/nvramstubs.o ++ cp $< $@ ++endif ++ ++ifeq ($(wildcard $(SRCBASE)/shared/bcmwpa.c),) ++bcmwpa.o: $(SRCBASE)/shared/linux/bcmwpa.o ++ cp $< $@ ++endif ++ ++shared_ksyms.c: shared_ksyms.sh $(HND_OBJS) ++ sh -e $< $(HND_OBJS) > $@ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/hnd/shared_ksyms.sh 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,21 @@ ++#!/bin/sh ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: shared_ksyms.sh,v 1.1.1.6 2004/04/12 04:31:58 honor Exp $ ++# ++ ++cat <<EOF ++#include <linux/config.h> ++#include <linux/module.h> ++EOF ++ ++for file in $* ; do ++ ${NM} $file | sed -ne 's/[0-9A-Fa-f]* [DT] \([^ ]*\)/extern void \1; EXPORT_SYMBOL(\1);/p' ++done +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/il/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,50 @@ ++# ++# Makefile for the Broadcom il driver ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.6 2004/04/12 04:31:58 honor Exp $ ++# ++ ++O_TARGET := il.o ++ ++IL_OBJS := il_linux.o ilc.o cert.o plarq.o pe_select_maxse.o ++ ++ifeq ($(CONFIG_IL_47XX),y) ++IL_OBJS += ilc47xx.o ++EXTRA_CFLAGS += -DBCM47XX_CHOPS ++endif ++ifeq ($(CONFIG_IL_42XX),y) ++IL_OBJS += ilc42xx.o ++EXTRA_CFLAGS += -DBCM42XX_CHOPS ++endif ++ ++export-objs := ++obj-y := $(IL_OBJS) ++obj-m := $(O_TARGET) ++ ++EXTRA_CFLAGS += -DDMA -DIL_CERT -DIL_PROTOS ++ ++ifneq ($(CONFIG_BRIDGE),n) ++EXTRA_CFLAGS += -DIL_BRIDGE ++endif ++ ++ifeq ($(CONFIG_LARQ_BUF),0) ++EXTRA_CFLAGS += -DLARQ_TINY ++endif ++ ++# Search for sources under src/il/sys or objects under src/il/linux ++ifneq ($(wildcard $(SRCBASE)/il/sys),) ++EXTRA_CFLAGS += -I$(SRCBASE)/il/sys ++vpath %.c $(SRCBASE)/il/sys $(SRCBASE)/shared ++else ++obj-y := $(foreach obj,$(IL_OBJS),$(SRCBASE)/il/linux/$(obj)) ++endif ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/mac/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,27 @@ ++# Copyright 2001, Cybertan Corporation ++# All Rights Reserved. ++# ++# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Cybertan Corporation; ++# the contents of this file may not be disclosed to third parties, copied or ++# duplicated in any form, in whole or in part, without the prior written ++# permission of Cybertan Corporation. ++# ++# ++# $Id: Makefile,v 1.1 2003/07/09 14:10:26 honor Exp $ ++# ++ ++O_TARGET := writemac.o ++ ++MAC_OBJS := mac.o ++ ++export-objs := ++obj-y := $(MAC_OBJS) ++obj-m := $(O_TARGET) ++ ++SRCBASE := $(TOPDIR)/../.. ++EXTRA_CFLAGS += -I$(SRCBASE)/include ++ ++vpath %.c $(SRCBASE)/shared ++ ++include $(TOPDIR)/Rules.make ++ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/Atan.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,177 @@ ++#include "Atan.h" ++#include "c47xx.h" ++ ++extern void conf_gpio(int x); ++ ++/*---------------------------------------------------------------------------- ++Write specified data to eeprom ++entry: *src = pointer to specified data to write ++ len = number of short(2 bytes) to be written ++*/ ++void write_eeprom( short RegNumber, unsigned short *data, int len ) ++{ ++ int i2; ++ unsigned short s_addr, s_data; ++ unsigned short *src; ++ ++ src = data; ++ SetEEpromToSendState(); ++// the write enable(WEN) instruction must be executed before any device ++// programming can be done ++ ++ s_data = 0x04c0; ++ SendAddrToEEprom(s_data); //00000001 0011000000B ++ SetCSToLowForEEprom(); ++ ++ s_addr = 0x0500 | (RegNumber & 0x0ff); //00000001 01dddddddd ++ s_data = *src; ++ ++ for (i2 = len; i2 > 0 ; i2 --) ++ { ++ SendAddrToEEprom(s_addr); //00000001 01dddddd ++ SendDataToEEprom(s_data); //dddddddd dddddddd ++ SetCSToLowForEEprom(); ++ SetCSToLowForEEprom(); ++ //WriteWait(); ++ s_addr ++; ++ src ++; ++ s_data = *src; ++ } ++// after all data has been written to EEprom , the write disable(WDS) ++// instruction must be executed ++ SetCSToHighForEEprom(); ++ s_data = 0x0400; ++ SendAddrToEEprom(s_data); //00000001 00000000B ++ SetCSToLowForEEprom(); ++ SetCSToLowForEEprom(); ++} ++ ++void SetEEpromToSendState() ++{ ++ conf_gpio(0x0); ++ conf_gpio(0x0); ++ conf_gpio(B_ECS); ++ conf_gpio(B_ECS); ++ ++// ;cs __-- ,bit 2 ++// ;sck ____ ,bit 3 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 4 ++// ; ++} ++ ++void ResetEEpromToSendState() ++{ ++ conf_gpio(0x0); ++ conf_gpio(0x0); ++ conf_gpio(0x0); ++ conf_gpio(0x0); ++ ++// ;cs ____ ,bit 2 ++// ;sck ____ ,bit 3 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 4 ++// ; ++} ++ ++void SetCSToLowForEEprom() ++{ ++ conf_gpio(0x0); ++ conf_gpio(B_ECK); ++ conf_gpio(B_ECK); ++ conf_gpio(0x0); ++ ++// ;cs ____ ,bit 2 ++// ;sck _--_ ,bit 3 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 4 ++// ; ++} ++ ++void SetCSToHighForEEprom() ++{ ++ conf_gpio(B_ECS); ++ conf_gpio(B_ECS|B_ECK); ++ conf_gpio(B_ECS|B_ECK); ++ conf_gpio(B_ECS); ++ ++// ;cs ---- ,bit 2 ++// ;sck _--_ ,bit 3 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 4 ++// ; ++} ++ ++void send_1ToEEprom() ++{ ++ conf_gpio(B_ECS|B_EDI); ++ conf_gpio(B_ECS|B_ECK|B_EDI); ++ conf_gpio(B_ECS|B_ECK|B_EDI); ++ conf_gpio(B_ECS|B_EDI); ++ ++// ;cs ---- ,bit 2 ++// ;sck _--_ ,bit 3 ++// ;di ---- ,bit 5 ++// ;do ____ ,bit 4 ++// ; ++} ++ ++void send_0ToEEprom() ++{ ++ conf_gpio(B_ECS); ++ conf_gpio(B_ECS|B_ECK); ++ conf_gpio(B_ECS|B_ECK); ++ conf_gpio(B_ECS); ++ ++// ;cs ---- ,bit 2 ++// ;sck _--_ ,bit 3 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 4 ++// ; ++} ++ ++#if 0 ++void WriteWait() ++{ ++ unsigned int status; ++ ++ SetCSToLowForEEprom(); ++ SetCSToHighForEEprom(); ++ do { ++ SetCSToHighForEEprom(); ++ //status = ReadGPIOData(EDO); ++ status = gpio & B_EDO; // read EDO bit ++ } ++ while (!status); // wait for write - ready ++ SetCSToLowForEEprom(); ++} ++#endif ++ ++void SendDataToEEprom(short s_data) ++{ ++ int data_mask; ++ ++ for (data_mask = 0x8000; data_mask != 0; ) ++ { ++ if (s_data & data_mask) ++ send_1ToEEprom(); ++ else ++ send_0ToEEprom(); ++ data_mask = data_mask >> 1; ++ } ++} ++ ++void SendAddrToEEprom(short s_data) ++{ ++ int data_mask; ++ ++ for (data_mask = 0x0400 ;data_mask != 0; ) ++ { ++ if (s_data & data_mask) ++ send_1ToEEprom(); ++ else ++ send_0ToEEprom(); ++ data_mask = data_mask >> 1; ++ } ++} ++ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/Atan.h 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,18 @@ ++#ifndef _ATAN_H_ ++#define _ATAN_H_ ++ ++#define SINGLECOLOUR 0x1 ++#define DUALCOLOUR 0x2 ++ ++void write_eeprom(short,unsigned short *,int); ++void SetEEpromToSendState(void); ++void ResetEEpromToSendState(void); ++void SetCSToLowForEEprom(void); ++void SetCSToHighForEEprom(void); ++void send_1ToEEprom(void); ++void send_0ToEEprom(void); ++//void WriteWait(void); ++void SendAddrToEEprom(short); ++void SendDataToEEprom(short); ++ ++#endif +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,27 @@ ++# Copyright 2001, Cybertan Corporation ++# All Rights Reserved. ++# ++# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Cybertan Corporation; ++# the contents of this file may not be disclosed to third parties, copied or ++# duplicated in any form, in whole or in part, without the prior written ++# permission of Cybertan Corporation. ++# ++# ++# $Id: Makefile,v 1.2 2004/03/02 13:23:33 cnhsieh Exp $ ++# ++ ++O_TARGET := port_based_qos_mod.o ++ ++PORT_BASED_QOS_MOD_OBJS := port_based_qos.o Atan.o c47xx.o eeprom.o ++ ++export-objs := ++obj-y := $(PORT_BASED_QOS_MOD_OBJS) ++obj-m := $(O_TARGET) ++ ++SRCBASE := $(TOPDIR)/../.. ++EXTRA_CFLAGS += -I$(SRCBASE)/include -Wall -I$(SRCBASE)/ ++ ++vpath %.c $(SRCBASE)/shared ++ ++include $(TOPDIR)/Rules.make ++ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/c47xx.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,85 @@ ++#include <typedefs.h> ++#include <sbutils.h> ++#include <bcmdevs.h> ++#include <osl.h> ++#include <bcmnvram.h> ++#include <bcmutils.h> ++ ++#include <sbpci.h> ++#include <sbchipc.h> ++#include <sbconfig.h> ++#include <sbextif.h> ++#include <sbmips.h> ++#include "c47xx.h" ++extern uint32 sb_gpioouten(void *sbh, uint32 mask, uint32 val); ++extern uint32 sb_gpioout(void *sbh, uint32 mask, uint32 val); ++extern uint32 sb_gpioin(void *sbh); ++extern uint32 sb_gpiointmask(void *sbh, uint32 mask, uint32 val); ++ ++#define OUTENMASK B_RESET|B_ECS|B_ECK|B_EDI ++#define CFGMASK B_ECS|B_ECK|B_EDI ++#define BIT(x) (1 << (x)) ++#define ASSERT(exp) do {} while (0) ++ ++void ++conf_gpio(int x) ++{ ++ ASSERT(sbh); ++ ++ /* Enable all of output pins */ ++ sb_gpioouten(sbh, OUTENMASK, OUTENMASK); ++ ++ /* We don't want the B_RESET pin changed, unless ++ * it tries to set the B_RESET pin. ++ */ ++ if (x & B_RESET) ++ sb_gpioout(sbh, OUTENMASK, x); ++ else ++ sb_gpioout(sbh, CFGMASK, x); ++ ++} ++ ++void ++gpio_line_set(int x, unsigned int value) ++{ ++ ASSERT(sbh); ++ ++ if (value == 1) ++ sb_gpioout(sbh, BIT(x), BIT(x)); ++ else if (value == 0) ++ sb_gpioout(sbh, BIT(x), 0); ++} ++ ++void ++gpio_line_get(int x, int *value) ++{ ++ ASSERT(sbh); ++ ++ *value = (sb_gpioin(sbh) >> x) & 0x1; ++} ++ ++void ++gpio_line_config_in(int x) ++{ ++ ASSERT(sbh); ++ ++ sb_gpioouten(sbh, BIT(x), 0); ++ sb_gpiointmask(sbh, BIT(x), BIT(x)); ++} ++ ++void ++gpio_line_config_out(int x) ++{ ++ ASSERT(sbh); ++ ++ sb_gpiointmask(sbh, BIT(x), 0); ++ sb_gpioouten(sbh, BIT(x), BIT(x)); ++} ++ ++void ++gpio_line_config_out_all(int x) ++{ ++ ASSERT(sbh); ++ ++ sb_gpioouten(sbh, OUTENMASK, OUTENMASK); ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/c47xx.h 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,23 @@ ++#ifndef _C47XX_H_ ++#define _C47XX_H_ ++ ++extern void *bcm947xx_sbh; ++#define sbh bcm947xx_sbh ++ ++#define GPIO0 0 ++#define GPIO1 1 ++#define GPIO2 2 ++#define GPIO3 3 ++#define GPIO4 4 ++#define GPIO5 5 ++#define GPIO6 6 ++#define GPIO7 7 ++#define GPIO8 8 ++ ++#define B_RESET 1<<GPIO0 ++#define B_ECS 1<<GPIO2 ++#define B_ECK 1<<GPIO3 ++#define B_EDO 1<<GPIO4 ++#define B_EDI 1<<GPIO5 ++ ++#endif +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/eeprom.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,355 @@ ++#include <linux/delay.h> ++ ++#define EEDO_PIN 4 ++#define EECS_PIN 2 ++#define EECK_PIN 3 ++#define EEDI_PIN 5 ++#define RESET_PIN 0 ++ ++static void SetCSToLowForEEprom(void); ++//static void SetCSToHighForEEprom(void); ++static void send1ToEEprom(void); ++static void send0ToEEprom(void); ++static void InitSerialInterface(void); ++static void SerialPulse(void); ++static void WriteDataToRegister(unsigned short RegNumber, unsigned short data); ++void ReadDataFromRegister(unsigned short addr, unsigned short *hidata, unsigned short *lodata,int select_count); ++static void WriteDataToEEprom(unsigned short addr, unsigned short data); ++static void WriteCmdToEEprom(unsigned short cmd); ++extern void gpio_line_set(int x, unsigned int value); ++extern void gpio_line_get(int x, int *value); ++extern void gpio_line_config_out(int x); ++extern void gpio_line_config_in(int x); ++extern void gpio_line_config_out_all(void); ++// ;cs __-- ,bit 3 ++// ;sck ____ ,bit 4 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 6 ++// ; ++ ++static void SetEEpromToSendState(void) ++{ ++ gpio_line_set(EECS_PIN, 0); ++ gpio_line_set(EECK_PIN, 0); ++ gpio_line_set(EEDI_PIN, 1); ++// gpio_line_set(EEDO_PIN, 1); /* high impedance */ ++ ++ mdelay(1); ++ gpio_line_set(EECS_PIN, 1); ++// gpio_line_set(EEDO_PIN, 1); /* high impedance */ ++} ++ ++#if 0 ++static void EEpromInit(void) ++{ ++ gpio_line_set(EECS_PIN, 0); ++ gpio_line_set(EECK_PIN, 0); ++ gpio_line_set(EEDI_PIN, 1); ++ gpio_line_set(EEDO_PIN, 1); /* high impedance */ ++ ++ mdelay(1); ++} ++ ++// ;cs ____ ,bit 3 ++// ;sck ____ ,bit 4 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 6 ++// ; ++static void ResetEEpromToSendState(void) ++{ ++ gpio_line_set(EECS_PIN, 0); ++ gpio_line_set(EEDI_PIN, 0); ++ //gpio_line_set(EEDO_PIN, 0); ++ gpio_line_set(EECK_PIN, 0); ++} ++#endif /* 0 */ ++ ++// ;cs ____ ,bit 3 ++// ;sck _--_ ,bit 4 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 6 ++// ; ++static void SetCSToLowForEEprom(void) ++{ ++ /* minimum tcs is 1us */ ++ gpio_line_set(EECS_PIN, 0); ++ gpio_line_set(EECS_PIN, 0); ++ ++ gpio_line_set(EECK_PIN, 0); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 0); ++ ++ gpio_line_set(EECS_PIN, 1); ++ ++ udelay(10); ++} ++ ++#if 0 ++// ;cs ---- ,bit 3 ++// ;sck _--_ ,bit 4 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 6 ++// ; ++static void SetCSToHighForEEprom(void) ++{ ++ gpio_line_set(EECS_PIN, 1); ++ ++ /* min tskh and tskl is 1us */ ++ gpio_line_set(EECK_PIN, 1); ++ udelay(2); ++ gpio_line_set(EECK_PIN, 0); ++} ++#endif /* 0 */ ++ ++// ;cs ---- ,bit 3 ++// ;sck _--_ ,bit 4 ++// ;di ---- ,bit 5 ++// ;do ____ ,bit 6 ++// ; ++static void send1ToEEprom(void) ++{ ++//printf("send1ToEEprom(1)..."); ++ gpio_line_set(EEDI_PIN, 1); ++ ++ gpio_line_set(EECK_PIN, 0); ++ udelay(1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ udelay(1); ++ gpio_line_set(EECK_PIN, 0); ++} ++ ++// ;cs ---- ,bit 3 ++// ;sck _--_ ,bit 4 ++// ;di ____ ,bit 5 ++// ;do ____ ,bit 6 ++// ; ++static void send0ToEEprom(void) ++{ ++//printf("send0ToEEprom(0)..."); ++ gpio_line_set(EEDI_PIN, 0); ++ ++ gpio_line_set(EECK_PIN, 0); ++ udelay(1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 1); ++ udelay(1); ++ gpio_line_set(EECK_PIN, 0); ++} ++ ++static void WriteDataToEEprom(unsigned short addr, unsigned short data) ++{ ++ unsigned short addr_mask, data_mask; ++ ++ SetEEpromToSendState(); ++ for (addr_mask = 0x400; addr_mask != 0; ) ++ { ++ if (addr & addr_mask) ++ send1ToEEprom(); ++ else ++ send0ToEEprom(); ++ addr_mask = addr_mask >> 1; ++ } ++ for (data_mask = 0x8000; data_mask != 0; ) ++ { ++ if (data & data_mask) ++ send1ToEEprom(); ++ else ++ send0ToEEprom(); ++ data_mask = data_mask >> 1; ++ } ++ SetCSToLowForEEprom(); ++} ++ ++static void WriteCmdToEEprom(unsigned short cmd) ++{ ++ unsigned short cmd_mask; ++ ++ SetEEpromToSendState(); ++ for (cmd_mask = 0x0400 ;cmd_mask != 0; ) ++ { ++ if (cmd & cmd_mask) ++ send1ToEEprom(); ++ else ++ send0ToEEprom(); ++ cmd_mask = cmd_mask >> 1; ++ } ++ SetCSToLowForEEprom(); ++} ++ ++/* ++ * Write data to configure registers through EEPROM interface, even we do not have ++ * an external EEPROM connectted, ADM6996 got a virtual AT39C66 inside ++ */ ++static void WriteDataToRegister(unsigned short RegNumber, unsigned short data) ++{ ++ unsigned short cmd, addr; ++ ++ printk("WriteDataToRegister(RegNumber=0x%x, data=0x%x)\n", RegNumber, data); ++ ++// the write enable(WEN) instruction must be executed before any device ++// programming can be done ++ cmd = 0x04c0; ++ WriteCmdToEEprom(cmd); //00000001 0011000000B ++ ++ addr = 0x0500 | (RegNumber & 0x0ff); //00000001 01dddddddd ++ WriteDataToEEprom(addr, data); //00000001 01dddddd ++ ++ ++// after all data has been written to EEprom , the write disable(WDS) ++// instruction must be executed ++ cmd = 0x0400; ++ WriteCmdToEEprom(cmd); //00000001 00000000B ++} ++ ++static void SerialDelay(int count) ++{ ++ udelay(count); ++} ++ ++static void InitSerialInterface(void) ++{ ++ gpio_line_set(EECK_PIN, 0); ++ gpio_line_set(EEDI_PIN, 0); ++} ++ ++static void SerialPulse(void) ++{ ++ gpio_line_set(EECK_PIN, 0); ++ gpio_line_set(EECK_PIN, 1); ++ SerialDelay(10); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_set(EECK_PIN, 0); ++} ++/* ++ * Since there is no EEPROM is our board, read from EEPROM need to obey the timing alike ++ * MII interface, EECK = MDC, EEDI = MDIO, please refer to section 4.3 of ADM6996 datasheet ++ */ ++void ReadDataFromRegister(unsigned short addr, unsigned short *hidata, unsigned short *lodata, int select_count) ++{ ++ unsigned short addr_mask, data_mask; ++ int value, i; ++ unsigned char StartBits, Opcode, TAbits; ++ ++ gpio_line_config_out_all(); ++ mdelay(1); ++ /* initialize serial interface */ ++ gpio_line_set(EECS_PIN, 0); ++ InitSerialInterface(); ++ ++ /* Preamble, 35 bits */ ++ gpio_line_set(EECK_PIN, 0); ++ gpio_line_set(EEDI_PIN, 1); ++ for (i = 0; i < 35; i++) ++ { ++ gpio_line_set(EECK_PIN, 1); ++ SerialDelay(10); ++ gpio_line_set(EECK_PIN, 0); ++ SerialDelay(10); ++ } ++ ++ /* Start bits, 2-bit(01b) */ ++ InitSerialInterface(); ++ StartBits = 0x01; ++ for (i = 0; i < 2; i++) ++ { ++ value = (StartBits & 2) ? 1 : 0; ++ gpio_line_set(EEDI_PIN, value); ++ SerialDelay(1); ++ SerialPulse(); ++ StartBits <<= 1; ++ } ++ ++ /* Opcode, read = 10b */ ++ InitSerialInterface(); ++ Opcode = 0x02; ++ for (i = 0; i < 2; i++) ++ { ++ value = (Opcode & 0x02) ? 1 : 0; ++ gpio_line_set(EEDI_PIN, value); ++ SerialDelay(1); ++ SerialPulse(); ++ Opcode <<= 1; ++ } ++ ++ /* 10 bits register address */ ++ /* 1-bit Table Select, 2-bit Device Address, 7-bit Register Address */ ++ InitSerialInterface(); ++ if (select_count) ++ addr = (addr & 0x7f) | 0x200; ++ else ++ addr = addr & 0x7f ; ++ for (addr_mask = 0x200; addr_mask != 0; addr_mask >>= 1) ++ { ++ value = (addr & addr_mask) ? 1 : 0; ++ gpio_line_set(EEDI_PIN, value); ++ SerialDelay(1); ++ SerialPulse(); ++ } ++ ++ /* TA, turnaround 2-bit */ ++ InitSerialInterface(); ++ TAbits = 0x02; ++ gpio_line_config_in(EEDI_PIN); ++ for (i = 0; i < 2; i++) ++ { ++ gpio_line_set(EECK_PIN, 1); ++ SerialDelay(4); ++ gpio_line_get(EEDI_PIN, &value); ++ SerialDelay(4); ++ TAbits <<= 1; ++ gpio_line_set(EECK_PIN, 1); ++ } ++ ++ ++ /* Latch data from serial management EEDI pin */ ++ *hidata = 0; ++ gpio_line_set(EECK_PIN, 0); ++ for (data_mask = 0x8000; data_mask != 0; data_mask >>= 1) ++ { ++ SerialDelay(4); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_get(EEDI_PIN, &value); ++ if (value) ++ { ++ *hidata |= data_mask; ++ } ++ gpio_line_set(EECK_PIN, 0); ++ SerialDelay(4); ++ } ++ *lodata = 0; ++ gpio_line_set(EECK_PIN, 0); ++ for (data_mask = 0x8000; data_mask != 0; data_mask >>= 1) ++ { ++ SerialDelay(4); ++ gpio_line_set(EECK_PIN, 1); ++ gpio_line_get(EEDI_PIN, &value); ++ if (value) ++ { ++ *lodata |= data_mask; ++ } ++ gpio_line_set(EECK_PIN, 0); ++ SerialDelay(4); ++ } ++ ++ SerialDelay(2); ++ ++ /* Idle, EECK must send at least one clock at idle time */ ++ SerialPulse(); ++ gpio_line_set(EECK_PIN, 0); ++ SerialDelay(10); ++ gpio_line_set(EECK_PIN, 1); ++ SerialDelay(10); ++ gpio_line_set(EECK_PIN, 0); ++ SerialPulse(); ++ ++ gpio_line_config_out(EEDI_PIN); ++ gpio_line_set(EECS_PIN, 1); ++ ++ printk("ReadDataFromRegister(addr=0x%x, hidata=0x%x, lodata=0x%x)\n", addr, *hidata, *lodata); ++} +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/port_based_qos/port_based_qos.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,460 @@ ++ /* ++ * Remaining issues: ++ * + stats support ++ * + multicast support ++ * + media sense ++ * + half/full duplex ++ * - random MAC addr. ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/ethtool.h> ++#include <linux/mii.h> ++#include <asm/io.h> ++ ++#include <linux/sysctl.h> ++#include <cy_conf.h> ++ ++#define MODULE_NAME "port_based_qos_mod" ++#define DEVICE_NAME "qos" ++#define MODULE_VERSION "0.0.1" ++ ++extern void ReadDataFromRegister(unsigned short addr, unsigned short *hidata, unsigned short *lodata,int select_count); ++ ++#ifdef PERFORMANCE_SUPPORT ++static struct ctl_table_header *qos_sysctl_header; ++static unsigned long qos[28]; ++ ++static ctl_table mytable[] = { ++ { 2000, "qos", ++ qos, sizeof(qos), ++ 0644, NULL, ++ proc_dointvec }, ++ { 0 } ++}; ++ ++static unsigned short statis_addr_map[7][6] ={ ++ {0x04, 0x06, 0x08, 0x0a, 0x0b, 0x0c}, ++ {0x16, 0x18, 0x1a, 0x1c, 0x1d, 0x1e}, ++ {0x0d, 0x0f, 0x11, 0x13, 0x14, 0x15}, ++ {0x1f, 0x21, 0x23, 0x25, 0x26, 0x27}, ++ {0x31, 0x33, 0x35, 0x37, 0x38, 0x39}, ++ {0x28, 0x2a, 0x2c, 0x2e, 0x2f, 0x30}, ++ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01} ++}; ++ ++unsigned long get_statistic_from_serial(unsigned short port, unsigned short item) ++{ ++ unsigned short hidata, lodata; ++ ++ ReadDataFromRegister(statis_addr_map[item][port], &hidata, &lodata, 1); ++ return ((hidata << 16) | lodata); ++} ++#endif ++ ++#ifdef HW_QOS_SUPPORT ++struct port_qos_t{ ++ int addr; ++ int content_mask; ++ int *content_set; ++}; ++ ++void WriteDataToRegister_(unsigned short reg_idx, unsigned short content_idx); ++extern void write_eeprom(short,short *,int); ++ ++#define BANDWIDTH_1_BIT 2 ++#define BANDWIDTH_2_BIT 4 ++#define BANDWIDTH_3_BIT 6 ++#define BANDWIDTH_4_BIT 7 ++ ++#define PORT_CONFIG_1 0x3 ++#define PORT_CONFIG_2 0x5 ++#define PORT_CONFIG_3 0x7 ++#define PORT_CONFIG_4 0x8 ++#define BANDWIDTH_CTL_123 0x31 ++#define BANDWIDTH_CTL_4 0x32 ++#define BANDWIDTH_CTL_ENABLE 0x33 ++#define DISCARD_MODE 0x10 ++#define TOS_PRIO_MAP 0xf ++ ++#define PRIORITY_MASK 0xfc7f ++#define PRIORITY_DISABLE_MASK 0xfc7e ++#define FLOW_CTL_MASK 0xfffe ++#define RATE_LIMIT_MASK_1 0xff8f ++#define RATE_LIMIT_MASK_2 0xf8ff ++#define RATE_LIMIT_MASK_3 0x8fff ++#define RATE_LIMIT_MASK_4 0xfff8 ++#define BANDWIDTH_CTL_MASK 0xff2b ++#define DISCARD_MASK 0x0fff ++ ++#define BANDWIDTH_ENABLE_1 1 << BANDWIDTH_1_BIT//04 ++#define BANDWIDTH_ENABLE_2 1 << BANDWIDTH_2_BIT//10 ++#define BANDWIDTH_ENABLE_3 1 << BANDWIDTH_3_BIT//40 ++#define BANDWIDTH_ENABLE_4 1 << BANDWIDTH_4_BIT//80 ++#define BANDWIDTH_CTL_MASK_1 0xffff^BANDWIDTH_ENABLE_1//0xfffb ++#define BANDWIDTH_CTL_MASK_2 0xffff^BANDWIDTH_ENABLE_2//0xffef ++#define BANDWIDTH_CTL_MASK_3 0xffff^BANDWIDTH_ENABLE_3//0xffbf ++#define BANDWIDTH_CTL_MASK_4 0xffff^BANDWIDTH_ENABLE_4//0xff7f ++ ++/*static int disable_content[] = {0x0}; ++//static int enable_content[] = {0xd4, 0x0cff};//bit 7,6,4,2; Q1=11(50%),Q0=00(0%)*/ ++//static int sw_content[] = {0x0,0x0c00};//bit 7,6,4,2; Q1=11(50%),Q0=00(0%) ++static int sw_content[] = {0x0,0xc000};//bit 7,6,4,2; Q1=11(50%),Q0=00(0%) ++static int port_priority_content[] = {0x080,0x380};//Q0,Q3 ++//static int port_priority_content[] = {0x300,0x0};//Q1,Q0 ++static int port_flow_ctl_content[] = {0x0,0x1}; ++static int port_rate_limit_content_1[] = {0x0,0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70}; ++static int port_rate_limit_content_2[] = {0x0,0x000,0x100,0x200,0x300,0x400,0x500,0x600,0x700}; ++static int port_rate_limit_content_3[] = {0x0,0x0000,0x1000,0x2000,0x3000,0x4000,0x5000,0x6000,0x7000}; ++static int port_rate_limit_content_4[] = {0x0,0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7}; ++static int port_rate_limit_enable_1[] = {0x0, BANDWIDTH_ENABLE_1}; ++static int port_rate_limit_enable_2[] = {0x0, BANDWIDTH_ENABLE_2}; ++static int port_rate_limit_enable_3[] = {0x0, BANDWIDTH_ENABLE_3}; ++static int port_rate_limit_enable_4[] = {0x0, BANDWIDTH_ENABLE_4}; ++ ++static struct port_qos_t port_mii_disable[] = { ++ { BANDWIDTH_CTL_ENABLE, BANDWIDTH_CTL_MASK, sw_content}, ++ //{ DISCARD_MODE, DISCARD_MASK, sw_content}, ++ { PORT_CONFIG_1, PRIORITY_MASK, sw_content},//port_priority_1 ++ { PORT_CONFIG_2, PRIORITY_MASK, sw_content},//port_priority_2 ++ { PORT_CONFIG_3, PRIORITY_MASK, sw_content},//port_priority_3 ++ { PORT_CONFIG_4, PRIORITY_MASK, sw_content},//port_priority_4 ++ { PORT_CONFIG_1, FLOW_CTL_MASK, &port_flow_ctl_content[1]},//port_flow_control_1 ++ { PORT_CONFIG_2, FLOW_CTL_MASK, &port_flow_ctl_content[1]},//port_flow_control_2 ++ { PORT_CONFIG_3, FLOW_CTL_MASK, &port_flow_ctl_content[1]},//port_flow_control_3 ++ { PORT_CONFIG_4, FLOW_CTL_MASK, &port_flow_ctl_content[1]},//port_flow_control_4 ++ { -1} ++}; ++ ++static struct port_qos_t port_mii_enable[] = { ++ //{ BANDWIDTH_CTL_ENABLE, BANDWIDTH_CTL_MASK, enable_content}, ++ //{ DISCARD_MODE, DISCARD_MASK, sw_content}, ++ { -1} ++}; ++ ++struct port_qos_t *port_mii_sw_array[] = {port_mii_disable, port_mii_enable}; ++ ++/*static struct port_qos_t port_mii_addr[] = { ++ { PORT_CONFIG_1, PRIORITY_MASK, port_priority_content},//port_priority_1 ++ { PORT_CONFIG_1, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_1 ++ //{ "port_frame_type_1", 0x3}, ++ { BANDWIDTH_CTL_123, RATE_LIMIT_MASK_14, port_rate_limit_content_14},//port_rate_limit_1 ++ { PORT_CONFIG_2, PRIORITY_MASK, port_priority_content},//port_priority_2 ++ { PORT_CONFIG_2, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_2 ++ //{ "port_frame_type_2", 0x5}, ++ { BANDWIDTH_CTL_123, RATE_LIMIT_MASK_2, port_rate_limit_content_2},//port_rate_limit_2 ++ { PORT_CONFIG_3, PRIORITY_MASK, port_priority_content},//port_priority_3 ++ { PORT_CONFIG_3, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_3 ++ //{ "port_frame_type_3", 0x7}, ++ { BANDWIDTH_CTL_123, RATE_LIMIT_MASK_3, port_rate_limit_content_3},//port_rate_limit_3 ++ //{ "port_priority_4", 0x8, 0x380}, ++ { PORT_CONFIG_4, PRIORITY_MASK, port_priority_content},//port_priority_4 ++ { PORT_CONFIG_4, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_4 ++ //{ "port_frame_type_4", 0x8}, ++ { BANDWIDTH_CTL_4, RATE_LIMIT_MASK_14, port_rate_limit_content_14},//port_rate_limit_4 ++ { -1} ++};*/ ++ ++static struct port_qos_t priority_1[] = { ++ { PORT_CONFIG_1, PRIORITY_MASK, port_priority_content},//port_priority_1 ++ { -1} ++}; ++static struct port_qos_t flow_control_1[] = { ++ { PORT_CONFIG_1, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_1 ++ { -1} ++}; ++static struct port_qos_t rate_limit_1[] = { ++ { BANDWIDTH_CTL_123, RATE_LIMIT_MASK_1, port_rate_limit_content_1},//port_rate_limit_1 ++ { BANDWIDTH_CTL_ENABLE, BANDWIDTH_CTL_MASK_1, port_rate_limit_enable_1},//port_rate_limit_4 ++ { -1} ++}; ++static struct port_qos_t priority_2[] = { ++ { PORT_CONFIG_2, PRIORITY_MASK, port_priority_content},//port_priority_2 ++ { -1} ++}; ++static struct port_qos_t flow_control_2[] = { ++ { PORT_CONFIG_2, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_2 ++ { -1} ++}; ++static struct port_qos_t rate_limit_2[] = { ++ { BANDWIDTH_CTL_123, RATE_LIMIT_MASK_2, port_rate_limit_content_2},//port_rate_limit_2 ++ { BANDWIDTH_CTL_ENABLE, BANDWIDTH_CTL_MASK_2, port_rate_limit_enable_2},//port_rate_limit_4 ++ { -1} ++}; ++static struct port_qos_t priority_3[] = { ++ { PORT_CONFIG_3, PRIORITY_MASK, port_priority_content},//port_priority_3 ++ { -1} ++}; ++static struct port_qos_t flow_control_3[] = { ++ { PORT_CONFIG_3, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_3 ++ { -1} ++}; ++static struct port_qos_t rate_limit_3[] = { ++ { BANDWIDTH_CTL_123, RATE_LIMIT_MASK_3, port_rate_limit_content_3},//port_rate_limit_3 ++ { BANDWIDTH_CTL_ENABLE, BANDWIDTH_CTL_MASK_3, port_rate_limit_enable_3},//port_rate_limit_4 ++ { -1} ++}; ++static struct port_qos_t priority_4[] = { ++ { PORT_CONFIG_4, PRIORITY_MASK, port_priority_content},//port_priority_4 ++ { -1} ++}; ++static struct port_qos_t flow_control_4[] = { ++ { PORT_CONFIG_4, FLOW_CTL_MASK, port_flow_ctl_content},//port_flow_control_4 ++ { -1} ++}; ++static struct port_qos_t rate_limit_4[] = { ++ { BANDWIDTH_CTL_4, RATE_LIMIT_MASK_4, port_rate_limit_content_4},//port_rate_limit_4 ++ { BANDWIDTH_CTL_ENABLE, BANDWIDTH_CTL_MASK_4, port_rate_limit_enable_4},//port_rate_limit_4 ++ { -1} ++}; ++ ++static struct port_qos_t *port_mii_addr[] = { ++ priority_1, ++ flow_control_1, ++ rate_limit_1, ++ priority_2, ++ flow_control_2, ++ rate_limit_2, ++ priority_3, ++ flow_control_3, ++ rate_limit_3, ++ priority_4, ++ flow_control_4, ++ rate_limit_4, ++ NULL ++}; ++ ++void WriteDataToRegister_(unsigned short reg_idx, unsigned short content_idx) ++{ ++ short RegNumber; ++ unsigned short data, hidata=0x0, lodata=0x0; ++ int i; ++ struct port_qos_t *port_qos = port_mii_addr[reg_idx]; ++ ++ //printk("\nWriteDataToRegister_:reg_idx=%d content_idx=%d\n", reg_idx, content_idx); ++ if (!port_qos) ++ port_qos = port_mii_sw_array[content_idx]; ++ ++ for (i=0; port_qos[i].addr != -1; i++) ++ { ++ RegNumber = port_qos[i].addr; ++ ReadDataFromRegister(RegNumber, &hidata, &lodata, 0); ++ ++ if (!(RegNumber % 2)) /* even port number use lower word */ ++ hidata = lodata; ++ ++ data = (hidata & port_qos[i].content_mask) | (((i > 0) && (content_idx > 1))? port_qos[i].content_set[1] : port_qos[i].content_set[content_idx]); ++ ++ write_eeprom(RegNumber, &data, 1); ++ ReadDataFromRegister(RegNumber, &hidata, &lodata, 0); ++ } ++ ReadDataFromRegister(0xf, &hidata, &lodata, 0); ++ ++ /*RegNumber = port_mii_addr[reg_idx].addr; ++ if (RegNumber == -1)//Disable or Enable ++ { ++ struct port_qos_t *port_mii_sw = port_mii_sw_array[content_idx]; ++ ++ printk("\nWriteDataToRegister_:reg_idx=%d content_idx=%d\n", reg_idx, content_idx); ++ for (i=0; port_mii_sw[i].addr != -1; i++) ++ { ++ RegNumber = port_mii_sw[i].addr; ++ ++ ReadDataFromRegister(RegNumber, &hidata, &lodata, 0); ++ ++ if (!(RegNumber % 2)) ++ hidata = lodata; ++ ++ data = (hidata & port_mii_sw[i].content_mask) | port_mii_sw[i].content_set[i]; ++ ++ write_eeprom(RegNumber, &data, 1); ++ ++ ReadDataFromRegister(RegNumber, &hidata, &lodata, 0); ++ printk("\n============== %s===============\n", (content_idx==0)?"disable":"enable"); ++ } ++ } ++ else ++ { ++ ReadDataFromRegister(RegNumber, &hidata, &lodata, 0); ++ ++ if (!(RegNumber % 2)) ++ hidata = lodata; ++ ++ data = (hidata & port_mii_addr[reg_idx].content_mask) | port_mii_addr[reg_idx].content_set[content_idx]; ++ ++ write_eeprom(RegNumber, &data, 1); ++ ReadDataFromRegister(RegNumber, &hidata, &lodata, 0); ++ }*/ ++} ++#endif ++ ++static int dev_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) ++{ ++ struct mii_ioctl_data *data = (struct mii_ioctl_data *)req->ifr_data; ++#ifdef PERFORMANCE_SUPPORT ++ int item, port; ++ ++ unsigned long status_item; ++#endif ++ ++ switch (cmd) ++ { ++ case SIOCGMIIPHY: /* Get address of MII PHY in use. */ ++ case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ ++ ++ /* Fall through to the SIOCGMIIREG, taken from eepro100 and rtl ++ * drivers */ ++#ifdef PERFORMANCE_SUPPORT ++ case SIOCGMIIREG: /* Read MII PHY register. */ ++ for (item=0; item<6; item++) ++ for (port=1; port<5; port++){ ++ qos[(item * 4) + (port-1)] = get_statistic_from_serial(port, item); ++ } ++ ++ status_item = get_statistic_from_serial(0, 6); ++ ++ qos[24] = (0x1 & (status_item >> 8)); ++ qos[25] = (0x1 & (status_item >> 16)); ++ qos[26] = (0x1 & (status_item >> 24)); ++ qos[27] = (0x1 & (status_item >> 28)); ++ ++ return 0; ++#endif ++ ++ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ ++#ifdef HW_QOS_SUPPORT ++ case SIOCSMIIREG: /* Write MII PHY register. */ ++ { ++ printk("\n x phy_id=%x\n", data->phy_id); ++ printk("\n x reg_num=%x\n", data->reg_num); ++ printk("\n x val_in=%x\n", data->val_in); ++ printk("\n x val_out=%x\n", data->val_out); ++ ++ WriteDataToRegister_(data->phy_id, data->val_in); ++ return 0; ++ } ++#endif ++ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int __devinit qos_eth_probe(struct net_device *dev) ++{ ++ ++ SET_MODULE_OWNER(dev); ++ ++ ether_setup(dev); ++ ++ strcpy(dev->name, DEVICE_NAME "0"); ++ ++ dev->do_ioctl = dev_do_ioctl; ++ ++ return 0; ++} ++ ++#ifdef HW_QOS_SUPPORT ++static char *port_option_name[] = { ++ "port_priority_1", ++ "port_flow_control_1", ++ //{ "port_frame_type_1", ++ "port_rate_limit_1", ++ "port_priority_2", ++ "port_flow_control_2", ++ //{ "port_frame_type_2", ++ "port_rate_limit_2", ++ "port_priority_3", ++ "port_flow_control_3", ++ //{ "port_frame_type_3", ++ "port_rate_limit_3", ++ "port_priority_4", ++ //{ "port_priority_4", PORT_CONFIG_4, PRIORITY_MASK, port_priority_content}, ++ "port_flow_control_4", ++ //{ "port_frame_type_4", ++ "port_rate_limit_4", ++ "QoS", ++ NULL ++}; ++ ++extern char *nvram_get(const char *name); ++extern uint bcm_atoi(char *s); ++ ++static int set_port_option(struct net_device *dev, unsigned short port_addr, char *option_content) ++{ ++ struct ifreq ifr; ++ struct mii_ioctl_data stats; ++ ++ stats.phy_id=port_addr; ++ stats.val_in=bcm_atoi(option_content); ++ ++ ifr.ifr_data = (void *)&stats; ++ ++ return dev_do_ioctl(dev, &ifr, SIOCSMIIREG); ++} ++ ++ ++void ++restore_default_from_NV(struct net_device *dev) ++{ ++ unsigned short i; ++ char *value = NULL; ++ ++ for (i = 0; port_option_name[i]; i++) ++ { ++ if((value = nvram_get(port_option_name[i]))) ++ set_port_option(dev, i, value); ++ } ++ return; ++} ++#endif ++ ++static struct net_device qos_devices; ++ ++/* Module initialization and cleanup */ ++int init_module(void) ++{ ++ int res; ++ struct net_device *dev; ++ ++ printk("Initializing " MODULE_NAME " driver " MODULE_VERSION "\n"); ++ ++ dev = &qos_devices; ++ ++ dev->init = qos_eth_probe; ++ ++ if ((res = register_netdev(dev))) ++ printk("Failed to register netdev. res = %d\n", res); ++ ++#ifdef PERFORMANCE_SUPPORT ++ qos_sysctl_header = register_sysctl_table(mytable, 0); ++#endif ++#ifdef HW_QOS_SUPPORT ++ restore_default_from_NV(dev); ++ write_eeprom(TOS_PRIO_MAP, &sw_content[0], 1);/* disable TOS priority map*/ ++#endif ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++ struct net_device *dev = &qos_devices; ++ if (dev->priv != NULL) ++ { ++ unregister_netdev(dev); ++ kfree(dev->priv); ++ dev->priv = NULL; ++ } ++ ++#ifdef PERFORMANCE_SUPPORT ++ unregister_sysctl_table(qos_sysctl_header); ++#endif ++} ++ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/net/wl/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,68 @@ ++# ++# Makefile for the Broadcom wl driver ++# ++# Copyright 2004, Broadcom Corporation ++# All Rights Reserved. ++# ++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++# ++# $Id: Makefile,v 1.1.1.7 2004/04/12 04:32:06 honor Exp $ ++# ++ ++O_TARGET := wl.o ++ ++WL_OBJS := wl_linux.o wlc.o d11ucode.o wlc_phy.o wlc_rate.o wlc_led.o wlc_security.o rc4.o tkhash.o bcmwpa.o ++ ++INSUP_OBJS := aes.o aeskeywrap.o hmac.o md5.o passhash.o prf.o rijndael-alg-fst.o sha1.o ++ ++# Alternate ioctl interfaces ++ifeq ($(CONFIG_NET_WIRELESS),y) ++WL_OBJS += wlc_cmn_ioctl.o ++endif ++ifeq ($(CONFIG_WL_OID),y) ++WL_OBJS += wl_oid.o ++endif ++ ++ifeq ($(CONFIG_WL_STA),y) ++WL_OBJS += $(INSUP_OBJS) ++endif ++ ++# Prefix driver variants ++WL_APOBJS := $(foreach obj,$(WL_OBJS),ap_$(obj)) ++WL_STAOBJS := $(foreach obj,$(WL_OBJS) wlc_sup.o,sta_$(obj)) ++WL_APSTAOBJS := $(foreach obj,$(WL_OBJS) wlc_sup.o,apsta_$(obj)) ++ifneq ($(CONFIG_WL_STA),y) ++WL_APSTAOBJS += $(foreach obj,$(INSUP_OBJS), apsta_$(obj)) ++endif ++ ++# Either or both ++ifeq ($(CONFIG_WL_AP),y) ++AP := AP ++endif ++ifeq ($(CONFIG_WL_STA),y) ++STA := STA ++endif ++ ++# Build all variants as modules but link only one of them ++export-objs := ++obj-y := $(WL_$(AP)$(STA)OBJS) ++obj-m := $(O_TARGET) ++variant-objs := $(WL_APOBJS) $(WL_STAOBJS) $(WL_APSTAOBJS) ++ ++EXTRA_CFLAGS += -DDMA ++ ++# Search for sources under src/wl/sys or objects under src/wl/linux ++ifneq ($(wildcard $(SRCBASE)/wl/sys),) ++EXTRA_CFLAGS += -I$(SRCBASE)/wl/sys ++vpath %.c $(SRCBASE)/wl/sys $(SRCBASE)/shared $(SRCBASE)/crypto ++else ++obj-y := $(foreach obj,$(obj-y),$(SRCBASE)/wl/linux/$(obj)) ++variant-objs := $(foreach obj,$(variant-objs),$(SRCBASE)/wl/linux/$(obj)) ++endif ++ ++include $(TOPDIR)/Rules.make ++ ++ +--- linux-2.4.20/drivers/pcmcia/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:01.000000000 -0500 ++++ linux-2.4.20/drivers/pcmcia/Makefile 2005-01-07 05:39:02.000000000 -0500 +@@ -64,6 +64,10 @@ + au1000_ss-objs-$(CONFIG_PCMCIA_PB1X00) += au1000_pb1x00.o + au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00) += au1000_db1x00.o + ++obj-$(CONFIG_PCMCIA_BCM4710) += bcm4710_ss.o ++bcm4710_ss-objs := bcm4710_generic.o ++bcm4710_ss-objs += bcm4710_pcmcia.o ++ + obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o + obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o + +@@ -98,5 +102,8 @@ + au1x00_ss.o: $(au1000_ss-objs-y) + $(LD) -r -o $@ $(au1000_ss-objs-y) + ++bcm4710_ss.o: $(bcm4710_ss-objs) ++ $(LD) -r -o $@ $(bcm4710_ss-objs) ++ + yenta_socket.o: $(yenta_socket-objs) + $(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs) +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/pcmcia/bcm4710_generic.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,912 @@ ++/* ++ * ++ * bcm47xx pcmcia driver ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * Based on sa1100_generic.c from www.handhelds.org, ++ * and au1000_generic.c from oss.sgi.com. ++ * ++ * $Id: bcm4710_generic.c,v 1.1.1.7 2004/04/12 04:32:07 honor Exp $ ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/delay.h> ++#include <linux/ioport.h> ++#include <linux/kernel.h> ++#include <linux/tqueue.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/proc_fs.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/vmalloc.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bulkmem.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/bus_ops.h> ++#include "cs_internal.h" ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++ ++#include <typedefs.h> ++#include <bcm4710.h> ++#include <sbextif.h> ++ ++#include "bcm4710pcmcia.h" ++ ++#ifdef PCMCIA_DEBUG ++static int pc_debug = PCMCIA_DEBUG; ++#endif ++ ++MODULE_DESCRIPTION("Linux PCMCIA Card Services: bcm47xx Socket Controller"); ++ ++/* This structure maintains housekeeping state for each socket, such ++ * as the last known values of the card detect pins, or the Card Services ++ * callback value associated with the socket: ++ */ ++static struct bcm47xx_pcmcia_socket *pcmcia_socket; ++static int socket_count; ++ ++ ++/* Returned by the low-level PCMCIA interface: */ ++static struct pcmcia_low_level *pcmcia_low_level; ++ ++/* Event poll timer structure */ ++static struct timer_list poll_timer; ++ ++ ++/* Prototypes for routines which are used internally: */ ++ ++static int bcm47xx_pcmcia_driver_init(void); ++static void bcm47xx_pcmcia_driver_shutdown(void); ++static void bcm47xx_pcmcia_task_handler(void *data); ++static void bcm47xx_pcmcia_poll_event(unsigned long data); ++static void bcm47xx_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs); ++static struct tq_struct bcm47xx_pcmcia_task; ++ ++#ifdef CONFIG_PROC_FS ++static int bcm47xx_pcmcia_proc_status(char *buf, char **start, ++ off_t pos, int count, int *eof, void *data); ++#endif ++ ++ ++/* Prototypes for operations which are exported to the ++ * in-kernel PCMCIA core: ++ */ ++ ++static int bcm47xx_pcmcia_init(unsigned int sock); ++static int bcm47xx_pcmcia_suspend(unsigned int sock); ++static int bcm47xx_pcmcia_register_callback(unsigned int sock, ++ void (*handler)(void *, unsigned int), void *info); ++static int bcm47xx_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap); ++static int bcm47xx_pcmcia_get_status(unsigned int sock, u_int *value); ++static int bcm47xx_pcmcia_get_socket(unsigned int sock, socket_state_t *state); ++static int bcm47xx_pcmcia_set_socket(unsigned int sock, socket_state_t *state); ++static int bcm47xx_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *io); ++static int bcm47xx_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *io); ++static int bcm47xx_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *mem); ++static int bcm47xx_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *mem); ++#ifdef CONFIG_PROC_FS ++static void bcm47xx_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base); ++#endif ++ ++static struct pccard_operations bcm47xx_pcmcia_operations = { ++ bcm47xx_pcmcia_init, ++ bcm47xx_pcmcia_suspend, ++ bcm47xx_pcmcia_register_callback, ++ bcm47xx_pcmcia_inquire_socket, ++ bcm47xx_pcmcia_get_status, ++ bcm47xx_pcmcia_get_socket, ++ bcm47xx_pcmcia_set_socket, ++ bcm47xx_pcmcia_get_io_map, ++ bcm47xx_pcmcia_set_io_map, ++ bcm47xx_pcmcia_get_mem_map, ++ bcm47xx_pcmcia_set_mem_map, ++#ifdef CONFIG_PROC_FS ++ bcm47xx_pcmcia_proc_setup ++#endif ++}; ++ ++ ++/* ++ * bcm47xx_pcmcia_driver_init() ++ * ++ * This routine performs a basic sanity check to ensure that this ++ * kernel has been built with the appropriate board-specific low-level ++ * PCMCIA support, performs low-level PCMCIA initialization, registers ++ * this socket driver with Card Services, and then spawns the daemon ++ * thread which is the real workhorse of the socket driver. ++ * ++ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information ++ * on the low-level kernel interface. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int __init bcm47xx_pcmcia_driver_init(void) ++{ ++ servinfo_t info; ++ struct pcmcia_init pcmcia_init; ++ struct pcmcia_state state; ++ unsigned int i; ++ unsigned long tmp; ++ ++ ++ printk("\nBCM47XX PCMCIA (CS release %s)\n", CS_RELEASE); ++ ++ CardServices(GetCardServicesInfo, &info); ++ ++ if (info.Revision != CS_RELEASE_CODE) { ++ printk(KERN_ERR "Card Services release codes do not match\n"); ++ return -1; ++ } ++ ++#ifdef CONFIG_BCM4710 ++ pcmcia_low_level=&bcm4710_pcmcia_ops; ++#else ++#error Unsupported Broadcom BCM47XX board. ++#endif ++ ++ pcmcia_init.handler=bcm47xx_pcmcia_interrupt; ++ ++ if ((socket_count = pcmcia_low_level->init(&pcmcia_init)) < 0) { ++ printk(KERN_ERR "Unable to initialize PCMCIA service.\n"); ++ return -EIO; ++ } else { ++ printk("\t%d PCMCIA sockets initialized.\n", socket_count); ++ } ++ ++ pcmcia_socket = ++ kmalloc(sizeof(struct bcm47xx_pcmcia_socket) * socket_count, ++ GFP_KERNEL); ++ memset(pcmcia_socket, 0, ++ sizeof(struct bcm47xx_pcmcia_socket) * socket_count); ++ if (!pcmcia_socket) { ++ printk(KERN_ERR "Card Services can't get memory \n"); ++ return -1; ++ } ++ ++ for (i = 0; i < socket_count; i++) { ++ if (pcmcia_low_level->socket_state(i, &state) < 0) { ++ printk(KERN_ERR "Unable to get PCMCIA status\n"); ++ return -EIO; ++ } ++ pcmcia_socket[i].k_state = state; ++ pcmcia_socket[i].cs_state.csc_mask = SS_DETECT; ++ ++ if (i == 0) { ++ pcmcia_socket[i].virt_io = ++ (unsigned long)ioremap_nocache(EXTIF_PCMCIA_IOBASE(BCM4710_EXTIF), 0x1000); ++ /* Substract ioport base which gets added by in/out */ ++ pcmcia_socket[i].virt_io -= mips_io_port_base; ++ pcmcia_socket[i].phys_attr = ++ (unsigned long)EXTIF_PCMCIA_CFGBASE(BCM4710_EXTIF); ++ pcmcia_socket[i].phys_mem = ++ (unsigned long)EXTIF_PCMCIA_MEMBASE(BCM4710_EXTIF); ++ } else { ++ printk(KERN_ERR "bcm4710: socket 1 not supported\n"); ++ return 1; ++ } ++ } ++ ++ /* Only advertise as many sockets as we can detect: */ ++ if (register_ss_entry(socket_count, &bcm47xx_pcmcia_operations) < 0) { ++ printk(KERN_ERR "Unable to register socket service routine\n"); ++ return -ENXIO; ++ } ++ ++ /* Start the event poll timer. ++ * It will reschedule by itself afterwards. ++ */ ++ bcm47xx_pcmcia_poll_event(0); ++ ++ DEBUG(1, "bcm4710: initialization complete\n"); ++ return 0; ++ ++} ++ ++module_init(bcm47xx_pcmcia_driver_init); ++ ++ ++/* ++ * bcm47xx_pcmcia_driver_shutdown() ++ * ++ * Invokes the low-level kernel service to free IRQs associated with this ++ * socket controller and reset GPIO edge detection. ++ */ ++static void __exit bcm47xx_pcmcia_driver_shutdown(void) ++{ ++ int i; ++ ++ del_timer_sync(&poll_timer); ++ unregister_ss_entry(&bcm47xx_pcmcia_operations); ++ pcmcia_low_level->shutdown(); ++ flush_scheduled_tasks(); ++ for (i = 0; i < socket_count; i++) { ++ if (pcmcia_socket[i].virt_io) ++ iounmap((void *)pcmcia_socket[i].virt_io); ++ if (pcmcia_socket[i].phys_attr) ++ iounmap((void *)pcmcia_socket[i].phys_attr); ++ if (pcmcia_socket[i].phys_mem) ++ iounmap((void *)pcmcia_socket[i].phys_mem); ++ } ++ DEBUG(1, "bcm4710: shutdown complete\n"); ++} ++ ++module_exit(bcm47xx_pcmcia_driver_shutdown); ++ ++/* ++ * bcm47xx_pcmcia_init() ++ * We perform all of the interesting initialization tasks in ++ * bcm47xx_pcmcia_driver_init(). ++ * ++ * Returns: 0 ++ */ ++static int bcm47xx_pcmcia_init(unsigned int sock) ++{ ++ DEBUG(1, "%s(): initializing socket %u\n", __FUNCTION__, sock); ++ ++ return 0; ++} ++ ++/* ++ * bcm47xx_pcmcia_suspend() ++ * ++ * We don't currently perform any actions on a suspend. ++ * ++ * Returns: 0 ++ */ ++static int bcm47xx_pcmcia_suspend(unsigned int sock) ++{ ++ DEBUG(1, "%s(): suspending socket %u\n", __FUNCTION__, sock); ++ ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_events() ++ * ++ * Helper routine to generate a Card Services event mask based on ++ * state information obtained from the kernel low-level PCMCIA layer ++ * in a recent (and previous) sampling. Updates `prev_state'. ++ * ++ * Returns: an event mask for the given socket state. ++ */ ++static inline unsigned ++bcm47xx_pcmcia_events(struct pcmcia_state *state, ++ struct pcmcia_state *prev_state, ++ unsigned int mask, unsigned int flags) ++{ ++ unsigned int events=0; ++ ++ if (state->bvd1 != prev_state->bvd1) { ++ ++ DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); ++ ++ events |= mask & (flags & SS_IOCARD) ? SS_STSCHG : SS_BATDEAD; ++ } ++ ++ if (state->bvd2 != prev_state->bvd2) { ++ ++ DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); ++ ++ events |= mask & (flags & SS_IOCARD) ? 0 : SS_BATWARN; ++ } ++ ++ if (state->detect != prev_state->detect) { ++ ++ DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect); ++ ++ events |= mask & SS_DETECT; ++ } ++ ++ ++ if (state->ready != prev_state->ready) { ++ ++ DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready); ++ ++ events |= mask & ((flags & SS_IOCARD) ? 0 : SS_READY); ++ } ++ ++ if (events != 0) { ++ DEBUG(2, "events: %s%s%s%s%s\n", ++ (events & SS_DETECT) ? "DETECT " : "", ++ (events & SS_READY) ? "READY " : "", ++ (events & SS_BATDEAD) ? "BATDEAD " : "", ++ (events & SS_BATWARN) ? "BATWARN " : "", ++ (events & SS_STSCHG) ? "STSCHG " : ""); ++ } ++ ++ *prev_state=*state; ++ return events; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_task_handler() ++ * ++ * Processes serviceable socket events using the "eventd" thread context. ++ * ++ * Event processing (specifically, the invocation of the Card Services event ++ * callback) occurs in this thread rather than in the actual interrupt ++ * handler due to the use of scheduling operations in the PCMCIA core. ++ */ ++static void bcm47xx_pcmcia_task_handler(void *data) ++{ ++ struct pcmcia_state state; ++ int i, events, irq_status; ++ ++ DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); ++ ++ for (i = 0; i < socket_count; i++) { ++ if ((irq_status = pcmcia_low_level->socket_state(i, &state)) < 0) ++ printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n"); ++ ++ events = bcm47xx_pcmcia_events(&state, ++ &pcmcia_socket[i].k_state, ++ pcmcia_socket[i].cs_state.csc_mask, ++ pcmcia_socket[i].cs_state.flags); ++ ++ if (pcmcia_socket[i].handler != NULL) { ++ pcmcia_socket[i].handler(pcmcia_socket[i].handler_info, ++ events); ++ } ++ } ++} ++ ++static struct tq_struct bcm47xx_pcmcia_task = { ++ routine: bcm47xx_pcmcia_task_handler ++}; ++ ++ ++/* ++ * bcm47xx_pcmcia_poll_event() ++ * ++ * Let's poll for events in addition to IRQs since IRQ only is unreliable... ++ */ ++static void bcm47xx_pcmcia_poll_event(unsigned long dummy) ++{ ++ DEBUG(4, "%s(): polling for events\n", __FUNCTION__); ++ ++ poll_timer.function = bcm47xx_pcmcia_poll_event; ++ poll_timer.expires = jiffies + BCM47XX_PCMCIA_POLL_PERIOD; ++ add_timer(&poll_timer); ++ schedule_task(&bcm47xx_pcmcia_task); ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_interrupt() ++ * ++ * Service routine for socket driver interrupts (requested by the ++ * low-level PCMCIA init() operation via bcm47xx_pcmcia_thread()). ++ * ++ * The actual interrupt-servicing work is performed by ++ * bcm47xx_pcmcia_task(), largely because the Card Services event- ++ * handling code performs scheduling operations which cannot be ++ * executed from within an interrupt context. ++ */ ++static void ++bcm47xx_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) ++{ ++ DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); ++ schedule_task(&bcm47xx_pcmcia_task); ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_register_callback() ++ * ++ * Implements the register_callback() operation for the in-kernel ++ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If ++ * the function pointer `handler' is not NULL, remember the callback ++ * location in the state for `sock', and increment the usage counter ++ * for the driver module. (The callback is invoked from the interrupt ++ * service routine, bcm47xx_pcmcia_interrupt(), to notify Card Services ++ * of interesting events.) Otherwise, clear the callback pointer in the ++ * socket state and decrement the module usage count. ++ * ++ * Returns: 0 ++ */ ++static int ++bcm47xx_pcmcia_register_callback(unsigned int sock, ++ void (*handler)(void *, unsigned int), void *info) ++{ ++ if (handler == NULL) { ++ pcmcia_socket[sock].handler = NULL; ++ MOD_DEC_USE_COUNT; ++ } else { ++ MOD_INC_USE_COUNT; ++ pcmcia_socket[sock].handler = handler; ++ pcmcia_socket[sock].handler_info = info; ++ } ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_inquire_socket() ++ * ++ * Implements the inquire_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_InquireSocket in Card Services). Of note is ++ * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of ++ * `cap' to "trick" Card Services into tolerating large "I/O memory" ++ * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory ++ * resource database check. (Mapped memory is set up within the socket ++ * driver itself.) ++ * ++ * In conjunction with the STATIC_MAP capability is a new field, ++ * `io_offset', recommended by David Hinds. Rather than go through ++ * the SetIOMap interface (which is not quite suited for communicating ++ * window locations up from the socket driver), we just pass up ++ * an offset which is applied to client-requested base I/O addresses ++ * in alloc_io_space(). ++ * ++ * Returns: 0 on success, -1 if no pin has been configured for `sock' ++ */ ++static int ++bcm47xx_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) ++{ ++ struct pcmcia_irq_info irq_info; ++ ++ if (sock >= socket_count) { ++ printk(KERN_ERR "bcm47xx: socket %u not configured\n", sock); ++ return -1; ++ } ++ ++ /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the ++ * force_low argument to validate_mem() in rsrc_mgr.c -- since in ++ * general, the mapped * addresses of the PCMCIA memory regions ++ * will not be within 0xffff, setting force_low would be ++ * undesirable. ++ * ++ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory ++ * resource database; we instead pass up physical address ranges ++ * and allow other parts of Card Services to deal with remapping. ++ * ++ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but ++ * not 32-bit CardBus devices. ++ */ ++ cap->features = (SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); ++ ++ irq_info.sock = sock; ++ irq_info.irq = -1; ++ ++ if (pcmcia_low_level->get_irq_info(&irq_info) < 0) { ++ printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock); ++ return -1; ++ } ++ ++ cap->irq_mask = 0; ++ cap->map_size = PAGE_SIZE; ++ cap->pci_irq = irq_info.irq; ++ cap->io_offset = pcmcia_socket[sock].virt_io; ++ ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_get_status() ++ * ++ * Implements the get_status() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetStatus in Card Services). Essentially just ++ * fills in bits in `status' according to internal driver state or ++ * the value of the voltage detect chipselect register. ++ * ++ * As a debugging note, during card startup, the PCMCIA core issues ++ * three set_socket() commands in a row the first with RESET deasserted, ++ * the second with RESET asserted, and the last with RESET deasserted ++ * again. Following the third set_socket(), a get_status() command will ++ * be issued. The kernel is looking for the SS_READY flag (see ++ * setup_socket(), reset_socket(), and unreset_socket() in cs.c). ++ * ++ * Returns: 0 ++ */ ++static int ++bcm47xx_pcmcia_get_status(unsigned int sock, unsigned int *status) ++{ ++ struct pcmcia_state state; ++ ++ ++ if ((pcmcia_low_level->socket_state(sock, &state)) < 0) { ++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); ++ return -1; ++ } ++ ++ pcmcia_socket[sock].k_state = state; ++ ++ *status = state.detect ? SS_DETECT : 0; ++ ++ *status |= state.ready ? SS_READY : 0; ++ ++ /* The power status of individual sockets is not available ++ * explicitly from the hardware, so we just remember the state ++ * and regurgitate it upon request: ++ */ ++ *status |= pcmcia_socket[sock].cs_state.Vcc ? SS_POWERON : 0; ++ ++ if (pcmcia_socket[sock].cs_state.flags & SS_IOCARD) ++ *status |= state.bvd1 ? SS_STSCHG : 0; ++ else { ++ if (state.bvd1 == 0) ++ *status |= SS_BATDEAD; ++ else if (state.bvd2 == 0) ++ *status |= SS_BATWARN; ++ } ++ ++ *status |= state.vs_3v ? SS_3VCARD : 0; ++ ++ *status |= state.vs_Xv ? SS_XVCARD : 0; ++ ++ DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n", ++ (*status&SS_DETECT)?"DETECT ":"", ++ (*status&SS_READY)?"READY ":"", ++ (*status&SS_BATDEAD)?"BATDEAD ":"", ++ (*status&SS_BATWARN)?"BATWARN ":"", ++ (*status&SS_POWERON)?"POWERON ":"", ++ (*status&SS_STSCHG)?"STSCHG ":"", ++ (*status&SS_3VCARD)?"3VCARD ":"", ++ (*status&SS_XVCARD)?"XVCARD ":""); ++ ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_get_socket() ++ * ++ * Implements the get_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetSocket in Card Services). Not a very ++ * exciting routine. ++ * ++ * Returns: 0 ++ */ ++static int ++bcm47xx_pcmcia_get_socket(unsigned int sock, socket_state_t *state) ++{ ++ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ /* This information was given to us in an earlier call to set_socket(), ++ * so we're just regurgitating it here: ++ */ ++ *state = pcmcia_socket[sock].cs_state; ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_set_socket() ++ * ++ * Implements the set_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetSocket in Card Services). We more or ++ * less punt all of this work and let the kernel handle the details ++ * of power configuration, reset, &c. We also record the value of ++ * `state' in order to regurgitate it to the PCMCIA core later. ++ * ++ * Returns: 0 ++ */ ++static int ++bcm47xx_pcmcia_set_socket(unsigned int sock, socket_state_t *state) ++{ ++ struct pcmcia_configure configure; ++ ++ DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" ++ "\tVcc %d Vpp %d irq %d\n", ++ (state->csc_mask == 0) ? "<NONE>" : "", ++ (state->csc_mask & SS_DETECT) ? "DETECT " : "", ++ (state->csc_mask & SS_READY) ? "READY " : "", ++ (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "", ++ (state->csc_mask & SS_BATWARN) ? "BATWARN " : "", ++ (state->csc_mask & SS_STSCHG) ? "STSCHG " : "", ++ (state->flags == 0) ? "<NONE>" : "", ++ (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "", ++ (state->flags & SS_IOCARD) ? "IOCARD " : "", ++ (state->flags & SS_RESET) ? "RESET " : "", ++ (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "", ++ (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "", ++ state->Vcc, state->Vpp, state->io_irq); ++ ++ configure.sock = sock; ++ configure.vcc = state->Vcc; ++ configure.vpp = state->Vpp; ++ configure.output = (state->flags & SS_OUTPUT_ENA) ? 1 : 0; ++ configure.speaker = (state->flags & SS_SPKR_ENA) ? 1 : 0; ++ configure.reset = (state->flags & SS_RESET) ? 1 : 0; ++ ++ if (pcmcia_low_level->configure_socket(&configure) < 0) { ++ printk(KERN_ERR "Unable to configure socket %u\n", sock); ++ return -1; ++ } ++ ++ pcmcia_socket[sock].cs_state = *state; ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_get_io_map() ++ * ++ * Implements the get_io_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetIOMap in Card Services). Just returns an ++ * I/O map descriptor which was assigned earlier by a set_io_map(). ++ * ++ * Returns: 0 on success, -1 if the map index was out of range ++ */ ++static int ++bcm47xx_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) ++{ ++ DEBUG(2, "bcm47xx_pcmcia_get_io_map: sock %d\n", sock); ++ ++ if (map->map >= MAX_IO_WIN) { ++ printk(KERN_ERR "%s(): map (%d) out of range\n", ++ __FUNCTION__, map->map); ++ return -1; ++ } ++ ++ *map = pcmcia_socket[sock].io_map[map->map]; ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_set_io_map() ++ * ++ * Implements the set_io_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetIOMap in Card Services). We configure ++ * the map speed as requested, but override the address ranges ++ * supplied by Card Services. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++int ++bcm47xx_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) ++{ ++ unsigned int speed; ++ unsigned long start; ++ ++ DEBUG(2, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n" ++ "\tflags: %s%s%s%s%s%s%s%s\n", ++ map->map, map->speed, map->start, map->stop, ++ (map->flags == 0) ? "<NONE>" : "", ++ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", ++ (map->flags & MAP_16BIT) ? "16BIT " : "", ++ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", ++ (map->flags & MAP_0WS) ? "0WS " : "", ++ (map->flags & MAP_WRPROT) ? "WRPROT " : "", ++ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "", ++ (map->flags & MAP_PREFETCH) ? "PREFETCH " : ""); ++ ++ if (map->map >= MAX_IO_WIN) { ++ printk(KERN_ERR "%s(): map (%d) out of range\n", ++ __FUNCTION__, map->map); ++ return -1; ++ } ++ ++ if (map->flags & MAP_ACTIVE) { ++ speed = (map->speed > 0) ? map->speed : BCM47XX_PCMCIA_IO_SPEED; ++ pcmcia_socket[sock].speed_io = speed; ++ } ++ ++ start = map->start; ++ ++ if (map->stop == 1) { ++ map->stop = PAGE_SIZE - 1; ++ } ++ ++ map->start = pcmcia_socket[sock].virt_io; ++ map->stop = map->start + (map->stop - start); ++ pcmcia_socket[sock].io_map[map->map] = *map; ++ DEBUG(2, "set_io_map %d start %x stop %x\n", ++ map->map, map->start, map->stop); ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_get_mem_map() ++ * ++ * Implements the get_mem_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetMemMap in Card Services). Just returns a ++ * memory map descriptor which was assigned earlier by a ++ * set_mem_map() request. ++ * ++ * Returns: 0 on success, -1 if the map index was out of range ++ */ ++static int ++bcm47xx_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) ++{ ++ DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if (map->map >= MAX_WIN) { ++ printk(KERN_ERR "%s(): map (%d) out of range\n", ++ __FUNCTION__, map->map); ++ return -1; ++ } ++ ++ *map = pcmcia_socket[sock].mem_map[map->map]; ++ return 0; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_set_mem_map() ++ * ++ * Implements the set_mem_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetMemMap in Card Services). We configure ++ * the map speed as requested, but override the address ranges ++ * supplied by Card Services. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int ++bcm47xx_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) ++{ ++ unsigned int speed; ++ unsigned long start; ++ u_long flags; ++ ++ if (map->map >= MAX_WIN) { ++ printk(KERN_ERR "%s(): map (%d) out of range\n", ++ __FUNCTION__, map->map); ++ return -1; ++ } ++ ++ DEBUG(2, "\tmap %u speed %u\n\tsys_start %#lx\n" ++ "\tsys_stop %#lx\n\tcard_start %#x\n" ++ "\tflags: %s%s%s%s%s%s%s%s\n", ++ map->map, map->speed, map->sys_start, map->sys_stop, ++ map->card_start, (map->flags == 0) ? "<NONE>" : "", ++ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", ++ (map->flags & MAP_16BIT) ? "16BIT " : "", ++ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", ++ (map->flags & MAP_0WS) ? "0WS " : "", ++ (map->flags & MAP_WRPROT) ? "WRPROT " : "", ++ (map->flags & MAP_ATTRIB) ? "ATTRIB " : "", ++ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : ""); ++ ++ if (map->flags & MAP_ACTIVE) { ++ /* When clients issue RequestMap, the access speed is not always ++ * properly configured: ++ */ ++ speed = (map->speed > 0) ? map->speed : BCM47XX_PCMCIA_MEM_SPEED; ++ ++ /* TBD */ ++ if (map->flags & MAP_ATTRIB) { ++ pcmcia_socket[sock].speed_attr = speed; ++ } else { ++ pcmcia_socket[sock].speed_mem = speed; ++ } ++ } ++ ++ save_flags(flags); ++ cli(); ++ start = map->sys_start; ++ ++ if (map->sys_stop == 0) ++ map->sys_stop = PAGE_SIZE - 1; ++ ++ if (map->flags & MAP_ATTRIB) { ++ map->sys_start = pcmcia_socket[sock].phys_attr + ++ map->card_start; ++ } else { ++ map->sys_start = pcmcia_socket[sock].phys_mem + ++ map->card_start; ++ } ++ ++ map->sys_stop = map->sys_start + (map->sys_stop - start); ++ pcmcia_socket[sock].mem_map[map->map] = *map; ++ restore_flags(flags); ++ DEBUG(2, "set_mem_map %d start %x stop %x card_start %x\n", ++ map->map, map->sys_start, map->sys_stop, ++ map->card_start); ++ return 0; ++} ++ ++ ++#if defined(CONFIG_PROC_FS) ++ ++/* ++ * bcm47xx_pcmcia_proc_setup() ++ * ++ * Implements the proc_setup() operation for the in-kernel PCMCIA ++ * service (formerly SS_ProcSetup in Card Services). ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static void ++bcm47xx_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) ++{ ++ struct proc_dir_entry *entry; ++ ++ if ((entry = create_proc_entry("status", 0, base)) == NULL) { ++ printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); ++ return; ++ } ++ ++ entry->read_proc = bcm47xx_pcmcia_proc_status; ++ entry->data = (void *)sock; ++} ++ ++ ++/* ++ * bcm47xx_pcmcia_proc_status() ++ * ++ * Implements the /proc/bus/pccard/??/status file. ++ * ++ * Returns: the number of characters added to the buffer ++ */ ++static int ++bcm47xx_pcmcia_proc_status(char *buf, char **start, off_t pos, ++ int count, int *eof, void *data) ++{ ++ char *p = buf; ++ unsigned int sock = (unsigned int)data; ++ ++ p += sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", ++ pcmcia_socket[sock].k_state.detect ? "detect " : "", ++ pcmcia_socket[sock].k_state.ready ? "ready " : "", ++ pcmcia_socket[sock].k_state.bvd1 ? "bvd1 " : "", ++ pcmcia_socket[sock].k_state.bvd2 ? "bvd2 " : "", ++ pcmcia_socket[sock].k_state.wrprot ? "wrprot " : "", ++ pcmcia_socket[sock].k_state.vs_3v ? "vs_3v " : "", ++ pcmcia_socket[sock].k_state.vs_Xv ? "vs_Xv " : ""); ++ ++ p += sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", ++ pcmcia_socket[sock].k_state.detect ? "SS_DETECT " : "", ++ pcmcia_socket[sock].k_state.ready ? "SS_READY " : "", ++ pcmcia_socket[sock].cs_state.Vcc ? "SS_POWERON " : "", ++ pcmcia_socket[sock].cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", ++ (pcmcia_socket[sock].cs_state.flags & SS_IOCARD && ++ pcmcia_socket[sock].k_state.bvd1) ? "SS_STSCHG " : "", ++ ((pcmcia_socket[sock].cs_state.flags & SS_IOCARD) == 0 && ++ (pcmcia_socket[sock].k_state.bvd1 == 0)) ? "SS_BATDEAD " : "", ++ ((pcmcia_socket[sock].cs_state.flags & SS_IOCARD) == 0 && ++ (pcmcia_socket[sock].k_state.bvd2 == 0)) ? "SS_BATWARN " : "", ++ pcmcia_socket[sock].k_state.vs_3v ? "SS_3VCARD " : "", ++ pcmcia_socket[sock].k_state.vs_Xv ? "SS_XVCARD " : ""); ++ ++ p += sprintf(p, "mask : %s%s%s%s%s\n", ++ pcmcia_socket[sock].cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "", ++ pcmcia_socket[sock].cs_state.csc_mask & SS_READY ? "SS_READY " : "", ++ pcmcia_socket[sock].cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "", ++ pcmcia_socket[sock].cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "", ++ pcmcia_socket[sock].cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : ""); ++ ++ p += sprintf(p, "cs_flags : %s%s%s%s%s\n", ++ pcmcia_socket[sock].cs_state.flags & SS_PWR_AUTO ? ++ "SS_PWR_AUTO " : "", ++ pcmcia_socket[sock].cs_state.flags & SS_IOCARD ? ++ "SS_IOCARD " : "", ++ pcmcia_socket[sock].cs_state.flags & SS_RESET ? ++ "SS_RESET " : "", ++ pcmcia_socket[sock].cs_state.flags & SS_SPKR_ENA ? ++ "SS_SPKR_ENA " : "", ++ pcmcia_socket[sock].cs_state.flags & SS_OUTPUT_ENA ? ++ "SS_OUTPUT_ENA " : ""); ++ ++ p += sprintf(p, "Vcc : %d\n", pcmcia_socket[sock].cs_state.Vcc); ++ p += sprintf(p, "Vpp : %d\n", pcmcia_socket[sock].cs_state.Vpp); ++ p += sprintf(p, "irq : %d\n", pcmcia_socket[sock].cs_state.io_irq); ++ p += sprintf(p, "I/O : %u\n", pcmcia_socket[sock].speed_io); ++ p += sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr); ++ p += sprintf(p, "common : %u\n", pcmcia_socket[sock].speed_mem); ++ return p-buf; ++} ++ ++ ++#endif /* defined(CONFIG_PROC_FS) */ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/pcmcia/bcm4710_pcmcia.c 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,266 @@ ++/* ++ * BCM4710 specific pcmcia routines. ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * $Id: bcm4710_pcmcia.c,v 1.1.1.7 2004/04/12 04:32:07 honor Exp $ ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/delay.h> ++#include <linux/ioport.h> ++#include <linux/kernel.h> ++#include <linux/tqueue.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/proc_fs.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/pci.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bulkmem.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/bus_ops.h> ++#include "cs_internal.h" ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++ ++ ++#include <typedefs.h> ++#include <bcmdevs.h> ++#include <bcm4710.h> ++#include <sbconfig.h> ++#include <sbextif.h> ++ ++#include "bcm4710pcmcia.h" ++ ++/* Use a static var for irq dev_id */ ++static int bcm47xx_pcmcia_dev_id; ++ ++/* Do we think we have a card or not? */ ++static int bcm47xx_pcmcia_present = 0; ++ ++ ++static void bcm4710_pcmcia_reset(void) ++{ ++ extifregs_t *eir; ++ unsigned long s; ++ uint32 out0, out1, outen; ++ ++ ++ eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t)); ++ ++ save_and_cli(s); ++ ++ /* Use gpio7 to reset the pcmcia slot */ ++ outen = readl(&eir->gpio[0].outen); ++ outen |= BCM47XX_PCMCIA_RESET; ++ out0 = readl(&eir->gpio[0].out); ++ out0 &= ~(BCM47XX_PCMCIA_RESET); ++ out1 = out0 | BCM47XX_PCMCIA_RESET; ++ ++ writel(out0, &eir->gpio[0].out); ++ writel(outen, &eir->gpio[0].outen); ++ mdelay(1); ++ writel(out1, &eir->gpio[0].out); ++ mdelay(1); ++ writel(out0, &eir->gpio[0].out); ++ ++ restore_flags(s); ++} ++ ++ ++static int bcm4710_pcmcia_init(struct pcmcia_init *init) ++{ ++ struct pci_dev *pdev; ++ extifregs_t *eir; ++ uint32 outen, intp, intm, tmp; ++ uint16 *attrsp; ++ int rc = 0, i; ++ extern unsigned long bcm4710_cpu_cycle; ++ ++ ++ if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_EXTIF, NULL))) { ++ printk(KERN_ERR "bcm4710_pcmcia: extif not found\n"); ++ return -ENODEV; ++ } ++ eir = (extifregs_t *) ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); ++ ++ /* Initialize the pcmcia i/f: 16bit no swap */ ++ writel(CF_EM_PCMCIA | CF_DS | CF_EN, &eir->pcmcia_config); ++ ++#ifdef notYet ++ ++ /* Set the timing for memory accesses */ ++ tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */ ++ tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */ ++ tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */ ++ tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */ ++ writel(tmp, &eir->pcmcia_memwait); /* 0x01020a0c for a 100Mhz clock */ ++ ++ /* Set the timing for I/O accesses */ ++ tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */ ++ tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */ ++ tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */ ++ tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */ ++ writel(tmp, &eir->pcmcia_iowait); /* 0x01020a0c for a 100Mhz clock */ ++ ++ /* Set the timing for attribute accesses */ ++ tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */ ++ tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */ ++ tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */ ++ tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */ ++ writel(tmp, &eir->pcmcia_attrwait); /* 0x01020a0c for a 100Mhz clock */ ++ ++#endif ++ /* Make sure gpio0 and gpio5 are inputs */ ++ outen = readl(&eir->gpio[0].outen); ++ outen &= ~(BCM47XX_PCMCIA_WP | BCM47XX_PCMCIA_STSCHG | BCM47XX_PCMCIA_RESET); ++ writel(outen, &eir->gpio[0].outen); ++ ++ /* Issue a reset to the pcmcia socket */ ++ bcm4710_pcmcia_reset(); ++ ++#ifdef DO_BCM47XX_PCMCIA_INTERRUPTS ++ /* Setup gpio5 to be the STSCHG interrupt */ ++ intp = readl(&eir->gpiointpolarity); ++ writel(intp | BCM47XX_PCMCIA_STSCHG, &eir->gpiointpolarity); /* Active low */ ++ intm = readl(&eir->gpiointmask); ++ writel(intm | BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask); /* Enable it */ ++#endif ++ ++ DEBUG(2, "bcm4710_pcmcia after reset:\n"); ++ DEBUG(2, "\textstatus\t= 0x%08x:\n", readl(&eir->extstatus)); ++ DEBUG(2, "\tpcmcia_config\t= 0x%08x:\n", readl(&eir->pcmcia_config)); ++ DEBUG(2, "\tpcmcia_memwait\t= 0x%08x:\n", readl(&eir->pcmcia_memwait)); ++ DEBUG(2, "\tpcmcia_attrwait\t= 0x%08x:\n", readl(&eir->pcmcia_attrwait)); ++ DEBUG(2, "\tpcmcia_iowait\t= 0x%08x:\n", readl(&eir->pcmcia_iowait)); ++ DEBUG(2, "\tgpioin\t\t= 0x%08x:\n", readl(&eir->gpioin)); ++ DEBUG(2, "\tgpio_outen0\t= 0x%08x:\n", readl(&eir->gpio[0].outen)); ++ DEBUG(2, "\tgpio_out0\t= 0x%08x:\n", readl(&eir->gpio[0].out)); ++ DEBUG(2, "\tgpiointpolarity\t= 0x%08x:\n", readl(&eir->gpiointpolarity)); ++ DEBUG(2, "\tgpiointmask\t= 0x%08x:\n", readl(&eir->gpiointmask)); ++ ++#ifdef DO_BCM47XX_PCMCIA_INTERRUPTS ++ /* Request pcmcia interrupt */ ++ rc = request_irq(BCM47XX_PCMCIA_IRQ, init->handler, SA_INTERRUPT, ++ "PCMCIA Interrupt", &bcm47xx_pcmcia_dev_id); ++#endif ++ ++ attrsp = (uint16 *)ioremap_nocache(EXTIF_PCMCIA_CFGBASE(BCM4710_EXTIF), 0x1000); ++ tmp = readw(&attrsp[0]); ++ DEBUG(2, "\tattr[0] = 0x%04x\n", tmp); ++ if ((tmp == 0x7fff) || (tmp == 0x7f00)) { ++ bcm47xx_pcmcia_present = 0; ++ } else { ++ bcm47xx_pcmcia_present = 1; ++ } ++ ++ /* There's only one socket */ ++ return 1; ++} ++ ++static int bcm4710_pcmcia_shutdown(void) ++{ ++ extifregs_t *eir; ++ uint32 intm; ++ ++ eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t)); ++ ++ /* Disable the pcmcia i/f */ ++ writel(0, &eir->pcmcia_config); ++ ++ /* Reset gpio's */ ++ intm = readl(&eir->gpiointmask); ++ writel(intm & ~BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask); /* Disable it */ ++ ++ free_irq(BCM47XX_PCMCIA_IRQ, &bcm47xx_pcmcia_dev_id); ++ ++ return 0; ++} ++ ++static int ++bcm4710_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) ++{ ++ extifregs_t *eir; ++ ++ eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t)); ++ ++ ++ if (sock != 0) { ++ printk(KERN_ERR "bcm4710 socket_state bad sock %d\n", sock); ++ return -1; ++ } ++ ++ if (bcm47xx_pcmcia_present) { ++ state->detect = 1; ++ state->ready = 1; ++ state->bvd1 = 1; ++ state->bvd2 = 1; ++ state->wrprot = (readl(&eir->gpioin) & BCM47XX_PCMCIA_WP) == BCM47XX_PCMCIA_WP; ++ state->vs_3v = 0; ++ state->vs_Xv = 0; ++ } else { ++ state->detect = 0; ++ state->ready = 0; ++ } ++ ++ return 1; ++} ++ ++ ++static int bcm4710_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ++{ ++ if (info->sock >= BCM47XX_PCMCIA_MAX_SOCK) return -1; ++ ++ info->irq = BCM47XX_PCMCIA_IRQ; ++ ++ return 0; ++} ++ ++ ++static int ++bcm4710_pcmcia_configure_socket(const struct pcmcia_configure *configure) ++{ ++ if (configure->sock >= BCM47XX_PCMCIA_MAX_SOCK) return -1; ++ ++ ++ DEBUG(2, "Vcc %dV Vpp %dV output %d speaker %d reset %d\n", configure->vcc, ++ configure->vpp, configure->output, configure->speaker, configure->reset); ++ ++ if ((configure->vcc != 50) || (configure->vpp != 50)) { ++ printk("%s: bad Vcc/Vpp (%d:%d)\n", __FUNCTION__, configure->vcc, ++ configure->vpp); ++ } ++ ++ if (configure->reset) { ++ /* Issue a reset to the pcmcia socket */ ++ DEBUG(1, "%s: Reseting socket\n", __FUNCTION__); ++ bcm4710_pcmcia_reset(); ++ } ++ ++ ++ return 0; ++} ++ ++struct pcmcia_low_level bcm4710_pcmcia_ops = { ++ bcm4710_pcmcia_init, ++ bcm4710_pcmcia_shutdown, ++ bcm4710_pcmcia_socket_state, ++ bcm4710_pcmcia_get_irq_info, ++ bcm4710_pcmcia_configure_socket ++}; ++ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/drivers/pcmcia/bcm4710pcmcia.h 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,118 @@ ++/* ++ * ++ * bcm47xx pcmcia driver ++ * ++ * Copyright 2004, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * Based on sa1100.h and include/asm-arm/arch-sa1100/pcmica.h ++ * from www.handhelds.org, ++ * and au1000_generic.c from oss.sgi.com. ++ * ++ * $Id: bcm4710pcmcia.h,v 1.1.1.7 2004/04/12 04:32:07 honor Exp $ ++ */ ++ ++#if !defined(_BCM4710PCMCIA_H) ++#define _BCM4710PCMCIA_H ++ ++#include <pcmcia/cs_types.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bulkmem.h> ++#include <pcmcia/cistpl.h> ++#include "cs_internal.h" ++ ++ ++/* The 47xx can only support one socket */ ++#define BCM47XX_PCMCIA_MAX_SOCK 1 ++ ++/* In the bcm947xx gpio's are used for some pcmcia functions */ ++#define BCM47XX_PCMCIA_WP 0x01 /* Bit 0 is WP input */ ++#define BCM47XX_PCMCIA_STSCHG 0x20 /* Bit 5 is STSCHG input/interrupt */ ++#define BCM47XX_PCMCIA_RESET 0x80 /* Bit 7 is RESET */ ++ ++#define BCM47XX_PCMCIA_IRQ 2 ++ ++/* The socket driver actually works nicely in interrupt-driven form, ++ * so the (relatively infrequent) polling is "just to be sure." ++ */ ++#define BCM47XX_PCMCIA_POLL_PERIOD (2 * HZ) ++ ++#define BCM47XX_PCMCIA_IO_SPEED (255) ++#define BCM47XX_PCMCIA_MEM_SPEED (300) ++ ++ ++struct pcmcia_state { ++ unsigned detect: 1, ++ ready: 1, ++ bvd1: 1, ++ bvd2: 1, ++ wrprot: 1, ++ vs_3v: 1, ++ vs_Xv: 1; ++}; ++ ++ ++struct pcmcia_configure { ++ unsigned sock: 8, ++ vcc: 8, ++ vpp: 8, ++ output: 1, ++ speaker: 1, ++ reset: 1; ++}; ++ ++struct pcmcia_irq_info { ++ unsigned int sock; ++ unsigned int irq; ++}; ++ ++/* This structure encapsulates per-socket state which we might need to ++ * use when responding to a Card Services query of some kind. ++ */ ++struct bcm47xx_pcmcia_socket { ++ socket_state_t cs_state; ++ struct pcmcia_state k_state; ++ unsigned int irq; ++ void (*handler)(void *, unsigned int); ++ void *handler_info; ++ pccard_io_map io_map[MAX_IO_WIN]; ++ pccard_mem_map mem_map[MAX_WIN]; ++ ioaddr_t virt_io, phys_attr, phys_mem; ++ unsigned short speed_io, speed_attr, speed_mem; ++}; ++ ++struct pcmcia_init { ++ void (*handler)(int irq, void *dev, struct pt_regs *regs); ++}; ++ ++struct pcmcia_low_level { ++ int (*init)(struct pcmcia_init *); ++ int (*shutdown)(void); ++ int (*socket_state)(unsigned sock, struct pcmcia_state *); ++ int (*get_irq_info)(struct pcmcia_irq_info *); ++ int (*configure_socket)(const struct pcmcia_configure *); ++}; ++ ++extern struct pcmcia_low_level bcm47xx_pcmcia_ops; ++ ++/* I/O pins replacing memory pins ++ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) ++ * ++ * These signals change meaning when going from memory-only to ++ * memory-or-I/O interface: ++ */ ++#define iostschg bvd1 ++#define iospkr bvd2 ++ ++ ++/* ++ * Declaration for implementation specific low_level operations. ++ */ ++extern struct pcmcia_low_level bcm4710_pcmcia_ops; ++ ++#endif /* !defined(_BCM4710PCMCIA_H) */ +--- linux-2.4.20/include/asm-mips/asm.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/asm.h 2005-01-08 12:10:12.593676448 -0500 +@@ -387,4 +387,16 @@ + + #define SSNOP sll zero,zero,1 + ++/* ++ * mips32/64 has some extra CP0 register selected by the low bits of ++ * the mfc0/mtc0 instruction. Note that dst and src CANNOT have '$' ++ * signs in them. ++ */ ++#define MFC0_SEL(dst, src, sel)\ ++ .word (0x40000000 | ((dst)<<16) | ((src)<<11) | (sel)) ++ ++ ++#define MTC0_SEL(dst, src, sel)\ ++ .word (0x40800000 | ((dst)<<16) | ((src)<<11) | (sel)) ++ + #endif /* __ASM_ASM_H */ +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.20/include/asm-mips/bcm4710_cache.h 2005-01-07 05:39:02.000000000 -0500 +@@ -0,0 +1,229 @@ ++ ++#ifndef _MIPS_R4KCACHE_H ++#define _MIPS_R4KCACHE_H ++ ++#include <asm/asm.h> ++#include <asm/cacheops.h> ++ ++#include <typedefs.h> ++#include <sbconfig.h> ++#include <bcm4710.h> ++#include <asm/paccess.h> ++#define BCM4710_DUMMY_RREG() (((sbconfig_t *)(KSEG1ADDR(BCM4710_REG_SDRAM + SBCONFIGOFF)))->sbimstate) ++#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr)) ++#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); }) ++ ++static inline void flush_icache_line_indexed(unsigned long addr) ++{ ++ unsigned long waystep = icache_size/mips_cpu.icache.ways; ++ unsigned int way; ++ ++ for (way = 0; way < mips_cpu.icache.ways; way++) ++ { ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n\t" ++ "cache %1, (%0)\n\t" ++ ".set mips0\n\t" ++ ".set reorder" ++ : ++ : "r" (addr), ++ "i" (Index_Invalidate_I)); ++ ++ addr += waystep; ++ } ++} ++ ++static inline void flush_dcache_line_indexed(unsigned long addr) ++{ ++ unsigned long waystep = dcache_size/mips_cpu.dcache.ways; ++ unsigned int way; ++ ++ for (way = 0; way < mips_cpu.dcache.ways; way++) ++ { ++ BCM4710_DUMMY_RREG(); ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n\t" ++ "cache %1, (%0)\n\t" ++ ".set mips0\n\t" ++ ".set reorder" ++ : ++ : "r" (addr), ++ "i" (Index_Writeback_Inv_D)); ++ ++ addr += waystep; ++ } ++} ++ ++static inline void flush_icache_line(unsigned long addr) ++{ ++ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n\t" ++ "cache %1, (%0)\n\t" ++ ".set mips0\n\t" ++ ".set reorder" ++ : ++ : "r" (addr), ++ "i" (Hit_Invalidate_I)); ++} ++ ++static inline void flush_dcache_line(unsigned long addr) ++{ ++ BCM4710_DUMMY_RREG(); ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n\t" ++ "cache %1, (%0)\n\t" ++ ".set mips0\n\t" ++ ".set reorder" ++ : ++ : "r" (addr), ++ "i" (Hit_Writeback_Inv_D)); ++} ++ ++static inline void invalidate_dcache_line(unsigned long addr) ++{ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n\t" ++ "cache %1, (%0)\n\t" ++ ".set mips0\n\t" ++ ".set reorder" ++ : ++ : "r" (addr), ++ "i" (Hit_Invalidate_D)); ++} ++ ++/* ++ * The next two are for badland addresses like signal trampolines. ++ */ ++static inline void protected_flush_icache_line(unsigned long addr) ++{ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n" ++ "1:\tcache %1,(%0)\n" ++ "2:\t.set mips0\n\t" ++ ".set reorder\n\t" ++ ".section\t__ex_table,\"a\"\n\t" ++ STR(PTR)"\t1b,2b\n\t" ++ ".previous" ++ : ++ : "r" (addr), ++ "i" (Hit_Invalidate_I)); ++} ++ ++static inline void protected_writeback_dcache_line(unsigned long addr) ++{ ++ BCM4710_DUMMY_RREG(); ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n" ++ "1:\tcache %1,(%0)\n" ++ "2:\t.set mips0\n\t" ++ ".set reorder\n\t" ++ ".section\t__ex_table,\"a\"\n\t" ++ STR(PTR)"\t1b,2b\n\t" ++ ".previous" ++ : ++ : "r" (addr), ++ "i" (Hit_Writeback_D)); ++} ++ ++#define cache_unroll(base,op) \ ++ __asm__ __volatile__(" \ ++ .set noreorder; \ ++ .set mips3; \ ++ cache %1, (%0); \ ++ .set mips0; \ ++ .set reorder" \ ++ : \ ++ : "r" (base), \ ++ "i" (op)); ++ ++ ++static inline void blast_dcache(void) ++{ ++ unsigned long start = KSEG0; ++ unsigned long end = (start + dcache_size); ++ ++ while(start < end) { ++ BCM4710_DUMMY_RREG(); ++ cache_unroll(start,Index_Writeback_Inv_D); ++ start += dc_lsize; ++ } ++} ++ ++static inline void blast_dcache_page(unsigned long page) ++{ ++ unsigned long start = page; ++ unsigned long end = (start + PAGE_SIZE); ++ ++ BCM4710_FILL_TLB(start); ++ while(start < end) { ++ BCM4710_DUMMY_RREG(); ++ cache_unroll(start,Hit_Writeback_Inv_D); ++ start += dc_lsize; ++ } ++} ++ ++static inline void blast_dcache_page_indexed(unsigned long page) ++{ ++ unsigned long start; ++ unsigned long end = (page + PAGE_SIZE); ++ unsigned long waystep = dcache_size/mips_cpu.dcache.ways; ++ unsigned int way; ++ ++ for (way = 0; way < mips_cpu.dcache.ways; way++) { ++ start = page + way*waystep; ++ while(start < end) { ++ BCM4710_DUMMY_RREG(); ++ cache_unroll(start,Index_Writeback_Inv_D); ++ start += dc_lsize; ++ } ++ } ++} ++ ++static inline void blast_icache(void) ++{ ++ unsigned long start = KSEG0; ++ unsigned long end = (start + icache_size); ++ ++ while(start < end) { ++ cache_unroll(start,Index_Invalidate_I); ++ start += ic_lsize; ++ } ++} ++ ++static inline void blast_icache_page(unsigned long page) ++{ ++ unsigned long start = page; ++ unsigned long end = (start + PAGE_SIZE); ++ ++ BCM4710_FILL_TLB(start); ++ while(start < end) { ++ cache_unroll(start,Hit_Invalidate_I); ++ start += ic_lsize; ++ } ++} ++ ++static inline void blast_icache_page_indexed(unsigned long page) ++{ ++ unsigned long start; ++ unsigned long end = (page + PAGE_SIZE); ++ unsigned long waystep = icache_size/mips_cpu.icache.ways; ++ unsigned int way; ++ ++ for (way = 0; way < mips_cpu.icache.ways; way++) { ++ start = page + way*waystep; ++ while(start < end) { ++ cache_unroll(start,Index_Invalidate_I); ++ start += ic_lsize; ++ } ++ } ++} ++ ++#endif /* !(_MIPS_R4KCACHE_H) */ +--- linux-2.4.20/include/asm-mips/bootinfo.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/bootinfo.h 2005-01-08 12:17:06.878695552 -0500 +@@ -36,6 +36,7 @@ + #define MACH_GROUP_NEC_VR41XX 19 /* NEC Vr41xx based boards/gadgets */ + #define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */ + #define MACH_GROUP_LASAT 21 ++#define MACH_GROUP_BRCM 22 /* Broadcom Boards */ + + /* + * Valid machtype values for group unknown (low order halfword of mips_machtype) +@@ -179,7 +180,15 @@ + #define MACH_VICTOR_MPC30X 3 /* Victor MP-C303/304 */ + #define MACH_IBM_WORKPAD 4 /* IBM WorkPad z50 */ + #define MACH_CASIO_E55 5 /* CASIO CASSIOPEIA E-10/15/55/65 */ +-#define MACH_TANBAC_TB0226 6 /* TANBAC TB0226 (MBASE) */ ++ ++/* ++ * Valid machtypes for group Broadcom ++ */ ++#define MACH_BCM93725 0 ++#define MACH_BCM93725_VJ 1 ++#define MACH_BCM93730 2 ++#define MACH_BCM947XX 3 ++#define MACH_BCM933XX 4 + + #define CL_SIZE (256) + +--- linux-2.4.20/include/asm-mips/cpu.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/cpu.h 2005-01-08 12:10:11.203887728 -0500 +@@ -24,6 +24,11 @@ + spec. + */ + ++#define PRID_COPT_MASK 0xff000000 ++#define PRID_COMP_MASK 0x00ff0000 ++#define PRID_IMP_MASK 0x0000ff00 ++#define PRID_REV_MASK 0x000000ff ++ + #define PRID_COMP_LEGACY 0x000000 + #define PRID_COMP_MIPS 0x010000 + #define PRID_COMP_BROADCOM 0x020000 +@@ -65,10 +70,17 @@ + #define PRID_IMP_20KC 0x8200 + #define PRID_IMP_4KEC 0x8400 + #define PRID_IMP_4KSC 0x8600 +- ++#define PRID_IMP_BCM4710 0x4000 ++#define PRID_IMP_BCM3302 0x9000 ++#define PRID_IMP_BCM3303 0x9100 ++#define PRID_IMP_BCM3303 0x9100 + + #define PRID_IMP_UNKNOWN 0xff00 + ++#define BCM330X(id) \ ++ (((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == (PRID_COMP_BROADCOM | PRID_IMP_BCM3302)) \ ++ || ((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == (PRID_COMP_BROADCOM | PRID_IMP_BCM3303))) ++ + /* + * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE + */ +@@ -139,7 +151,7 @@ + CPU_TX3912, CPU_TX3922, CPU_TX3927, CPU_AU1000, CPU_4KEC, CPU_4KSC, + CPU_VR41XX, CPU_R5500, CPU_TX49XX, CPU_TX39XX, CPU_AU1500, CPU_20KC, + CPU_VR4111, CPU_VR4121, CPU_VR4122, CPU_VR4131, CPU_VR4181, CPU_VR4181A, +- CPU_AU1100, CPU_LAST ++ CPU_AU1100, CPU_BCM4710, CPU_BCM3302, CPU_LAST + }; + + #endif /* !__ASSEMBLY__ */ +--- linux-2.4.20/include/asm-mips/mips32_cache.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/mips32_cache.h 2005-01-07 05:39:02.000000000 -0500 +@@ -325,4 +325,17 @@ + } + } + ++extern inline void fill_icache_line(unsigned long addr) ++{ ++ __asm__ __volatile__( ++ ".set noreorder\n\t" ++ ".set mips3\n\t" ++ "cache %1, (%0)\n\t" ++ ".set mips0\n\t" ++ ".set reorder" ++ : ++ : "r" (addr), ++ "i" (Fill)); ++} ++ + #endif /* !(_MIPS_R4KCACHE_H) */ +--- linux-2.4.20/include/asm-mips/mipsregs.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/mipsregs.h 2005-01-07 05:39:44.000000000 -0500 +@@ -400,13 +400,75 @@ + #define TX49_CONF_HALT (_ULCAST_(1) << 18) + #define TX49_CONF_CWFON (_ULCAST_(1) << 27) + +-/* +- * R10000 performance counter definitions. +- * +- * FIXME: The R10000 performance counter opens a nice way to implement CPU +- * time accounting with a precission of one cycle. I don't have +- * R10000 silicon but just a manual, so ... +- */ ++/* mips32/64 definitions for CP0 config register */ ++#define CONF_MT_MASK 0x00000380 /* MMU Type */ ++#define CONF_MT_NONE 0x00000000 /* No mmu */ ++#define CONF_MT_TLB 0x00000080 /* TLB present */ ++#define CONF_MT_BAT 0x00000100 /* Block address translation */ ++#define CONF_MT_FM 0x00000180 /* Fixed map (Like 4Kp/4Km) */ ++#define CONF_AR_MASK 0x00001c00 /* Architecture revision */ ++#define CONF_AT_MASK 0x00006000 /* Architecture type */ ++#define CONF_AT_M32 0x00000000 /* mips32 */ ++#define CONF_AT_M6432 0x00002000 /* mips64/mips32?? */ ++#define CONF_AT_M64 0x00004000 /* mips64 */ ++#define CONF_BE 0x00008000 /* BigEndian */ ++#define CONF_BM 0x00010000 /* Burst Mode */ ++#define CONF_BM_SEQ 0x00000000 /* Sequential */ ++#define CONF_BM_SB 0x00010000 /* SubBlock */ ++#define CONF_MM_MASK 0x00060000 /* Merge Mode */ ++#define CONF_MM_NONE 0x00000000 /* No merging */ ++#define CONF_MM_SYSAD 0x00020000 /* SysAD merging */ ++#define CONF_MM_FULL 0x00040000 /* Full merging */ ++#define CONF_MDU 0x00100000 /* Slow MDU */ ++#define CONF_KU_MASK 0x0e000000 /* Kuseg and useg cacheability (for MT=FM) */ ++#define CONF_K23_MASK 0x70000000 /* Kseg2 and Kseg3 cacheability (for MT=FM) */ ++#define CONF_M 0x80000000 /* config1 register present */ ++ ++/* mips32/64 definitions for CP0 config1 register */ ++#define CONF1_FP 0x00000001 /* FPU present */ ++#define CONF1_EP 0x00000002 /* EJTAG present */ ++#define CONF1_CA 0x00000004 /* Code compression (mips16) implemented */ ++#define CONF1_WR 0x00000008 /* Watch registers present */ ++#define CONF1_PC 0x00000010 /* Performance counters present */ ++#define CONF1_DA_SHIFT 7 /* Data cache associativity */ ++#define CONF1_DA_MASK 0x00000380 ++#define CONF1_DA_BASE 1 ++#define CONF1_DA_DM 0x00000000 /* Direct mapped */ ++#define CONF1_DA_2W 0x00000080 /* 2-way */ ++#define CONF1_DA_3W 0x00000100 /* 3-way */ ++#define CONF1_DA_4W 0x00000180 /* 4-way */ ++#define CONF1_DL_SHIFT 10 /* Data cache line size */ ++#define CONF1_DL_MASK 0x00001c00 ++#define CONF1_DL_BASE 2 ++#define CONF1_DL_NONE 0x00000000 /* No data cache present */ ++#define CONF1_DL_16 0x00000c00 /* 16 bytes */ ++#define CONF1_DS_SHIFT 13 /* Data cache sets/way */ ++#define CONF1_DS_MASK 0x0000e000 ++#define CONF1_DS_BASE 64 ++#define CONF1_DS_64 0x00000000 /* 64 sets */ ++#define CONF1_DS_128 0x00002000 /* 128 sets */ ++#define CONF1_DS_256 0x00004000 /* 256 sets */ ++#define CONF1_IA_SHIFT 16 /* Instruction cache associativity */ ++#define CONF1_IA_MASK 0x00070000 ++#define CONF1_IA_BASE 1 ++#define CONF1_IA_DM 0x00000000 /* Direct mapped */ ++#define CONF1_IA_2W 0x00010000 /* 2-way */ ++#define CONF1_IA_3W 0x00020000 /* 3-way */ ++#define CONF1_IA_4W 0x00030000 /* 4-way */ ++#define CONF1_IL_SHIFT 19 /* Instruction cache line size */ ++#define CONF1_IL_MASK 0x00380000 ++#define CONF1_IL_BASE 2 ++#define CONF1_IL_NONE 0x00000000 /* No data cache present */ ++#define CONF1_IL_16 0x00180000 /* 16 bytes */ ++#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */ ++#define CONF1_IS_MASK 0x01c00000 ++#define CONF1_IS_BASE 64 ++#define CONF1_IS_64 0x00000000 /* 64 sets */ ++#define CONF1_IS_128 0x00400000 /* 128 sets */ ++#define CONF1_IS_256 0x00800000 /* 256 sets */ ++#define CONF1_MS_MASK 0x7e000000 /* Number of tlb entries */ ++#define CONF1_MS_SHIFT 25 ++ + + /* + * Events counted by counter #0 +@@ -727,6 +789,20 @@ + #define read_c0_framemask() __read_32bit_c0_register($21, 0) + #define write_c0_framemask(val) __write_32bit_c0_register($21, 0, val) + ++#define read_c0_diag() __read_32bit_c0_register($22, 0) ++#define read_c0_diag1() __read_32bit_c0_register($22, 1) ++#define read_c0_diag2() __read_32bit_c0_register($22, 2) ++#define read_c0_diag3() __read_32bit_c0_register($22, 3) ++#define read_c0_diag4() __read_32bit_c0_register($22, 4) ++#define read_c0_diag5() __read_32bit_c0_register($22, 5) ++ ++#define write_c0_diag(val) __write_32bit_c0_register($22, 0, val) ++#define write_c0_diag1(val) __write_32bit_c0_register($22, 1, val) ++#define write_c0_diag2(val) __write_32bit_c0_register($22, 2, val) ++#define write_c0_diag3(val) __write_32bit_c0_register($22, 3, val) ++#define write_c0_diag4(val) __write_32bit_c0_register($22, 4, val) ++#define write_c0_diag5(val) __write_32bit_c0_register($22, 5, val) ++ + #define read_c0_debug() __read_32bit_c0_register($23, 0) + #define write_c0_debug(val) __write_32bit_c0_register($23, 0, val) + +@@ -844,6 +920,14 @@ + __BUILD_SET_C0(cause,CP0_CAUSE) + __BUILD_SET_C0(config,CP0_CONFIG) + ++/* ++ * Functions to access the performance counter and control registers ++ */ ++extern asmlinkage unsigned int read_perf_cntr(unsigned int counter); ++extern asmlinkage void write_perf_cntr(unsigned int counter, unsigned int val); ++extern asmlinkage unsigned int read_perf_cntl(unsigned int counter); ++extern asmlinkage void write_perf_cntl(unsigned int counter, unsigned int val); ++ + #endif /* !__ASSEMBLY__ */ + + #endif /* _ASM_MIPSREGS_H */ +--- linux-2.4.20/include/asm-mips/pci.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/pci.h 2005-01-08 12:15:03.133507680 -0500 +@@ -117,12 +117,7 @@ + if (direction == PCI_DMA_NONE) + out_of_line_bug(); + +- if (direction != PCI_DMA_TODEVICE) { +- unsigned long addr; +- +- addr = baddr_to_bus(hwdev->bus, dma_addr) + PAGE_OFFSET; +- dma_cache_wback_inv(addr, size); +- } ++ /* Nothing to do */ + } + + /* +@@ -203,8 +198,7 @@ + } else { + sg->dma_address = page_to_bus(sg->page) + + sg->offset; +- dma_cache_wback_inv((unsigned long) +- (page_address(sg->page) + sg->offset), ++ dma_cache_wback_inv((unsigned long)page_address(sg->page) + sg->offset, + sg->length); + } + } +--- linux-2.4.20/include/asm-mips/serial.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/serial.h 2005-01-08 12:15:06.999919896 -0500 +@@ -181,6 +181,13 @@ + #define TXX927_SERIAL_PORT_DEFNS + #endif + ++#ifdef CONFIG_BCM947XX ++/* reserve 4 ports to be configured at runtime */ ++#define BCM947XX_SERIAL_PORT_DEFNS { 0, }, { 0, }, { 0, }, { 0, }, ++#else ++#define BCM947XX_SERIAL_PORT_DEFNS ++#endif ++ + #ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT + #define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ +@@ -313,6 +320,7 @@ + #endif + + #define SERIAL_PORT_DFNS \ ++ BCM947XX_SERIAL_PORT_DEFNS \ + IVR_SERIAL_PORT_DEFNS \ + ITE_SERIAL_PORT_DEFNS \ + ATLAS_SERIAL_PORT_DEFNS \ +--- linux-2.4.20/include/asm-mips/stackframe.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/stackframe.h 2005-01-08 12:15:32.798997840 -0500 +@@ -201,12 +201,25 @@ + lw $3, PT_R3(sp); \ + lw $2, PT_R2(sp) + ++#ifdef CONFIG_BCM4710 ++ + #define RESTORE_SP_AND_RET \ + lw sp, PT_R29(sp); \ + .set mips3; \ ++ nop; \ ++ nop; \ + eret; \ + .set mips0 + ++#else ++ ++#define RESTORE_SP_AND_RET \ ++ lw sp, PT_R29(sp); \ ++ .set mips3; \ ++ eret; \ ++ .set mips0 ++#endif ++ + #endif + + #define RESTORE_SP \ +--- linux-2.4.20/include/asm-mips/system.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/include/asm-mips/system.h 2005-01-08 12:15:03.002527592 -0500 +@@ -16,6 +16,8 @@ + #ifndef _ASM_SYSTEM_H + #define _ASM_SYSTEM_H + ++#ifdef __KERNEL__ ++ + #include <linux/config.h> + #include <asm/sgidefs.h> + +@@ -316,4 +318,6 @@ + #define die_if_kernel(msg, regs) \ + __die_if_kernel(msg, regs, __FILE__ ":", __FUNCTION__, __LINE__) + ++#endif /* __KERNEL__ */ ++ + #endif /* _ASM_SYSTEM_H */ +--- linux-2.4.20/init/do_mounts.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/init/do_mounts.c 2005-01-08 12:16:21.913531296 -0500 +@@ -238,7 +238,16 @@ + { "ftlb", 0x2c08 }, + { "ftlc", 0x2c10 }, + { "ftld", 0x2c18 }, ++#if defined(CONFIG_MTD_BLOCK) || defined(CONFIG_MTD_BLOCK_RO) + { "mtdblock", 0x1f00 }, ++ { "mtdblock0",0x1f00 }, ++ { "mtdblock1",0x1f01 }, ++ { "mtdblock2",0x1f02 }, ++ { "mtdblock3",0x1f03 }, ++#endif ++#ifdef CONFIG_BLK_DEV_DUMMY ++ { "dummy",0x2000 }, ++#endif + { NULL, 0 } + }; + +@@ -468,6 +477,7 @@ + struct minix_super_block *minixsb; + struct ext2_super_block *ext2sb; + struct romfs_super_block *romfsb; ++ struct cramfs_super *cramfsb; + int nblocks = -1; + unsigned char *buf; + +@@ -478,6 +488,7 @@ + minixsb = (struct minix_super_block *) buf; + ext2sb = (struct ext2_super_block *) buf; + romfsb = (struct romfs_super_block *) buf; ++ cramfsb = (struct cramfs_super *) buf; + memset(buf, 0xe5, size); + + /* +@@ -497,6 +508,13 @@ + goto done; + } + ++#ifdef CONFIG_BLK_DEV_INITRD ++ /* ++ * Fallback if size cannot be determined by superblock ++ */ ++ nblocks = (initrd_end-initrd_start+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++#endif ++ + /* romfs is at block zero too */ + if (romfsb->word0 == ROMSB_WORD0 && + romfsb->word1 == ROMSB_WORD1) { +@@ -507,6 +525,16 @@ + goto done; + } + ++ /* so is cramfs */ ++ if (cramfsb->magic == CRAMFS_MAGIC) { ++ printk(KERN_NOTICE ++ "RAMDISK: cramfs filesystem found at block %d\n", ++ start_block); ++ if (cramfsb->flags & CRAMFS_FLAG_FSID_VERSION_2) ++ nblocks = (cramfsb->size+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; ++ goto done; ++ } ++ + /* + * Read block 1 to test for minix and ext2 superblock + */ +@@ -535,6 +563,7 @@ + printk(KERN_NOTICE + "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", + start_block); ++ nblocks = -1; + + done: + lseek(fd, start_block * BLOCK_SIZE, 0); +@@ -757,6 +786,17 @@ + change_floppy("root floppy"); + } + #endif ++#if defined(CONFIG_MTD_BLOCK) || defined(CONFIG_MTD_BLOCK_RO) ++ if (MAJOR(ROOT_DEV) == 31) { ++ /* rd_doload is for a ramload setup */ ++ if (rd_doload) { ++ if (rd_load_disk(0)) { ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); ++ create_dev("/dev/root", ROOT_DEV, NULL); ++ } ++ } ++ } ++#endif + mount_block_root("/dev/root", root_mountflags); + } + +--- linux-2.4.20/init/main.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:39:02.000000000 -0500 ++++ linux-2.4.20/init/main.c 2005-01-07 05:39:02.000000000 -0500 +@@ -554,6 +554,13 @@ + free_initmem(); + unlock_kernel(); + ++#ifdef CONFIG_NOROOT ++ for (;;) { ++ DECLARE_WAIT_QUEUE_HEAD(wait); ++ sleep_on(&wait); ++ } ++#endif ++ + if (open("/dev/console", O_RDWR, 0) < 0) + printk("Warning: unable to open an initial console.\n"); + +--- linux-2.4.20/net/bridge/br_device.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/bridge/br_device.c 2005-01-07 05:39:02.000000000 -0500 +@@ -121,6 +121,25 @@ + return -1; + } + ++extern void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr); ++ ++static int ++br_set_mac_address(struct net_device *dev, void *addr) ++{ ++ struct net_bridge *br = dev->priv; ++ struct sockaddr *sa = (struct sockaddr *) addr; ++ ++ write_lock_bh(&br->lock); ++ ++ memcpy(br->preferred_id.addr, sa->sa_data, ETH_ALEN); ++ ++ br_stp_recalculate_bridge_id(br); ++ ++ write_unlock_bh(&br->lock); ++ ++ return 0; ++} ++ + void br_dev_setup(struct net_device *dev) + { + memset(dev->dev_addr, 0, ETH_ALEN); +@@ -133,5 +152,5 @@ + dev->stop = br_dev_stop; + dev->accept_fastpath = br_dev_accept_fastpath; + dev->tx_queue_len = 0; +- dev->set_mac_address = NULL; ++ dev->set_mac_address = br_set_mac_address; + } +--- linux-2.4.20/net/bridge/br_fdb.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/bridge/br_fdb.c 2005-01-07 05:39:02.000000000 -0500 +@@ -290,10 +290,10 @@ + hash = br_mac_hash(addr); + + write_lock_bh(&br->hash_lock); ++ if (!is_local) { + fdb = br->hash[hash]; + while (fdb != NULL) { +- if (!fdb->is_local && +- !memcmp(fdb->addr.addr, addr, ETH_ALEN)) { ++ if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { + __fdb_possibly_replace(fdb, source, is_local); + write_unlock_bh(&br->hash_lock); + return; +@@ -301,6 +301,7 @@ + + fdb = fdb->next_hash; + } ++ } + + fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC); + if (fdb == NULL) { +--- linux-2.4.20/net/bridge/br_private.h~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/bridge/br_private.h 2005-01-08 12:16:21.367614288 -0500 +@@ -96,6 +96,7 @@ + int hello_time; + int forward_delay; + bridge_id bridge_id; ++ bridge_id preferred_id; + int bridge_max_age; + int bridge_hello_time; + int bridge_forward_delay; +--- linux-2.4.20/net/bridge/br_stp_if.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/bridge/br_stp_if.c 2005-01-07 05:39:02.000000000 -0500 +@@ -162,6 +162,12 @@ + + p = br->port_list; + while (p != NULL) { ++ /* match against preferred address first */ ++ if (memcmp(p->dev->dev_addr, br->preferred_id.addr, ETH_ALEN) == 0) { ++ addr = p->dev->dev_addr; ++ break; ++ } ++ + if (addr == br_mac_zero || + memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) + addr = p->dev->dev_addr; +--- linux-2.4.20/net/core/Makefile~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/core/Makefile 2005-01-08 12:16:20.333771456 -0500 +@@ -7,6 +7,8 @@ + # + # Note 2! The CFLAGS definition is now in the main makefile... + ++SRCBASE := $(TOPDIR)/../.. ++EXTRA_CFLAGS += -Wall -I$(SRCBASE)/ + O_TARGET := core.o + + export-objs := netfilter.o profile.o +--- linux-2.4.20/net/core/dev.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/core/dev.c 2005-01-08 12:16:21.372613528 -0500 +@@ -1245,6 +1245,19 @@ + local_irq_save(flags); + + netdev_rx_stat[this_cpu].total++; ++ ++#if defined(CONFIG_BCM4710) && defined(CONFIG_BRIDGE) ++ /* Optimisation for framebursting (allow interleaving of pkts by ++ immediately processing the rx pkt instead of Qing the pkt and deferring ++ the processing). Only optimise for bridging and guard against non ++ TASKLET based netif_rx calls. ++ */ ++ if (!in_irq() && skb->dev->br_port != NULL && br_handle_frame_hook != NULL){ ++ local_irq_restore(flags); ++ return(netif_receive_skb(skb)); ++ } ++#endif ++ + if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { + if (queue->input_pkt_queue.qlen) { + if (queue->throttle) +@@ -2005,6 +2018,7 @@ + { + struct net_device *dev; + int err; ++ struct net_device_stats *stats; + + if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) + return -ENODEV; +@@ -2119,6 +2133,16 @@ + ifr->ifr_ifindex = dev->ifindex; + return 0; + ++#ifdef PERFORMANCE_SUPPORT ++ case SIOCGIFSTATS: ++ if (!dev->get_stats || !(stats = dev->get_stats(dev))) ++ return -ENODEV; ++ if (copy_to_user(ifr->ifr_data, stats, ++ sizeof(struct net_device_stats))) ++ return -EFAULT; ++ return 0; ++#endif ++ + case SIOCGIFTXQLEN: + ifr->ifr_qlen = dev->tx_queue_len; + return 0; +--- linux-2.4.20/net/netsyms.c~2.4.20_broadcom_3_37_2_1109_US.patch 2005-01-07 05:38:15.000000000 -0500 ++++ linux-2.4.20/net/netsyms.c 2005-01-08 12:16:21.745556832 -0500 +@@ -435,20 +435,12 @@ + EXPORT_SYMBOL(neigh_add); + EXPORT_SYMBOL(neigh_dump_info); + +-EXPORT_SYMBOL(dev_set_allmulti); +-EXPORT_SYMBOL(dev_set_promiscuity); +-EXPORT_SYMBOL(sklist_remove_socket); +-EXPORT_SYMBOL(rtnl_sem); +-EXPORT_SYMBOL(rtnl_lock); +-EXPORT_SYMBOL(rtnl_unlock); +- + /* ABI emulation layers need this */ + EXPORT_SYMBOL(move_addr_to_kernel); + EXPORT_SYMBOL(move_addr_to_user); + + /* Used by at least ipip.c. */ + EXPORT_SYMBOL(ipv4_config); +-EXPORT_SYMBOL(dev_open); + + /* Used by other modules */ + EXPORT_SYMBOL(xrlim_allow); +@@ -460,6 +452,14 @@ + + #endif /* CONFIG_INET */ + ++EXPORT_SYMBOL(dev_open); ++EXPORT_SYMBOL(dev_set_allmulti); ++EXPORT_SYMBOL(dev_set_promiscuity); ++EXPORT_SYMBOL(sklist_remove_socket); ++EXPORT_SYMBOL(rtnl_sem); ++EXPORT_SYMBOL(rtnl_lock); ++EXPORT_SYMBOL(rtnl_unlock); ++ + #ifdef CONFIG_TR + EXPORT_SYMBOL(tr_type_trans); + #endif |