aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/obsolete/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/obsolete/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch')
-rw-r--r--recipes/obsolete/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch10239
1 files changed, 10239 insertions, 0 deletions
diff --git a/recipes/obsolete/linux/linux-wrt-2.4.20/2.4.20_broadcom_3_37_2_1109_US.patch b/recipes/obsolete/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/obsolete/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 = (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(&notifier);
++#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(&notifier);
++ 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