-diff -Nur linux-2.4.32/arch/mips/bcm947xx/cfe_env.c linux-2.4.32-brcm/arch/mips/bcm947xx/cfe_env.c
---- linux-2.4.32/arch/mips/bcm947xx/cfe_env.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/cfe_env.c 2005-12-19 01:56:35.104829500 +0100
+diff -Naur linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
+--- linux.old/arch/mips/Makefile 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/Makefile 2006-04-06 15:34:15.000000000 +0200
+@@ -726,6 +726,19 @@
+ endif
+
+ #
++# Broadcom BCM947XX variants
++#
++ifdef CONFIG_BCM947XX
++LIBS += arch/mips/bcm947xx/generic/brcm.o arch/mips/bcm947xx/bcm947xx.o
++SUBDIRS += arch/mips/bcm947xx/generic arch/mips/bcm947xx
++LOADADDR := 0x80001000
++
++zImage: vmlinux
++ $(MAKE) -C arch/$(ARCH)/bcm947xx/compressed
++export LOADADDR
++endif
++
++#
+ # Choosing incompatible machines durings configuration will result in
+ # error messages during linking. Select a default linkscript if
+ # none has been choosen above.
+@@ -778,6 +791,7 @@
+ $(MAKE) -C arch/$(ARCH)/tools clean
+ $(MAKE) -C arch/mips/baget clean
+ $(MAKE) -C arch/mips/lasat clean
++ $(MAKE) -C arch/mips/bcm947xx/compressed clean
+
+ archmrproper:
+ @$(MAKEBOOT) mrproper
+diff -Naur linux.old/arch/mips/bcm947xx/Makefile linux.dev/arch/mips/bcm947xx/Makefile
+--- linux.old/arch/mips/bcm947xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/Makefile 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,15 @@
++#
++# Makefile for the BCM947xx specific kernel interface routines
++# under Linux.
++#
++
++EXTRA_CFLAGS+=-I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER
++
++O_TARGET := bcm947xx.o
++
++export-objs := nvram_linux.o setup.o
++obj-y := prom.o setup.o time.o sbmips.o gpio.o
++obj-y += nvram.o nvram_linux.o sflash.o cfe_env.o
++obj-$(CONFIG_PCI) += sbpci.o pcibios.o
++
++include $(TOPDIR)/Rules.make
+diff -Naur linux.old/arch/mips/bcm947xx/cfe_env.c linux.dev/arch/mips/bcm947xx/cfe_env.c
+--- linux.old/arch/mips/bcm947xx/cfe_env.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/cfe_env.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,234 @@
+/*
+ * NVRAM variable manipulation (Linux kernel half)
+
+}
+
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/compressed/Makefile linux-2.4.32-brcm/arch/mips/bcm947xx/compressed/Makefile
---- linux-2.4.32/arch/mips/bcm947xx/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/compressed/Makefile 2005-12-16 23:39:10.668819500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/compressed/Makefile linux.dev/arch/mips/bcm947xx/compressed/Makefile
+--- linux.old/arch/mips/bcm947xx/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/compressed/Makefile 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,33 @@
+#
+# Makefile for Broadcom BCM947XX boards
+
+clean:
+ rm -f vmlinuz piggy
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/generic/int-handler.S linux-2.4.32-brcm/arch/mips/bcm947xx/generic/int-handler.S
---- linux-2.4.32/arch/mips/bcm947xx/generic/int-handler.S 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/generic/int-handler.S 2005-12-16 23:39:10.668819500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/generic/Makefile linux.dev/arch/mips/bcm947xx/generic/Makefile
+--- linux.old/arch/mips/bcm947xx/generic/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/generic/Makefile 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,15 @@
++#
++# Makefile for the BCM947xx specific kernel interface routines
++# under Linux.
++#
++
++.S.s:
++ $(CPP) $(AFLAGS) $< -o $*.s
++.S.o:
++ $(CC) $(AFLAGS) -c $< -o $*.o
++
++O_TARGET := brcm.o
++
++obj-y := int-handler.o irq.o
++
++include $(TOPDIR)/Rules.make
+diff -Naur linux.old/arch/mips/bcm947xx/generic/int-handler.S linux.dev/arch/mips/bcm947xx/generic/int-handler.S
+--- linux.old/arch/mips/bcm947xx/generic/int-handler.S 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/generic/int-handler.S 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,51 @@
+/*
+ * Generic interrupt handler for Broadcom MIPS boards
+ nop
+
+ END(brcmIRQ)
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/generic/irq.c linux-2.4.32-brcm/arch/mips/bcm947xx/generic/irq.c
---- linux-2.4.32/arch/mips/bcm947xx/generic/irq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/generic/irq.c 2005-12-16 23:39:10.668819500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/generic/irq.c linux.dev/arch/mips/bcm947xx/generic/irq.c
+--- linux.old/arch/mips/bcm947xx/generic/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/generic/irq.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,130 @@
+/*
+ * Generic interrupt control functions for Broadcom MIPS boards
+ breakpoint();
+#endif
+}
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/generic/Makefile linux-2.4.32-brcm/arch/mips/bcm947xx/generic/Makefile
---- linux-2.4.32/arch/mips/bcm947xx/generic/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/generic/Makefile 2005-12-16 23:39:10.668819500 +0100
-@@ -0,0 +1,15 @@
-+#
-+# Makefile for the BCM947xx specific kernel interface routines
-+# under Linux.
-+#
-+
-+.S.s:
-+ $(CPP) $(AFLAGS) $< -o $*.s
-+.S.o:
-+ $(CC) $(AFLAGS) -c $< -o $*.o
-+
-+O_TARGET := brcm.o
-+
-+obj-y := int-handler.o irq.o
-+
-+include $(TOPDIR)/Rules.make
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/gpio.c linux-2.4.32-brcm/arch/mips/bcm947xx/gpio.c
---- linux-2.4.32/arch/mips/bcm947xx/gpio.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/gpio.c 2005-12-16 23:39:10.668819500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/gpio.c linux.dev/arch/mips/bcm947xx/gpio.c
+--- linux.old/arch/mips/bcm947xx/gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/gpio.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,158 @@
+/*
+ * GPIO char driver
+
+module_init(gpio_init);
+module_exit(gpio_exit);
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/bcmdevs.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmdevs.h
---- linux-2.4.32/arch/mips/bcm947xx/include/bcmdevs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmdevs.h 2005-12-16 23:39:10.672819750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/bcmdevs.h linux.dev/arch/mips/bcm947xx/include/bcmdevs.h
+--- linux.old/arch/mips/bcm947xx/include/bcmdevs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmdevs.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,391 @@
+/*
+ * Broadcom device-specific manifest constants.
+#define GPIO_NUMPINS 16
+
+#endif /* _BCMDEVS_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/bcmendian.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmendian.h
---- linux-2.4.32/arch/mips/bcm947xx/include/bcmendian.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmendian.h 2005-12-16 23:39:10.672819750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/bcmendian.h linux.dev/arch/mips/bcm947xx/include/bcmendian.h
+--- linux.old/arch/mips/bcm947xx/include/bcmendian.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmendian.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,152 @@
+/*
+ * local version of endian.h - byte order defines
+)
+
+#endif /* _BCMENDIAN_H_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/bcmnvram.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmnvram.h
---- linux-2.4.32/arch/mips/bcm947xx/include/bcmnvram.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmnvram.h 2005-12-16 23:39:10.700821500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/bcmnvram.h linux.dev/arch/mips/bcm947xx/include/bcmnvram.h
+--- linux.old/arch/mips/bcm947xx/include/bcmnvram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmnvram.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,141 @@
+/*
+ * NVRAM variable manipulation
+#define NVRAM_MAX_PARAM_LEN 64
+
+#endif /* _bcmnvram_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/bcmsrom.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmsrom.h
---- linux-2.4.32/arch/mips/bcm947xx/include/bcmsrom.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmsrom.h 2005-12-16 23:39:10.704821750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/bcmsrom.h linux.dev/arch/mips/bcm947xx/include/bcmsrom.h
+--- linux.old/arch/mips/bcm947xx/include/bcmsrom.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmsrom.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,23 @@
+/*
+ * Misc useful routines to access NIC local SROM/OTP .
+extern int srom_write(uint bus, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf);
+
+#endif /* _bcmsrom_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/bcmutils.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmutils.h
---- linux-2.4.32/arch/mips/bcm947xx/include/bcmutils.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/bcmutils.h 2005-12-16 23:39:10.704821750 +0100
-@@ -0,0 +1,313 @@
+diff -Naur linux.old/arch/mips/bcm947xx/include/bcmutils.h linux.dev/arch/mips/bcm947xx/include/bcmutils.h
+--- linux.old/arch/mips/bcm947xx/include/bcmutils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmutils.h 2006-04-06 17:07:30.000000000 +0200
+@@ -0,0 +1,287 @@
+/*
+ * Misc useful os-independent macros and functions.
+ *
+ } \
+}
+
-+/* generic osl packet queue */
-+struct pktq {
-+ void *head; /* first packet to dequeue */
-+ void *tail; /* last packet to dequeue */
-+ uint len; /* number of queued packets */
-+ uint maxlen; /* maximum number of queued packets */
-+ bool priority; /* enqueue by packet priority */
-+ uint8 prio_map[MAXPRIO+1]; /* user priority to packet enqueue policy map */
-+};
-+#define DEFAULT_QLEN 128
-+
-+#define pktq_len(q) ((q)->len)
-+#define pktq_avail(q) ((q)->maxlen - (q)->len)
-+#define pktq_head(q) ((q)->head)
-+#define pktq_full(q) ((q)->len >= (q)->maxlen)
-+#define _pktq_pri(q, pri) ((q)->prio_map[pri])
-+#define pktq_tailpri(q) ((q)->tail ? _pktq_pri(q, PKTPRIO((q)->tail)) : _pktq_pri(q, 0))
-+
-+/* externs */
-+/* packet */
-+extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf);
-+extern uint pkttotlen(osl_t *osh, void *);
-+extern void pktq_init(struct pktq *q, uint maxlen, const uint8 prio_map[]);
-+extern void pktenq(struct pktq *q, void *p, bool lifo);
-+extern void *pktdeq(struct pktq *q);
-+extern void *pktdeqtail(struct pktq *q);
+/* string */
+extern uint bcm_atoi(char *s);
+extern uchar bcm_toupper(uchar c);
+extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len);
+
+#endif /* _bcmutils_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/hnddma.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/hnddma.h
---- linux-2.4.32/arch/mips/bcm947xx/include/hnddma.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/hnddma.h 2005-12-16 23:39:10.708822000 +0100
-@@ -0,0 +1,71 @@
-+/*
-+ * Generic Broadcom Home Networking Division (HND) DMA engine SW interface
-+ * This supports the following chips: BCM42xx, 44xx, 47xx .
-+ *
-+ * Copyright 2005, 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$
-+ */
-+
-+#ifndef _hnddma_h_
-+#define _hnddma_h_
-+
-+/* export structure */
-+typedef volatile struct {
-+ /* rx error counters */
-+ uint rxgiants; /* rx giant frames */
-+ uint rxnobuf; /* rx out of dma descriptors */
-+ /* tx error counters */
-+ uint txnobuf; /* tx out of dma descriptors */
-+} hnddma_t;
-+
-+#ifndef di_t
-+#define di_t void
-+#endif
-+
-+#ifndef osl_t
-+#define osl_t void
-+#endif
-+
-+/* externs */
-+extern void * dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx,
-+ uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, uint *msg_level);
-+extern void dma_detach(di_t *di);
-+extern void dma_txreset(di_t *di);
-+extern void dma_rxreset(di_t *di);
-+extern void dma_txinit(di_t *di);
-+extern bool dma_txenabled(di_t *di);
-+extern void dma_rxinit(di_t *di);
-+extern void dma_rxenable(di_t *di);
-+extern bool dma_rxenabled(di_t *di);
-+extern void dma_txsuspend(di_t *di);
-+extern void dma_txresume(di_t *di);
-+extern bool dma_txsuspended(di_t *di);
-+extern bool dma_txsuspendedidle(di_t *di);
-+extern bool dma_txstopped(di_t *di);
-+extern bool dma_rxstopped(di_t *di);
-+extern int dma_txfast(di_t *di, void *p, uint32 coreflags);
-+extern void dma_fifoloopbackenable(di_t *di);
-+extern void *dma_rx(di_t *di);
-+extern void dma_rxfill(di_t *di);
-+extern void dma_txreclaim(di_t *di, bool forceall);
-+extern void dma_rxreclaim(di_t *di);
-+extern uintptr dma_getvar(di_t *di, char *name);
-+extern void *dma_getnexttxp(di_t *di, bool forceall);
-+extern void *dma_peeknexttxp(di_t *di);
-+extern void *dma_getnextrxp(di_t *di, bool forceall);
-+extern void dma_txblock(di_t *di);
-+extern void dma_txunblock(di_t *di);
-+extern uint dma_txactive(di_t *di);
-+extern void dma_txrotate(di_t *di);
-+
-+extern void dma_rxpiomode(dma32regs_t *);
-+extern void dma_txpioloopback(dma32regs_t *);
-+
-+
-+#endif /* _hnddma_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/hndmips.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/hndmips.h
---- linux-2.4.32/arch/mips/bcm947xx/include/hndmips.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/hndmips.h 2005-12-16 23:39:10.708822000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/hndmips.h linux.dev/arch/mips/bcm947xx/include/hndmips.h
+--- linux.old/arch/mips/bcm947xx/include/hndmips.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/hndmips.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,16 @@
+/*
+ * Alternate include file for HND sbmips.h since CFE also ships with
+ */
+
+#include "sbmips.h"
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/linux_osl.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/linux_osl.h
---- linux-2.4.32/arch/mips/bcm947xx/include/linux_osl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/linux_osl.h 2005-12-16 23:39:10.708822000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/linux_osl.h linux.dev/arch/mips/bcm947xx/include/linux_osl.h
+--- linux.old/arch/mips/bcm947xx/include/linux_osl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/linux_osl.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,371 @@
+/*
+ * Linux OS Independent Layer
+#define PKTBUFSZ 2048
+
+#endif /* _linux_osl_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/linuxver.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/linuxver.h
---- linux-2.4.32/arch/mips/bcm947xx/include/linuxver.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/linuxver.h 2005-12-16 23:39:10.748824500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/linuxver.h linux.dev/arch/mips/bcm947xx/include/linuxver.h
+--- linux.old/arch/mips/bcm947xx/include/linuxver.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/linuxver.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,411 @@
+/*
+ * Linux-specific abstractions to gain some independence from linux kernel versions.
+#endif
+
+#endif /* _linuxver_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/mipsinc.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/mipsinc.h
---- linux-2.4.32/arch/mips/bcm947xx/include/mipsinc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/mipsinc.h 2005-12-16 23:39:10.748824500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/mipsinc.h linux.dev/arch/mips/bcm947xx/include/mipsinc.h
+--- linux.old/arch/mips/bcm947xx/include/mipsinc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/mipsinc.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,552 @@
+/*
+ * HND Run Time Environment for standalone MIPS programs.
+#endif /* !_LANGUAGE_ASSEMBLY */
+
+#endif /* _MISPINC_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/osl.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/osl.h
---- linux-2.4.32/arch/mips/bcm947xx/include/osl.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/osl.h 2005-12-16 23:39:10.748824500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/osl.h linux.dev/arch/mips/bcm947xx/include/osl.h
+--- linux.old/arch/mips/bcm947xx/include/osl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/osl.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,42 @@
+/*
+ * OS Abstraction Layer
+#define MAXPRIO 7 /* 0-7 */
+
+#endif /* _osl_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/pcicfg.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/pcicfg.h
---- linux-2.4.32/arch/mips/bcm947xx/include/pcicfg.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/pcicfg.h 2005-12-16 23:39:10.752824750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/pcicfg.h linux.dev/arch/mips/bcm947xx/include/pcicfg.h
+--- linux.old/arch/mips/bcm947xx/include/pcicfg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/pcicfg.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,451 @@
+/*
+ * pcicfg.h: PCI configuration constants and structures.
+#define PCI_CFG_CMD_STAT_TA 0x08000000 /* target abort status */
+
+#endif
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbchipc.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbchipc.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbchipc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbchipc.h 2005-12-16 23:39:10.932836000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbchipc.h linux.dev/arch/mips/bcm947xx/include/sbchipc.h
+--- linux.old/arch/mips/bcm947xx/include/sbchipc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbchipc.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,440 @@
+/*
+ * SiliconBackplane Chipcommon core hardware definitions.
+#define OTP_MAGIC 0x4e56
+
+#endif /* _SBCHIPC_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbconfig.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbconfig.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbconfig.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbconfig.h 2005-12-16 23:39:10.932836000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbconfig.h linux.dev/arch/mips/bcm947xx/include/sbconfig.h
+--- linux.old/arch/mips/bcm947xx/include/sbconfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbconfig.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,342 @@
+/*
+ * Broadcom SiliconBackplane hardware register definitions.
+#define BISZ_SIZE 7 /* descriptor size in 32-bit intergers */
+
+#endif /* _SBCONFIG_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbextif.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbextif.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbextif.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbextif.h 2005-12-16 23:39:10.932836000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbextif.h linux.dev/arch/mips/bcm947xx/include/sbextif.h
+--- linux.old/arch/mips/bcm947xx/include/sbextif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbextif.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,242 @@
+/*
+ * Hardware-specific External Interface I/O core definitions
+#define CC_CLOCK_BASE 24000000 /* Half the clock freq. in the 4710 */
+
+#endif /* _SBEXTIF_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbhnddma.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbhnddma.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbhnddma.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbhnddma.h 2005-12-16 23:39:10.932836000 +0100
-@@ -0,0 +1,312 @@
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbmemc.h linux.dev/arch/mips/bcm947xx/include/sbmemc.h
+--- linux.old/arch/mips/bcm947xx/include/sbmemc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbmemc.h 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,148 @@
+/*
-+ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface
-+ * This supports the following chips: BCM42xx, 44xx, 47xx .
++ * BCM47XX Sonics SiliconBackplane DDR/SDRAM controller core hardware definitions.
+ *
+ * Copyright 2005, Broadcom Corporation
+ * All Rights Reserved.
+ * 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$
+ */
+
-+#ifndef _sbhnddma_h_
-+#define _sbhnddma_h_
++#ifndef _SBMEMC_H
++#define _SBMEMC_H
+
-+
-+/* 2byte-wide pio register set per channel(xmt or rcv) */
-+typedef volatile struct {
-+ uint16 fifocontrol;
-+ uint16 fifodata;
-+ uint16 fifofree; /* only valid in xmt channel, not in rcv channel */
-+ uint16 PAD;
-+} pio2regs_t;
++#ifdef _LANGUAGE_ASSEMBLY
+
-+/* a pair of pio channels(tx and rx) */
-+typedef volatile struct {
-+ pio2regs_t tx;
-+ pio2regs_t rx;
-+} pio2regp_t;
++#define MEMC_CONTROL 0x00
++#define MEMC_CONFIG 0x04
++#define MEMC_REFRESH 0x08
++#define MEMC_BISTSTAT 0x0c
++#define MEMC_MODEBUF 0x10
++#define MEMC_BKCLS 0x14
++#define MEMC_PRIORINV 0x18
++#define MEMC_DRAMTIM 0x1c
++#define MEMC_INTSTAT 0x20
++#define MEMC_INTMASK 0x24
++#define MEMC_INTINFO 0x28
++#define MEMC_NCDLCTL 0x30
++#define MEMC_RDNCDLCOR 0x34
++#define MEMC_WRNCDLCOR 0x38
++#define MEMC_MISCDLYCTL 0x3c
++#define MEMC_DQSGATENCDL 0x40
++#define MEMC_SPARE 0x44
++#define MEMC_TPADDR 0x48
++#define MEMC_TPDATA 0x4c
++#define MEMC_BARRIER 0x50
++#define MEMC_CORE 0x54
+
-+/* 4byte-wide pio register set per channel(xmt or rcv) */
-+typedef volatile struct {
-+ uint32 fifocontrol;
-+ uint32 fifodata;
-+} pio4regs_t;
+
-+/* a pair of pio channels(tx and rx) */
-+typedef volatile struct {
-+ pio4regs_t tx;
-+ pio4regs_t rx;
-+} pio4regp_t;
++#else
+
++/* Sonics side: MEMC core registers */
++typedef volatile struct sbmemcregs {
++ uint32 control;
++ uint32 config;
++ uint32 refresh;
++ uint32 biststat;
++ uint32 modebuf;
++ uint32 bkcls;
++ uint32 priorinv;
++ uint32 dramtim;
++ uint32 intstat;
++ uint32 intmask;
++ uint32 intinfo;
++ uint32 reserved1;
++ uint32 ncdlctl;
++ uint32 rdncdlcor;
++ uint32 wrncdlcor;
++ uint32 miscdlyctl;
++ uint32 dqsgatencdl;
++ uint32 spare;
++ uint32 tpaddr;
++ uint32 tpdata;
++ uint32 barrier;
++ uint32 core;
++} sbmemcregs_t;
+
++#endif
+
-+/* DMA structure:
-+ * support two DMA engines: 32 bits address or 64 bit addressing
-+ * basic DMA register set is per channel(transmit or receive)
-+ * a pair of channels is defined for convenience
-+ */
++/* MEMC Core Init values (OCP ID 0x80f) */
+
++/* For sdr: */
++#define MEMC_SD_CONFIG_INIT 0x00048000
++#define MEMC_SD_DRAMTIM2_INIT 0x000754d8
++#define MEMC_SD_DRAMTIM3_INIT 0x000754da
++#define MEMC_SD_RDNCDLCOR_INIT 0x00000000
++#define MEMC_SD_WRNCDLCOR_INIT 0x49351200
++#define MEMC_SD1_WRNCDLCOR_INIT 0x14500200 /* For corerev 1 (4712) */
++#define MEMC_SD_MISCDLYCTL_INIT 0x00061c1b
++#define MEMC_SD1_MISCDLYCTL_INIT 0x00021416 /* For corerev 1 (4712) */
++#define MEMC_SD_CONTROL_INIT0 0x00000002
++#define MEMC_SD_CONTROL_INIT1 0x00000008
++#define MEMC_SD_CONTROL_INIT2 0x00000004
++#define MEMC_SD_CONTROL_INIT3 0x00000010
++#define MEMC_SD_CONTROL_INIT4 0x00000001
++#define MEMC_SD_MODEBUF_INIT 0x00000000
++#define MEMC_SD_REFRESH_INIT 0x0000840f
+
-+/*** 32 bits addressing ***/
+
-+/* dma registers per channel(xmt or rcv) */
-+typedef volatile struct {
-+ uint32 control; /* enable, et al */
-+ uint32 addr; /* descriptor ring base address (4K aligned) */
-+ uint32 ptr; /* last descriptor posted to chip */
-+ uint32 status; /* current active descriptor, et al */
-+} dma32regs_t;
++/* This is for SDRM8X8X4 */
++#define MEMC_SDR_INIT 0x0008
++#define MEMC_SDR_MODE 0x32
++#define MEMC_SDR_NCDL 0x00020032
++#define MEMC_SDR1_NCDL 0x0002020f /* For corerev 1 (4712) */
+
-+typedef volatile struct {
-+ dma32regs_t xmt; /* dma tx channel */
-+ dma32regs_t rcv; /* dma rx channel */
-+} dma32regp_t;
++/* For ddr: */
++#define MEMC_CONFIG_INIT 0x00048000
++#define MEMC_DRAMTIM2_INIT 0x000754d8
++#define MEMC_DRAMTIM25_INIT 0x000754d9
++#define MEMC_RDNCDLCOR_INIT 0x00000000
++#define MEMC_RDNCDLCOR_SIMINIT 0xf6f6f6f6 /* For hdl sim */
++#define MEMC_WRNCDLCOR_INIT 0x49351200
++#define MEMC_1_WRNCDLCOR_INIT 0x14500200
++#define MEMC_DQSGATENCDL_INIT 0x00030000
++#define MEMC_MISCDLYCTL_INIT 0x21061c1b
++#define MEMC_1_MISCDLYCTL_INIT 0x21021400
++#define MEMC_NCDLCTL_INIT 0x00002001
++#define MEMC_CONTROL_INIT0 0x00000002
++#define MEMC_CONTROL_INIT1 0x00000008
++#define MEMC_MODEBUF_INIT0 0x00004000
++#define MEMC_CONTROL_INIT2 0x00000010
++#define MEMC_MODEBUF_INIT1 0x00000100
++#define MEMC_CONTROL_INIT3 0x00000010
++#define MEMC_CONTROL_INIT4 0x00000008
++#define MEMC_REFRESH_INIT 0x0000840f
++#define MEMC_CONTROL_INIT5 0x00000004
++#define MEMC_MODEBUF_INIT2 0x00000000
++#define MEMC_CONTROL_INIT6 0x00000010
++#define MEMC_CONTROL_INIT7 0x00000001
+
-+typedef volatile struct { /* diag access */
-+ uint32 fifoaddr; /* diag address */
-+ uint32 fifodatalow; /* low 32bits of data */
-+ uint32 fifodatahigh; /* high 32bits of data */
-+ uint32 pad; /* reserved */
-+} dma32diag_t;
+
-+/*
-+ * DMA Descriptor
-+ * Descriptors are only read by the hardware, never written back.
-+ */
-+typedef volatile struct {
-+ uint32 ctrl; /* misc control bits & bufcount */
-+ uint32 addr; /* data buffer address */
-+} dma32dd_t;
++/* This is for DDRM16X16X2 */
++#define MEMC_DDR_INIT 0x0009
++#define MEMC_DDR_MODE 0x62
++#define MEMC_DDR_NCDL 0x0005050a
++#define MEMC_DDR1_NCDL 0x00000a0a /* For corerev 1 (4712) */
+
-+/*
-+ * Each descriptor ring must be 4096byte aligned, and fit within a single 4096byte page.
-+ */
-+#define D32MAXRINGSZ 4096
-+#define D32RINGALIGN 4096
-+#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t))
++/* mask for sdr/ddr calibration registers */
++#define MEMC_RDNCDLCOR_RD_MASK 0x000000ff
++#define MEMC_WRNCDLCOR_WR_MASK 0x000000ff
++#define MEMC_DQSGATENCDL_G_MASK 0x000000ff
+
-+/* transmit channel control */
-+#define XC_XE ((uint32)1 << 0) /* transmit enable */
-+#define XC_SE ((uint32)1 << 1) /* transmit suspend request */
-+#define XC_LE ((uint32)1 << 2) /* loopback enable */
-+#define XC_FL ((uint32)1 << 4) /* flush request */
-+#define XC_AE ((uint32)3 << 16) /* address extension bits */
-+#define XC_AE_SHIFT 16
++/* masks for miscdlyctl registers */
++#define MEMC_MISC_SM_MASK 0x30000000
++#define MEMC_MISC_SM_SHIFT 28
++#define MEMC_MISC_SD_MASK 0x0f000000
++#define MEMC_MISC_SD_SHIFT 24
+
-+/* transmit descriptor table pointer */
-+#define XP_LD_MASK 0xfff /* last valid descriptor */
++/* hw threshhold for calculating wr/rd for sdr memc */
++#define MEMC_CD_THRESHOLD 128
+
-+/* transmit channel status */
-+#define XS_CD_MASK 0x0fff /* current descriptor pointer */
-+#define XS_XS_MASK 0xf000 /* transmit state */
-+#define XS_XS_SHIFT 12
-+#define XS_XS_DISABLED 0x0000 /* disabled */
-+#define XS_XS_ACTIVE 0x1000 /* active */
-+#define XS_XS_IDLE 0x2000 /* idle wait */
-+#define XS_XS_STOPPED 0x3000 /* stopped */
-+#define XS_XS_SUSP 0x4000 /* suspend pending */
-+#define XS_XE_MASK 0xf0000 /* transmit errors */
-+#define XS_XE_SHIFT 16
-+#define XS_XE_NOERR 0x00000 /* no error */
-+#define XS_XE_DPE 0x10000 /* descriptor protocol error */
-+#define XS_XE_DFU 0x20000 /* data fifo underrun */
-+#define XS_XE_BEBR 0x30000 /* bus error on buffer read */
-+#define XS_XE_BEDA 0x40000 /* bus error on descriptor access */
-+#define XS_AD_MASK 0xfff00000 /* active descriptor */
-+#define XS_AD_SHIFT 20
++/* Low bit of init register says if memc is ddr or sdr */
++#define MEMC_CONFIG_DDR 0x00000001
+
-+/* receive channel control */
-+#define RC_RE ((uint32)1 << 0) /* receive enable */
-+#define RC_RO_MASK 0xfe /* receive frame offset */
-+#define RC_RO_SHIFT 1
-+#define RC_FM ((uint32)1 << 8) /* direct fifo receive (pio) mode */
-+#define RC_AE ((uint32)3 << 16) /* address extension bits */
-+#define RC_AE_SHIFT 16
++#endif /* _SBMEMC_H */
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbmips.h linux.dev/arch/mips/bcm947xx/include/sbmips.h
+--- linux.old/arch/mips/bcm947xx/include/sbmips.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbmips.h 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,62 @@
++/*
++ * Broadcom SiliconBackplane MIPS definitions
++ *
++ * SB MIPS cores are custom MIPS32 processors with SiliconBackplane
++ * OCP interfaces. The CP0 processor ID is 0x00024000, where bits
++ * 23:16 mean Broadcom and bits 15:8 mean a MIPS core with an OCP
++ * interface. The core revision is stored in the SB ID register in SB
++ * configuration space.
++ *
++ * Copyright 2005, 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$
++ */
+
-+/* receive descriptor table pointer */
-+#define RP_LD_MASK 0xfff /* last valid descriptor */
++#ifndef _SBMIPS_H
++#define _SBMIPS_H
+
-+/* receive channel status */
-+#define RS_CD_MASK 0x0fff /* current descriptor pointer */
-+#define RS_RS_MASK 0xf000 /* receive state */
-+#define RS_RS_SHIFT 12
-+#define RS_RS_DISABLED 0x0000 /* disabled */
-+#define RS_RS_ACTIVE 0x1000 /* active */
-+#define RS_RS_IDLE 0x2000 /* idle wait */
-+#define RS_RS_STOPPED 0x3000 /* reserved */
-+#define RS_RE_MASK 0xf0000 /* receive errors */
-+#define RS_RE_SHIFT 16
-+#define RS_RE_NOERR 0x00000 /* no error */
-+#define RS_RE_DPE 0x10000 /* descriptor protocol error */
-+#define RS_RE_DFO 0x20000 /* data fifo overflow */
-+#define RS_RE_BEBW 0x30000 /* bus error on buffer write */
-+#define RS_RE_BEDA 0x40000 /* bus error on descriptor access */
-+#define RS_AD_MASK 0xfff00000 /* active descriptor */
-+#define RS_AD_SHIFT 20
++#include <mipsinc.h>
+
-+/* fifoaddr */
-+#define FA_OFF_MASK 0xffff /* offset */
-+#define FA_SEL_MASK 0xf0000 /* select */
-+#define FA_SEL_SHIFT 16
-+#define FA_SEL_XDD 0x00000 /* transmit dma data */
-+#define FA_SEL_XDP 0x10000 /* transmit dma pointers */
-+#define FA_SEL_RDD 0x40000 /* receive dma data */
-+#define FA_SEL_RDP 0x50000 /* receive dma pointers */
-+#define FA_SEL_XFD 0x80000 /* transmit fifo data */
-+#define FA_SEL_XFP 0x90000 /* transmit fifo pointers */
-+#define FA_SEL_RFD 0xc0000 /* receive fifo data */
-+#define FA_SEL_RFP 0xd0000 /* receive fifo pointers */
-+#define FA_SEL_RSD 0xe0000 /* receive frame status data */
-+#define FA_SEL_RSP 0xf0000 /* receive frame status pointers */
++#ifndef _LANGUAGE_ASSEMBLY
+
-+/* descriptor control flags */
-+#define CTRL_BC_MASK 0x1fff /* buffer byte count */
-+#define CTRL_AE ((uint32)3 << 16) /* address extension bits */
-+#define CTRL_AE_SHIFT 16
-+#define CTRL_EOT ((uint32)1 << 28) /* end of descriptor table */
-+#define CTRL_IOC ((uint32)1 << 29) /* interrupt on completion */
-+#define CTRL_EOF ((uint32)1 << 30) /* end of frame */
-+#define CTRL_SOF ((uint32)1 << 31) /* start of frame */
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
+
-+/* control flags in the range [27:20] are core-specific and not defined here */
-+#define CTRL_CORE_MASK 0x0ff00000
++typedef volatile struct {
++ uint32 corecontrol;
++ uint32 PAD[2];
++ uint32 biststatus;
++ uint32 PAD[4];
++ uint32 intstatus;
++ uint32 intmask;
++ uint32 timer;
++} mipsregs_t;
+
-+/*** 64 bits addressing ***/
++extern uint32 sb_flag(sb_t *sbh);
++extern uint sb_irq(sb_t *sbh);
+
-+/* dma registers per channel(xmt or rcv) */
-+typedef volatile struct {
-+ uint32 control; /* enable, et al */
-+ uint32 ptr; /* last descriptor posted to chip */
-+ uint32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */
-+ uint32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */
-+ uint32 status0; /* current descriptor, xmt state */
-+ uint32 status1; /* active descriptor, xmt error */
-+} dma64regs_t;
++extern void BCMINIT(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift));
+
-+typedef volatile struct {
-+ dma64regs_t tx; /* dma64 tx channel */
-+ dma64regs_t rx; /* dma64 rx channel */
-+} dma64regp_t;
++extern void *sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap);
++extern void sb_jtagm_disable(void *h);
++extern uint32 jtag_rwreg(void *h, uint32 ir, uint32 dr);
++extern void BCMINIT(sb_mips_init)(sb_t *sbh);
++extern uint32 BCMINIT(sb_mips_clock)(sb_t *sbh);
++extern bool BCMINIT(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock);
++extern void BCMINIT(enable_pfc)(uint32 mode);
++extern uint32 BCMINIT(sb_memc_get_ncdl)(sb_t *sbh);
+
-+typedef volatile struct { /* diag access */
-+ uint32 fifoaddr; /* diag address */
-+ uint32 fifodatalow; /* low 32bits of data */
-+ uint32 fifodatahigh; /* high 32bits of data */
-+ uint32 pad; /* reserved */
-+} dma64diag_t;
+
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#endif /* _SBMIPS_H */
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbpci.h linux.dev/arch/mips/bcm947xx/include/sbpci.h
+--- linux.old/arch/mips/bcm947xx/include/sbpci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbpci.h 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,122 @@
+/*
-+ * DMA Descriptor
-+ * Descriptors are only read by the hardware, never written back.
-+ */
-+typedef volatile struct {
-+ uint32 ctrl1; /* misc control bits & bufcount */
-+ uint32 ctrl2; /* buffer count and address extension */
-+ uint32 addrlow; /* memory address of the first byte of the date buffer, bits 31:0 */
-+ uint32 addrhigh; /* memory address of the first byte of the date buffer, bits 63:32 */
-+} dma64dd_t;
-+
-+/*
-+ * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical addresss.
++ * BCM47XX Sonics SiliconBackplane PCI core hardware definitions.
++ *
++ * $Id$
++ * Copyright 2005, 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.
+ */
-+#define D64MAXRINGSZ 8192
-+#define D64RINGALIGN 8192
-+#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t))
+
-+/* transmit channel control */
-+#define D64_XC_XE 0x00000001 /* transmit enable */
-+#define D64_XC_SE 0x00000002 /* transmit suspend request */
-+#define D64_XC_LE 0x00000004 /* loopback enable */
-+#define D64_XC_FL 0x00000010 /* flush request */
-+#define D64_XC_AE 0x00110000 /* address extension bits */
-+#define D64_XC_AE_SHIFT 16
++#ifndef _SBPCI_H
++#define _SBPCI_H
+
-+/* transmit descriptor table pointer */
-+#define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
+
-+/* transmit channel status */
-+#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */
-+#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */
-+#define D64_XS0_XS_SHIFT 28
-+#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */
-+#define D64_XS0_XS_ACTIVE 0x10000000 /* active */
-+#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */
-+#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */
-+#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */
++/* Sonics side: PCI core and host control registers */
++typedef struct sbpciregs {
++ uint32 control; /* PCI control */
++ uint32 PAD[3];
++ uint32 arbcontrol; /* PCI arbiter control */
++ uint32 PAD[3];
++ uint32 intstatus; /* Interrupt status */
++ uint32 intmask; /* Interrupt mask */
++ uint32 sbtopcimailbox; /* Sonics to PCI mailbox */
++ uint32 PAD[9];
++ uint32 bcastaddr; /* Sonics broadcast address */
++ uint32 bcastdata; /* Sonics broadcast data */
++ uint32 PAD[2];
++ uint32 gpioin; /* ro: gpio input (>=rev2) */
++ uint32 gpioout; /* rw: gpio output (>=rev2) */
++ uint32 gpioouten; /* rw: gpio output enable (>= rev2) */
++ uint32 gpiocontrol; /* rw: gpio control (>= rev2) */
++ uint32 PAD[36];
++ uint32 sbtopci0; /* Sonics to PCI translation 0 */
++ uint32 sbtopci1; /* Sonics to PCI translation 1 */
++ uint32 sbtopci2; /* Sonics to PCI translation 2 */
++ uint32 PAD[445];
++ uint16 sprom[36]; /* SPROM shadow Area */
++ uint32 PAD[46];
++} sbpciregs_t;
+
-+#define D64_XS1_AD_MASK 0x0001ffff /* active descriptor */
-+#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */
-+#define D64_XS1_XE_SHIFT 28
-+#define D64_XS1_XE_NOERR 0x00000000 /* no error */
-+#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */
-+#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */
-+#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */
-+#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */
-+#define D64_XS1_XE_COREE 0x50000000 /* core error */
++/* PCI control */
++#define PCI_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */
++#define PCI_RST 0x02 /* Value driven out to pin */
++#define PCI_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */
++#define PCI_CLK 0x08 /* Gate for clock driven out to pin */
+
-+/* receive channel control */
-+#define D64_RC_RE 0x00000001 /* receive enable */
-+#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */
-+#define D64_RC_RO_SHIFT 1
-+#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */
-+#define D64_RC_AE 0x00110000 /* address extension bits */
-+#define D64_RC_AE_SHIFT 16
++/* PCI arbiter control */
++#define PCI_INT_ARB 0x01 /* When set, use an internal arbiter */
++#define PCI_EXT_ARB 0x02 /* When set, use an external arbiter */
++#define PCI_PARKID_MASK 0x06 /* Selects which agent is parked on an idle bus */
++#define PCI_PARKID_SHIFT 1
++#define PCI_PARKID_LAST 0 /* Last requestor */
++#define PCI_PARKID_4710 1 /* 4710 */
++#define PCI_PARKID_EXTREQ0 2 /* External requestor 0 */
++#define PCI_PARKID_EXTREQ1 3 /* External requestor 1 */
+
-+/* receive descriptor table pointer */
-+#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */
++/* Interrupt status/mask */
++#define PCI_INTA 0x01 /* PCI INTA# is asserted */
++#define PCI_INTB 0x02 /* PCI INTB# is asserted */
++#define PCI_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */
++#define PCI_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */
++#define PCI_PME 0x10 /* PCI PME# is asserted */
+
-+/* receive channel status */
-+#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */
-+#define D64_RS0_RS_MASK 0xf0000000 /* receive state */
-+#define D64_RS0_RS_SHIFT 28
-+#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */
-+#define D64_RS0_RS_ACTIVE 0x10000000 /* active */
-+#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */
-+#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */
-+#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */
++/* (General) PCI/SB mailbox interrupts, two bits per pci function */
++#define MAILBOX_F0_0 0x100 /* function 0, int 0 */
++#define MAILBOX_F0_1 0x200 /* function 0, int 1 */
++#define MAILBOX_F1_0 0x400 /* function 1, int 0 */
++#define MAILBOX_F1_1 0x800 /* function 1, int 1 */
++#define MAILBOX_F2_0 0x1000 /* function 2, int 0 */
++#define MAILBOX_F2_1 0x2000 /* function 2, int 1 */
++#define MAILBOX_F3_0 0x4000 /* function 3, int 0 */
++#define MAILBOX_F3_1 0x8000 /* function 3, int 1 */
+
-+#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */
-+#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */
-+#define D64_RS1_RE_SHIFT 28
-+#define D64_RS1_RE_NOERR 0x00000000 /* no error */
-+#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */
-+#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */
-+#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */
-+#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */
-+#define D64_RS1_RE_COREE 0x50000000 /* core error */
++/* Sonics broadcast address */
++#define BCAST_ADDR_MASK 0xff /* Broadcast register address */
+
-+/* fifoaddr */
-+#define D64_FA_OFF_MASK 0xffff /* offset */
-+#define D64_FA_SEL_MASK 0xf0000 /* select */
-+#define D64_FA_SEL_SHIFT 16
-+#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */
-+#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */
-+#define D64_FA_SEL_RDD 0x40000 /* receive dma data */
-+#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */
-+#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */
-+#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */
-+#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */
-+#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */
-+#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */
-+#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */
++/* Sonics to PCI translation types */
++#define SBTOPCI0_MASK 0xfc000000
++#define SBTOPCI1_MASK 0xfc000000
++#define SBTOPCI2_MASK 0xc0000000
++#define SBTOPCI_MEM 0
++#define SBTOPCI_IO 1
++#define SBTOPCI_CFG0 2
++#define SBTOPCI_CFG1 3
++#define SBTOPCI_PREF 0x4 /* prefetch enable */
++#define SBTOPCI_BURST 0x8 /* burst enable */
++#define SBTOPCI_RC_MASK 0x30 /* read command (>= rev11) */
++#define SBTOPCI_RC_READ 0x00 /* memory read */
++#define SBTOPCI_RC_READLINE 0x10 /* memory read line */
++#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
+
-+/* descriptor control flags 1 */
-+#define D64_CTRL1_EOT ((uint32)1 << 28) /* end of descriptor table */
-+#define D64_CTRL1_IOC ((uint32)1 << 29) /* interrupt on completion */
-+#define D64_CTRL1_EOF ((uint32)1 << 30) /* end of frame */
-+#define D64_CTRL1_SOF ((uint32)1 << 31) /* start of frame */
++/* PCI core index in SROM shadow area */
++#define SRSH_PI_OFFSET 0 /* first word */
++#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
++#define SRSH_PI_SHIFT 12 /* bit 15:12 */
+
-+/* descriptor control flags 2 */
-+#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count mask */
-+#define D64_CTRL2_AE 0x00110000 /* address extension bits */
-+#define D64_CTRL2_AE_SHIFT 16
++/* PCI side: Reserved PCI configuration registers (see pcicfg.h) */
++#define cap_list rsvd_a[0]
++#define bar0_window dev_dep[0x80 - 0x40]
++#define bar1_window dev_dep[0x84 - 0x40]
++#define sprom_control dev_dep[0x88 - 0x40]
+
-+/* control flags in the range [27:20] are core-specific and not defined here */
-+#define D64_CTRL_CORE_MASK 0x0ff00000
++#ifndef _LANGUAGE_ASSEMBLY
++
++extern int sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
++extern int sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
++extern void sbpci_ban(uint16 core);
++extern int sbpci_init(sb_t *sbh);
++extern void sbpci_check(sb_t *sbh);
+
++#endif /* !_LANGUAGE_ASSEMBLY */
+
-+#endif /* _sbhnddma_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbmemc.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbmemc.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbmemc.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbmemc.h 2005-12-16 23:39:10.932836000 +0100
-@@ -0,0 +1,148 @@
++#endif /* _SBPCI_H */
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbpcie.h linux.dev/arch/mips/bcm947xx/include/sbpcie.h
+--- linux.old/arch/mips/bcm947xx/include/sbpcie.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbpcie.h 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,199 @@
+/*
-+ * BCM47XX Sonics SiliconBackplane DDR/SDRAM controller core hardware definitions.
++ * BCM43XX SiliconBackplane PCIE core hardware definitions.
+ *
++ * $Id:
+ * Copyright 2005, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * 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$
+ */
+
-+#ifndef _SBMEMC_H
-+#define _SBMEMC_H
++#ifndef _SBPCIE_H
++#define _SBPCIE_H
+
-+#ifdef _LANGUAGE_ASSEMBLY
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
+
-+#define MEMC_CONTROL 0x00
-+#define MEMC_CONFIG 0x04
-+#define MEMC_REFRESH 0x08
-+#define MEMC_BISTSTAT 0x0c
-+#define MEMC_MODEBUF 0x10
-+#define MEMC_BKCLS 0x14
-+#define MEMC_PRIORINV 0x18
-+#define MEMC_DRAMTIM 0x1c
-+#define MEMC_INTSTAT 0x20
-+#define MEMC_INTMASK 0x24
-+#define MEMC_INTINFO 0x28
-+#define MEMC_NCDLCTL 0x30
-+#define MEMC_RDNCDLCOR 0x34
-+#define MEMC_WRNCDLCOR 0x38
-+#define MEMC_MISCDLYCTL 0x3c
-+#define MEMC_DQSGATENCDL 0x40
-+#define MEMC_SPARE 0x44
-+#define MEMC_TPADDR 0x48
-+#define MEMC_TPDATA 0x4c
-+#define MEMC_BARRIER 0x50
-+#define MEMC_CORE 0x54
++/* PCIE Enumeration space offsets*/
++#define PCIE_CORE_CONFIG_OFFSET 0x0
++#define PCIE_FUNC0_CONFIG_OFFSET 0x400
++#define PCIE_FUNC1_CONFIG_OFFSET 0x500
++#define PCIE_FUNC2_CONFIG_OFFSET 0x600
++#define PCIE_FUNC3_CONFIG_OFFSET 0x700
++#define PCIE_SPROM_SHADOW_OFFSET 0x800
++#define PCIE_SBCONFIG_OFFSET 0xE00
+
++/* PCIE Bar0 Address Mapping. Each function maps 16KB config space */
++#define PCIE_BAR0_WINMAPCORE_OFFSET 0x0
++#define PCIE_BAR0_EXTSPROM_OFFSET 0x1000
++#define PCIE_BAR0_PCIECORE_OFFSET 0x2000
++#define PCIE_BAR0_CCCOREREG_OFFSET 0x3000
+
-+#else
-+
-+/* Sonics side: MEMC core registers */
-+typedef volatile struct sbmemcregs {
-+ uint32 control;
-+ uint32 config;
-+ uint32 refresh;
-+ uint32 biststat;
-+ uint32 modebuf;
-+ uint32 bkcls;
-+ uint32 priorinv;
-+ uint32 dramtim;
-+ uint32 intstat;
-+ uint32 intmask;
-+ uint32 intinfo;
-+ uint32 reserved1;
-+ uint32 ncdlctl;
-+ uint32 rdncdlcor;
-+ uint32 wrncdlcor;
-+ uint32 miscdlyctl;
-+ uint32 dqsgatencdl;
-+ uint32 spare;
-+ uint32 tpaddr;
-+ uint32 tpdata;
-+ uint32 barrier;
-+ uint32 core;
-+} sbmemcregs_t;
-+
-+#endif
-+
-+/* MEMC Core Init values (OCP ID 0x80f) */
-+
-+/* For sdr: */
-+#define MEMC_SD_CONFIG_INIT 0x00048000
-+#define MEMC_SD_DRAMTIM2_INIT 0x000754d8
-+#define MEMC_SD_DRAMTIM3_INIT 0x000754da
-+#define MEMC_SD_RDNCDLCOR_INIT 0x00000000
-+#define MEMC_SD_WRNCDLCOR_INIT 0x49351200
-+#define MEMC_SD1_WRNCDLCOR_INIT 0x14500200 /* For corerev 1 (4712) */
-+#define MEMC_SD_MISCDLYCTL_INIT 0x00061c1b
-+#define MEMC_SD1_MISCDLYCTL_INIT 0x00021416 /* For corerev 1 (4712) */
-+#define MEMC_SD_CONTROL_INIT0 0x00000002
-+#define MEMC_SD_CONTROL_INIT1 0x00000008
-+#define MEMC_SD_CONTROL_INIT2 0x00000004
-+#define MEMC_SD_CONTROL_INIT3 0x00000010
-+#define MEMC_SD_CONTROL_INIT4 0x00000001
-+#define MEMC_SD_MODEBUF_INIT 0x00000000
-+#define MEMC_SD_REFRESH_INIT 0x0000840f
-+
-+
-+/* This is for SDRM8X8X4 */
-+#define MEMC_SDR_INIT 0x0008
-+#define MEMC_SDR_MODE 0x32
-+#define MEMC_SDR_NCDL 0x00020032
-+#define MEMC_SDR1_NCDL 0x0002020f /* For corerev 1 (4712) */
-+
-+/* For ddr: */
-+#define MEMC_CONFIG_INIT 0x00048000
-+#define MEMC_DRAMTIM2_INIT 0x000754d8
-+#define MEMC_DRAMTIM25_INIT 0x000754d9
-+#define MEMC_RDNCDLCOR_INIT 0x00000000
-+#define MEMC_RDNCDLCOR_SIMINIT 0xf6f6f6f6 /* For hdl sim */
-+#define MEMC_WRNCDLCOR_INIT 0x49351200
-+#define MEMC_1_WRNCDLCOR_INIT 0x14500200
-+#define MEMC_DQSGATENCDL_INIT 0x00030000
-+#define MEMC_MISCDLYCTL_INIT 0x21061c1b
-+#define MEMC_1_MISCDLYCTL_INIT 0x21021400
-+#define MEMC_NCDLCTL_INIT 0x00002001
-+#define MEMC_CONTROL_INIT0 0x00000002
-+#define MEMC_CONTROL_INIT1 0x00000008
-+#define MEMC_MODEBUF_INIT0 0x00004000
-+#define MEMC_CONTROL_INIT2 0x00000010
-+#define MEMC_MODEBUF_INIT1 0x00000100
-+#define MEMC_CONTROL_INIT3 0x00000010
-+#define MEMC_CONTROL_INIT4 0x00000008
-+#define MEMC_REFRESH_INIT 0x0000840f
-+#define MEMC_CONTROL_INIT5 0x00000004
-+#define MEMC_MODEBUF_INIT2 0x00000000
-+#define MEMC_CONTROL_INIT6 0x00000010
-+#define MEMC_CONTROL_INIT7 0x00000001
-+
-+
-+/* This is for DDRM16X16X2 */
-+#define MEMC_DDR_INIT 0x0009
-+#define MEMC_DDR_MODE 0x62
-+#define MEMC_DDR_NCDL 0x0005050a
-+#define MEMC_DDR1_NCDL 0x00000a0a /* For corerev 1 (4712) */
-+
-+/* mask for sdr/ddr calibration registers */
-+#define MEMC_RDNCDLCOR_RD_MASK 0x000000ff
-+#define MEMC_WRNCDLCOR_WR_MASK 0x000000ff
-+#define MEMC_DQSGATENCDL_G_MASK 0x000000ff
-+
-+/* masks for miscdlyctl registers */
-+#define MEMC_MISC_SM_MASK 0x30000000
-+#define MEMC_MISC_SM_SHIFT 28
-+#define MEMC_MISC_SD_MASK 0x0f000000
-+#define MEMC_MISC_SD_SHIFT 24
-+
-+/* hw threshhold for calculating wr/rd for sdr memc */
-+#define MEMC_CD_THRESHOLD 128
-+
-+/* Low bit of init register says if memc is ddr or sdr */
-+#define MEMC_CONFIG_DDR 0x00000001
-+
-+#endif /* _SBMEMC_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbmips.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbmips.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbmips.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbmips.h 2005-12-16 23:39:10.936836250 +0100
-@@ -0,0 +1,62 @@
-+/*
-+ * Broadcom SiliconBackplane MIPS definitions
-+ *
-+ * SB MIPS cores are custom MIPS32 processors with SiliconBackplane
-+ * OCP interfaces. The CP0 processor ID is 0x00024000, where bits
-+ * 23:16 mean Broadcom and bits 15:8 mean a MIPS core with an OCP
-+ * interface. The core revision is stored in the SB ID register in SB
-+ * configuration space.
-+ *
-+ * Copyright 2005, 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$
-+ */
-+
-+#ifndef _SBMIPS_H
-+#define _SBMIPS_H
-+
-+#include <mipsinc.h>
-+
-+#ifndef _LANGUAGE_ASSEMBLY
-+
-+/* cpp contortions to concatenate w/arg prescan */
-+#ifndef PAD
-+#define _PADLINE(line) pad ## line
-+#define _XSTR(line) _PADLINE(line)
-+#define PAD _XSTR(__LINE__)
-+#endif /* PAD */
-+
-+typedef volatile struct {
-+ uint32 corecontrol;
-+ uint32 PAD[2];
-+ uint32 biststatus;
-+ uint32 PAD[4];
-+ uint32 intstatus;
-+ uint32 intmask;
-+ uint32 timer;
-+} mipsregs_t;
-+
-+extern uint32 sb_flag(sb_t *sbh);
-+extern uint sb_irq(sb_t *sbh);
-+
-+extern void BCMINIT(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift));
-+
-+extern void *sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap);
-+extern void sb_jtagm_disable(void *h);
-+extern uint32 jtag_rwreg(void *h, uint32 ir, uint32 dr);
-+extern void BCMINIT(sb_mips_init)(sb_t *sbh);
-+extern uint32 BCMINIT(sb_mips_clock)(sb_t *sbh);
-+extern bool BCMINIT(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock);
-+extern void BCMINIT(enable_pfc)(uint32 mode);
-+extern uint32 BCMINIT(sb_memc_get_ncdl)(sb_t *sbh);
-+
-+
-+#endif /* _LANGUAGE_ASSEMBLY */
-+
-+#endif /* _SBMIPS_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbpcie.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbpcie.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbpcie.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbpcie.h 2005-12-16 23:39:10.936836250 +0100
-@@ -0,0 +1,199 @@
-+/*
-+ * BCM43XX SiliconBackplane PCIE core hardware definitions.
-+ *
-+ * $Id:
-+ * Copyright 2005, 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.
-+ */
-+
-+#ifndef _SBPCIE_H
-+#define _SBPCIE_H
-+
-+/* cpp contortions to concatenate w/arg prescan */
-+#ifndef PAD
-+#define _PADLINE(line) pad ## line
-+#define _XSTR(line) _PADLINE(line)
-+#define PAD _XSTR(__LINE__)
-+#endif
-+
-+/* PCIE Enumeration space offsets*/
-+#define PCIE_CORE_CONFIG_OFFSET 0x0
-+#define PCIE_FUNC0_CONFIG_OFFSET 0x400
-+#define PCIE_FUNC1_CONFIG_OFFSET 0x500
-+#define PCIE_FUNC2_CONFIG_OFFSET 0x600
-+#define PCIE_FUNC3_CONFIG_OFFSET 0x700
-+#define PCIE_SPROM_SHADOW_OFFSET 0x800
-+#define PCIE_SBCONFIG_OFFSET 0xE00
-+
-+/* PCIE Bar0 Address Mapping. Each function maps 16KB config space */
-+#define PCIE_BAR0_WINMAPCORE_OFFSET 0x0
-+#define PCIE_BAR0_EXTSPROM_OFFSET 0x1000
-+#define PCIE_BAR0_PCIECORE_OFFSET 0x2000
-+#define PCIE_BAR0_CCCOREREG_OFFSET 0x3000
-+
-+/* SB side: PCIE core and host control registers */
-+typedef struct sbpcieregs {
++/* SB side: PCIE core and host control registers */
++typedef struct sbpcieregs {
+
+ uint32 PAD[3];
+ uint32 biststatus; /* bist Status: 0x00C*/
+#define SERDES_RX_CDRBW 7 /* CDR BW */
+
+#endif /* _SBPCIE_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbpci.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbpci.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbpci.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbpci.h 2005-12-16 23:39:10.936836250 +0100
-@@ -0,0 +1,122 @@
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbpcmcia.h linux.dev/arch/mips/bcm947xx/include/sbpcmcia.h
+--- linux.old/arch/mips/bcm947xx/include/sbpcmcia.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbpcmcia.h 2006-04-06 15:34:14.000000000 +0200
+@@ -0,0 +1,146 @@
+/*
-+ * BCM47XX Sonics SiliconBackplane PCI core hardware definitions.
++ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
+ *
+ * $Id$
+ * Copyright 2005, Broadcom Corporation
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ */
+
-+#ifndef _SBPCI_H
-+#define _SBPCI_H
++#ifndef _SBPCMCIA_H
++#define _SBPCMCIA_H
+
-+/* cpp contortions to concatenate w/arg prescan */
-+#ifndef PAD
-+#define _PADLINE(line) pad ## line
-+#define _XSTR(line) _PADLINE(line)
-+#define PAD _XSTR(__LINE__)
-+#endif
+
-+/* Sonics side: PCI core and host control registers */
-+typedef struct sbpciregs {
-+ uint32 control; /* PCI control */
-+ uint32 PAD[3];
-+ uint32 arbcontrol; /* PCI arbiter control */
-+ uint32 PAD[3];
-+ uint32 intstatus; /* Interrupt status */
-+ uint32 intmask; /* Interrupt mask */
-+ uint32 sbtopcimailbox; /* Sonics to PCI mailbox */
-+ uint32 PAD[9];
-+ uint32 bcastaddr; /* Sonics broadcast address */
-+ uint32 bcastdata; /* Sonics broadcast data */
-+ uint32 PAD[2];
-+ uint32 gpioin; /* ro: gpio input (>=rev2) */
-+ uint32 gpioout; /* rw: gpio output (>=rev2) */
-+ uint32 gpioouten; /* rw: gpio output enable (>= rev2) */
-+ uint32 gpiocontrol; /* rw: gpio control (>= rev2) */
-+ uint32 PAD[36];
-+ uint32 sbtopci0; /* Sonics to PCI translation 0 */
-+ uint32 sbtopci1; /* Sonics to PCI translation 1 */
-+ uint32 sbtopci2; /* Sonics to PCI translation 2 */
-+ uint32 PAD[445];
-+ uint16 sprom[36]; /* SPROM shadow Area */
-+ uint32 PAD[46];
-+} sbpciregs_t;
++/* All the addresses that are offsets in attribute space are divided
++ * by two to account for the fact that odd bytes are invalid in
++ * attribute space and our read/write routines make the space appear
++ * as if they didn't exist. Still we want to show the original numbers
++ * as documented in the hnd_pcmcia core manual.
++ */
+
-+/* PCI control */
-+#define PCI_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */
-+#define PCI_RST 0x02 /* Value driven out to pin */
-+#define PCI_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */
-+#define PCI_CLK 0x08 /* Gate for clock driven out to pin */
-+
-+/* PCI arbiter control */
-+#define PCI_INT_ARB 0x01 /* When set, use an internal arbiter */
-+#define PCI_EXT_ARB 0x02 /* When set, use an external arbiter */
-+#define PCI_PARKID_MASK 0x06 /* Selects which agent is parked on an idle bus */
-+#define PCI_PARKID_SHIFT 1
-+#define PCI_PARKID_LAST 0 /* Last requestor */
-+#define PCI_PARKID_4710 1 /* 4710 */
-+#define PCI_PARKID_EXTREQ0 2 /* External requestor 0 */
-+#define PCI_PARKID_EXTREQ1 3 /* External requestor 1 */
-+
-+/* Interrupt status/mask */
-+#define PCI_INTA 0x01 /* PCI INTA# is asserted */
-+#define PCI_INTB 0x02 /* PCI INTB# is asserted */
-+#define PCI_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */
-+#define PCI_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */
-+#define PCI_PME 0x10 /* PCI PME# is asserted */
-+
-+/* (General) PCI/SB mailbox interrupts, two bits per pci function */
-+#define MAILBOX_F0_0 0x100 /* function 0, int 0 */
-+#define MAILBOX_F0_1 0x200 /* function 0, int 1 */
-+#define MAILBOX_F1_0 0x400 /* function 1, int 0 */
-+#define MAILBOX_F1_1 0x800 /* function 1, int 1 */
-+#define MAILBOX_F2_0 0x1000 /* function 2, int 0 */
-+#define MAILBOX_F2_1 0x2000 /* function 2, int 1 */
-+#define MAILBOX_F3_0 0x4000 /* function 3, int 0 */
-+#define MAILBOX_F3_1 0x8000 /* function 3, int 1 */
-+
-+/* Sonics broadcast address */
-+#define BCAST_ADDR_MASK 0xff /* Broadcast register address */
-+
-+/* Sonics to PCI translation types */
-+#define SBTOPCI0_MASK 0xfc000000
-+#define SBTOPCI1_MASK 0xfc000000
-+#define SBTOPCI2_MASK 0xc0000000
-+#define SBTOPCI_MEM 0
-+#define SBTOPCI_IO 1
-+#define SBTOPCI_CFG0 2
-+#define SBTOPCI_CFG1 3
-+#define SBTOPCI_PREF 0x4 /* prefetch enable */
-+#define SBTOPCI_BURST 0x8 /* burst enable */
-+#define SBTOPCI_RC_MASK 0x30 /* read command (>= rev11) */
-+#define SBTOPCI_RC_READ 0x00 /* memory read */
-+#define SBTOPCI_RC_READLINE 0x10 /* memory read line */
-+#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
-+
-+/* PCI core index in SROM shadow area */
-+#define SRSH_PI_OFFSET 0 /* first word */
-+#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
-+#define SRSH_PI_SHIFT 12 /* bit 15:12 */
-+
-+/* PCI side: Reserved PCI configuration registers (see pcicfg.h) */
-+#define cap_list rsvd_a[0]
-+#define bar0_window dev_dep[0x80 - 0x40]
-+#define bar1_window dev_dep[0x84 - 0x40]
-+#define sprom_control dev_dep[0x88 - 0x40]
-+
-+#ifndef _LANGUAGE_ASSEMBLY
-+
-+extern int sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
-+extern int sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
-+extern void sbpci_ban(uint16 core);
-+extern int sbpci_init(sb_t *sbh);
-+extern void sbpci_check(sb_t *sbh);
-+
-+#endif /* !_LANGUAGE_ASSEMBLY */
-+
-+#endif /* _SBPCI_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbpcmcia.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbpcmcia.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbpcmcia.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbpcmcia.h 2005-12-16 23:39:10.936836250 +0100
-@@ -0,0 +1,146 @@
-+/*
-+ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
-+ *
-+ * $Id$
-+ * Copyright 2005, 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.
-+ */
-+
-+#ifndef _SBPCMCIA_H
-+#define _SBPCMCIA_H
-+
-+
-+/* All the addresses that are offsets in attribute space are divided
-+ * by two to account for the fact that odd bytes are invalid in
-+ * attribute space and our read/write routines make the space appear
-+ * as if they didn't exist. Still we want to show the original numbers
-+ * as documented in the hnd_pcmcia core manual.
-+ */
-+
-+/* PCMCIA Function Configuration Registers */
-+#define PCMCIA_FCR (0x700 / 2)
++/* PCMCIA Function Configuration Registers */
++#define PCMCIA_FCR (0x700 / 2)
+
+#define FCR0_OFF 0
+#define FCR1_OFF (0x40 / 2)
+#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */
+
+#endif /* _SBPCMCIA_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbsdram.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbsdram.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbsdram.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbsdram.h 2005-12-16 23:39:10.936836250 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbsdram.h linux.dev/arch/mips/bcm947xx/include/sbsdram.h
+--- linux.old/arch/mips/bcm947xx/include/sbsdram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbsdram.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,75 @@
+/*
+ * BCM47XX Sonics SiliconBackplane SDRAM controller core hardware definitions.
+#define MEM8MX16X2 0xc29 /* 32 MB */
+
+#endif /* _SBSDRAM_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbsocram.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbsocram.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbsocram.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbsocram.h 2005-12-16 23:39:10.936836250 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbsocram.h linux.dev/arch/mips/bcm947xx/include/sbsocram.h
+--- linux.old/arch/mips/bcm947xx/include/sbsocram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbsocram.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,37 @@
+/*
+ * BCM47XX Sonics SiliconBackplane embedded ram core
+#define SOCRAM_MEMSIZE_BASESHIFT 16
+
+#endif /* _SBSOCRAM_H */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sbutils.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbutils.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sbutils.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sbutils.h 2005-12-16 23:39:10.936836250 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sbutils.h linux.dev/arch/mips/bcm947xx/include/sbutils.h
+--- linux.old/arch/mips/bcm947xx/include/sbutils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbutils.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,140 @@
+/*
+ * Misc utility routines for accessing chip-specific features
+#define SB_DEVPATH_BUFSZ 16 /* min buffer size in bytes */
+
+#endif /* _sbutils_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/sflash.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/sflash.h
---- linux-2.4.32/arch/mips/bcm947xx/include/sflash.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/sflash.h 2005-12-16 23:39:10.936836250 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/sflash.h linux.dev/arch/mips/bcm947xx/include/sflash.h
+--- linux.old/arch/mips/bcm947xx/include/sflash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sflash.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,36 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+extern struct sflash * sflash_init(chipcregs_t *cc);
+
+#endif /* _sflash_h_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/trxhdr.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/trxhdr.h
---- linux-2.4.32/arch/mips/bcm947xx/include/trxhdr.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/trxhdr.h 2005-12-16 23:39:10.940836500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/trxhdr.h linux.dev/arch/mips/bcm947xx/include/trxhdr.h
+--- linux.old/arch/mips/bcm947xx/include/trxhdr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/trxhdr.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,33 @@
+/*
+ * TRX image file header format.
+
+/* Compatibility */
+typedef struct trx_header TRXHDR, *PTRXHDR;
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/include/typedefs.h linux-2.4.32-brcm/arch/mips/bcm947xx/include/typedefs.h
---- linux-2.4.32/arch/mips/bcm947xx/include/typedefs.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/include/typedefs.h 2005-12-16 23:39:10.940836500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/include/typedefs.h linux.dev/arch/mips/bcm947xx/include/typedefs.h
+--- linux.old/arch/mips/bcm947xx/include/typedefs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/typedefs.h 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2005, Broadcom Corporation
+#endif /* USE_TYPEDEF_DEFAULTS */
+
+#endif /* _TYPEDEFS_H_ */
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/Makefile linux-2.4.32-brcm/arch/mips/bcm947xx/Makefile
---- linux-2.4.32/arch/mips/bcm947xx/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/Makefile 2005-12-19 01:56:51.733868750 +0100
-@@ -0,0 +1,15 @@
-+#
-+# Makefile for the BCM947xx specific kernel interface routines
-+# under Linux.
-+#
-+
-+EXTRA_CFLAGS+=-I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER
-+
-+O_TARGET := bcm947xx.o
-+
-+export-objs := nvram_linux.o setup.o
-+obj-y := prom.o setup.o time.o sbmips.o gpio.o
-+obj-y += nvram.o nvram_linux.o sflash.o cfe_env.o
-+obj-$(CONFIG_PCI) += sbpci.o pcibios.o
-+
-+include $(TOPDIR)/Rules.make
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/nvram.c linux-2.4.32-brcm/arch/mips/bcm947xx/nvram.c
---- linux-2.4.32/arch/mips/bcm947xx/nvram.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/nvram.c 2005-12-19 01:05:00.079582750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/nvram.c linux.dev/arch/mips/bcm947xx/nvram.c
+--- linux.old/arch/mips/bcm947xx/nvram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/nvram.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,320 @@
+/*
+ * NVRAM variable manipulation (common)
+{
+ BCMINIT(nvram_free)();
+}
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/nvram_linux.c linux-2.4.32-brcm/arch/mips/bcm947xx/nvram_linux.c
---- linux-2.4.32/arch/mips/bcm947xx/nvram_linux.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/nvram_linux.c 2005-12-19 01:09:59.782313000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/nvram_linux.c linux.dev/arch/mips/bcm947xx/nvram_linux.c
+--- linux.old/arch/mips/bcm947xx/nvram_linux.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/nvram_linux.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,653 @@
+/*
+ * NVRAM variable manipulation (Linux kernel half)
+
+module_init(dev_nvram_init);
+module_exit(dev_nvram_exit);
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/pcibios.c linux-2.4.32-brcm/arch/mips/bcm947xx/pcibios.c
---- linux-2.4.32/arch/mips/bcm947xx/pcibios.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/pcibios.c 2005-12-16 23:39:10.944836750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/pcibios.c linux.dev/arch/mips/bcm947xx/pcibios.c
+--- linux.old/arch/mips/bcm947xx/pcibios.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/pcibios.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,355 @@
+/*
+ * Low-Level PCI and SB support for BCM47xx (Linux support code)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/prom.c linux-2.4.32-brcm/arch/mips/bcm947xx/prom.c
---- linux-2.4.32/arch/mips/bcm947xx/prom.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/prom.c 2005-12-16 23:39:10.944836750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/prom.c linux.dev/arch/mips/bcm947xx/prom.c
+--- linux.old/arch/mips/bcm947xx/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/prom.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,41 @@
+/*
+ * Early initialization code for BCM94710 boards
+prom_free_prom_memory(void)
+{
+}
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/sbmips.c linux-2.4.32-brcm/arch/mips/bcm947xx/sbmips.c
---- linux-2.4.32/arch/mips/bcm947xx/sbmips.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/sbmips.c 2005-12-16 23:39:10.944836750 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/sbmips.c linux.dev/arch/mips/bcm947xx/sbmips.c
+--- linux.old/arch/mips/bcm947xx/sbmips.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sbmips.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,1038 @@
+/*
+ * BCM47XX Sonics SiliconBackplane MIPS core routines
+ return ret;
+}
+
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/sbpci.c linux-2.4.32-brcm/arch/mips/bcm947xx/sbpci.c
---- linux-2.4.32/arch/mips/bcm947xx/sbpci.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/sbpci.c 2005-12-16 23:39:10.948837000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/sbpci.c linux.dev/arch/mips/bcm947xx/sbpci.c
+--- linux.old/arch/mips/bcm947xx/sbpci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sbpci.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,588 @@
+/*
+ * Low-Level PCI and SB support for BCM47xx
+ sb_setcoreidx(sbh, coreidx);
+}
+
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/setup.c linux-2.4.32-brcm/arch/mips/bcm947xx/setup.c
---- linux-2.4.32/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/setup.c 2005-12-20 00:29:40.187416500 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/setup.c linux.dev/arch/mips/bcm947xx/setup.c
+--- linux.old/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/setup.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,234 @@
+/*
+ * Generic setup routines for Broadcom MIPS boards
+}
+
+EXPORT_SYMBOL(bcm947xx_sbh);
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/sflash.c linux-2.4.32-brcm/arch/mips/bcm947xx/sflash.c
---- linux-2.4.32/arch/mips/bcm947xx/sflash.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/sflash.c 2005-12-16 23:39:10.948837000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/sflash.c linux.dev/arch/mips/bcm947xx/sflash.c
+--- linux.old/arch/mips/bcm947xx/sflash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sflash.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,418 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ return ret;
+}
+
-diff -Nur linux-2.4.32/arch/mips/bcm947xx/time.c linux-2.4.32-brcm/arch/mips/bcm947xx/time.c
---- linux-2.4.32/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/bcm947xx/time.c 2005-12-16 23:39:10.948837000 +0100
+diff -Naur linux.old/arch/mips/bcm947xx/time.c linux.dev/arch/mips/bcm947xx/time.c
+--- linux.old/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/time.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2004, Broadcom Corporation
+ /* Enable the timer interrupt */
+ setup_irq(7, &bcm947xx_timer_irqaction);
+}
-diff -Nur linux-2.4.32/arch/mips/config-shared.in linux-2.4.32-brcm/arch/mips/config-shared.in
---- linux-2.4.32/arch/mips/config-shared.in 2005-01-19 15:09:27.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/config-shared.in 2005-12-16 23:39:11.080845250 +0100
-@@ -205,6 +205,14 @@
+diff -Naur linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared.in
+--- linux.old/arch/mips/config-shared.in 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/config-shared.in 2006-04-06 15:34:14.000000000 +0200
+@@ -208,6 +208,14 @@
fi
define_bool CONFIG_MIPS_RTC y
fi
bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
bool 'Support for TANBAC TB0226 (Mbase)' CONFIG_TANBAC_TB0226
bool 'Support for TANBAC TB0229 (VR4131DIMM)' CONFIG_TANBAC_TB0229
-@@ -226,6 +234,11 @@
+@@ -229,6 +237,11 @@
define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
#
# Select some configuration options automatically based on user selections.
#
if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
-@@ -533,6 +546,13 @@
+@@ -554,6 +567,13 @@
define_bool CONFIG_SWAP_IO_SPACE_L y
define_bool CONFIG_BOOT_ELF32 y
fi
if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
define_bool CONFIG_ARC32 y
define_bool CONFIG_ARC_MEMORY y
-@@ -1011,7 +1031,11 @@
+@@ -1042,7 +1062,11 @@
bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
bool 'Enable run-time debugging' CONFIG_RUNTIME_DEBUG
dep_bool ' Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_KGDB
if [ "$CONFIG_KGDB" = "y" ]; then
define_bool CONFIG_DEBUG_INFO y
-diff -Nur linux-2.4.32/arch/mips/kernel/cpu-probe.c linux-2.4.32-brcm/arch/mips/kernel/cpu-probe.c
---- linux-2.4.32/arch/mips/kernel/cpu-probe.c 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/kernel/cpu-probe.c 2005-12-16 23:39:11.084845500 +0100
-@@ -174,7 +174,7 @@
+diff -Naur linux.old/arch/mips/kernel/cpu-probe.c linux.dev/arch/mips/kernel/cpu-probe.c
+--- linux.old/arch/mips/kernel/cpu-probe.c 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/kernel/cpu-probe.c 2006-04-06 15:34:14.000000000 +0200
+@@ -162,7 +162,7 @@
static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
{
case PRID_IMP_R2000:
c->cputype = CPU_R2000;
c->isa_level = MIPS_CPU_ISA_I;
-@@ -184,7 +184,7 @@
+@@ -172,7 +172,7 @@
c->tlbsize = 64;
break;
case PRID_IMP_R3000:
if (cpu_has_confreg())
c->cputype = CPU_R3081E;
else
-@@ -199,12 +199,12 @@
+@@ -187,12 +187,12 @@
break;
case PRID_IMP_R4000:
if (read_c0_config() & CONF_SC) {
c->cputype = CPU_R4400SC;
else
c->cputype = CPU_R4000SC;
-@@ -450,7 +450,7 @@
+@@ -438,7 +438,7 @@
static inline void cpu_probe_mips(struct cpuinfo_mips *c)
{
decode_config1(c);
case PRID_IMP_4KC:
c->cputype = CPU_4KC;
c->isa_level = MIPS_CPU_ISA_M32;
-@@ -491,10 +491,10 @@
+@@ -479,10 +479,10 @@
{
decode_config1(c);
c->options |= MIPS_CPU_PREFETCH;
case 0:
c->cputype = CPU_AU1000;
break;
-@@ -522,10 +522,34 @@
+@@ -510,10 +510,34 @@
}
}
case PRID_IMP_SB1:
c->cputype = CPU_SB1;
c->isa_level = MIPS_CPU_ISA_M64;
-@@ -547,7 +571,7 @@
+@@ -535,7 +559,7 @@
static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
{
decode_config1(c);
case PRID_IMP_SR71000:
c->cputype = CPU_SR71000;
c->isa_level = MIPS_CPU_ISA_M64;
-@@ -572,7 +596,7 @@
+@@ -560,7 +584,7 @@
c->cputype = CPU_UNKNOWN;
c->processor_id = read_c0_prid();
case PRID_COMP_LEGACY:
cpu_probe_legacy(c);
-@@ -583,6 +607,9 @@
+@@ -571,6 +595,9 @@
case PRID_COMP_ALCHEMY:
cpu_probe_alchemy(c);
break;
case PRID_COMP_SIBYTE:
cpu_probe_sibyte(c);
break;
-diff -Nur linux-2.4.32/arch/mips/kernel/head.S linux-2.4.32-brcm/arch/mips/kernel/head.S
---- linux-2.4.32/arch/mips/kernel/head.S 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/kernel/head.S 2005-12-16 23:39:11.084845500 +0100
+diff -Naur linux.old/arch/mips/kernel/head.S linux.dev/arch/mips/kernel/head.S
+--- linux.old/arch/mips/kernel/head.S 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/kernel/head.S 2006-04-06 15:34:14.000000000 +0200
@@ -28,12 +28,20 @@
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
/* The following two symbols are used for kernel profiling. */
EXPORT(stext)
-diff -Nur linux-2.4.32/arch/mips/kernel/proc.c linux-2.4.32-brcm/arch/mips/kernel/proc.c
---- linux-2.4.32/arch/mips/kernel/proc.c 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/kernel/proc.c 2005-12-16 23:39:11.084845500 +0100
+diff -Naur linux.old/arch/mips/kernel/proc.c linux.dev/arch/mips/kernel/proc.c
+--- linux.old/arch/mips/kernel/proc.c 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/kernel/proc.c 2006-04-06 15:34:14.000000000 +0200
@@ -78,9 +78,10 @@
[CPU_AU1550] "Au1550",
[CPU_24K] "MIPS 24K",
static int show_cpuinfo(struct seq_file *m, void *v)
{
unsigned int version = current_cpu_data.processor_id;
-diff -Nur linux-2.4.32/arch/mips/kernel/setup.c linux-2.4.32-brcm/arch/mips/kernel/setup.c
---- linux-2.4.32/arch/mips/kernel/setup.c 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/kernel/setup.c 2005-12-16 23:39:11.140849000 +0100
-@@ -495,6 +495,7 @@
+diff -Naur linux.old/arch/mips/kernel/setup.c linux.dev/arch/mips/kernel/setup.c
+--- linux.old/arch/mips/kernel/setup.c 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/kernel/setup.c 2006-04-06 15:34:14.000000000 +0200
+@@ -493,6 +493,7 @@
void swarm_setup(void);
void hp_setup(void);
void au1x00_setup(void);
void frame_info_init(void);
frame_info_init();
-@@ -693,6 +694,11 @@
+@@ -691,6 +692,11 @@
pmc_yosemite_setup();
break;
#endif
default:
panic("Unsupported architecture");
}
-diff -Nur linux-2.4.32/arch/mips/kernel/traps.c linux-2.4.32-brcm/arch/mips/kernel/traps.c
---- linux-2.4.32/arch/mips/kernel/traps.c 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/kernel/traps.c 2005-12-16 23:39:11.140849000 +0100
-@@ -913,6 +913,7 @@
+diff -Naur linux.old/arch/mips/kernel/traps.c linux.dev/arch/mips/kernel/traps.c
+--- linux.old/arch/mips/kernel/traps.c 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/kernel/traps.c 2006-04-06 15:34:14.000000000 +0200
+@@ -920,6 +920,7 @@
void __init trap_init(void)
{
extern char except_vec1_generic;
extern char except_vec3_generic, except_vec3_r4000;
extern char except_vec_ejtag_debug;
extern char except_vec4;
-@@ -922,6 +923,7 @@
+@@ -927,6 +928,7 @@
/* Copy the generic exception handler code to it's final destination. */
memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
/*
* Setup default vectors
-@@ -980,6 +982,12 @@
+@@ -985,6 +987,12 @@
set_except_vector(13, handle_tr);
set_except_vector(22, handle_mdmx);
if (cpu_has_fpu && !cpu_has_nofpuex)
set_except_vector(15, handle_fpe);
-diff -Nur linux-2.4.32/arch/mips/Makefile linux-2.4.32-brcm/arch/mips/Makefile
---- linux-2.4.32/arch/mips/Makefile 2005-01-19 15:09:26.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/Makefile 2005-12-16 23:39:10.668819500 +0100
-@@ -715,6 +715,19 @@
- endif
-
- #
-+# Broadcom BCM947XX variants
-+#
-+ifdef CONFIG_BCM947XX
-+LIBS += arch/mips/bcm947xx/generic/brcm.o arch/mips/bcm947xx/bcm947xx.o
-+SUBDIRS += arch/mips/bcm947xx/generic arch/mips/bcm947xx
-+LOADADDR := 0x80001000
-+
-+zImage: vmlinux
-+ $(MAKE) -C arch/$(ARCH)/bcm947xx/compressed
-+export LOADADDR
-+endif
-+
-+#
- # Choosing incompatible machines durings configuration will result in
- # error messages during linking. Select a default linkscript if
- # none has been choosen above.
-@@ -767,6 +780,7 @@
- $(MAKE) -C arch/$(ARCH)/tools clean
- $(MAKE) -C arch/mips/baget clean
- $(MAKE) -C arch/mips/lasat clean
-+ $(MAKE) -C arch/mips/bcm947xx/compressed clean
-
- archmrproper:
- @$(MAKEBOOT) mrproper
-diff -Nur linux-2.4.32/arch/mips/mm/c-r4k.c linux-2.4.32-brcm/arch/mips/mm/c-r4k.c
---- linux-2.4.32/arch/mips/mm/c-r4k.c 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/mm/c-r4k.c 2005-12-16 23:39:11.144849250 +0100
-@@ -1114,3 +1114,47 @@
+diff -Naur linux.old/arch/mips/mm/c-r4k.c linux.dev/arch/mips/mm/c-r4k.c
+--- linux.old/arch/mips/mm/c-r4k.c 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/mm/c-r4k.c 2006-04-06 15:34:15.000000000 +0200
+@@ -1166,3 +1166,47 @@
build_clear_page();
build_copy_page();
}
+}
+
+
-diff -Nur linux-2.4.32/arch/mips/pci/Makefile linux-2.4.32-brcm/arch/mips/pci/Makefile
---- linux-2.4.32/arch/mips/pci/Makefile 2005-01-19 15:09:29.000000000 +0100
-+++ linux-2.4.32-brcm/arch/mips/pci/Makefile 2005-12-16 23:39:11.144849250 +0100
+diff -Naur linux.old/arch/mips/pci/Makefile linux.dev/arch/mips/pci/Makefile
+--- linux.old/arch/mips/pci/Makefile 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/arch/mips/pci/Makefile 2006-04-06 15:34:14.000000000 +0200
@@ -13,7 +13,9 @@
obj-$(CONFIG_MIPS_MSC) += ops-msc.o
obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o
obj-$(CONFIG_PCI_AUTO) += pci_auto.o
include $(TOPDIR)/Rules.make
-diff -Nur linux-2.4.32/drivers/char/serial.c linux-2.4.32-brcm/drivers/char/serial.c
---- linux-2.4.32/drivers/char/serial.c 2005-11-16 20:12:54.000000000 +0100
-+++ linux-2.4.32-brcm/drivers/char/serial.c 2005-12-16 23:39:11.200852750 +0100
-@@ -422,6 +422,10 @@
+diff -Naur linux.old/drivers/char/serial.c linux.dev/drivers/char/serial.c
+--- linux.old/drivers/char/serial.c 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/drivers/char/serial.c 2006-04-06 15:34:14.000000000 +0200
+@@ -444,6 +444,10 @@
return inb(info->port+1);
#endif
case SERIAL_IO_MEM:
return readb((unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
default:
-@@ -442,6 +446,9 @@
+@@ -464,6 +468,9 @@
case SERIAL_IO_MEM:
writeb(value, (unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
break;
default:
outb(value, info->port+offset);
-@@ -1704,7 +1711,7 @@
+@@ -1728,7 +1735,7 @@
/* Special case since 134 is really 134.5 */
quot = (2*baud_base / 269);
else if (baud)
}
/* If the quotient is zero refuse the change */
if (!quot && old_termios) {
-@@ -1721,12 +1728,12 @@
+@@ -1745,12 +1752,12 @@
/* Special case since 134 is really 134.5 */
quot = (2*baud_base / 269);
else if (baud)
/*
* Work around a bug in the Oxford Semiconductor 952 rev B
* chip which causes it to seriously miscalculate baud rates
-@@ -5982,6 +5989,13 @@
+@@ -5994,6 +6001,13 @@
* Divisor, bytesize and parity
*/
state = rs_table + co->index;
if (doflow)
state->flags |= ASYNC_CONS_FLOW;
info = &async_sercons;
-@@ -5995,7 +6009,7 @@
+@@ -6007,7 +6021,7 @@
info->io_type = state->io_type;
info->iomem_base = state->iomem_base;
info->iomem_reg_shift = state->iomem_reg_shift;
cval = cflag & (CSIZE | CSTOPB);
#if defined(__powerpc__) || defined(__alpha__)
cval >>= 8;
-diff -Nur linux-2.4.32/drivers/net/Config.in linux-2.4.32-brcm/drivers/net/Config.in
---- linux-2.4.32/drivers/net/Config.in 2005-01-19 15:09:56.000000000 +0100
-+++ linux-2.4.32-brcm/drivers/net/Config.in 2005-12-16 23:39:11.232854750 +0100
+diff -Naur linux.old/drivers/net/Config.in linux.dev/drivers/net/Config.in
+--- linux.old/drivers/net/Config.in 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/drivers/net/Config.in 2006-04-06 15:34:14.000000000 +0200
@@ -2,6 +2,8 @@
# Network device configuration
#
source drivers/net/arcnet/Config.in
tristate 'Dummy net driver support' CONFIG_DUMMY
-diff -Nur linux-2.4.32/drivers/net/hnd/bcmsrom.c linux-2.4.32-brcm/drivers/net/hnd/bcmsrom.c
---- linux-2.4.32/drivers/net/hnd/bcmsrom.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/drivers/net/hnd/bcmsrom.c 2005-12-16 23:39:11.284858000 +0100
+diff -Naur linux.old/drivers/net/Makefile linux.dev/drivers/net/Makefile
+--- linux.old/drivers/net/Makefile 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/drivers/net/Makefile 2006-04-06 16:45:29.000000000 +0200
+@@ -3,6 +3,8 @@
+ # Makefile for the Linux network (ethercard) device drivers.
+ #
+
++EXTRA_CFLAGS := -I$(TOPDIR)/arch/mips/bcm947xx/include
++
+ obj-y :=
+ obj-m :=
+ obj-n :=
+@@ -39,6 +41,9 @@
+ obj-$(CONFIG_ISDN) += slhc.o
+ endif
+
++subdir-$(CONFIG_HND) += hnd
++subdir-$(CONFIG_WL) += wl
++subdir-$(CONFIG_WL2) += wl2
+ subdir-$(CONFIG_NET_PCMCIA) += pcmcia
+ subdir-$(CONFIG_NET_WIRELESS) += wireless
+ subdir-$(CONFIG_TULIP) += tulip
+@@ -69,6 +74,10 @@
+ obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
+ obj-$(CONFIG_SUNGEM) += sungem.o
+
++ifeq ($(CONFIG_HND),y)
++ obj-y += hnd/hnd.o
++endif
++
+ obj-$(CONFIG_MACE) += mace.o
+ obj-$(CONFIG_BMAC) += bmac.o
+ obj-$(CONFIG_GMAC) += gmac.o
+diff -Naur linux.old/drivers/net/hnd/Makefile linux.dev/drivers/net/hnd/Makefile
+--- linux.old/drivers/net/hnd/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/hnd/Makefile 2006-04-06 16:20:00.000000000 +0200
+@@ -0,0 +1,19 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++
++EXTRA_CFLAGS += -I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER
++
++O_TARGET := hnd.o
++
++HND_OBJS := bcmutils.o linux_osl.o sbutils.o bcmsrom.o
++
++export-objs := shared_ksyms.o
++obj-y := shared_ksyms.o $(HND_OBJS)
++obj-m := $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
++
++shared_ksyms.c: shared_ksyms.sh $(HND_OBJS)
++ sh -e $< $(HND_OBJS) > $@
+diff -Naur linux.old/drivers/net/hnd/bcmsrom.c linux.dev/drivers/net/hnd/bcmsrom.c
+--- linux.old/drivers/net/hnd/bcmsrom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/hnd/bcmsrom.c 2006-04-06 15:34:14.000000000 +0200
@@ -0,0 +1,938 @@
+/*
+ * Misc useful routines to access NIC SROM/OTP .
+ return (rc);
+}
+
-diff -Nur linux-2.4.32/drivers/net/hnd/bcmutils.c linux-2.4.32-brcm/drivers/net/hnd/bcmutils.c
---- linux-2.4.32/drivers/net/hnd/bcmutils.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/drivers/net/hnd/bcmutils.c 2005-12-16 23:39:11.288858250 +0100
-@@ -0,0 +1,1081 @@
+diff -Naur linux.old/drivers/net/hnd/bcmutils.c linux.dev/drivers/net/hnd/bcmutils.c
+--- linux.old/drivers/net/hnd/bcmutils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/hnd/bcmutils.c 2006-04-06 16:05:56.000000000 +0200
+@@ -0,0 +1,875 @@
+/*
+ * Misc useful OS-independent routines.
+ *
+#include <bcmdevs.h>
+
+#ifdef BCMDRIVER
-+/* copy a pkt buffer chain into a buffer */
-+uint
-+pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
-+{
-+ uint n, ret = 0;
-+
-+ if (len < 0)
-+ len = 4096; /* "infinite" */
-+
-+ /* skip 'offset' bytes */
-+ for (; p && offset; p = PKTNEXT(osh, p)) {
-+ if (offset < (uint)PKTLEN(osh, p))
-+ break;
-+ offset -= PKTLEN(osh, p);
-+ }
-+
-+ if (!p)
-+ return 0;
-+
-+ /* copy the data */
-+ for (; p && len; p = PKTNEXT(osh, p)) {
-+ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
-+ bcopy(PKTDATA(osh, p) + offset, buf, n);
-+ buf += n;
-+ len -= n;
-+ ret += n;
-+ offset = 0;
-+ }
++unsigned char bcm_ctype[] = {
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
++ _BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
++ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
++ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
++ _BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
++ _BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
++};
+
-+ return ret;
++uchar
++bcm_toupper(uchar c)
++{
++ if (bcm_islower(c))
++ c -= 'a'-'A';
++ return (c);
+}
+
-+/* return total length of buffer chain */
-+uint
-+pkttotlen(osl_t *osh, void *p)
++ulong
++bcm_strtoul(char *cp, char **endp, uint base)
+{
-+ uint total;
-+
-+ total = 0;
-+ for (; p; p = PKTNEXT(osh, p))
-+ total += PKTLEN(osh, p);
-+ return (total);
-+}
-+
-+void
-+pktq_init(struct pktq *q, uint maxlen, const uint8 prio_map[])
-+{
-+ q->head = q->tail = NULL;
-+ q->maxlen = maxlen;
-+ q->len = 0;
-+ if (prio_map) {
-+ q->priority = TRUE;
-+ bcopy(prio_map, q->prio_map, sizeof(q->prio_map));
-+ }
-+ else
-+ q->priority = FALSE;
-+}
-+
-+/* should always check pktq_full before calling pktenq */
-+void
-+pktenq(struct pktq *q, void *p, bool lifo)
-+{
-+ void *next, *prev;
-+
-+ /* allow 10 pkts slack */
-+ ASSERT(q->len < (q->maxlen + 10));
-+
-+ /* Queueing chains not allowed */
-+ ASSERT(PKTLINK(p) == NULL);
-+
-+ /* Queue is empty */
-+ if (q->tail == NULL) {
-+ ASSERT(q->head == NULL);
-+ q->head = q->tail = p;
-+ }
-+
-+ /* Insert at head or tail */
-+ else if (q->priority == FALSE) {
-+ /* Insert at head (LIFO) */
-+ if (lifo) {
-+ PKTSETLINK(p, q->head);
-+ q->head = p;
-+ }
-+ /* Insert at tail (FIFO) */
-+ else {
-+ ASSERT(PKTLINK(q->tail) == NULL);
-+ PKTSETLINK(q->tail, p);
-+ PKTSETLINK(p, NULL);
-+ q->tail = p;
-+ }
-+ }
-+
-+ /* Insert by priority */
-+ else {
-+ /* legal priorities 0-7 */
-+ ASSERT(PKTPRIO(p) <= MAXPRIO);
-+
-+ ASSERT(q->head);
-+ ASSERT(q->tail);
-+ /* Shortcut to insertion at tail */
-+ if (_pktq_pri(q, PKTPRIO(p)) < _pktq_pri(q, PKTPRIO(q->tail)) ||
-+ (!lifo && _pktq_pri(q, PKTPRIO(p)) <= _pktq_pri(q, PKTPRIO(q->tail)))) {
-+ prev = q->tail;
-+ next = NULL;
-+ }
-+ /* Insert at head or in the middle */
-+ else {
-+ prev = NULL;
-+ next = q->head;
-+ }
-+ /* Walk the queue */
-+ for (; next; prev = next, next = PKTLINK(next)) {
-+ /* Priority queue invariant */
-+ ASSERT(!prev || _pktq_pri(q, PKTPRIO(prev)) >= _pktq_pri(q, PKTPRIO(next)));
-+ /* Insert at head of string of packets of same priority (LIFO) */
-+ if (lifo) {
-+ if (_pktq_pri(q, PKTPRIO(p)) >= _pktq_pri(q, PKTPRIO(next)))
-+ break;
-+ }
-+ /* Insert at tail of string of packets of same priority (FIFO) */
-+ else {
-+ if (_pktq_pri(q, PKTPRIO(p)) > _pktq_pri(q, PKTPRIO(next)))
-+ break;
-+ }
-+ }
-+ /* Insert at tail */
-+ if (next == NULL) {
-+ ASSERT(PKTLINK(q->tail) == NULL);
-+ PKTSETLINK(q->tail, p);
-+ PKTSETLINK(p, NULL);
-+ q->tail = p;
-+ }
-+ /* Insert in the middle */
-+ else if (prev) {
-+ PKTSETLINK(prev, p);
-+ PKTSETLINK(p, next);
-+ }
-+ /* Insert at head */
-+ else {
-+ PKTSETLINK(p, q->head);
-+ q->head = p;
-+ }
-+ }
-+
-+ /* List invariants after insertion */
-+ ASSERT(q->head);
-+ ASSERT(PKTLINK(q->tail) == NULL);
-+
-+ q->len++;
-+}
-+
-+/* dequeue packet at head */
-+void*
-+pktdeq(struct pktq *q)
-+{
-+ void *p;
-+
-+ if ((p = q->head)) {
-+ ASSERT(q->tail);
-+ q->head = PKTLINK(p);
-+ PKTSETLINK(p, NULL);
-+ q->len--;
-+ if (q->head == NULL)
-+ q->tail = NULL;
-+ }
-+ else {
-+ ASSERT(q->tail == NULL);
-+ }
-+
-+ return (p);
-+}
-+
-+/* dequeue packet at tail */
-+void*
-+pktdeqtail(struct pktq *q)
-+{
-+ void *p;
-+ void *next, *prev;
-+
-+ if (q->head == q->tail) { /* last packet on queue or queue empty */
-+ p = q->head;
-+ q->head = q->tail = NULL;
-+ q->len = 0;
-+ return(p);
-+ }
-+
-+ /* start walk at head */
-+ prev = NULL;
-+ next = q->head;
-+
-+ /* Walk the queue to find prev of q->tail */
-+ for (; next; prev = next, next = PKTLINK(next)) {
-+ if (next == q->tail)
-+ break;
-+ }
-+
-+ ASSERT(prev);
-+
-+ PKTSETLINK(prev, NULL);
-+ q->tail = prev;
-+ q->len--;
-+ p = next;
-+
-+ return (p);
-+}
-+
-+unsigned char bcm_ctype[] = {
-+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
-+ _BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
-+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
-+ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
-+ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
-+ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
-+ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
-+ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
-+ _BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
-+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
-+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
-+ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
-+ _BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
-+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
-+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
-+ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
-+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
-+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
-+ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
-+ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
-+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
-+ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
-+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
-+ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
-+};
-+
-+uchar
-+bcm_toupper(uchar c)
-+{
-+ if (bcm_islower(c))
-+ c -= 'a'-'A';
-+ return (c);
-+}
-+
-+ulong
-+bcm_strtoul(char *cp, char **endp, uint base)
-+{
-+ ulong result, value;
-+ bool minus;
-+
-+ minus = FALSE;
++ ulong result, value;
++ bool minus;
++
++ minus = FALSE;
+
+ while (bcm_isspace(*cp))
+ cp++;
+ return crc;
+}
+
-+#ifdef notdef
-+#define CLEN 1499
-+#define CBUFSIZ (CLEN+4)
-+#define CNBUFS 5
++#ifdef notdef
++#define CLEN 1499
++#define CBUFSIZ (CLEN+4)
++#define CNBUFS 5
++
++void testcrc32(void)
++{
++ uint j,k,l;
++ uint8 *buf;
++ uint len[CNBUFS];
++ uint32 crcr;
++ uint32 crc32tv[CNBUFS] =
++ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
++
++ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
++
++ /* step through all possible alignments */
++ for (l=0;l<=4;l++) {
++ for (j=0; j<CNBUFS; j++) {
++ len[j] = CLEN;
++ for (k=0; k<len[j]; k++)
++ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
++ }
++
++ for (j=0; j<CNBUFS; j++) {
++ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
++ ASSERT(crcr == crc32tv[j]);
++ }
++ }
++
++ MFREE(buf, CBUFSIZ*CNBUFS);
++ return;
++}
++#endif
++
++
++/*
++ * Advance from the current 1-byte tag/1-byte length/variable-length value
++ * triple, to the next, returning a pointer to the next.
++ * If the current or next TLV is invalid (does not fit in given buffer length),
++ * NULL is returned.
++ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
++ * by the TLV paramter's length if it is valid.
++ */
++bcm_tlv_t *
++bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
++{
++ int len;
++
++ /* validate current elt */
++ if (!bcm_valid_tlv(elt, *buflen))
++ return NULL;
++
++ /* advance to next elt */
++ len = elt->len;
++ elt = (bcm_tlv_t*)(elt->data + len);
++ *buflen -= (2 + len);
++
++ /* validate next elt */
++ if (!bcm_valid_tlv(elt, *buflen))
++ return NULL;
++
++ return elt;
++}
++
++/*
++ * Traverse a string of 1-byte tag/1-byte length/variable-length value
++ * triples, returning a pointer to the substring whose first element
++ * matches tag
++ */
++bcm_tlv_t *
++bcm_parse_tlvs(void *buf, int buflen, uint key)
++{
++ bcm_tlv_t *elt;
++ int totlen;
++
++ elt = (bcm_tlv_t*)buf;
++ totlen = buflen;
++
++ /* find tagged parameter */
++ while (totlen >= 2) {
++ int len = elt->len;
++
++ /* validate remaining totlen */
++ if ((elt->id == key) && (totlen >= (len + 2)))
++ return (elt);
++
++ elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
++ totlen -= (len + 2);
++ }
++
++ return NULL;
++}
++
++/*
++ * Traverse a string of 1-byte tag/1-byte length/variable-length value
++ * triples, returning a pointer to the substring whose first element
++ * matches tag. Stop parsing when we see an element whose ID is greater
++ * than the target key.
++ */
++bcm_tlv_t *
++bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
++{
++ bcm_tlv_t *elt;
++ int totlen;
++
++ elt = (bcm_tlv_t*)buf;
++ totlen = buflen;
++
++ /* find tagged parameter */
++ while (totlen >= 2) {
++ uint id = elt->id;
++ int len = elt->len;
++
++ /* Punt if we start seeing IDs > than target key */
++ if (id > key)
++ return(NULL);
++
++ /* validate remaining totlen */
++ if ((id == key) && (totlen >= (len + 2)))
++ return (elt);
++
++ elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
++ totlen -= (len + 2);
++ }
++ return NULL;
++}
++/* routine to dump fields in a fileddesc structure */
++
++uint
++bcmdumpfields(readreg_rtn read_rtn, void *arg0, void *arg1, struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
++{
++ uint filled_len;
++ uint len;
++ struct fielddesc *cur_ptr;
++
++ filled_len = 0;
++ cur_ptr = fielddesc_array;
++
++ while (bufsize > (filled_len + 64)) {
++ if (cur_ptr->nameandfmt == NULL)
++ break;
++ len = sprintf(buf, cur_ptr->nameandfmt, read_rtn(arg0, arg1, cur_ptr->offset));
++ buf += len;
++ filled_len += len;
++ cur_ptr++;
++ }
++ return filled_len;
++}
++
++uint
++bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
++{
++ uint len;
++
++ len = strlen(name) + 1;
++
++ if ((len + datalen) > buflen)
++ return 0;
++
++ strcpy(buf, name);
++
++ /* append data onto the end of the name string */
++ memcpy(&buf[len], data, datalen);
++ len += datalen;
++
++ return len;
++}
++
++/* Quarter dBm units to mW
++ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
++ * Table is offset so the last entry is largest mW value that fits in
++ * a uint16.
++ */
++
++#define QDBM_OFFSET 153
++#define QDBM_TABLE_LEN 40
++
++/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
++ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
++ */
++#define QDBM_TABLE_LOW_BOUND 6493
++
++/* Largest mW value that will round down to the last table entry,
++ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
++ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
++ */
++#define QDBM_TABLE_HIGH_BOUND 64938
++
++static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
++/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
++/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
++/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
++/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
++/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
++/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
++};
++
++uint16
++bcm_qdbm_to_mw(uint8 qdbm)
++{
++ uint factor = 1;
++ int idx = qdbm - QDBM_OFFSET;
++
++ if (idx > QDBM_TABLE_LEN) {
++ /* clamp to max uint16 mW value */
++ return 0xFFFF;
++ }
++
++ /* scale the qdBm index up to the range of the table 0-40
++ * where an offset of 40 qdBm equals a factor of 10 mW.
++ */
++ while (idx < 0) {
++ idx += 40;
++ factor *= 10;
++ }
++
++ /* return the mW value scaled down to the correct factor of 10,
++ * adding in factor/2 to get proper rounding. */
++ return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
++}
++
++uint8
++bcm_mw_to_qdbm(uint16 mw)
++{
++ uint8 qdbm;
++ int offset;
++ uint mw_uint = mw;
++ uint boundary;
++
++ /* handle boundary case */
++ if (mw_uint <= 1)
++ return 0;
++
++ offset = QDBM_OFFSET;
++
++ /* move mw into the range of the table */
++ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
++ mw_uint *= 10;
++ offset -= 40;
++ }
++
++ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
++ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - nqdBm_to_mW_map[qdbm])/2;
++ if (mw_uint < boundary) break;
++ }
++
++ qdbm += (uint8)offset;
++
++ return(qdbm);
++}
+diff -Naur linux.old/drivers/net/hnd/linux_osl.c linux.dev/drivers/net/hnd/linux_osl.c
+--- linux.old/drivers/net/hnd/linux_osl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/hnd/linux_osl.c 2006-04-06 15:34:15.000000000 +0200
+@@ -0,0 +1,708 @@
++/*
++ * Linux OS Independent Layer
++ *
++ * Copyright 2005, 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$
++ */
++
++#define LINUX_OSL
++
++#include <typedefs.h>
++#include <bcmendian.h>
++#include <linux/module.h>
++#include <linuxver.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <linux/delay.h>
++#ifdef mips
++#include <asm/paccess.h>
++#endif
++#include <pcicfg.h>
++
++#define PCI_CFG_RETRY 10
++
++#define OS_HANDLE_MAGIC 0x1234abcd
++#define BCM_MEM_FILENAME_LEN 24
++
++typedef struct bcm_mem_link {
++ struct bcm_mem_link *prev;
++ struct bcm_mem_link *next;
++ uint size;
++ int line;
++ char file[BCM_MEM_FILENAME_LEN];
++} bcm_mem_link_t;
++
++struct os_handle {
++ uint magic;
++ void *pdev;
++ uint malloced;
++ uint failed;
++ bcm_mem_link_t *dbgmem_list;
++};
++
++static int16 linuxbcmerrormap[] = \
++{ 0, /* 0 */
++ -EINVAL, /* BCME_ERROR */
++ -EINVAL, /* BCME_BADARG*/
++ -EINVAL, /* BCME_BADOPTION*/
++ -EINVAL, /* BCME_NOTUP */
++ -EINVAL, /* BCME_NOTDOWN */
++ -EINVAL, /* BCME_NOTAP */
++ -EINVAL, /* BCME_NOTSTA */
++ -EINVAL, /* BCME_BADKEYIDX */
++ -EINVAL, /* BCME_RADIOOFF */
++ -EINVAL, /* BCME_NOTBANDLOCKED */
++ -EINVAL, /* BCME_NOCLK */
++ -EINVAL, /* BCME_BADRATESET */
++ -EINVAL, /* BCME_BADBAND */
++ -E2BIG, /* BCME_BUFTOOSHORT */
++ -E2BIG, /* BCME_BUFTOOLONG */
++ -EBUSY, /* BCME_BUSY */
++ -EINVAL, /* BCME_NOTASSOCIATED */
++ -EINVAL, /* BCME_BADSSIDLEN */
++ -EINVAL, /* BCME_OUTOFRANGECHAN */
++ -EINVAL, /* BCME_BADCHAN */
++ -EFAULT, /* BCME_BADADDR */
++ -ENOMEM, /* BCME_NORESOURCE */
++ -EOPNOTSUPP, /* BCME_UNSUPPORTED */
++ -EMSGSIZE, /* BCME_BADLENGTH */
++ -EINVAL, /* BCME_NOTREADY */
++ -EPERM, /* BCME_NOTPERMITTED */
++ -ENOMEM, /* BCME_NOMEM */
++ -EINVAL, /* BCME_ASSOCIATED */
++ -ERANGE, /* BCME_RANGE */
++ -EINVAL /* BCME_NOTFOUND */
++};
++
++/* translate bcmerrors into linux errors*/
++int
++osl_error(int bcmerror)
++{
++ int abs_bcmerror;
++ int array_size = ARRAYSIZE(linuxbcmerrormap);
++
++ abs_bcmerror = ABS(bcmerror);
++
++ if (bcmerror > 0)
++ abs_bcmerror = 0;
++
++ else if (abs_bcmerror >= array_size)
++ abs_bcmerror = BCME_ERROR;
++
++ return linuxbcmerrormap[abs_bcmerror];
++}
++
++osl_t *
++osl_attach(void *pdev)
++{
++ osl_t *osh;
++
++ osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
++ ASSERT(osh);
++
++ /*
++ * check the cases where
++ * 1.Error code Added to bcmerror table, but forgot to add it to the OS
++ * dependent error code
++ * 2. Error code is added to the bcmerror table, but forgot to add the
++ * corresponding errorstring(dummy call to bcmerrorstr)
++ */
++ bcmerrorstr(0);
++ ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
++
++ osh->magic = OS_HANDLE_MAGIC;
++ osh->malloced = 0;
++ osh->failed = 0;
++ osh->dbgmem_list = NULL;
++ osh->pdev = pdev;
++
++ return osh;
++}
++
++void
++osl_detach(osl_t *osh)
++{
++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC));
++ kfree(osh);
++}
++
++void*
++osl_pktget(osl_t *osh, uint len, bool send)
++{
++ struct sk_buff *skb;
++
++ if ((skb = dev_alloc_skb(len)) == NULL)
++ return (NULL);
++
++ skb_put(skb, len);
++
++ /* ensure the cookie field is cleared */
++ PKTSETCOOKIE(skb, NULL);
++
++ return ((void*) skb);
++}
++
++void
++osl_pktfree(void *p)
++{
++ struct sk_buff *skb, *nskb;
++
++ skb = (struct sk_buff*) p;
++
++ /* perversion: we use skb->next to chain multi-skb packets */
++ while (skb) {
++ nskb = skb->next;
++ skb->next = NULL;
++ if (skb->destructor) {
++ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if destructor exists */
++ dev_kfree_skb_any(skb);
++ } else {
++ /* can free immediately (even in_irq()) if destructor does not exist */
++ dev_kfree_skb(skb);
++ }
++ skb = nskb;
++ }
++}
++
++uint32
++osl_pci_read_config(osl_t *osh, uint offset, uint size)
++{
++ uint val;
++ uint retry=PCI_CFG_RETRY;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ /* only 4byte access supported */
++ ASSERT(size == 4);
++
++ do {
++ pci_read_config_dword(osh->pdev, offset, &val);
++ if (val != 0xffffffff)
++ break;
++ } while (retry--);
++
++
++ return (val);
++}
++
++void
++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
++{
++ uint retry=PCI_CFG_RETRY;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ /* only 4byte access supported */
++ ASSERT(size == 4);
++
++ do {
++ pci_write_config_dword(osh->pdev, offset, val);
++ if (offset!=PCI_BAR0_WIN)
++ break;
++ if (osl_pci_read_config(osh,offset,size) == val)
++ break;
++ } while (retry--);
++
++}
++
++/* return bus # for the pci device pointed by osh->pdev */
++uint
++osl_pci_bus(osl_t *osh)
++{
++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
++
++ return ((struct pci_dev *)osh->pdev)->bus->number;
++}
++
++/* return slot # for the pci device pointed by osh->pdev */
++uint
++osl_pci_slot(osl_t *osh)
++{
++ ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
++
++ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
++}
++
++static void
++osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
++{
++}
++
++void
++osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
++{
++ osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
++}
++
++void
++osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
++{
++ osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
++}
++
++
++#ifdef BCMDBG_MEM
++
++void*
++osl_debug_malloc(osl_t *osh, uint size, int line, char* file)
++{
++ bcm_mem_link_t *p;
++ char* basename;
++
++ ASSERT(size);
++
++ if ((p = (bcm_mem_link_t*)osl_malloc(osh, sizeof(bcm_mem_link_t) + size)) == NULL)
++ return (NULL);
++
++ p->size = size;
++ p->line = line;
++
++ basename = strrchr(file, '/');
++ /* skip the '/' */
++ if (basename)
++ basename++;
++
++ if (!basename)
++ basename = file;
++
++ strncpy(p->file, basename, BCM_MEM_FILENAME_LEN);
++ p->file[BCM_MEM_FILENAME_LEN - 1] = '\0';
++
++ /* link this block */
++ p->prev = NULL;
++ p->next = osh->dbgmem_list;
++ if (p->next)
++ p->next->prev = p;
++ osh->dbgmem_list = p;
++
++ return p + 1;
++}
++
++void
++osl_debug_mfree(osl_t *osh, void *addr, uint size, int line, char* file)
++{
++ bcm_mem_link_t *p = (bcm_mem_link_t *)((int8*)addr - sizeof(bcm_mem_link_t));
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ if (p->size == 0) {
++ printk("osl_debug_mfree: double free on addr 0x%x size %d at line %d file %s\n",
++ (uint)addr, size, line, file);
++ ASSERT(p->size);
++ return;
++ }
++
++ if (p->size != size) {
++ printk("osl_debug_mfree: dealloc size %d does not match alloc size %d on addr 0x%x at line %d file %s\n",
++ size, p->size, (uint)addr, line, file);
++ ASSERT(p->size == size);
++ return;
++ }
++
++ /* unlink this block */
++ if (p->prev)
++ p->prev->next = p->next;
++ if (p->next)
++ p->next->prev = p->prev;
++ if (osh->dbgmem_list == p)
++ osh->dbgmem_list = p->next;
++ p->next = p->prev = NULL;
++
++ osl_mfree(osh, p, size + sizeof(bcm_mem_link_t));
++}
++
++char*
++osl_debug_memdump(osl_t *osh, char *buf, uint sz)
++{
++ bcm_mem_link_t *p;
++ char *obuf;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++ obuf = buf;
++
++ buf += sprintf(buf, " Address\tSize\tFile:line\n");
++ for (p = osh->dbgmem_list; p && ((buf - obuf) < (sz - 128)); p = p->next)
++ buf += sprintf(buf, "0x%08x\t%5d\t%s:%d\n",
++ (int)p + sizeof(bcm_mem_link_t), p->size, p->file, p->line);
++
++ return (obuf);
++}
++
++#endif /* BCMDBG_MEM */
++
++void*
++osl_malloc(osl_t *osh, uint size)
++{
++ void *addr;
++
++ /* only ASSERT if osh is defined */
++ if (osh)
++ ASSERT(osh->magic == OS_HANDLE_MAGIC);
++
++ if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
++ if(osh)
++ osh->failed++;
++ return (NULL);
++ }
++ if (osh)
++ osh->malloced += size;
++
++ return (addr);
++}
++
++void
++osl_mfree(osl_t *osh, void *addr, uint size)
++{
++ if (osh) {
++ ASSERT(osh->magic == OS_HANDLE_MAGIC);
++ osh->malloced -= size;
++ }
++ kfree(addr);
++}
++
++uint
++osl_malloced(osl_t *osh)
++{
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++ return (osh->malloced);
++}
++
++uint osl_malloc_failed(osl_t *osh)
++{
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++ return (osh->failed);
++}
++
++void*
++osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap)
++{
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap));
++}
++
++void
++osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
++{
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
++}
++
++uint
++osl_dma_map(osl_t *osh, void *va, uint size, int direction)
++{
++ int dir;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
++ return (pci_map_single(osh->pdev, va, size, dir));
++}
++
++void
++osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
++{
++ int dir;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
++ pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
++}
++
++#if defined(BINOSL)
++void
++osl_assert(char *exp, char *file, int line)
++{
++ char tempbuf[255];
++
++ sprintf(tempbuf, "assertion \"%s\" failed: file \"%s\", line %d\n", exp, file, line);
++ panic(tempbuf);
++}
++#endif /* BCMDBG || BINOSL */
++
++void
++osl_delay(uint usec)
++{
++ uint d;
++
++ while (usec > 0) {
++ d = MIN(usec, 1000);
++ udelay(d);
++ usec -= d;
++ }
++}
++
++/*
++ * BINOSL selects the slightly slower function-call-based binary compatible osl.
++ */
++#ifdef BINOSL
++
++int
++osl_printf(const char *format, ...)
++{
++ va_list args;
++ char buf[1024];
++ int len;
++
++ /* sprintf into a local buffer because there *is* no "vprintk()".. */
++ va_start(args, format);
++ len = vsprintf(buf, format, args);
++ va_end(args);
++
++ if (len > sizeof (buf)) {
++ printk("osl_printf: buffer overrun\n");
++ return (0);
++ }
++
++ return (printk(buf));
++}
++
++int
++osl_sprintf(char *buf, const char *format, ...)
++{
++ va_list args;
++ int rc;
++
++ va_start(args, format);
++ rc = vsprintf(buf, format, args);
++ va_end(args);
++ return (rc);
++}
++
++int
++osl_strcmp(const char *s1, const char *s2)
++{
++ return (strcmp(s1, s2));
++}
++
++int
++osl_strncmp(const char *s1, const char *s2, uint n)
++{
++ return (strncmp(s1, s2, n));
++}
++
++int
++osl_strlen(const char *s)
++{
++ return (strlen(s));
++}
++
++char*
++osl_strcpy(char *d, const char *s)
++{
++ return (strcpy(d, s));
++}
++
++char*
++osl_strncpy(char *d, const char *s, uint n)
++{
++ return (strncpy(d, s, n));
++}
++
++void
++bcopy(const void *src, void *dst, int len)
++{
++ memcpy(dst, src, len);
++}
++
++int
++bcmp(const void *b1, const void *b2, int len)
++{
++ return (memcmp(b1, b2, len));
++}
++
++void
++bzero(void *b, int len)
++{
++ memset(b, '\0', len);
++}
++
++uint32
++osl_readl(volatile uint32 *r)
++{
++ return (readl(r));
++}
++
++uint16
++osl_readw(volatile uint16 *r)
++{
++ return (readw(r));
++}
++
++uint8
++osl_readb(volatile uint8 *r)
++{
++ return (readb(r));
++}
++
++void
++osl_writel(uint32 v, volatile uint32 *r)
++{
++ writel(v, r);
++}
++
++void
++osl_writew(uint16 v, volatile uint16 *r)
++{
++ writew(v, r);
++}
++
++void
++osl_writeb(uint8 v, volatile uint8 *r)
++{
++ writeb(v, r);
++}
++
++void *
++osl_uncached(void *va)
++{
++#ifdef mips
++ return ((void*)KSEG1ADDR(va));
++#else
++ return ((void*)va);
++#endif
++}
++
++uint
++osl_getcycles(void)
++{
++ uint cycles;
++
++#if defined(mips)
++ cycles = read_c0_count() * 2;
++#elif defined(__i386__)
++ rdtscl(cycles);
++#else
++ cycles = 0;
++#endif
++ return cycles;
++}
++
++void *
++osl_reg_map(uint32 pa, uint size)
++{
++ return (ioremap_nocache((unsigned long)pa, (unsigned long)size));
++}
++
++void
++osl_reg_unmap(void *va)
++{
++ iounmap(va);
++}
++
++int
++osl_busprobe(uint32 *val, uint32 addr)
++{
++#ifdef mips
++ return get_dbe(*val, (uint32*)addr);
++#else
++ *val = readl(addr);
++ return 0;
++#endif
++}
++
++uchar*
++osl_pktdata(osl_t *osh, void *skb)
++{
++ return (((struct sk_buff*)skb)->data);
++}
++
++uint
++osl_pktlen(osl_t *osh, void *skb)
++{
++ return (((struct sk_buff*)skb)->len);
++}
++
++uint
++osl_pktheadroom(osl_t *osh, void *skb)
++{
++ return (uint) skb_headroom((struct sk_buff *) skb);
++}
++
++uint
++osl_pkttailroom(osl_t *osh, void *skb)
++{
++ return (uint) skb_tailroom((struct sk_buff *) skb);
++}
++
++void*
++osl_pktnext(osl_t *osh, void *skb)
++{
++ return (((struct sk_buff*)skb)->next);
++}
++
++void
++osl_pktsetnext(void *skb, void *x)
++{
++ ((struct sk_buff*)skb)->next = (struct sk_buff*)x;
++}
++
++void
++osl_pktsetlen(osl_t *osh, void *skb, uint len)
++{
++ __skb_trim((struct sk_buff*)skb, len);
++}
++
++uchar*
++osl_pktpush(osl_t *osh, void *skb, int bytes)
++{
++ return (skb_push((struct sk_buff*)skb, bytes));
++}
++
++uchar*
++osl_pktpull(osl_t *osh, void *skb, int bytes)
++{
++ return (skb_pull((struct sk_buff*)skb, bytes));
++}
++
++void*
++osl_pktdup(osl_t *osh, void *skb)
++{
++ return (skb_clone((struct sk_buff*)skb, GFP_ATOMIC));
++}
++
++void*
++osl_pktcookie(void *skb)
++{
++ return ((void*)((struct sk_buff*)skb)->csum);
++}
++
++void
++osl_pktsetcookie(void *skb, void *x)
++{
++ ((struct sk_buff*)skb)->csum = (uint)x;
++}
++
++void*
++osl_pktlink(void *skb)
++{
++ return (((struct sk_buff*)skb)->prev);
++}
++
++void
++osl_pktsetlink(void *skb, void *x)
++{
++ ((struct sk_buff*)skb)->prev = (struct sk_buff*)x;
++}
++
++uint
++osl_pktprio(void *skb)
++{
++ return (((struct sk_buff*)skb)->priority);
++}
++
++void
++osl_pktsetprio(void *skb, uint x)
++{
++ ((struct sk_buff*)skb)->priority = x;
++}
++
++
++#endif /* BINOSL */
+diff -Naur linux.old/drivers/net/hnd/sbutils.c linux.dev/drivers/net/hnd/sbutils.c
+--- linux.old/drivers/net/hnd/sbutils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/hnd/sbutils.c 2006-04-06 15:34:15.000000000 +0200
+@@ -0,0 +1,2837 @@
++/*
++ * Misc utility routines for accessing chip-specific features
++ * of the SiliconBackplane-based Broadcom chips.
++ *
++ * Copyright 2005, 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$
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbpci.h>
++#include <sbpcie.h>
++#include <pcicfg.h>
++#include <sbpcmcia.h>
++#include <sbextif.h>
++#include <bcmsrom.h>
++
++/* debug/trace */
++#define SB_ERROR(args)
++
++
++typedef uint32 (*sb_intrsoff_t)(void *intr_arg);
++typedef void (*sb_intrsrestore_t)(void *intr_arg, uint32 arg);
++typedef bool (*sb_intrsenabled_t)(void *intr_arg);
++
++/* misc sb info needed by some of the routines */
++typedef struct sb_info {
++
++ struct sb_pub sb; /* back plane public state(must be first field of sb_info */
++
++ void *osh; /* osl os handle */
++ void *sdh; /* bcmsdh handle */
++
++ void *curmap; /* current regs va */
++ void *regs[SB_MAXCORES]; /* other regs va */
++
++ uint curidx; /* current core index */
++ uint dev_coreid; /* the core provides driver functions */
++
++ bool memseg; /* flag to toggle MEM_SEG register */
++
++ uint gpioidx; /* gpio control core index */
++ uint gpioid; /* gpio control coretype */
++
++ uint numcores; /* # discovered cores */
++ uint coreid[SB_MAXCORES]; /* id of each core */
++
++ void *intr_arg; /* interrupt callback function arg */
++ sb_intrsoff_t intrsoff_fn; /* function turns chip interrupts off */
++ sb_intrsrestore_t intrsrestore_fn; /* function restore chip interrupts */
++ sb_intrsenabled_t intrsenabled_fn; /* function to check if chip interrupts are enabled */
++
++} sb_info_t;
++
++/* local prototypes */
++static sb_info_t * BCMINIT(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, int *varsz);
++static void BCMINIT(sb_scan)(sb_info_t *si);
++static uint sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val);
++static uint _sb_coreidx(sb_info_t *si);
++static uint sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit);
++static uint BCMINIT(sb_pcidev2chip)(uint pcidev);
++static uint BCMINIT(sb_chip2numcores)(uint chip);
++static bool sb_ispcie(sb_info_t *si);
++static bool sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen);
++static int sb_pci_fixcfg(sb_info_t *si);
++
++/* routines to access mdio slave device registers */
++static int sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint readdr, uint val);
++static void BCMINIT(sb_war30841)(sb_info_t *si);
++
++/* delay needed between the mdio control/ mdiodata register data access */
++#define PR28829_DELAY() OSL_DELAY(10)
++
++
++/* global variable to indicate reservation/release of gpio's*/
++static uint32 sb_gpioreservation = 0;
++
++#define SB_INFO(sbh) (sb_info_t*)sbh
++#define SET_SBREG(sbh, r, mask, val) W_SBREG((sbh), (r), ((R_SBREG((sbh), (r)) & ~(mask)) | (val)))
++#define GOODCOREADDR(x) (((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && ISALIGNED((x), SB_CORE_SIZE))
++#define GOODREGS(regs) ((regs) && ISALIGNED((uintptr)(regs), SB_CORE_SIZE))
++#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)
++#define GOODIDX(idx) (((uint)idx) < SB_MAXCORES)
++#define BADIDX (SB_MAXCORES+1)
++#define NOREV -1
++
++#define PCI(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCI))
++#define PCIE(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCIE))
++
++/* sonicsrev */
++#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
++#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
++
++#define R_SBREG(sbh, sbr) sb_read_sbreg((sbh), (sbr))
++#define W_SBREG(sbh, sbr, v) sb_write_sbreg((sbh), (sbr), (v))
++#define AND_SBREG(sbh, sbr, v) W_SBREG((sbh), (sbr), (R_SBREG((sbh), (sbr)) & (v)))
++#define OR_SBREG(sbh, sbr, v) W_SBREG((sbh), (sbr), (R_SBREG((sbh), (sbr)) | (v)))
++
++/*
++ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
++ * after core switching to avoid invalid register accesss inside ISR.
++ */
++#define INTR_OFF(si, intr_val) \
++ if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
++ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); }
++#define INTR_RESTORE(si, intr_val) \
++ if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
++ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }
++
++/* dynamic clock control defines */
++#define LPOMINFREQ 25000 /* low power oscillator min */
++#define LPOMAXFREQ 43000 /* low power oscillator max */
++#define XTALMINFREQ 19800000 /* 20 MHz - 1% */
++#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */
++#define PCIMINFREQ 25000000 /* 25 MHz */
++#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */
++
++#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
++#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
++
++#define MIN_DUMPBUFLEN 32 /* debug */
++
++/* different register spaces to access thr'u pcie indirect access*/
++#define PCIE_CONFIGREGS 1
++#define PCIE_PCIEREGS 2
++
++/* GPIO Based LED powersave defines */
++#define DEFAULT_GPIO_ONTIME 10
++#define DEFAULT_GPIO_OFFTIME 90
++
++#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
++
++static uint32
++sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr)
++{
++ uint8 tmp;
++ uint32 val, intr_val = 0;
++
++
++ /*
++ * compact flash only has 11 bits address, while we needs 12 bits address.
++ * MEM_SEG will be OR'd with other 11 bits address in hardware,
++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
++ */
++ if(si->memseg) {
++ INTR_OFF(si, intr_val);
++ tmp = 1;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ sbr = (uint32) ((uintptr) sbr & ~(1 << 11)); /* mask out bit 11*/
++ }
++
++ val = R_REG(sbr);
++
++ if(si->memseg) {
++ tmp = 0;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ INTR_RESTORE(si, intr_val);
++ }
++
++ return (val);
++}
++
++static void
++sb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v)
++{
++ uint8 tmp;
++ volatile uint32 dummy;
++ uint32 intr_val = 0;
++
++
++ /*
++ * compact flash only has 11 bits address, while we needs 12 bits address.
++ * MEM_SEG will be OR'd with other 11 bits address in hardware,
++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
++ */
++ if(si->memseg) {
++ INTR_OFF(si, intr_val);
++ tmp = 1;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ sbr = (uint32) ((uintptr) sbr & ~(1 << 11)); /* mask out bit 11*/
++ }
++
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) {
++#ifdef IL_BIGENDIAN
++ dummy = R_REG(sbr);
++ W_REG(((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
++ dummy = R_REG(sbr);
++ W_REG((volatile uint16 *)sbr, (uint16)(v & 0xffff));
++#else
++ dummy = R_REG(sbr);
++ W_REG((volatile uint16 *)sbr, (uint16)(v & 0xffff));
++ dummy = R_REG(sbr);
++ W_REG(((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
++#endif
++ } else
++ W_REG(sbr, v);
++
++ if(si->memseg) {
++ tmp = 0;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ INTR_RESTORE(si, intr_val);
++ }
++}
++
++/*
++ * Allocate a sb handle.
++ * devid - pci device id (used to determine chip#)
++ * osh - opaque OS handle
++ * regs - virtual address of initial core registers
++ * bustype - pci/pcmcia/sb/sdio/etc
++ * vars - pointer to a pointer area for "environment" variables
++ * varsz - pointer to int to return the size of the vars
++ */
++sb_t *
++BCMINITFN(sb_attach)(uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, int *varsz)
++{
++ sb_info_t *si;
++
++ /* alloc sb_info_t */
++ if ((si = MALLOC(osh, sizeof (sb_info_t))) == NULL) {
++ SB_ERROR(("sb_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
++ return (NULL);
++ }
++
++ if (BCMINIT(sb_doattach)(si, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) {
++ MFREE(osh, si, sizeof (sb_info_t));
++ return (NULL);
++ }
++ return (sb_t *)si;
++}
++
++/* Using sb_kattach depends on SB_BUS support, either implicit */
++/* no limiting BCMBUSTYPE value) or explicit (value is SB_BUS). */
++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SB_BUS)
++
++/* global kernel resource */
++static sb_info_t ksi;
++
++/* generic kernel variant of sb_attach() */
++sb_t *
++BCMINITFN(sb_kattach)()
++{
++ uint32 *regs;
++
++ if (ksi.curmap == NULL) {
++ uint32 cid;
++
++ regs = (uint32 *)REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE);
++ cid = R_REG((uint32 *)regs);
++ if (((cid & CID_ID_MASK) == BCM4712_DEVICE_ID) &&
++ ((cid & CID_PKG_MASK) != BCM4712LARGE_PKG_ID) &&
++ ((cid & CID_REV_MASK) <= (3 << CID_REV_SHIFT))) {
++ uint32 *scc, val;
++
++ scc = (uint32 *)((uchar*)regs + OFFSETOF(chipcregs_t, slow_clk_ctl));
++ val = R_REG(scc);
++ SB_ERROR((" initial scc = 0x%x\n", val));
++ val |= SCC_SS_XTAL;
++ W_REG(scc, val);
++ }
++
++ if (BCMINIT(sb_doattach)(&ksi, BCM4710_DEVICE_ID, NULL, (void*)regs,
++ SB_BUS, NULL, NULL, NULL) == NULL) {
++ return NULL;
++ }
++ }
++
++ return (sb_t *)&ksi;
++}
++#endif
++
++static sb_info_t *
++BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, int *varsz)
++{
++ uint origidx;
++ chipcregs_t *cc;
++ sbconfig_t *sb;
++ uint32 w;
++
++ ASSERT(GOODREGS(regs));
++
++ bzero((uchar*)si, sizeof (sb_info_t));
++
++ si->sb.buscoreidx = si->gpioidx = BADIDX;
++
++ si->osh = osh;
++ si->curmap = regs;
++ si->sdh = sdh;
++
++ /* check to see if we are a sb core mimic'ing a pci core */
++ if (bustype == PCI_BUS) {
++ if (OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof (uint32)) == 0xffffffff)
++ bustype = SB_BUS;
++ else
++ bustype = PCI_BUS;
++ }
++
++ si->sb.bustype = bustype;
++ if (si->sb.bustype != BUSTYPE(si->sb.bustype)) {
++ SB_ERROR(("sb_doattach: bus type %d does not match configured bus type %d\n",
++ si->sb.bustype, BUSTYPE(si->sb.bustype)));
++ return NULL;
++ }
++
++ /* need to set memseg flag for CF card first before any sb registers access */
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS)
++ si->memseg = TRUE;
++
++ /* kludge to enable the clock on the 4306 which lacks a slowclock */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS)
++ sb_clkctl_xtal(&si->sb, XTAL|PLL, ON);
++
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ w = OSL_PCI_READ_CONFIG(osh, PCI_BAR0_WIN, sizeof (uint32));
++ if (!GOODCOREADDR(w))
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof (uint32), SB_ENUM_BASE);
++ }
++
++ /* initialize current core index value */
++ si->curidx = _sb_coreidx(si);
++
++ if (si->curidx == BADIDX) {
++ SB_ERROR(("sb_doattach: bad core index\n"));
++ return NULL;
++ }
++
++ /* get sonics backplane revision */
++ sb = REGS2SB(si->curmap);
++ si->sb.sonicsrev = (R_SBREG(si, &(sb)->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT;
++
++ /* keep and reuse the initial register mapping */
++ origidx = si->curidx;
++ if (BUSTYPE(si->sb.bustype) == SB_BUS)
++ si->regs[origidx] = regs;
++
++ /* is core-0 a chipcommon core? */
++ si->numcores = 1;
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, 0);
++ if (sb_coreid(&si->sb) != SB_CC)
++ cc = NULL;
++
++ /* determine chip id and rev */
++ if (cc) {
++ /* chip common core found! */
++ si->sb.chip = R_REG(&cc->chipid) & CID_ID_MASK;
++ si->sb.chiprev = (R_REG(&cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT;
++ si->sb.chippkg = (R_REG(&cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT;
++ } else {
++ /* The only pcmcia chip without a chipcommon core is a 4301 */
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS)
++ devid = BCM4301_DEVICE_ID;
++
++ /* no chip common core -- must convert device id to chip id */
++ if ((si->sb.chip = BCMINIT(sb_pcidev2chip)(devid)) == 0) {
++ SB_ERROR(("sb_doattach: unrecognized device id 0x%04x\n", devid));
++ sb_setcoreidx(&si->sb, origidx);
++ return NULL;
++ }
++ }
++
++ /* get chipcommon rev */
++ si->sb.ccrev = cc ? (int)sb_corerev(&si->sb) : NOREV;
++
++ /* determine numcores */
++ if (cc && ((si->sb.ccrev == 4) || (si->sb.ccrev >= 6)))
++ si->numcores = (R_REG(&cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT;
++ else
++ si->numcores = BCMINIT(sb_chip2numcores)(si->sb.chip);
++
++ /* return to original core */
++ sb_setcoreidx(&si->sb, origidx);
++
++ /* sanity checks */
++ ASSERT(si->sb.chip);
++
++ /* scan for cores */
++ BCMINIT(sb_scan)(si);
++
++ /* fixup necessary chip/core configurations */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ if (sb_pci_fixcfg(si)) {
++ SB_ERROR(("sb_doattach: sb_pci_fixcfg failed\n"));
++ return NULL;
++ }
++ }
++
++ /* srom_var_init() depends on sb_scan() info */
++ if (srom_var_init(si, si->sb.bustype, si->curmap, osh, vars, varsz)) {
++ SB_ERROR(("sb_doattach: srom_var_init failed: bad srom\n"));
++ return (NULL);
++ }
++
++ if (cc == NULL) {
++ /*
++ * The chip revision number is hardwired into all
++ * of the pci function config rev fields and is
++ * independent from the individual core revision numbers.
++ * For example, the "A0" silicon of each chip is chip rev 0.
++ * For PCMCIA we get it from the CIS instead.
++ */
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) {
++ ASSERT(vars);
++ si->sb.chiprev = getintvar(*vars, "chiprev");
++ } else if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_REV, sizeof (uint32));
++ si->sb.chiprev = w & 0xff;
++ } else
++ si->sb.chiprev = 0;
++ }
++
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) {
++ w = getintvar(*vars, "regwindowsz");
++ si->memseg = (w <= CFTABLE_REGWIN_2K) ? TRUE : FALSE;
++ }
++
++ /* gpio control core is required */
++ if (!GOODIDX(si->gpioidx)) {
++ SB_ERROR(("sb_doattach: gpio control core not found\n"));
++ return NULL;
++ }
++
++ /* get boardtype and boardrev */
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ /* do a pci config read to get subsystem id and subvendor id */
++ w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_SVID, sizeof (uint32));
++ si->sb.boardvendor = w & 0xffff;
++ si->sb.boardtype = (w >> 16) & 0xffff;
++ break;
++
++ case PCMCIA_BUS:
++ case SDIO_BUS:
++ si->sb.boardvendor = getintvar(*vars, "manfid");
++ si->sb.boardtype = getintvar(*vars, "prodid");
++ break;
++
++ case SB_BUS:
++ case JTAG_BUS:
++ si->sb.boardvendor = VENDOR_BROADCOM;
++ if ((si->sb.boardtype = getintvar(NULL, "boardtype")) == 0)
++ si->sb.boardtype = 0xffff;
++ break;
++ }
++
++ if (si->sb.boardtype == 0) {
++ SB_ERROR(("sb_doattach: unknown board type\n"));
++ ASSERT(si->sb.boardtype);
++ }
++
++ /* setup the GPIO based LED powersave register */
++ if (si->sb.ccrev >= 16) {
++ w = getintvar(*vars, "gpiotimerval");
++ if (!w)
++ w = DEFAULT_GPIOTIMERVAL;
++ sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w);
++ }
++
++
++ return (si);
++}
++
++uint
++sb_coreid(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &(sb)->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
++}
++
++uint
++sb_coreidx(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->curidx);
++}
++
++/* return current index of core */
++static uint
++_sb_coreidx(sb_info_t *si)
++{
++ sbconfig_t *sb;
++ uint32 sbaddr = 0;
++
++ ASSERT(si);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case SB_BUS:
++ sb = REGS2SB(si->curmap);
++ sbaddr = sb_base(R_SBREG(si, &sb->sbadmatch0));
++ break;
++
++ case PCI_BUS:
++ sbaddr = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof (uint32));
++ break;
++
++ case PCMCIA_BUS: {
++ uint8 tmp = 0;
++
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR0, &tmp, 1);
++ sbaddr = (uint)tmp << 12;
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR1, &tmp, 1);
++ sbaddr |= (uint)tmp << 16;
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR2, &tmp, 1);
++ sbaddr |= (uint)tmp << 24;
++ break;
++ }
++
++#ifdef BCMJTAG
++ case JTAG_BUS:
++ sbaddr = (uint32)si->curmap;
++ break;
++#endif /* BCMJTAG */
++
++ default:
++ ASSERT(0);
++ }
++
++ if (!GOODCOREADDR(sbaddr))
++ return BADIDX;
++
++ return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE);
++}
++
++uint
++sb_corevendor(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &(sb)->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
++}
++
++uint
++sb_corerev(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint sbidh;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++ sbidh = R_SBREG(si, &(sb)->sbidhigh);
++
++ return (SBCOREREV(sbidh));
++}
++
++void *
++sb_osh(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return si->osh;
++}
++
++#define SBTML_ALLOW (SBTML_PE | SBTML_FGC | SBTML_FL_MASK)
++
++/* set/clear sbtmstatelow core-specific flags */
++uint32
++sb_coreflags(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint32 w;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ ASSERT((val & ~mask) == 0);
++ ASSERT((mask & ~SBTML_ALLOW) == 0);
++
++ /* mask and set */
++ if (mask || val) {
++ w = (R_SBREG(si, &sb->sbtmstatelow) & ~mask) | val;
++ W_SBREG(si, &sb->sbtmstatelow, w);
++ }
++
++ /* return the new value */
++ return (R_SBREG(si, &sb->sbtmstatelow) & SBTML_ALLOW);
++}
++
++/* set/clear sbtmstatehigh core-specific flags */
++uint32
++sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint32 w;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ ASSERT((val & ~mask) == 0);
++ ASSERT((mask & ~SBTMH_FL_MASK) == 0);
++
++ /* mask and set */
++ if (mask || val) {
++ w = (R_SBREG(si, &sb->sbtmstatehigh) & ~mask) | val;
++ W_SBREG(si, &sb->sbtmstatehigh, w);
++ }
++
++ /* return the new value */
++ return (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_FL_MASK);
++}
++
++/* caller needs to take care of core-specific bist hazards */
++int
++sb_corebist(sb_t *sbh, uint coreid, uint coreunit)
++{
++ uint32 sblo;
++ uint coreidx;
++ sb_info_t *si;
++ int result = 0;
++
++ si = SB_INFO(sbh);
++
++ coreidx = sb_findcoreidx(si, coreid, coreunit);
++ if (!GOODIDX(coreidx))
++ result = BCME_ERROR;
++ else {
++ sblo = sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatelow), 0, 0);
++ sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatelow), ~0, (sblo | SBTML_FGC | SBTML_BE));
++
++ SPINWAIT(((sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatehigh), 0, 0) & SBTMH_BISTD) == 0), 100000);
++
++ if (sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatehigh), 0, 0) & SBTMH_BISTF)
++ result = BCME_ERROR;
++
++ sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatelow), ~0, sblo);
++ }
++
++ return result;
++}
++
++bool
++sb_iscoreup(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &(sb)->sbtmstatelow) & (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK);
++}
++
++/*
++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
++ * switch back to the original core, and return the new value.
++ */
++static uint
++sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val)
++{
++ uint origidx;
++ uint32 *r;
++ uint w;
++ uint intr_val = 0;
++
++ ASSERT(GOODIDX(coreidx));
++ ASSERT(regoff < SB_CORE_SIZE);
++ ASSERT((val & ~mask) == 0);
++
++ INTR_OFF(si, intr_val);
++
++ /* save current core index */
++ origidx = sb_coreidx(&si->sb);
++
++ /* switch core */
++ r = (uint32*) ((uchar*) sb_setcoreidx(&si->sb, coreidx) + regoff);
++
++ /* mask and set */
++ if (mask || val) {
++ if (regoff >= SBCONFIGOFF) {
++ w = (R_SBREG(si, r) & ~mask) | val;
++ W_SBREG(si, r, w);
++ } else {
++ w = (R_REG(r) & ~mask) | val;
++ W_REG(r, w);
++ }
++ }
++
++ /* readback */
++ if (regoff >= SBCONFIGOFF)
++ w = R_SBREG(si, r);
++ else
++ w = R_REG(r);
++
++ /* restore core index */
++ if (origidx != coreidx)
++ sb_setcoreidx(&si->sb, origidx);
++
++ INTR_RESTORE(si, intr_val);
++ return (w);
++}
++
++#define DWORD_ALIGN(x) (x & ~(0x03))
++#define BYTE_POS(x) (x & 0x3)
++#define WORD_POS(x) (x & 0x1)
++
++#define BYTE_SHIFT(x) (8 * BYTE_POS(x))
++#define WORD_SHIFT(x) (16 * WORD_POS(x))
++
++#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
++#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
++
++#define read_pci_cfg_byte(a) \
++ (BYTE_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xff)
++
++#define read_pci_cfg_write(a) \
++ (WORD_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xffff)
++
++
++/* return TRUE if requested capability exists in the PCI config space */
++static bool
++sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen)
++{
++ uint8 cap_id;
++ uint8 cap_ptr;
++ uint32 bufsize;
++ uint8 byte_val;
++
++ if (BUSTYPE(si->sb.bustype) != PCI_BUS)
++ return FALSE;
++
++ /* check for Header type 0*/
++ byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
++ if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)
++ return FALSE;
++
++ /* check if the capability pointer field exists */
++ byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
++ if (!(byte_val & PCI_CAPPTR_PRESENT))
++ return FALSE;
++
++ cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
++ /* check if the capability pointer is 0x00 */
++ if (cap_ptr == 0x00)
++ return FALSE;
++
++
++ /* loop thr'u the capability list and see if the pcie capabilty exists */
++
++ cap_id = read_pci_cfg_byte(cap_ptr);
++
++ while (cap_id != req_cap_id) {
++ cap_ptr = read_pci_cfg_byte((cap_ptr+1));
++ if (cap_ptr == 0x00) break;
++ cap_id = read_pci_cfg_byte(cap_ptr);
++ }
++ if (cap_id != req_cap_id) {
++ return FALSE;
++ }
++ /* found the caller requested capability */
++ if ((buf != NULL) && (buflen != NULL)) {
++ bufsize = *buflen;
++ if (!bufsize) goto end;
++ *buflen = 0;
++ /* copy the cpability data excluding cap ID and next ptr */
++ cap_ptr += 2;
++ if ((bufsize + cap_ptr) > SZPCR)
++ bufsize = SZPCR - cap_ptr;
++ *buflen = bufsize;
++ while (bufsize--) {
++ *buf = read_pci_cfg_byte(cap_ptr);
++ cap_ptr++;
++ buf++;
++ }
++ }
++end:
++ return TRUE;
++}
++
++/* return TRUE if PCIE capability exists the pci config space */
++static bool
++sb_ispcie(sb_info_t *si)
++{
++ return(sb_find_pci_capability(si, PCI_CAP_PCIECAP_ID, NULL, NULL));
++}
++
++/* scan the sb enumerated space to identify all cores */
++static void
++BCMINITFN(sb_scan)(sb_info_t *si)
++{
++ uint origidx;
++ uint i;
++ bool pci;
++ bool pcie;
++ uint pciidx;
++ uint pcieidx;
++ uint pcirev;
++ uint pcierev;
++
++
++
++ /* numcores should already be set */
++ ASSERT((si->numcores > 0) && (si->numcores <= SB_MAXCORES));
++
++ /* save current core index */
++ origidx = sb_coreidx(&si->sb);
++
++ si->sb.buscorerev = NOREV;
++ si->sb.buscoreidx = BADIDX;
++
++ si->gpioidx = BADIDX;
++
++ pci = pcie = FALSE;
++ pcirev = pcierev = NOREV;
++ pciidx = pcieidx = BADIDX;
++
++ for (i = 0; i < si->numcores; i++) {
++ sb_setcoreidx(&si->sb, i);
++ si->coreid[i] = sb_coreid(&si->sb);
++
++ if (si->coreid[i] == SB_PCI) {
++ pciidx = i;
++ pcirev = sb_corerev(&si->sb);
++ pci = TRUE;
++ } else if (si->coreid[i] == SB_PCIE) {
++ pcieidx = i;
++ pcierev = sb_corerev(&si->sb);
++ pcie = TRUE;
++ } else if (si->coreid[i] == SB_PCMCIA) {
++ si->sb.buscorerev = sb_corerev(&si->sb);
++ si->sb.buscoretype = si->coreid[i];
++ si->sb.buscoreidx = i;
++ }
++ }
++ if (pci && pcie) {
++ if (sb_ispcie(si))
++ pci = FALSE;
++ else
++ pcie = FALSE;
++ }
++ if (pci) {
++ si->sb.buscoretype = SB_PCI;
++ si->sb.buscorerev = pcirev;
++ si->sb.buscoreidx = pciidx;
++ }
++ else if (pcie) {
++ si->sb.buscoretype = SB_PCIE;
++ si->sb.buscorerev = pcierev;
++ si->sb.buscoreidx = pcieidx;
++ }
++
++ /*
++ * Find the gpio "controlling core" type and index.
++ * Precedence:
++ * - if there's a chip common core - use that
++ * - else if there's a pci core (rev >= 2) - use that
++ * - else there had better be an extif core (4710 only)
++ */
++ if (GOODIDX(sb_findcoreidx(si, SB_CC, 0))) {
++ si->gpioidx = sb_findcoreidx(si, SB_CC, 0);
++ si->gpioid = SB_CC;
++ } else if (PCI(si) && (si->sb.buscorerev >= 2)) {
++ si->gpioidx = si->sb.buscoreidx;
++ si->gpioid = SB_PCI;
++ } else if (sb_findcoreidx(si, SB_EXTIF, 0)) {
++ si->gpioidx = sb_findcoreidx(si, SB_EXTIF, 0);
++ si->gpioid = SB_EXTIF;
++ } else
++ ASSERT(si->gpioidx != BADIDX);
++
++ /* return to original core index */
++ sb_setcoreidx(&si->sb, origidx);
++}
++
++/* may be called with core in reset */
++void
++sb_detach(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint idx;
++
++ si = SB_INFO(sbh);
++
++ if (si == NULL)
++ return;
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS)
++ for (idx = 0; idx < SB_MAXCORES; idx++)
++ if (si->regs[idx]) {
++ REG_UNMAP(si->regs[idx]);
++ si->regs[idx] = NULL;
++ }
++
++ if (si != &ksi)
++ MFREE(si->osh, si, sizeof (sb_info_t));
++}
++
++/* use pci dev id to determine chip id for chips not having a chipcommon core */
++static uint
++BCMINITFN(sb_pcidev2chip)(uint pcidev)
++{
++ if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID))
++ return (BCM4710_DEVICE_ID);
++ if ((pcidev >= BCM4402_DEVICE_ID) && (pcidev <= BCM4402_V90_ID))
++ return (BCM4402_DEVICE_ID);
++ if (pcidev == BCM4401_ENET_ID)
++ return (BCM4402_DEVICE_ID);
++ if ((pcidev >= BCM4307_V90_ID) && (pcidev <= BCM4307_D11B_ID))
++ return (BCM4307_DEVICE_ID);
++ if (pcidev == BCM4301_DEVICE_ID)
++ return (BCM4301_DEVICE_ID);
++
++ return (0);
++}
++
++/* convert chip number to number of i/o cores */
++static uint
++BCMINITFN(sb_chip2numcores)(uint chip)
++{
++ if (chip == BCM4710_DEVICE_ID)
++ return (9);
++ if (chip == BCM4402_DEVICE_ID)
++ return (3);
++ if ((chip == BCM4301_DEVICE_ID) || (chip == BCM4307_DEVICE_ID))
++ return (5);
++ if (chip == BCM4306_DEVICE_ID) /* < 4306c0 */
++ return (6);
++ if (chip == BCM4704_DEVICE_ID)
++ return (9);
++ if (chip == BCM5365_DEVICE_ID)
++ return (7);
++
++ SB_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", chip));
++ ASSERT(0);
++ return (1);
++}
++
++/* return index of coreid or BADIDX if not found */
++static uint
++sb_findcoreidx( sb_info_t *si, uint coreid, uint coreunit)
++{
++ uint found;
++ uint i;
++
++ found = 0;
++
++ for (i = 0; i < si->numcores; i++)
++ if (si->coreid[i] == coreid) {
++ if (found == coreunit)
++ return (i);
++ found++;
++ }
++
++ return (BADIDX);
++}
++
++/*
++ * this function changes logical "focus" to the indiciated core,
++ * must be called with interrupt off.
++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core
++ */
++void*
++sb_setcoreidx(sb_t *sbh, uint coreidx)
++{
++ sb_info_t *si;
++ uint32 sbaddr;
++ uint8 tmp;
++
++ si = SB_INFO(sbh);
++
++ if (coreidx >= si->numcores)
++ return (NULL);
++
++ /*
++ * If the user has provided an interrupt mask enabled function,
++ * then assert interrupts are disabled before switching the core.
++ */
++ ASSERT((si->intrsenabled_fn == NULL) || !(*(si)->intrsenabled_fn)((si)->intr_arg));
++
++ sbaddr = SB_ENUM_BASE + (coreidx * SB_CORE_SIZE);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case SB_BUS:
++ /* map new one */
++ if (!si->regs[coreidx]) {
++ si->regs[coreidx] = (void*)REG_MAP(sbaddr, SB_CORE_SIZE);
++ ASSERT(GOODREGS(si->regs[coreidx]));
++ }
++ si->curmap = si->regs[coreidx];
++ break;
++
++ case PCI_BUS:
++ /* point bar0 window */
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, 4, sbaddr);
++ break;
++
++ case PCMCIA_BUS:
++ tmp = (sbaddr >> 12) & 0x0f;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR0, &tmp, 1);
++ tmp = (sbaddr >> 16) & 0xff;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR1, &tmp, 1);
++ tmp = (sbaddr >> 24) & 0xff;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR2, &tmp, 1);
++ break;
++#ifdef BCMJTAG
++ case JTAG_BUS:
++ /* map new one */
++ if (!si->regs[coreidx]) {
++ si->regs[coreidx] = (void *)sbaddr;
++ ASSERT(GOODREGS(si->regs[coreidx]));
++ }
++ si->curmap = si->regs[coreidx];
++ break;
++#endif /* BCMJTAG */
++ }
++
++ si->curidx = coreidx;
++
++ return (si->curmap);
++}
++
++/*
++ * this function changes logical "focus" to the indiciated core,
++ * must be called with interrupt off.
++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core
++ */
++void*
++sb_setcore(sb_t *sbh, uint coreid, uint coreunit)
++{
++ sb_info_t *si;
++ uint idx;
++
++ si = SB_INFO(sbh);
++ idx = sb_findcoreidx(si, coreid, coreunit);
++ if (!GOODIDX(idx))
++ return (NULL);
++
++ return (sb_setcoreidx(sbh, idx));
++}
++
++/* return chip number */
++uint
++BCMINITFN(sb_chip)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chip);
++}
++
++/* return chip revision number */
++uint
++BCMINITFN(sb_chiprev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chiprev);
++}
++
++/* return chip common revision number */
++uint
++BCMINITFN(sb_chipcrev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.ccrev);
++}
++
++/* return chip package option */
++uint
++BCMINITFN(sb_chippkg)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chippkg);
++}
++
++/* return PCI core rev. */
++uint
++BCMINITFN(sb_pcirev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.buscorerev);
++}
++
++bool
++BCMINITFN(sb_war16165)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (PCI(si) && (si->sb.buscorerev <= 10));
++}
++
++static void
++BCMINITFN(sb_war30841)(sb_info_t *si)
++{
++ sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
++ sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
++ sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
++}
++
++/* return PCMCIA core rev. */
++uint
++BCMINITFN(sb_pcmciarev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.buscorerev);
++}
++
++/* return board vendor id */
++uint
++BCMINITFN(sb_boardvendor)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.boardvendor);
++}
++
++/* return boardtype */
++uint
++BCMINITFN(sb_boardtype)(sb_t *sbh)
++{
++ sb_info_t *si;
++ char *var;
++
++ si = SB_INFO(sbh);
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS && si->sb.boardtype == 0xffff) {
++ /* boardtype format is a hex string */
++ si->sb.boardtype = getintvar(NULL, "boardtype");
++
++ /* backward compatibility for older boardtype string format */
++ if ((si->sb.boardtype == 0) && (var = getvar(NULL, "boardtype"))) {
++ if (!strcmp(var, "bcm94710dev"))
++ si->sb.boardtype = BCM94710D_BOARD;
++ else if (!strcmp(var, "bcm94710ap"))
++ si->sb.boardtype = BCM94710AP_BOARD;
++ else if (!strcmp(var, "bu4710"))
++ si->sb.boardtype = BU4710_BOARD;
++ else if (!strcmp(var, "bcm94702mn"))
++ si->sb.boardtype = BCM94702MN_BOARD;
++ else if (!strcmp(var, "bcm94710r1"))
++ si->sb.boardtype = BCM94710R1_BOARD;
++ else if (!strcmp(var, "bcm94710r4"))
++ si->sb.boardtype = BCM94710R4_BOARD;
++ else if (!strcmp(var, "bcm94702cpci"))
++ si->sb.boardtype = BCM94702CPCI_BOARD;
++ else if (!strcmp(var, "bcm95380_rr"))
++ si->sb.boardtype = BCM95380RR_BOARD;
++ }
++ }
++
++ return (si->sb.boardtype);
++}
++
++/* return bus type of sbh device */
++uint
++sb_bus(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.bustype);
++}
++
++/* return bus core type */
++uint
++sb_buscoretype(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (si->sb.buscoretype);
++}
++
++/* return bus core revision */
++uint
++sb_buscorerev(sb_t *sbh)
++{
++ sb_info_t *si;
++ si = SB_INFO(sbh);
++
++ return (si->sb.buscorerev);
++}
++
++/* return list of found cores */
++uint
++sb_corelist(sb_t *sbh, uint coreid[])
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ bcopy((uchar*)si->coreid, (uchar*)coreid, (si->numcores * sizeof (uint)));
++ return (si->numcores);
++}
++
++/* return current register mapping */
++void *
++sb_coreregs(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ ASSERT(GOODREGS(si->curmap));
++
++ return (si->curmap);
++}
++
++
++/* do buffered registers update */
++void
++sb_commit(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++
++ origidx = si->curidx;
++ ASSERT(GOODIDX(origidx));
++
++ INTR_OFF(si, intr_val);
++
++ /* switch over to chipcommon core if there is one, else use pci */
++ if (si->sb.ccrev != NOREV) {
++ chipcregs_t *ccregs = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
++
++ /* do the buffer registers update */
++ W_REG(&ccregs->broadcastaddress, SB_COMMIT);
++ W_REG(&ccregs->broadcastdata, 0x0);
++ } else if (PCI(si)) {
++ sbpciregs_t *pciregs = (sbpciregs_t *)sb_setcore(sbh, SB_PCI, 0);
++
++ /* do the buffer registers update */
++ W_REG(&pciregs->bcastaddr, SB_COMMIT);
++ W_REG(&pciregs->bcastdata, 0x0);
++ } else
++ ASSERT(0);
++
++ /* restore core index */
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++}
++
++/* reset and re-enable a core */
++void
++sb_core_reset(sb_t *sbh, uint32 bits)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ volatile uint32 dummy;
++
++ si = SB_INFO(sbh);
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ /*
++ * Must do the disable sequence first to work for arbitrary current core state.
++ */
++ sb_core_disable(sbh, bits);
++
++ /*
++ * Now do the initialization sequence.
++ */
++
++ /* set reset while enabling the clock and forcing them on throughout the core */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++
++ if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_SERR) {
++ W_SBREG(si, &sb->sbtmstatehigh, 0);
++ }
++ if ((dummy = R_SBREG(si, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
++ AND_SBREG(si, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
++ }
++
++ /* clear reset and allow it to propagate throughout the core */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++
++ /* leave clock enabled */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_CLK | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++}
++
++void
++sb_core_tofixup(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ if ( (BUSTYPE(si->sb.bustype) != PCI_BUS) || PCIE(si) || (PCI(si) && (si->sb.buscorerev >= 5)) )
++ return;
++
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS) {
++ SET_SBREG(si, &sb->sbimconfiglow,
++ SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x5 << SBIMCL_RTO_SHIFT) | 0x3);
++ } else {
++ if (sb_coreid(sbh) == SB_PCI) {
++ SET_SBREG(si, &sb->sbimconfiglow,
++ SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
++ } else {
++ SET_SBREG(si, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0);
++ }
++ }
++
++ sb_commit(sbh);
++}
++
++/*
++ * Set the initiator timeout for the "master core".
++ * The master core is defined to be the core in control
++ * of the chip and so it issues accesses to non-memory
++ * locations (Because of dma *any* core can access memeory).
++ *
++ * The routine uses the bus to decide who is the master:
++ * SB_BUS => mips
++ * JTAG_BUS => chipc
++ * PCI_BUS => pci or pcie
++ * PCMCIA_BUS => pcmcia
++ * SDIO_BUS => pcmcia
++ *
++ * This routine exists so callers can disable initiator
++ * timeouts so accesses to very slow devices like otp
++ * won't cause an abort. The routine allows arbitrary
++ * settings of the service and request timeouts, though.
++ *
++ * Returns the timeout state before changing it or -1
++ * on error.
++ */
++
++#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK)
++
++uint32
++sb_set_initiator_to(sb_t *sbh, uint32 to)
++{
++ sb_info_t *si;
++ uint origidx, idx;
++ uint intr_val = 0;
++ uint32 tmp, ret = 0xffffffff;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ if ((to & ~TO_MASK) != 0)
++ return ret;
++
++ /* Figure out the master core */
++ idx = BADIDX;
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ idx = si->sb.buscoreidx;
++ break;
++ case JTAG_BUS:
++ idx = SB_CC_IDX;
++ break;
++ case PCMCIA_BUS:
++ case SDIO_BUS:
++ idx = sb_findcoreidx(si, SB_PCMCIA, 0);
++ break;
++ case SB_BUS:
++ if ((idx = sb_findcoreidx(si, SB_MIPS33, 0)) == BADIDX)
++ idx = sb_findcoreidx(si, SB_MIPS, 0);
++ break;
++ default:
++ ASSERT(0);
++ }
++ if (idx == BADIDX)
++ return ret;
++
++ INTR_OFF(si, intr_val);
++ origidx = sb_coreidx(sbh);
++
++ sb = REGS2SB(sb_setcoreidx(sbh, idx));
++
++ tmp = R_SBREG(si, &sb->sbimconfiglow);
++ ret = tmp & TO_MASK;
++ W_SBREG(si, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to);
++
++ sb_commit(sbh);
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return ret;
++}
++
++void
++sb_core_disable(sb_t *sbh, uint32 bits)
++{
++ sb_info_t *si;
++ volatile uint32 dummy;
++ uint32 rej;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ /* if core is already in reset, just return */
++ if (R_SBREG(si, &sb->sbtmstatelow) & SBTML_RESET)
++ return;
++
++ /* reject value changed between sonics 2.2 and 2.3 */
++ if (si->sb.sonicsrev == SONICS_2_2)
++ rej = (1 << SBTML_REJ_SHIFT);
++ else
++ rej = (2 << SBTML_REJ_SHIFT);
++
++ /* if clocks are not enabled, put into reset and return */
++ if ((R_SBREG(si, &sb->sbtmstatelow) & SBTML_CLK) == 0)
++ goto disable;
++
++ /* set target reject and spin until busy is clear (preserve core-specific bits) */
++ OR_SBREG(si, &sb->sbtmstatelow, rej);
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++ SPINWAIT((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
++
++ if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT) {
++ OR_SBREG(si, &sb->sbimstate, SBIM_RJ);
++ dummy = R_SBREG(si, &sb->sbimstate);
++ OSL_DELAY(1);
++ SPINWAIT((R_SBREG(si, &sb->sbimstate) & SBIM_BY), 100000);
++ }
++
++ /* set reset and reject while enabling the clocks */
++ W_SBREG(si, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | rej | SBTML_RESET));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(10);
++
++ /* don't forget to clear the initiator reject bit */
++ if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT)
++ AND_SBREG(si, &sb->sbimstate, ~SBIM_RJ);
++
++disable:
++ /* leave reset and reject asserted */
++ W_SBREG(si, &sb->sbtmstatelow, (bits | rej | SBTML_RESET));
++ OSL_DELAY(1);
++}
++
++/* set chip watchdog reset timer to fire in 'ticks' backplane cycles */
++void
++sb_watchdog(sb_t *sbh, uint ticks)
++{
++ sb_info_t *si = SB_INFO(sbh);
++
++ /* instant NMI */
++ switch (si->gpioid) {
++ case SB_CC:
++ sb_corereg(si, 0, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
++ break;
++ case SB_EXTIF:
++ sb_corereg(si, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks);
++ break;
++ }
++}
++
++/* initialize the pcmcia core */
++void
++sb_pcmcia_init(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint8 cor;
++
++ si = SB_INFO(sbh);
++
++ /* enable d11 mac interrupts */
++ if (si->sb.chip == BCM4301_DEVICE_ID) {
++ /* Have to use FCR2 in 4301 */
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_FCR2 + PCMCIA_COR, &cor, 1);
++ cor |= COR_IRQEN | COR_FUNEN;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_FCR2 + PCMCIA_COR, &cor, 1);
++ } else {
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_FCR0 + PCMCIA_COR, &cor, 1);
++ cor |= COR_IRQEN | COR_FUNEN;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_FCR0 + PCMCIA_COR, &cor, 1);
++ }
++
++}
++
++
++/*
++ * Configure the pci core for pci client (NIC) action
++ * coremask is the bitvec of cores by index to be enabled.
++ */
++void
++sb_pci_setup(sb_t *sbh, uint coremask)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ sbpciregs_t *pciregs;
++ uint32 sbflag;
++ uint32 w;
++ uint idx;
++ int reg_val;
++
++ si = SB_INFO(sbh);
++
++ /* if not pci bus, we're done */
++ if (BUSTYPE(si->sb.bustype) != PCI_BUS)
++ return;
++
++ ASSERT(PCI(si) || PCIE(si));
++ ASSERT(si->sb.buscoreidx != BADIDX);
++
++ /* get current core index */
++ idx = si->curidx;
++
++ /* we interrupt on this backplane flag number */
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++ sbflag = R_SBREG(si, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
++
++ /* switch over to pci core */
++ pciregs = (sbpciregs_t*) sb_setcoreidx(sbh, si->sb.buscoreidx);
++ sb = REGS2SB(pciregs);
++
++ /*
++ * Enable sb->pci interrupts. Assume
++ * PCI rev 2.3 support was added in pci core rev 6 and things changed..
++ */
++ if (PCIE(si) || (PCI(si) && ((si->sb.buscorerev) >= 6))) {
++ /* pci config write to set this core bit in PCIIntMask */
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32));
++ w |= (coremask << PCI_SBIM_SHIFT);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32), w);
++ } else {
++ /* set sbintvec bit for our flag number */
++ OR_SBREG(si, &sb->sbintvec, (1 << sbflag));
++ }
++
++ if (PCI(si)) {
++ OR_REG(&pciregs->sbtopci2, (SBTOPCI_PREF|SBTOPCI_BURST));
++ if (si->sb.buscorerev >= 11)
++ OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI);
++ if (si->sb.buscorerev < 5) {
++ SET_SBREG(si, &sb->sbimconfiglow, SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
++ sb_commit(sbh);
++ }
++ }
++
++ if (PCIE(si) && (si->sb.buscorerev == 0)) {
++ reg_val = sb_pcie_readreg((void *)sbh, (void *)PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG);
++ reg_val |= 0x8;
++ sb_pcie_writereg((void *)sbh, (void *)PCIE_PCIEREGS, PCIE_TLP_WORKAROUNDSREG, reg_val);
++
++ reg_val = sb_pcie_readreg((void *)sbh, (void *)PCIE_PCIEREGS, PCIE_DLLP_LCREG);
++ reg_val &= ~(0x40);
++ sb_pcie_writereg(sbh, (void *)PCIE_PCIEREGS, PCIE_DLLP_LCREG, reg_val);
++
++ BCMINIT(sb_war30841)(si);
++ }
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++}
++
++uint32
++sb_base(uint32 admatch)
++{
++ uint32 base;
++ uint type;
++
++ type = admatch & SBAM_TYPE_MASK;
++ ASSERT(type < 3);
++
++ base = 0;
++
++ if (type == 0) {
++ base = admatch & SBAM_BASE0_MASK;
++ } else if (type == 1) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ base = admatch & SBAM_BASE1_MASK;
++ } else if (type == 2) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ base = admatch & SBAM_BASE2_MASK;
++ }
++
++ return (base);
++}
++
++uint32
++sb_size(uint32 admatch)
++{
++ uint32 size;
++ uint type;
++
++ type = admatch & SBAM_TYPE_MASK;
++ ASSERT(type < 3);
++
++ size = 0;
++
++ if (type == 0) {
++ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1);
++ } else if (type == 1) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1);
++ } else if (type == 2) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1);
++ }
++
++ return (size);
++}
++
++/* return the core-type instantiation # of the current core */
++uint
++sb_coreunit(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint idx;
++ uint coreid;
++ uint coreunit;
++ uint i;
++
++ si = SB_INFO(sbh);
++ coreunit = 0;
++
++ idx = si->curidx;
++
++ ASSERT(GOODREGS(si->curmap));
++ coreid = sb_coreid(sbh);
++
++ /* count the cores of our type */
++ for (i = 0; i < idx; i++)
++ if (si->coreid[i] == coreid)
++ coreunit++;
++
++ return (coreunit);
++}
++
++static INLINE uint32
++factor6(uint32 x)
++{
++ switch (x) {
++ case CC_F6_2: return 2;
++ case CC_F6_3: return 3;
++ case CC_F6_4: return 4;
++ case CC_F6_5: return 5;
++ case CC_F6_6: return 6;
++ case CC_F6_7: return 7;
++ default: return 0;
++ }
++}
++
++/* calculate the speed the SB would run at given a set of clockcontrol values */
++uint32
++sb_clock_rate(uint32 pll_type, uint32 n, uint32 m)
++{
++ uint32 n1, n2, clock, m1, m2, m3, mc;
++
++ n1 = n & CN_N1_MASK;
++ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
++
++ if (pll_type == PLL_TYPE6) {
++ if (m & CC_T6_MMASK)
++ return CC_T6_M1;
++ else
++ return CC_T6_M0;
++ } else if ((pll_type == PLL_TYPE1) ||
++ (pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE7)) {
++ n1 = factor6(n1);
++ n2 += CC_F5_BIAS;
++ } else if (pll_type == PLL_TYPE2) {
++ n1 += CC_T2_BIAS;
++ n2 += CC_T2_BIAS;
++ ASSERT((n1 >= 2) && (n1 <= 7));
++ ASSERT((n2 >= 5) && (n2 <= 23));
++ } else if (pll_type == PLL_TYPE5) {
++ return (100000000);
++ } else
++ ASSERT(0);
++ /* PLL types 3 and 7 use BASE2 (25Mhz) */
++ if ((pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE7)) {
++ clock = CC_CLOCK_BASE2 * n1 * n2;
++ }
++ else
++ clock = CC_CLOCK_BASE1 * n1 * n2;
++
++ if (clock == 0)
++ return 0;
++
++ m1 = m & CC_M1_MASK;
++ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
++ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
++ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
++
++ if ((pll_type == PLL_TYPE1) ||
++ (pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE7)) {
++ m1 = factor6(m1);
++ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
++ m2 += CC_F5_BIAS;
++ else
++ m2 = factor6(m2);
++ m3 = factor6(m3);
++
++ switch (mc) {
++ case CC_MC_BYPASS: return (clock);
++ case CC_MC_M1: return (clock / m1);
++ case CC_MC_M1M2: return (clock / (m1 * m2));
++ case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3));
++ case CC_MC_M1M3: return (clock / (m1 * m3));
++ default: return (0);
++ }
++ } else {
++ ASSERT(pll_type == PLL_TYPE2);
++
++ m1 += CC_T2_BIAS;
++ m2 += CC_T2M2_BIAS;
++ m3 += CC_T2_BIAS;
++ ASSERT((m1 >= 2) && (m1 <= 7));
++ ASSERT((m2 >= 3) && (m2 <= 10));
++ ASSERT((m3 >= 2) && (m3 <= 7));
++
++ if ((mc & CC_T2MC_M1BYP) == 0)
++ clock /= m1;
++ if ((mc & CC_T2MC_M2BYP) == 0)
++ clock /= m2;
++ if ((mc & CC_T2MC_M3BYP) == 0)
++ clock /= m3;
++
++ return(clock);
++ }
++}
++
++/* returns the current speed the SB is running at */
++uint32
++sb_clock(sb_t *sbh)
++{
++ sb_info_t *si;
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ uint32 n, m;
++ uint idx;
++ uint32 pll_type, rate;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++ idx = si->curidx;
++ pll_type = PLL_TYPE1;
++
++ INTR_OFF(si, intr_val);
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ n = R_REG(&eir->clockcontrol_n);
++ m = R_REG(&eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ n = R_REG(&cc->clockcontrol_n);
++ if (pll_type == PLL_TYPE6)
++ m = R_REG(&cc->clockcontrol_mips);
++ else if (pll_type == PLL_TYPE3)
++ {
++ // Added by Chen-I for 5365
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++ m = R_REG(&cc->clockcontrol_sb);
++ else
++ m = R_REG(&cc->clockcontrol_m2);
++ }
++ else
++ m = R_REG(&cc->clockcontrol_sb);
++ } else {
++ INTR_RESTORE(si, intr_val);
++ return 0;
++ }
++
++ // Added by Chen-I for 5365
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++ {
++ rate = 100000000;
++ }
++ else
++ {
++ /* calculate rate */
++ rate = sb_clock_rate(pll_type, n, m);
++ if (pll_type == PLL_TYPE3)
++ rate = rate / 2;
++ }
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ INTR_RESTORE(si, intr_val);
++
++ return rate;
++}
++
++/* change logical "focus" to the gpio core for optimized access */
++void*
++sb_gpiosetcore(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (sb_setcoreidx(sbh, si->gpioidx));
++}
++
++/* mask&set gpiocontrol bits */
++uint32
++sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiocontrol);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpiocontrol);
++ break;
++
++ case SB_EXTIF:
++ return (0);
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio output enable bits */
++uint32
++sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioouten);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioouten);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpio[0].outen);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio output bits */
++uint32
++sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioout);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioout);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpio[0].out);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
+
-+void testcrc32(void)
++/* reserve one gpio */
++uint32
++sb_gpioreserve(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
+{
-+ uint j,k,l;
-+ uint8 *buf;
-+ uint len[CNBUFS];
-+ uint32 crcr;
-+ uint32 crc32tv[CNBUFS] =
-+ {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
++ sb_info_t *si;
+
-+ ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
++ si = SB_INFO(sbh);
+
-+ /* step through all possible alignments */
-+ for (l=0;l<=4;l++) {
-+ for (j=0; j<CNBUFS; j++) {
-+ len[j] = CLEN;
-+ for (k=0; k<len[j]; k++)
-+ *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
-+ }
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
+
-+ for (j=0; j<CNBUFS; j++) {
-+ crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
-+ ASSERT(crcr == crc32tv[j]);
-+ }
++ /* only cores on SB_BUS share GPIO's and only applcation users need to reserve/release GPIO */
++ if ( (BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) {
++ ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority));
++ return -1;
++ }
++ /* make sure only one bit is set */
++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
++ return -1;
+ }
+
-+ MFREE(buf, CBUFSIZ*CNBUFS);
-+ return;
-+}
-+#endif
++ /* already reserved */
++ if (sb_gpioreservation & gpio_bitmask)
++ return -1;
++ /* set reservation */
++ sb_gpioreservation |= gpio_bitmask;
+
++ return sb_gpioreservation;
++}
+
++/* release one gpio */
+/*
-+ * Advance from the current 1-byte tag/1-byte length/variable-length value
-+ * triple, to the next, returning a pointer to the next.
-+ * If the current or next TLV is invalid (does not fit in given buffer length),
-+ * NULL is returned.
-+ * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
-+ * by the TLV paramter's length if it is valid.
-+ */
-+bcm_tlv_t *
-+bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
++ * releasing the gpio doesn't change the current value on the GPIO last write value
++ * persists till some one overwrites it
++*/
++
++uint32
++sb_gpiorelease(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
+{
-+ int len;
++ sb_info_t *si;
+
-+ /* validate current elt */
-+ if (!bcm_valid_tlv(elt, *buflen))
-+ return NULL;
-+
-+ /* advance to next elt */
-+ len = elt->len;
-+ elt = (bcm_tlv_t*)(elt->data + len);
-+ *buflen -= (2 + len);
-+
-+ /* validate next elt */
-+ if (!bcm_valid_tlv(elt, *buflen))
-+ return NULL;
++ si = SB_INFO(sbh);
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* only cores on SB_BUS share GPIO's and only applcation users need to reserve/release GPIO */
++ if ( (BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) {
++ ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority));
++ return -1;
++ }
++ /* make sure only one bit is set */
++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
++ return -1;
++ }
+
-+ return elt;
++ /* already released */
++ if (!(sb_gpioreservation & gpio_bitmask))
++ return -1;
++
++ /* clear reservation */
++ sb_gpioreservation &= ~gpio_bitmask;
++
++ return sb_gpioreservation;
+}
+
-+/*
-+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
-+ * triples, returning a pointer to the substring whose first element
-+ * matches tag
-+ */
-+bcm_tlv_t *
-+bcm_parse_tlvs(void *buf, int buflen, uint key)
++/* return the current gpioin register value */
++uint32
++sb_gpioin(sb_t *sbh)
+{
-+ bcm_tlv_t *elt;
-+ int totlen;
++ sb_info_t *si;
++ uint regoff;
+
-+ elt = (bcm_tlv_t*)buf;
-+ totlen = buflen;
++ si = SB_INFO(sbh);
++ regoff = 0;
+
-+ /* find tagged parameter */
-+ while (totlen >= 2) {
-+ int len = elt->len;
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioin);
++ break;
+
-+ /* validate remaining totlen */
-+ if ((elt->id == key) && (totlen >= (len + 2)))
-+ return (elt);
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioin);
++ break;
+
-+ elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
-+ totlen -= (len + 2);
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpioin);
++ break;
+ }
-+
-+ return NULL;
++
++ return (sb_corereg(si, si->gpioidx, regoff, 0, 0));
+}
+
-+/*
-+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
-+ * triples, returning a pointer to the substring whose first element
-+ * matches tag. Stop parsing when we see an element whose ID is greater
-+ * than the target key.
-+ */
-+bcm_tlv_t *
-+bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
++/* mask&set gpio interrupt polarity bits */
++uint32
++sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
+{
-+ bcm_tlv_t *elt;
-+ int totlen;
++ sb_info_t *si;
++ uint regoff;
+
-+ elt = (bcm_tlv_t*)buf;
-+ totlen = buflen;
++ si = SB_INFO(sbh);
++ regoff = 0;
+
-+ /* find tagged parameter */
-+ while (totlen >= 2) {
-+ uint id = elt->id;
-+ int len = elt->len;
-+
-+ /* Punt if we start seeing IDs > than target key */
-+ if (id > key)
-+ return(NULL);
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
+
-+ /* validate remaining totlen */
-+ if ((id == key) && (totlen >= (len + 2)))
-+ return (elt);
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
+
-+ elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
-+ totlen -= (len + 2);
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
++ break;
++
++ case SB_PCI:
++ /* pci gpio implementation does not support interrupt polarity */
++ ASSERT(0);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpiointpolarity);
++ break;
+ }
-+ return NULL;
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
+}
-+/* routine to dump fields in a fileddesc structure */
+
-+uint
-+bcmdumpfields(readreg_rtn read_rtn, void *arg0, void *arg1, struct fielddesc *fielddesc_array, char *buf, uint32 bufsize)
++/* mask&set gpio interrupt mask bits */
++uint32
++sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
+{
-+ uint filled_len;
-+ uint len;
-+ struct fielddesc *cur_ptr;
++ sb_info_t *si;
++ uint regoff;
+
-+ filled_len = 0;
-+ cur_ptr = fielddesc_array;
++ si = SB_INFO(sbh);
++ regoff = 0;
+
-+ while (bufsize > (filled_len + 64)) {
-+ if (cur_ptr->nameandfmt == NULL)
-+ break;
-+ len = sprintf(buf, cur_ptr->nameandfmt, read_rtn(arg0, arg1, cur_ptr->offset));
-+ buf += len;
-+ filled_len += len;
-+ cur_ptr++;
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
+ }
-+ return filled_len;
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiointmask);
++ break;
++
++ case SB_PCI:
++ /* pci gpio implementation does not support interrupt mask */
++ ASSERT(0);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpiointmask);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* assign the gpio to an led */
++uint32
++sb_gpioled(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ if (si->sb.ccrev < 16)
++ return -1;
++
++ /* gpio led powersave reg */
++ return(sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val));
+}
+
-+uint
-+bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
++/* mask&set gpio timer val */
++uint32
++sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 gpiotimerval)
+{
-+ uint len;
-+
-+ len = strlen(name) + 1;
-+
-+ if ((len + datalen) > buflen)
-+ return 0;
-+
-+ strcpy(buf, name);
++ sb_info_t *si;
++ si = SB_INFO(sbh);
+
-+ /* append data onto the end of the name string */
-+ memcpy(&buf[len], data, datalen);
-+ len += datalen;
++ if (si->sb.ccrev < 16)
++ return -1;
+
-+ return len;
++ return(sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
+}
+
-+/* Quarter dBm units to mW
-+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
-+ * Table is offset so the last entry is largest mW value that fits in
-+ * a uint16.
-+ */
-+
-+#define QDBM_OFFSET 153
-+#define QDBM_TABLE_LEN 40
+
-+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
-+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
-+ */
-+#define QDBM_TABLE_LOW_BOUND 6493
++/* return the slow clock source - LPO, XTAL, or PCI */
++static uint
++sb_slowclk_src(sb_info_t *si)
++{
++ chipcregs_t *cc;
+
-+/* Largest mW value that will round down to the last table entry,
-+ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
-+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
-+ */
-+#define QDBM_TABLE_HIGH_BOUND 64938
+
-+static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
-+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
-+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
-+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
-+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
-+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
-+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
-+};
++ ASSERT(sb_coreid(&si->sb) == SB_CC);
+
-+uint16
-+bcm_qdbm_to_mw(uint8 qdbm)
-+{
-+ uint factor = 1;
-+ int idx = qdbm - QDBM_OFFSET;
-+
-+ if (idx > QDBM_TABLE_LEN) {
-+ /* clamp to max uint16 mW value */
-+ return 0xFFFF;
-+ }
-+
-+ /* scale the qdBm index up to the range of the table 0-40
-+ * where an offset of 40 qdBm equals a factor of 10 mW.
-+ */
-+ while (idx < 0) {
-+ idx += 40;
-+ factor *= 10;
-+ }
-+
-+ /* return the mW value scaled down to the correct factor of 10,
-+ * adding in factor/2 to get proper rounding. */
-+ return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
++ if (si->sb.ccrev < 6) {
++ if ((BUSTYPE(si->sb.bustype) == PCI_BUS)
++ && (OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32)) & PCI_CFG_GPIO_SCS))
++ return (SCC_SS_PCI);
++ else
++ return (SCC_SS_XTAL);
++ } else if (si->sb.ccrev < 10) {
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
++ return (R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK);
++ } else /* Insta-clock */
++ return (SCC_SS_XTAL);
+}
+
-+uint8
-+bcm_mw_to_qdbm(uint16 mw)
++/* return the ILP (slowclock) min or max frequency */
++static uint
++sb_slowclk_freq(sb_info_t *si, bool max)
+{
-+ uint8 qdbm;
-+ int offset;
-+ uint mw_uint = mw;
-+ uint boundary;
-+
-+ /* handle boundary case */
-+ if (mw_uint <= 1)
-+ return 0;
-+
-+ offset = QDBM_OFFSET;
-+
-+ /* move mw into the range of the table */
-+ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
-+ mw_uint *= 10;
-+ offset -= 40;
-+ }
++ chipcregs_t *cc;
++ uint32 slowclk;
++ uint div;
+
-+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
-+ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - nqdBm_to_mW_map[qdbm])/2;
-+ if (mw_uint < boundary) break;
-+ }
+
-+ qdbm += (uint8)offset;
++ ASSERT(sb_coreid(&si->sb) == SB_CC);
+
-+ return(qdbm);
-+}
-diff -Nur linux-2.4.32/drivers/net/hnd/hnddma.c linux-2.4.32-brcm/drivers/net/hnd/hnddma.c
---- linux-2.4.32/drivers/net/hnd/hnddma.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.4.32-brcm/drivers/net/hnd/hnddma.c 2005-12-16 23:39:11.288858250 +0100
-@@ -0,0 +1,1527 @@
-+/*
-+ * Generic Broadcom Home Networking Division (HND) DMA module.
-+ * This supports the following chips: BCM42xx, 44xx, 47xx .
-+ *
-+ * Copyright 2005, 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$
-+ */
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
+
-+#include <typedefs.h>
-+#include <osl.h>
-+#include <bcmendian.h>
-+#include <sbconfig.h>
-+#include <bcmutils.h>
-+#include <bcmdevs.h>
-+#include <sbutils.h>
++ /* shouldn't be here unless we've established the chip has dynamic clk control */
++ ASSERT(R_REG(&cc->capabilities) & CAP_PWR_CTL);
+
-+struct dma_info; /* forward declaration */
-+#define di_t struct dma_info
++ slowclk = sb_slowclk_src(si);
++ if (si->sb.ccrev < 6) {
++ if (slowclk == SCC_SS_PCI)
++ return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64));
++ else
++ return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32));
++ } else if (si->sb.ccrev < 10) {
++ div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
++ if (slowclk == SCC_SS_LPO)
++ return (max? LPOMAXFREQ : LPOMINFREQ);
++ else if (slowclk == SCC_SS_XTAL)
++ return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div));
++ else if (slowclk == SCC_SS_PCI)
++ return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div));
++ else
++ ASSERT(0);
++ } else {
++ /* Chipc rev 10 is InstaClock */
++ div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT;
++ div = 4 * (div + 1);
++ return (max ? XTALMAXFREQ : (XTALMINFREQ/div));
++ }
++ return (0);
++}
+
-+#include <sbhnddma.h>
-+#include <hnddma.h>
++static void
++sb_clkctl_setdelay(sb_info_t *si, void *chipcregs)
++{
++ chipcregs_t * cc;
++ uint slowmaxfreq, pll_delay, slowclk;
++ uint pll_on_delay, fref_sel_delay;
+
-+/* debug/trace */
-+#define DMA_ERROR(args)
-+#define DMA_TRACE(args)
++ pll_delay = PLL_DELAY;
+
-+/* default dma message level (if input msg_level pointer is null in dma_attach()) */
-+static uint dma_msg_level =
-+ 0;
++ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
++ * since the xtal will also be powered down by dynamic clk control logic.
++ */
++ slowclk = sb_slowclk_src(si);
++ if (slowclk != SCC_SS_XTAL)
++ pll_delay += XTAL_ON_DELAY;
+
-+#define MAXNAMEL 8
++ /* Starting with 4318 it is ILP that is used for the delays */
++ slowmaxfreq = sb_slowclk_freq(si, (si->sb.ccrev >= 10) ? FALSE : TRUE);
+
-+/* dma engine software state */
-+typedef struct dma_info {
-+ hnddma_t hnddma; /* exported structure */
-+ uint *msg_level; /* message level pointer */
-+ char name[MAXNAMEL]; /* callers name for diag msgs */
-+
-+ void *osh; /* os handle */
-+ sb_t *sbh; /* sb handle */
-+
-+ bool dma64; /* dma64 enabled */
-+ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
-+
-+ dma32regs_t *d32txregs; /* 32 bits dma tx engine registers */
-+ dma32regs_t *d32rxregs; /* 32 bits dma rx engine registers */
-+ dma64regs_t *d64txregs; /* 64 bits dma tx engine registers */
-+ dma64regs_t *d64rxregs; /* 64 bits dma rx engine registers */
++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
+
-+ uint32 dma64align; /* either 8k or 4k depends on number of dd */
-+ dma32dd_t *txd32; /* pointer to dma32 tx descriptor ring */
-+ dma64dd_t *txd64; /* pointer to dma64 tx descriptor ring */
-+ uint ntxd; /* # tx descriptors tunable */
-+ uint txin; /* index of next descriptor to reclaim */
-+ uint txout; /* index of next descriptor to post */
-+ uint txavail; /* # free tx descriptors */
-+ void **txp; /* pointer to parallel array of pointers to packets */
-+ ulong txdpa; /* physical address of descriptor ring */
-+ uint txdalign; /* #bytes added to alloc'd mem to align txd */
-+ uint txdalloc; /* #bytes allocated for the ring */
++ cc = (chipcregs_t *)chipcregs;
++ W_REG(&cc->pll_on_delay, pll_on_delay);
++ W_REG(&cc->fref_sel_delay, fref_sel_delay);
++}
+
-+ dma32dd_t *rxd32; /* pointer to dma32 rx descriptor ring */
-+ dma64dd_t *rxd64; /* pointer to dma64 rx descriptor ring */
-+ uint nrxd; /* # rx descriptors tunable */
-+ uint rxin; /* index of next descriptor to reclaim */
-+ uint rxout; /* index of next descriptor to post */
-+ void **rxp; /* pointer to parallel array of pointers to packets */
-+ ulong rxdpa; /* physical address of descriptor ring */
-+ uint rxdalign; /* #bytes added to alloc'd mem to align rxd */
-+ uint rxdalloc; /* #bytes allocated for the ring */
++int
++sb_pwrctl_slowclk(void *sbh, bool set, uint *div)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint intr_val = 0;
++ uint err = 0;
++
++ si = SB_INFO(sbh);
+
-+ /* tunables */
-+ uint rxbufsize; /* rx buffer size in bytes */
-+ uint nrxpost; /* # rx buffers to keep posted */
-+ uint rxoffset; /* rxcontrol offset */
-+ uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */
-+ uint ddoffsethigh; /* add to get dma address of descriptor ring, high 32 bits */
-+ uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */
-+ uint dataoffsethigh; /* add to get dma address of data buffer, high 32 bits */
-+} dma_info_t;
++ /* chipcommon cores prior to rev6 don't support slowclkcontrol */
++ if (si->sb.ccrev < 6)
++ return 1;
+
-+#ifdef BCMDMA64
-+#define DMA64_ENAB(di) ((di)->dma64)
-+#else
-+#define DMA64_ENAB(di) (0)
-+#endif
++ /* chipcommon cores rev10 are a whole new ball game */
++ if (si->sb.ccrev >= 10)
++ return 1;
+
-+/* descriptor bumping macros */
-+#define XXD(x, n) ((x) & ((n) - 1))
-+#define TXD(x) XXD((x), di->ntxd)
-+#define RXD(x) XXD((x), di->nrxd)
-+#define NEXTTXD(i) TXD(i + 1)
-+#define PREVTXD(i) TXD(i - 1)
-+#define NEXTRXD(i) RXD(i + 1)
-+#define NTXDACTIVE(h, t) TXD(t - h)
-+#define NRXDACTIVE(h, t) RXD(t - h)
++ if (set && ((*div % 4) || (*div < 4)))
++ return 2;
++
++ INTR_OFF(si, intr_val);
++ origidx = si->curidx;
++ cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0);
++ ASSERT(cc != NULL);
++
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL)) {
++ err = 3;
++ goto done;
++ }
+
-+/* macros to convert between byte offsets and indexes */
-+#define B2I(bytes, type) ((bytes) / sizeof(type))
-+#define I2B(index, type) ((index) * sizeof(type))
++ if (set) {
++ SET_REG(&cc->slow_clk_ctl, SCC_CD_MASK, ((*div / 4 - 1) << SCC_CD_SHIFT));
++ sb_clkctl_setdelay(sbh, (void *)cc);
++ } else
++ *div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
+
-+#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
-+#define PCI32ADDR_HIGH_SHIFT 30
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return err;
++}
+
++/* initialize power control delay registers */
++void sb_clkctl_init(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
+
-+/* prototypes */
-+static bool dma_isaddrext(dma_info_t *di);
-+static bool dma_alloc(dma_info_t *di, uint direction);
++ si = SB_INFO(sbh);
+
-+static bool dma32_alloc(dma_info_t *di, uint direction);
-+static void dma32_txreset(dma_info_t *di);
-+static void dma32_rxreset(dma_info_t *di);
-+static bool dma32_txsuspendedidle(dma_info_t *di);
-+static int dma32_txfast(dma_info_t *di, void *p0, uint32 coreflags);
-+static void* dma32_getnexttxp(dma_info_t *di, bool forceall);
-+static void* dma32_getnextrxp(dma_info_t *di, bool forceall);
-+static void dma32_txrotate(di_t *di);
++ origidx = si->curidx;
+
-+/* prototype or stubs */
-+#ifdef BCMDMA64
-+static bool dma64_alloc(dma_info_t *di, uint direction);
-+static void dma64_txreset(dma_info_t *di);
-+static void dma64_rxreset(dma_info_t *di);
-+static bool dma64_txsuspendedidle(dma_info_t *di);
-+static int dma64_txfast(dma_info_t *di, void *p0, uint32 coreflags);
-+static void* dma64_getnexttxp(dma_info_t *di, bool forceall);
-+static void* dma64_getnextrxp(dma_info_t *di, bool forceall);
-+static void dma64_txrotate(di_t *di);
-+#else
-+static bool dma64_alloc(dma_info_t *di, uint direction) { return TRUE; }
-+static void dma64_txreset(dma_info_t *di) {}
-+static void dma64_rxreset(dma_info_t *di) {}
-+static bool dma64_txsuspendedidle(dma_info_t *di) { return TRUE;}
-+static int dma64_txfast(dma_info_t *di, void *p0, uint32 coreflags) { return 0; }
-+static void* dma64_getnexttxp(dma_info_t *di, bool forceall) { return NULL; }
-+static void* dma64_getnextrxp(dma_info_t *di, bool forceall) { return NULL; }
-+static void dma64_txrotate(di_t *di) { return; }
-+#endif
++ if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
++ return;
+
-+/* old dmaregs struct for compatibility */
-+typedef volatile struct {
-+ /* transmit channel */
-+ uint32 xmtcontrol; /* enable, et al */
-+ uint32 xmtaddr; /* descriptor ring base address (4K aligned) */
-+ uint32 xmtptr; /* last descriptor posted to chip */
-+ uint32 xmtstatus; /* current active descriptor, et al */
-+
-+ /* receive channel */
-+ uint32 rcvcontrol; /* enable, et al */
-+ uint32 rcvaddr; /* descriptor ring base address (4K aligned) */
-+ uint32 rcvptr; /* last descriptor posted to chip */
-+ uint32 rcvstatus; /* current active descriptor, et al */
-+} dmaregs_t;
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
++ goto done;
+
-+typedef struct {
-+ uint ddoffset;
-+ uint dataoffset;
-+} compat_data;
++ /* 4317pc does not work with SlowClock less than 5 MHz */
++ if ((BUSTYPE(si->sb.bustype) == PCMCIA_BUS) && (si->sb.ccrev >= 6) && (si->sb.ccrev < 10))
++ SET_REG(&cc->slow_clk_ctl, SCC_CD_MASK, (ILP_DIV_5MHZ << SCC_CD_SHIFT));
+
-+static compat_data *ugly_hack = NULL;
++ /* set all Instaclk chip ILP to 1 MHz */
++ else if (si->sb.ccrev >= 10)
++ SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
++
++ sb_clkctl_setdelay(si, (void *)cc);
+
-+void*
-+dma_attold(void *drv, void *osh, char *name, dmaregs_t *regs, uint ntxd, uint nrxd,
-+ uint rxbufsize, uint nrxpost, uint rxoffset, uint ddoffset, uint dataoffset, uint *msg_level)
++done:
++ sb_setcoreidx(sbh, origidx);
++}
++void sb_pwrctl_init(sb_t *sbh)
+{
-+ dma32regs_t *dtx = regs;
-+ dma32regs_t *drx = dtx + 1;
-+
-+ ugly_hack = kmalloc(sizeof(ugly_hack), GFP_KERNEL);
-+ ugly_hack->ddoffset = ddoffset;
-+ ugly_hack->dataoffset = dataoffset;
-+ dma_attach((osl_t *) osh, name, NULL, dtx, drx, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, msg_level);
-+ ugly_hack = NULL;
++sb_clkctl_init(sbh);
+}
++/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
++uint16
++sb_clkctl_fast_pwrup_delay(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint slowminfreq;
++ uint16 fpdelay;
++ uint intr_val = 0;
+
++ si = SB_INFO(sbh);
++ fpdelay = 0;
++ origidx = si->curidx;
+
-+void*
-+dma_attach(osl_t *osh, char *name, sb_t *sbh, void *dmaregstx, void *dmaregsrx,
-+ uint ntxd, uint nrxd, uint rxbufsize, uint nrxpost, uint rxoffset, uint *msg_level)
-+{
-+ dma_info_t *di;
-+ uint size;
++ INTR_OFF(si, intr_val);
+
-+ /* allocate private info structure */
-+ if ((di = MALLOC(osh, sizeof (dma_info_t))) == NULL) {
-+ return (NULL);
-+ }
-+ bzero((char*)di, sizeof (dma_info_t));
++ if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
++ goto done;
+
-+ di->msg_level = msg_level ? msg_level : &dma_msg_level;
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
++ goto done;
+
-+ if (sbh != NULL)
-+ di->dma64 = ((sb_coreflagshi(sbh, 0, 0) & SBTMH_DMA64) == SBTMH_DMA64);
++ slowminfreq = sb_slowclk_freq(si, FALSE);
++ fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + (slowminfreq - 1)) / slowminfreq;
+
-+#ifndef BCMDMA64
-+ if (di->dma64) {
-+ DMA_ERROR(("dma_attach: driver doesn't have the capability to support 64 bits DMA\n"));
-+ goto fail;
-+ }
-+#endif
-+
-+ /* check arguments */
-+ ASSERT(ISPOWEROF2(ntxd));
-+ ASSERT(ISPOWEROF2(nrxd));
-+ if (nrxd == 0)
-+ ASSERT(dmaregsrx == NULL);
-+ if (ntxd == 0)
-+ ASSERT(dmaregstx == NULL);
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return (fpdelay);
++}
++uint16 sb_pwrctl_fast_pwrup_delay(sb_t *sbh)
++{
++return sb_clkctl_fast_pwrup_delay(sbh);
++}
++/* turn primary xtal and/or pll off/on */
++int
++sb_clkctl_xtal(sb_t *sbh, uint what, bool on)
++{
++ sb_info_t *si;
++ uint32 in, out, outen;
+
++ si = SB_INFO(sbh);
+
-+ /* init dma reg pointer */
-+ if (di->dma64) {
-+ ASSERT(ntxd <= D64MAXDD);
-+ ASSERT(nrxd <= D64MAXDD);
-+ di->d64txregs = (dma64regs_t *)dmaregstx;
-+ di->d64rxregs = (dma64regs_t *)dmaregsrx;
++ switch (BUSTYPE(si->sb.bustype)) {
+
-+ di->dma64align = D64RINGALIGN;
-+ if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2)) {
-+ /* for smaller dd table, HW relax the alignment requirement */
-+ di->dma64align = D64RINGALIGN / 2;
-+ }
-+ } else {
-+ ASSERT(ntxd <= D32MAXDD);
-+ ASSERT(nrxd <= D32MAXDD);
-+ di->d32txregs = (dma32regs_t *)dmaregstx;
-+ di->d32rxregs = (dma32regs_t *)dmaregsrx;
-+ }
+
++ case PCMCIA_BUS:
++ return (0);
+
-+ /* make a private copy of our callers name */
-+ strncpy(di->name, name, MAXNAMEL);
-+ di->name[MAXNAMEL-1] = '\0';
+
-+ di->osh = osh;
-+ di->sbh = sbh;
++ case PCI_BUS:
+
-+ /* save tunables */
-+ di->ntxd = ntxd;
-+ di->nrxd = nrxd;
-+ di->rxbufsize = rxbufsize;
-+ di->nrxpost = nrxpost;
-+ di->rxoffset = rxoffset;
++ /* pcie core doesn't have any mapping to control the xtal pu */
++ if (PCIE(si))
++ return -1;
+
-+ /*
-+ * figure out the DMA physical address offset for dd and data
-+ * for old chips w/o sb, use zero
-+ * for new chips w sb,
-+ * PCI/PCIE: they map silicon backplace address to zero based memory, need offset
-+ * Other bus: use zero
-+ * SB_BUS BIGENDIAN kludge: use sdram swapped region for data buffer, not descriptor
-+ */
-+ di->ddoffsetlow = 0;
-+ di->dataoffsetlow = 0;
-+ if (ugly_hack != NULL) {
-+ di->ddoffsetlow = ugly_hack->ddoffset;
-+ di->dataoffsetlow = ugly_hack->dataoffset;
-+ di->ddoffsethigh = 0;
-+ di->dataoffsethigh = 0;
-+ } else if (sbh != NULL) {
-+ if (sbh->bustype == PCI_BUS) { /* for pci bus, add offset */
-+ if ((sbh->buscoretype == SB_PCIE) && di->dma64){
-+ di->ddoffsetlow = 0;
-+ di->ddoffsethigh = SB_PCIE_DMA_H32;
++ in = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_IN, sizeof (uint32));
++ out = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32));
++ outen = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof (uint32));
++
++ /*
++ * Avoid glitching the clock if GPRS is already using it.
++ * We can't actually read the state of the PLLPD so we infer it
++ * by the value of XTAL_PU which *is* readable via gpioin.
++ */
++ if (on && (in & PCI_CFG_GPIO_XTAL))
++ return (0);
++
++ if (what & XTAL)
++ outen |= PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ outen |= PCI_CFG_GPIO_PLL;
++
++ if (on) {
++ /* turn primary xtal on */
++ if (what & XTAL) {
++ out |= PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ out |= PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32), out);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof (uint32), outen);
++ OSL_DELAY(XTAL_ON_DELAY);
++ }
++
++ /* turn pll on */
++ if (what & PLL) {
++ out &= ~PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32), out);
++ OSL_DELAY(2000);
++ }
+ } else {
-+ di->ddoffsetlow = SB_PCI_DMA;
-+ di->ddoffsethigh = 0;
++ if (what & XTAL)
++ out &= ~PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ out |= PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32), out);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof (uint32), outen);
+ }
-+ di->dataoffsetlow = di->ddoffsetlow;
-+ di->dataoffsethigh = di->ddoffsethigh;
-+ }
-+#if defined(__mips__) && defined(IL_BIGENDIAN)
-+ /* use sdram swapped region for data buffers but not dma descriptors */
-+ di->dataoffsetlow = di->dataoffsetlow + SB_SDRAM_SWAPPED;
-+#endif
++
++ default:
++ return (-1);
+ }
+
-+ di->addrext = ((ugly_hack == NULL) ? dma_isaddrext(di) : 0);
++ return (0);
++}
+
-+ DMA_TRACE(("%s: dma_attach: osh %p ntxd %d nrxd %d rxbufsize %d nrxpost %d rxoffset %d ddoffset 0x%x dataoffset 0x%x\n",
-+ name, osh, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, di->ddoffsetlow, di->dataoffsetlow));
++int sb_pwrctl_xtal(sb_t *sbh, uint what, bool on)
++{
++return sb_clkctl_xtal(sbh,what,on);
++}
+
-+ /* allocate tx packet pointer vector */
-+ if (ntxd) {
-+ size = ntxd * sizeof (void*);
-+ if ((di->txp = MALLOC(osh, size)) == NULL) {
-+ DMA_ERROR(("%s: dma_attach: out of tx memory, malloced %d bytes\n", di->name, MALLOCED(osh)));
-+ goto fail;
-+ }
-+ bzero((char*)di->txp, size);
-+ }
++/* set dynamic clk control mode (forceslow, forcefast, dynamic) */
++/* returns true if ignore pll off is set and false if it is not */
++bool
++sb_clkctl_clk(sb_t *sbh, uint mode)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint32 scc;
++ bool forcefastclk=FALSE;
++ uint intr_val = 0;
+
-+ /* allocate rx packet pointer vector */
-+ if (nrxd) {
-+ size = nrxd * sizeof (void*);
-+ if ((di->rxp = MALLOC(osh, size)) == NULL) {
-+ DMA_ERROR(("%s: dma_attach: out of rx memory, malloced %d bytes\n", di->name, MALLOCED(osh)));
-+ goto fail;
-+ }
-+ bzero((char*)di->rxp, size);
-+ }
++ si = SB_INFO(sbh);
+
-+ /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */
-+ if (ntxd) {
-+ if (!dma_alloc(di, DMA_TX))
-+ goto fail;
-+ }
++ /* chipcommon cores prior to rev6 don't support dynamic clock control */
++ if (si->sb.ccrev < 6)
++ return (FALSE);
+
-+ /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */
-+ if (nrxd) {
-+ if (!dma_alloc(di, DMA_RX))
-+ goto fail;
-+ }
++ /* chipcommon cores rev10 are a whole new ball game */
++ if (si->sb.ccrev >= 10)
++ return (FALSE);
+
-+ if ((di->ddoffsetlow == SB_PCI_DMA) && (di->txdpa > SB_PCI_DMA_SZ) && !di->addrext) {
-+ DMA_ERROR(("%s: dma_attach: txdpa 0x%lx: addrext not supported\n", di->name, di->txdpa));
-+ goto fail;
-+ }
-+ if ((di->ddoffsetlow == SB_PCI_DMA) && (di->rxdpa > SB_PCI_DMA_SZ) && !di->addrext) {
-+ DMA_ERROR(("%s: dma_attach: rxdpa 0x%lx: addrext not supported\n", di->name, di->rxdpa));
-+ goto fail;
-+ }
++ INTR_OFF(si, intr_val);
+
-+ return ((void*)di);
++ origidx = si->curidx;
+
-+fail:
-+ dma_detach((void*)di);
-+ return (NULL);
-+}
++ cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0);
++ ASSERT(cc != NULL);
+
-+static bool
-+dma_alloc(dma_info_t *di, uint direction)
-+{
-+ if (DMA64_ENAB(di)) {
-+ return dma64_alloc(di, direction);
-+ } else {
-+ return dma32_alloc(di, direction);
-+ }
-+}
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
++ goto done;
+
-+/* may be called with core in reset */
-+void
-+dma_detach(dma_info_t *di)
-+{
-+ if (di == NULL)
-+ return;
++ switch (mode) {
++ case CLK_FAST: /* force fast (pll) clock */
++ /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
++ sb_clkctl_xtal(&si->sb, XTAL, ON);
+
-+ DMA_TRACE(("%s: dma_detach\n", di->name));
++ SET_REG(&cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
++ break;
+
-+ /* shouldn't be here if descriptors are unreclaimed */
-+ ASSERT(di->txin == di->txout);
-+ ASSERT(di->rxin == di->rxout);
++ case CLK_DYNAMIC: /* enable dynamic clock control */
++ scc = R_REG(&cc->slow_clk_ctl);
++ scc &= ~(SCC_FS | SCC_IP | SCC_XC);
++ if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
++ scc |= SCC_XC;
++ W_REG(&cc->slow_clk_ctl, scc);
+
-+ /* free dma descriptor rings */
-+ if (di->txd32)
-+ DMA_FREE_CONSISTENT(di->osh, ((int8*)di->txd32 - di->txdalign), di->txdalloc, (di->txdpa - di->txdalign));
-+ if (di->rxd32)
-+ DMA_FREE_CONSISTENT(di->osh, ((int8*)di->rxd32 - di->rxdalign), di->rxdalloc, (di->rxdpa - di->rxdalign));
++ /* for dynamic control, we have to release our xtal_pu "force on" */
++ if (scc & SCC_XC)
++ sb_clkctl_xtal(&si->sb, XTAL, OFF);
++ break;
+
-+ /* free packet pointer vectors */
-+ if (di->txp)
-+ MFREE(di->osh, (void*)di->txp, (di->ntxd * sizeof (void*)));
-+ if (di->rxp)
-+ MFREE(di->osh, (void*)di->rxp, (di->nrxd * sizeof (void*)));
++ default:
++ ASSERT(0);
++ }
+
-+ /* free our private info structure */
-+ MFREE(di->osh, (void*)di, sizeof (dma_info_t));
++ /* Is the h/w forcing the use of the fast clk */
++ forcefastclk = (bool)((R_REG(&cc->slow_clk_ctl) & SCC_IP) == SCC_IP);
++
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return (forcefastclk);
+}
+
-+/* return TRUE if this dma engine supports DmaExtendedAddrChanges, otherwise FALSE */
-+static bool
-+dma_isaddrext(dma_info_t *di)
++bool sb_pwrctl_clk(sb_t *sbh, uint mode)
+{
-+ uint32 w;
-+
-+ if (DMA64_ENAB(di)) {
-+ OR_REG(&di->d64txregs->control, D64_XC_AE);
-+ w = R_REG(&di->d32txregs->control);
-+ AND_REG(&di->d32txregs->control, ~D64_XC_AE);
-+ return ((w & XC_AE) == D64_XC_AE);
-+ } else {
-+ OR_REG(&di->d32txregs->control, XC_AE);
-+ w = R_REG(&di->d32txregs->control);
-+ AND_REG(&di->d32txregs->control, ~XC_AE);
-+ return ((w & XC_AE) == XC_AE);
-+ }
++return sb_clkctl_clk(sbh, mode);
+}
-+
++/* register driver interrupt disabling and restoring callback functions */
+void
-+dma_txreset(dma_info_t *di)
++sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg)
+{
-+ DMA_TRACE(("%s: dma_txreset\n", di->name));
++ sb_info_t *si;
+
-+ if (DMA64_ENAB(di))
-+ dma64_txreset(di);
-+ else
-+ dma32_txreset(di);
++ si = SB_INFO(sbh);
++ si->intr_arg = intr_arg;
++ si->intrsoff_fn = (sb_intrsoff_t)intrsoff_fn;
++ si->intrsrestore_fn = (sb_intrsrestore_t)intrsrestore_fn;
++ si->intrsenabled_fn = (sb_intrsenabled_t)intrsenabled_fn;
++ /* save current core id. when this function called, the current core
++ * must be the core which provides driver functions(il, et, wl, etc.)
++ */
++ si->dev_coreid = si->coreid[si->curidx];
+}
+
++
+void
-+dma_rxreset(dma_info_t *di)
++sb_corepciid(sb_t *sbh, uint16 *pcivendor, uint16 *pcidevice,
++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif)
+{
-+ DMA_TRACE(("%s: dma_rxreset\n", di->name));
++ uint vendor, core, unit;
++ uint chip, chippkg;
++ char varname[8];
++ uint8 class, subclass, progif;
++
++ vendor = sb_corevendor(sbh);
++ core = sb_coreid(sbh);
++ unit = sb_coreunit(sbh);
+
-+ if (DMA64_ENAB(di))
-+ dma64_rxreset(di);
-+ else
-+ dma32_rxreset(di);
-+}
++ chip = BCMINIT(sb_chip)(sbh);
++ chippkg = BCMINIT(sb_chippkg)(sbh);
+
-+/* initialize descriptor table base address */
-+static void
-+dma_ddtable_init(dma_info_t *di, uint direction, ulong pa)
-+{
-+ if (DMA64_ENAB(di)) {
-+ if (direction == DMA_TX) {
-+ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow);
-+ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh);
-+ } else {
-+ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow);
-+ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh);
-+ }
-+ } else {
-+ uint32 offset = di->ddoffsetlow;
-+ if ((offset != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
-+ if (direction == DMA_TX)
-+ W_REG(&di->d32txregs->addr, (pa + offset));
-+ else
-+ W_REG(&di->d32rxregs->addr, (pa + offset));
-+ } else {
-+ /* dma32 address extension */
-+ uint32 ae;
-+ ASSERT(di->addrext);
-+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
++ progif = 0;
+
-+ if (direction == DMA_TX) {
-+ W_REG(&di->d32txregs->addr, ((pa & ~PCI32ADDR_HIGH) + offset));
-+ SET_REG(&di->d32txregs->control, XC_AE, (ae << XC_AE_SHIFT));
-+ } else {
-+ W_REG(&di->d32rxregs->addr, ((pa & ~PCI32ADDR_HIGH) + offset));
-+ SET_REG(&di->d32rxregs->control, RC_AE, (ae << RC_AE_SHIFT));
++ /* Known vendor translations */
++ switch (vendor) {
++ case SB_VEND_BCM:
++ vendor = VENDOR_BROADCOM;
++ break;
++ }
++
++ /* Determine class based on known core codes */
++ switch (core) {
++ case SB_ILINE20:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM47XX_ILINE_ID;
++ break;
++ case SB_ENET:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM47XX_ENET_ID;
++ break;
++ case SB_SDRAM:
++ case SB_MEMC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_RAM;
++ break;
++ case SB_PCI:
++ case SB_PCIE:
++ class = PCI_CLASS_BRIDGE;
++ subclass = PCI_BRIDGE_PCI;
++ break;
++ case SB_MIPS:
++ case SB_MIPS33:
++ class = PCI_CLASS_CPU;
++ subclass = PCI_CPU_MIPS;
++ break;
++ case SB_CODEC:
++ class = PCI_CLASS_COMM;
++ subclass = PCI_COMM_MODEM;
++ core = BCM47XX_V90_ID;
++ break;
++ case SB_USB:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ core = BCM47XX_USB_ID;
++ break;
++ case SB_USB11H:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ core = BCM47XX_USBH_ID;
++ break;
++ case SB_USB11D:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ core = BCM47XX_USBD_ID;
++ break;
++ case SB_IPSEC:
++ class = PCI_CLASS_CRYPT;
++ subclass = PCI_CRYPT_NETWORK;
++ core = BCM47XX_IPSEC_ID;
++ break;
++ case SB_ROBO:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ core = BCM47XX_ROBO_ID;
++ break;
++ case SB_EXTIF:
++ case SB_CC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_FLASH;
++ break;
++ case SB_D11:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ /* Let an nvram variable override this */
++ sprintf(varname, "wl%did", unit);
++ if ((core = getintvar(NULL, varname)) == 0) {
++ if (chip == BCM4712_DEVICE_ID) {
++ if (chippkg == BCM4712SMALL_PKG_ID)
++ core = BCM4306_D11G_ID;
++ else
++ core = BCM4306_D11DUAL_ID;
+ }
+ }
++ break;
++
++ default:
++ class = subclass = progif = 0xff;
++ break;
+ }
++
++ *pcivendor = (uint16)vendor;
++ *pcidevice = (uint16)core;
++ *pciclass = class;
++ *pcisubclass = subclass;
++ *pciprogif = progif;
+}
+
-+/* init the tx or rx descriptor */
-+static INLINE void
-+dma32_dd_upd(dma_info_t *di, dma32dd_t *ddring, ulong pa, uint outidx, uint32 *ctrl)
-+{
-+ uint offset = di->dataoffsetlow;
+
-+ if ((offset != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
-+ W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + offset));
-+ W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*ctrl));
-+ } else {
-+ /* address extension */
-+ uint32 ae;
-+ ASSERT(di->addrext);
-+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
+
-+ *ctrl |= (ae << CTRL_AE_SHIFT);
-+ W_SM(&ddring[outidx].addr, BUS_SWAP32((pa & ~PCI32ADDR_HIGH) + offset));
-+ W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*ctrl));
-+ }
-+}
+
-+/* init the tx or rx descriptor */
-+static INLINE void
-+dma64_dd_upd(dma_info_t *di, dma64dd_t *ddring, ulong pa, uint outidx, uint32 *flags, uint32 bufcount)
++/* use the mdio interface to write to mdio slaves */
++static int
++sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint regaddr, uint val)
+{
-+ uint32 bufaddr_low = pa + di->dataoffsetlow;
-+ uint32 bufaddr_high = 0 + di->dataoffsethigh;
++ uint mdiodata;
++ uint i = 0;
++ sbpcieregs_t *pcieregs;
+
-+ uint32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
++ pcieregs = (sbpcieregs_t*) sb_setcoreidx(&si->sb, si->sb.buscoreidx);
++ ASSERT (pcieregs);
+
-+ W_SM(&ddring[outidx].addrlow, BUS_SWAP32(bufaddr_low));
-+ W_SM(&ddring[outidx].addrhigh, BUS_SWAP32(bufaddr_high));
-+ W_SM(&ddring[outidx].ctrl1, BUS_SWAP32(*flags));
-+ W_SM(&ddring[outidx].ctrl2, BUS_SWAP32(ctrl2));
-+}
++ /* enable mdio access to SERDES */
++ W_REG((&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
+
-+void
-+dma_txinit(dma_info_t *di)
-+{
-+ DMA_TRACE(("%s: dma_txinit\n", di->name));
++ mdiodata = MDIODATA_START | MDIODATA_WRITE |
++ (physmedia << MDIODATA_DEVADDR_SHF) |
++ (regaddr << MDIODATA_REGADDR_SHF) | MDIODATA_TA | val;
+
-+ di->txin = di->txout = 0;
-+ di->txavail = di->ntxd - 1;
++ W_REG((&pcieregs->mdiodata), mdiodata);
+
-+ /* clear tx descriptor ring */
-+ if (DMA64_ENAB(di)) {
-+ BZERO_SM((void*)di->txd64, (di->ntxd * sizeof (dma64dd_t)));
-+ W_REG(&di->d64txregs->control, XC_XE);
-+ dma_ddtable_init(di, DMA_TX, di->txdpa);
-+ } else {
-+ BZERO_SM((void*)di->txd32, (di->ntxd * sizeof (dma32dd_t)));
-+ W_REG(&di->d32txregs->control, XC_XE);
-+ dma_ddtable_init(di, DMA_TX, di->txdpa);
-+ }
-+}
++ PR28829_DELAY();
+
-+bool
-+dma_txenabled(dma_info_t *di)
-+{
-+ uint32 xc;
-+
-+ /* If the chip is dead, it is not enabled :-) */
-+ if (DMA64_ENAB(di)) {
-+ xc = R_REG(&di->d64txregs->control);
-+ return ((xc != 0xffffffff) && (xc & D64_XC_XE));
-+ } else {
-+ xc = R_REG(&di->d32txregs->control);
-+ return ((xc != 0xffffffff) && (xc & XC_XE));
++ /* retry till the transaction is complete */
++ while ( i < 10 ) {
++ if (R_REG(&(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) {
++ /* Disable mdio access to SERDES */
++ W_REG((&pcieregs->mdiocontrol), 0);
++ return 0;
++ }
++ OSL_DELAY(1000);
++ i++;
+ }
-+}
-+
-+void
-+dma_txsuspend(dma_info_t *di)
-+{
-+ DMA_TRACE(("%s: dma_txsuspend\n", di->name));
-+ if (DMA64_ENAB(di))
-+ OR_REG(&di->d64txregs->control, D64_XC_SE);
-+ else
-+ OR_REG(&di->d32txregs->control, XC_SE);
-+}
+
-+void
-+dma_txresume(dma_info_t *di)
-+{
-+ DMA_TRACE(("%s: dma_txresume\n", di->name));
-+ if (DMA64_ENAB(di))
-+ AND_REG(&di->d64txregs->control, ~D64_XC_SE);
-+ else
-+ AND_REG(&di->d32txregs->control, ~XC_SE);
-+}
++ SB_ERROR(("sb_pcie_mdiowrite: timed out\n"));
++ /* Disable mdio access to SERDES */
++ W_REG((&pcieregs->mdiocontrol), 0);
++ ASSERT(0);
++ return 1;
+
-+bool
-+dma_txsuspendedidle(dma_info_t *di)
-+{
-+ if (DMA64_ENAB(di))
-+ return dma64_txsuspendedidle(di);
-+ else
-+ return dma32_txsuspendedidle(di);
+}
+
-+bool
-+dma_txsuspended(dma_info_t *di)
++/* indirect way to read pcie config regs*/
++uint
++sb_pcie_readreg(void *sb, void* arg1, uint offset)
+{
-+ if (DMA64_ENAB(di))
-+ return ((R_REG(&di->d64txregs->control) & D64_XC_SE) == D64_XC_SE);
-+ else
-+ return ((R_REG(&di->d32txregs->control) & XC_SE) == XC_SE);
-+}
++ sb_info_t *si;
++ sb_t *sbh;
++ uint retval = 0xFFFFFFFF;
++ sbpcieregs_t *pcieregs;
++ uint addrtype;
+
-+bool
-+dma_txstopped(dma_info_t *di)
-+{
-+ if (DMA64_ENAB(di))
-+ return ((R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK) == D64_XS0_XS_STOPPED);
-+ else
-+ return ((R_REG(&di->d32txregs->status) & XS_XS_MASK) == XS_XS_STOPPED);
-+}
++ sbh = (sb_t *)sb;
++ si = SB_INFO(sbh);
++ ASSERT (PCIE(si));
+
-+bool
-+dma_rxstopped(dma_info_t *di)
-+{
-+ if (DMA64_ENAB(di))
-+ return ((R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK) == D64_RS0_RS_STOPPED);
-+ else
-+ return ((R_REG(&di->d32rxregs->status) & RS_RS_MASK) == RS_RS_STOPPED);
-+}
++ pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0);
++ ASSERT (pcieregs);
+
-+void
-+dma_fifoloopbackenable(dma_info_t *di)
-+{
-+ DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
-+ if (DMA64_ENAB(di))
-+ OR_REG(&di->d64txregs->control, D64_XC_LE);
-+ else
-+ OR_REG(&di->d32txregs->control, XC_LE);
++ addrtype = (uint)((uintptr)arg1);
++ switch(addrtype) {
++ case PCIE_CONFIGREGS:
++ W_REG((&pcieregs->configaddr),offset);
++ retval = R_REG(&(pcieregs->configdata));
++ break;
++ case PCIE_PCIEREGS:
++ W_REG(&(pcieregs->pcieaddr),offset);
++ retval = R_REG(&(pcieregs->pciedata));
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++ return retval;
+}
+
-+void
-+dma_rxinit(dma_info_t *di)
++/* indirect way to write pcie config/mdio/pciecore regs*/
++uint
++sb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val)
+{
-+ DMA_TRACE(("%s: dma_rxinit\n", di->name));
-+
-+ di->rxin = di->rxout = 0;
++ sb_info_t *si;
++ sbpcieregs_t *pcieregs;
++ uint addrtype;
+
-+ /* clear rx descriptor ring */
-+ if (DMA64_ENAB(di)) {
-+ BZERO_SM((void*)di->rxd64, (di->nrxd * sizeof (dma64dd_t)));
-+ dma_rxenable(di);
-+ dma_ddtable_init(di, DMA_RX, di->rxdpa);
-+ } else {
-+ BZERO_SM((void*)di->rxd32, (di->nrxd * sizeof (dma32dd_t)));
-+ dma_rxenable(di);
-+ dma_ddtable_init(di, DMA_RX, di->rxdpa);
-+ }
-+}
++ si = SB_INFO(sbh);
++ ASSERT (PCIE(si));
+
-+void
-+dma_rxenable(dma_info_t *di)
-+{
-+ DMA_TRACE(("%s: dma_rxenable\n", di->name));
-+ if (DMA64_ENAB(di))
-+ W_REG(&di->d64rxregs->control, ((di->rxoffset << D64_RC_RO_SHIFT) | D64_RC_RE));
-+ else
-+ W_REG(&di->d32rxregs->control, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
-+}
++ pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0);
++ ASSERT (pcieregs);
+
-+bool
-+dma_rxenabled(dma_info_t *di)
-+{
-+ uint32 rc;
++ addrtype = (uint)((uintptr)arg1);
+
-+ if (DMA64_ENAB(di)) {
-+ rc = R_REG(&di->d64rxregs->control);
-+ return ((rc != 0xffffffff) && (rc & D64_RC_RE));
-+ } else {
-+ rc = R_REG(&di->d32rxregs->control);
-+ return ((rc != 0xffffffff) && (rc & RC_RE));
++ switch(addrtype) {
++ case PCIE_CONFIGREGS:
++ W_REG((&pcieregs->configaddr),offset);
++ W_REG((&pcieregs->configdata),val);
++ break;
++ case PCIE_PCIEREGS:
++ W_REG((&pcieregs->pcieaddr),offset);
++ W_REG((&pcieregs->pciedata),val);
++ break;
++ default:
++ ASSERT(0);
++ break;
+ }
++ return 0;
+}
+
+
-+/* !! tx entry routine */
++/* Build device path. Support SB, PCI, and JTAG for now. */
+int
-+dma_txfast(dma_info_t *di, void *p0, uint32 coreflags)
++sb_devpath(sb_t *sbh, char *path, int size)
+{
-+ if (DMA64_ENAB(di)) {
-+ return dma64_txfast(di, p0, coreflags);
-+ } else {
-+ return dma32_txfast(di, p0, coreflags);
++ ASSERT(path);
++ ASSERT(size >= SB_DEVPATH_BUFSZ);
++
++ switch (BUSTYPE((SB_INFO(sbh))->sb.bustype)) {
++ case SB_BUS:
++ case JTAG_BUS:
++ sprintf(path, "sb/%u/", sb_coreidx(sbh));
++ break;
++ case PCI_BUS:
++ ASSERT((SB_INFO(sbh))->osh);
++ sprintf(path, "pci/%u/%u/", OSL_PCI_BUS((SB_INFO(sbh))->osh),
++ OSL_PCI_SLOT((SB_INFO(sbh))->osh));
++ break;
++ case PCMCIA_BUS:
++ SB_ERROR(("sb_devpath: OSL_PCMCIA_BUS() not implemented, bus 1 assumed\n"));
++ SB_ERROR(("sb_devpath: OSL_PCMCIA_SLOT() not implemented, slot 1 assumed\n"));
++ sprintf(path, "pc/%u/%u/", 1, 1);
++ break;
++ case SDIO_BUS:
++ SB_ERROR(("sb_devpath: device 0 assumed\n"));
++ sprintf(path, "sd/%u/", sb_coreidx(sbh));
++ break;
++ default:
++ ASSERT(0);
++ break;
+ }
++
++ return 0;
+}
+
-+/* !! rx entry routine, returns a pointer to the next frame received, or NULL if there are no more */
-+void*
-+dma_rx(dma_info_t *di)
++/* Fix chip's configuration. The current core may be changed upon return */
++static int
++sb_pci_fixcfg(sb_info_t *si)
+{
-+ void *p;
-+ uint len;
-+ int skiplen = 0;
-+
-+ while ((p = dma_getnextrxp(di, FALSE))) {
-+ /* skip giant packets which span multiple rx descriptors */
-+ if (skiplen > 0) {
-+ skiplen -= di->rxbufsize;
-+ if (skiplen < 0)
-+ skiplen = 0;
-+ PKTFREE(di->osh, p, FALSE);
-+ continue;
-+ }
++ uint origidx, pciidx;
++ sbpciregs_t *pciregs;
++ sbpcieregs_t *pcieregs;
++ uint16 val16, *reg16;
++ char name[SB_DEVPATH_BUFSZ+16], *value;
++ char devpath[SB_DEVPATH_BUFSZ];
+
-+ len = ltoh16(*(uint16*)(PKTDATA(di->osh, p)));
-+ DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
++ ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS);
+
-+ /* bad frame length check */
-+ if (len > (di->rxbufsize - di->rxoffset)) {
-+ DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len));
-+ if (len > 0)
-+ skiplen = len - (di->rxbufsize - di->rxoffset);
-+ PKTFREE(di->osh, p, FALSE);
-+ di->hnddma.rxgiants++;
-+ continue;
-+ }
++ /* Fix PCI(e) SROM shadow area */
++ /* save the current index */
++ origidx = sb_coreidx(&si->sb);
+
-+ /* set actual length */
-+ PKTSETLEN(di->osh, p, (di->rxoffset + len));
++ /* check 'pi' is correct and fix it if not */
++ if (si->sb.buscoretype == SB_PCIE) {
++ pcieregs = (sbpcieregs_t *)sb_setcore(&si->sb, SB_PCIE, 0);
++ ASSERT(pcieregs);
++ reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
++ }
++ else if (si->sb.buscoretype == SB_PCI) {
++ pciregs = (sbpciregs_t *)sb_setcore(&si->sb, SB_PCI, 0);
++ ASSERT(pciregs);
++ reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
++ }
++ else {
++ ASSERT(0);
++ return -1;
++ }
++ pciidx = sb_coreidx(&si->sb);
++ val16 = R_REG(reg16);
++ if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) {
++ val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK);
++ W_REG(reg16, val16);
++ }
+
-+ break;
++ /* restore the original index */
++ sb_setcoreidx(&si->sb, origidx);
++
++ /* Fix bar0window */
++ /* !do it last, it changes the current core! */
++ if (sb_devpath(&si->sb, devpath, sizeof(devpath)))
++ return -1;
++ sprintf(name, "%sb0w", devpath);
++ if ((value = getvar(NULL, name))) {
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32),
++ bcm_strtoul(value, NULL, 16));
++ /* update curidx since the current core is changed */
++ si->curidx = _sb_coreidx(si);
++ if (si->curidx == BADIDX) {
++ SB_ERROR(("sb_pci_fixcfg: bad core index\n"));
++ return -1;
++ }
+ }
+
-+ return (p);
++ return 0;
+}
+
-+/* post receive buffers */
-+void
-+dma_rxfill(dma_info_t *di)
-+{
-+ void *p;
-+ uint rxin, rxout;
-+ uint32 ctrl;
-+ uint n;
-+ uint i;
-+ uint32 pa;
-+ uint rxbufsize;
+diff -Naur linux.old/drivers/net/hnd/shared_ksyms.sh linux.dev/drivers/net/hnd/shared_ksyms.sh
+--- linux.old/drivers/net/hnd/shared_ksyms.sh 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/hnd/shared_ksyms.sh 2006-04-06 15:34:15.000000000 +0200
+@@ -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 2005/03/16 13:50:00 wbx Exp $
++#
+
-+ /*
-+ * Determine how many receive buffers we're lacking
-+ * from the full complement, allocate, initialize,
-+ * and post them, then update the chip rx lastdscr.
-+ */
++cat <<EOF
++#include <linux/config.h>
++#include <linux/module.h>
++EOF
+
-+ rxin = di->rxin;
-+ rxout = di->rxout;
-+ rxbufsize = di->rxbufsize;
++for file in $* ; do
++ ${NM} $file | sed -ne 's/[0-9A-Fa-f]* [DT] \([^ ]*\)/extern void \1; EXPORT_SYMBOL(\1);/p'
++done
+diff -Naur linux.old/drivers/net/wireless/Config.in linux.dev/drivers/net/wireless/Config.in
+--- linux.old/drivers/net/wireless/Config.in 2006-04-06 15:38:09.000000000 +0200
++++ linux.dev/drivers/net/wireless/Config.in 2006-04-06 17:04:48.000000000 +0200
+@@ -13,6 +13,8 @@
+ fi
+
+ if [ "$CONFIG_PCI" = "y" ]; then
++ dep_tristate ' Proprietary Broadcom BCM43xx 802.11 Wireless support (old)' CONFIG_WL
++ dep_tristate ' Proprietary Broadcom BCM43xx 802.11 Wireless support (new)' CONFIG_WL2
+ dep_tristate ' Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)' CONFIG_PLX_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+ dep_tristate ' Hermes in TMD7160/NCP130 based PCI adaptor support (Pheecom WL-PCI etc.) (EXPERIMENTAL)' CONFIG_TMD_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+ dep_tristate ' Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)' CONFIG_PCI_HERMES $CONFIG_HERMES $CONFIG_EXPERIMENTAL
+diff -Naur linux.old/drivers/net/wl/Makefile linux.dev/drivers/net/wl/Makefile
+--- linux.old/drivers/net/wl/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/wl/Makefile 2006-04-06 16:56:38.000000000 +0200
+@@ -0,0 +1,27 @@
++#
++# 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.2 2005/03/29 03:32:18 mbm Exp $
+
-+ n = di->nrxpost - NRXDACTIVE(rxin, rxout);
++EXTRA_CFLAGS += -I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER
+
-+ DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
++O_TARGET := wl.o
+
-+ for (i = 0; i < n; i++) {
-+ if ((p = PKTGET(di->osh, rxbufsize, FALSE)) == NULL) {
-+ DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
-+ di->hnddma.rxnobuf++;
-+ break;
-+ }
++obj-y := apsta_aeskeywrap.o apsta_aes.o apsta_bcmwpa.o apsta_d11ucode.o
++obj-y += apsta_hmac.o apsta_md5.o apsta_passhash.o apsta_prf.o apsta_rc4.o
++obj-y += apsta_rijndael-alg-fst.o apsta_sha1.o apsta_tkhash.o apsta_wlc_led.o
++obj-y += apsta_wlc_phy.o apsta_wlc_rate.o apsta_wlc_security.o
++obj-y += apsta_wlc_sup.o apsta_wlc_wet.o apsta_wl_linux.o apsta_wlc.o
++obj-y += compat.o hnddma.o
+
-+ /* Do a cached write instead of uncached write since DMA_MAP
-+ * will flush the cache. */
-+ *(uint32*)(PKTDATA(di->osh, p)) = 0;
++obj-m := $(O_TARGET)
+
-+ pa = (uint32) DMA_MAP(di->osh, PKTDATA(di->osh, p), rxbufsize, DMA_RX, p);
-+ ASSERT(ISALIGNED(pa, 4));
++include $(TOPDIR)/Rules.make
+diff -Naur linux.old/drivers/net/wl/compat.c linux.dev/drivers/net/wl/compat.c
+--- linux.old/drivers/net/wl/compat.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/wl/compat.c 2006-04-06 17:12:19.000000000 +0200
+@@ -0,0 +1,237 @@
++/*
++ * Misc useful OS-independent routines.
++ *
++ * Copyright 2005, 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$
++ */
+
-+ /* save the free packet pointer */
-+ ASSERT(di->rxp[rxout] == NULL);
-+ di->rxp[rxout] = p;
++#include <typedefs.h>
++#ifdef BCMDRIVER
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmnvram.h>
++#else
++#include <stdio.h>
++#include <string.h>
++#endif
++#include "pktq.h"
++#include <bcmutils.h>
++#include <bcmendian.h>
++#include <bcmdevs.h>
+
-+ if (DMA64_ENAB(di)) {
-+ /* prep the descriptor control value */
-+ if (rxout == (di->nrxd - 1))
-+ ctrl = CTRL_EOT;
++#ifdef BCMDRIVER
++/* copy a pkt buffer chain into a buffer */
++uint
++pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
++{
++ uint n, ret = 0;
+
-+ dma64_dd_upd(di, di->rxd64, pa, rxout, &ctrl, rxbufsize);
-+ } else {
-+ /* prep the descriptor control value */
-+ ctrl = rxbufsize;
-+ if (rxout == (di->nrxd - 1))
-+ ctrl |= CTRL_EOT;
-+ dma32_dd_upd(di, di->rxd32, pa, rxout, &ctrl);
-+ }
++ if (len < 0)
++ len = 4096; /* "infinite" */
+
-+ rxout = NEXTRXD(rxout);
++ /* skip 'offset' bytes */
++ for (; p && offset; p = PKTNEXT(osh, p)) {
++ if (offset < (uint)PKTLEN(osh, p))
++ break;
++ offset -= PKTLEN(osh, p);
+ }
+
-+ di->rxout = rxout;
++ if (!p)
++ return 0;
+
-+ /* update the chip lastdscr pointer */
-+ if (DMA64_ENAB(di)) {
-+ W_REG(&di->d64rxregs->ptr, I2B(rxout, dma64dd_t));
-+ } else {
-+ W_REG(&di->d32rxregs->ptr, I2B(rxout, dma32dd_t));
++ /* copy the data */
++ for (; p && len; p = PKTNEXT(osh, p)) {
++ n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
++ bcopy(PKTDATA(osh, p) + offset, buf, n);
++ buf += n;
++ len -= n;
++ ret += n;
++ offset = 0;
+ }
++
++ return ret;
+}
+
-+void
-+dma_txreclaim(dma_info_t *di, bool forceall)
++/* return total length of buffer chain */
++uint
++pkttotlen(osl_t *osh, void *p)
+{
-+ void *p;
-+
-+ DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
++ uint total;
+
-+ while ((p = dma_getnexttxp(di, forceall)))
-+ PKTFREE(di->osh, p, TRUE);
++ total = 0;
++ for (; p; p = PKTNEXT(osh, p))
++ total += PKTLEN(osh, p);
++ return (total);
+}
+
-+/*
-+ * Reclaim next completed txd (txds if using chained buffers) and
-+ * return associated packet.
-+ * If 'force' is true, reclaim txd(s) and return associated packet
-+ * regardless of the value of the hardware "curr" pointer.
-+ */
-+void*
-+dma_getnexttxp(dma_info_t *di, bool forceall)
++void
++pktq_init(struct pktq *q, uint maxlen, const uint8 prio_map[])
+{
-+ if (DMA64_ENAB(di)) {
-+ return dma64_getnexttxp(di, forceall);
-+ } else {
-+ return dma32_getnexttxp(di, forceall);
++ q->head = q->tail = NULL;
++ q->maxlen = maxlen;
++ q->len = 0;
++ if (prio_map) {
++ q->priority = TRUE;
++ bcopy(prio_map, q->prio_map, sizeof(q->prio_map));
+ }
++ else
++ q->priority = FALSE;
+}
-+
-+/* like getnexttxp but no reclaim */
-+void*
-+dma_peeknexttxp(dma_info_t *di)
++
++
++/* should always check pktq_full before calling pktenq */
++void
++pktenq(struct pktq *q, void *p, bool lifo)
+{
-+ uint end, i;
++ void *next, *prev;
+
-+ if (DMA64_ENAB(di)) {
-+ end = B2I(R_REG(&di->d64txregs->status0) & D64_XS0_CD_MASK, dma64dd_t);
-+ } else {
-+ end = B2I(R_REG(&di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
++ /* allow 10 pkts slack */
++ ASSERT(q->len < (q->maxlen + 10));
++
++ /* Queueing chains not allowed */
++ ASSERT(PKTLINK(p) == NULL);
++
++ /* Queue is empty */
++ if (q->tail == NULL) {
++ ASSERT(q->head == NULL);
++ q->head = q->tail = p;
+ }
+
-+ for (i = di->txin; i != end; i = NEXTTXD(i))
-+ if (di->txp[i])
-+ return (di->txp[i]);
++ /* Insert at head or tail */
++ else if (q->priority == FALSE) {
++ /* Insert at head (LIFO) */
++ if (lifo) {
++ PKTSETLINK(p, q->head);
++ q->head = p;
++ }
++ /* Insert at tail (FIFO) */
++ else {
++ ASSERT(PKTLINK(q->tail) == NULL);
++ PKTSETLINK(q->tail, p);
++ PKTSETLINK(p, NULL);
++ q->tail = p;
++ }
++ }
+
-+ return (NULL);
-+}
++ /* Insert by priority */
++ else {
++ /* legal priorities 0-7 */
++ ASSERT(PKTPRIO(p) <= MAXPRIO);
+
-+/*
-+ * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
-+ */
-+void
-+dma_txrotate(di_t *di)
-+{
-+ if (DMA64_ENAB(di)) {
-+ dma64_txrotate(di);
-+ } else {
-+ dma32_txrotate(di);
++ ASSERT(q->head);
++ ASSERT(q->tail);
++ /* Shortcut to insertion at tail */
++ if (_pktq_pri(q, PKTPRIO(p)) < _pktq_pri(q, PKTPRIO(q->tail)) ||
++ (!lifo && _pktq_pri(q, PKTPRIO(p)) <= _pktq_pri(q, PKTPRIO(q->tail)))) {
++ prev = q->tail;
++ next = NULL;
++ }
++ /* Insert at head or in the middle */
++ else {
++ prev = NULL;
++ next = q->head;
++ }
++ /* Walk the queue */
++ for (; next; prev = next, next = PKTLINK(next)) {
++ /* Priority queue invariant */
++ ASSERT(!prev || _pktq_pri(q, PKTPRIO(prev)) >= _pktq_pri(q, PKTPRIO(next)));
++ /* Insert at head of string of packets of same priority (LIFO) */
++ if (lifo) {
++ if (_pktq_pri(q, PKTPRIO(p)) >= _pktq_pri(q, PKTPRIO(next)))
++ break;
++ }
++ /* Insert at tail of string of packets of same priority (FIFO) */
++ else {
++ if (_pktq_pri(q, PKTPRIO(p)) > _pktq_pri(q, PKTPRIO(next)))
++ break;
++ }
++ }
++ /* Insert at tail */
++ if (next == NULL) {
++ ASSERT(PKTLINK(q->tail) == NULL);
++ PKTSETLINK(q->tail, p);
++ PKTSETLINK(p, NULL);
++ q->tail = p;
++ }
++ /* Insert in the middle */
++ else if (prev) {
++ PKTSETLINK(prev, p);
++ PKTSETLINK(p, next);
++ }
++ /* Insert at head */
++ else {
++ PKTSETLINK(p, q->head);
++ q->head = p;
++ }
+ }
++
++ /* List invariants after insertion */
++ ASSERT(q->head);
++ ASSERT(PKTLINK(q->tail) == NULL);
++
++ q->len++;
+}
+
-+void
-+dma_rxreclaim(dma_info_t *di)
++/* dequeue packet at head */
++void*
++pktdeq(struct pktq *q)
+{
+ void *p;
+
-+ DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
++ if ((p = q->head)) {
++ ASSERT(q->tail);
++ q->head = PKTLINK(p);
++ PKTSETLINK(p, NULL);
++ q->len--;
++ if (q->head == NULL)
++ q->tail = NULL;
++ }
++ else {
++ ASSERT(q->tail == NULL);
++ }
+
-+ while ((p = dma_getnextrxp(di, TRUE)))
-+ PKTFREE(di->osh, p, FALSE);
++ return (p);
+}
+
-+void *
-+dma_getnextrxp(dma_info_t *di, bool forceall)
++/* dequeue packet at tail */
++void*
++pktdeqtail(struct pktq *q)
+{
-+ if (DMA64_ENAB(di)) {
-+ return dma64_getnextrxp(di, forceall);
-+ } else {
-+ return dma32_getnextrxp(di, forceall);
++ void *p;
++ void *next, *prev;
++
++ if (q->head == q->tail) { /* last packet on queue or queue empty */
++ p = q->head;
++ q->head = q->tail = NULL;
++ q->len = 0;
++ return(p);
+ }
-+}
+
-+uintptr
-+dma_getvar(dma_info_t *di, char *name)
-+{
-+ if (!strcmp(name, "&txavail"))
-+ return ((uintptr) &di->txavail);
-+ else {
-+ ASSERT(0);
++ /* start walk at head */
++ prev = NULL;
++ next = q->head;
++
++ /* Walk the queue to find prev of q->tail */
++ for (; next; prev = next, next = PKTLINK(next)) {
++ if (next == q->tail)
++ break;
+ }
-+ return (0);
-+}
+
-+void
-+dma_txblock(dma_info_t *di)
-+{
-+ di->txavail = 0;
-+}
++ ASSERT(prev);
+
-+void
-+dma_txunblock(dma_info_t *di)
-+{
-+ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+}
++ PKTSETLINK(prev, NULL);
++ q->tail = prev;
++ q->len--;
++ p = next;
+
-+uint
-+dma_txactive(dma_info_t *di)
-+{
-+ return (NTXDACTIVE(di->txin, di->txout));
-+}
-+
-+void
-+dma_rxpiomode(dma32regs_t *regs)
-+{
-+ W_REG(®s->control, RC_FM);
++ return (p);
+}
++#endif
+
-+void
-+dma_txpioloopback(dma32regs_t *regs)
-+{
-+ OR_REG(®s->control, XC_LE);
-+}
+
+diff -Naur linux.old/drivers/net/wl/hnddma.c linux.dev/drivers/net/wl/hnddma.c
+--- linux.old/drivers/net/wl/hnddma.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/wl/hnddma.c 2006-04-06 16:58:24.000000000 +0200
+@@ -0,0 +1,1453 @@
++/*
++ * Generic Broadcom Home Networking Division (HND) DMA module.
++ * This supports the following chips: BCM42xx, 44xx, 47xx .
++ *
++ * Copyright 2005, 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$
++ */
+
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <sbconfig.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sbutils.h>
+
++struct dma_info; /* forward declaration */
++#define di_t struct dma_info
+
-+/*** 32 bits DMA non-inline functions ***/
-+static bool
-+dma32_alloc(dma_info_t *di, uint direction)
-+{
-+ uint size;
-+ uint ddlen;
-+ void *va;
++#include "sbhnddma.h"
++#include "hnddma.h"
+
-+ ddlen = sizeof (dma32dd_t);
++/* debug/trace */
++#define DMA_ERROR(args)
++#define DMA_TRACE(args)
+
-+ size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
++/* default dma message level (if input msg_level pointer is null in dma_attach()) */
++static uint dma_msg_level =
++ 0;
+
-+ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, D32RINGALIGN))
-+ size += D32RINGALIGN;
++#define MAXNAMEL 8
+
++/* dma engine software state */
++typedef struct dma_info {
++ hnddma_t hnddma; /* exported structure */
++ uint *msg_level; /* message level pointer */
++ char name[MAXNAMEL]; /* callers name for diag msgs */
++
++ void *osh; /* os handle */
++ sb_t *sbh; /* sb handle */
++
++ bool dma64; /* dma64 enabled */
++ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
++
++ dma32regs_t *d32txregs; /* 32 bits dma tx engine registers */
++ dma32regs_t *d32rxregs; /* 32 bits dma rx engine registers */
++ dma64regs_t *d64txregs; /* 64 bits dma tx engine registers */
++ dma64regs_t *d64rxregs; /* 64 bits dma rx engine registers */
+
-+ if (direction == DMA_TX) {
-+ if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->txdpa)) == NULL) {
-+ DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n", di->name));
-+ return FALSE;
-+ }
++ uint32 dma64align; /* either 8k or 4k depends on number of dd */
++ dma32dd_t *txd32; /* pointer to dma32 tx descriptor ring */
++ dma64dd_t *txd64; /* pointer to dma64 tx descriptor ring */
++ uint ntxd; /* # tx descriptors tunable */
++ uint txin; /* index of next descriptor to reclaim */
++ uint txout; /* index of next descriptor to post */
++ uint txavail; /* # free tx descriptors */
++ void **txp; /* pointer to parallel array of pointers to packets */
++ ulong txdpa; /* physical address of descriptor ring */
++ uint txdalign; /* #bytes added to alloc'd mem to align txd */
++ uint txdalloc; /* #bytes allocated for the ring */
+
-+ di->txd32 = (dma32dd_t*) ROUNDUP((uintptr)va, D32RINGALIGN);
-+ di->txdalign = (uint)((int8*)di->txd32 - (int8*)va);
-+ di->txdpa += di->txdalign;
-+ di->txdalloc = size;
-+ ASSERT(ISALIGNED((uintptr)di->txd32, D32RINGALIGN));
-+ } else {
-+ if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->rxdpa)) == NULL) {
-+ DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n", di->name));
-+ return FALSE;
-+ }
-+ di->rxd32 = (dma32dd_t*) ROUNDUP((uintptr)va, D32RINGALIGN);
-+ di->rxdalign = (uint)((int8*)di->rxd32 - (int8*)va);
-+ di->rxdpa += di->rxdalign;
-+ di->rxdalloc = size;
-+ ASSERT(ISALIGNED((uintptr)di->rxd32, D32RINGALIGN));
-+ }
++ dma32dd_t *rxd32; /* pointer to dma32 rx descriptor ring */
++ dma64dd_t *rxd64; /* pointer to dma64 rx descriptor ring */
++ uint nrxd; /* # rx descriptors tunable */
++ uint rxin; /* index of next descriptor to reclaim */
++ uint rxout; /* index of next descriptor to post */
++ void **rxp; /* pointer to parallel array of pointers to packets */
++ ulong rxdpa; /* physical address of descriptor ring */
++ uint rxdalign; /* #bytes added to alloc'd mem to align rxd */
++ uint rxdalloc; /* #bytes allocated for the ring */
+
-+ return TRUE;
-+}
++ /* tunables */
++ uint rxbufsize; /* rx buffer size in bytes */
++ uint nrxpost; /* # rx buffers to keep posted */
++ uint rxoffset; /* rxcontrol offset */
++ uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */
++ uint ddoffsethigh; /* add to get dma address of descriptor ring, high 32 bits */
++ uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */
++ uint dataoffsethigh; /* add to get dma address of data buffer, high 32 bits */
++} dma_info_t;
+
-+static void
-+dma32_txreset(dma_info_t *di)
-+{
-+ uint32 status;
++#ifdef BCMDMA64
++#define DMA64_ENAB(di) ((di)->dma64)
++#else
++#define DMA64_ENAB(di) (0)
++#endif
+
-+ /* suspend tx DMA first */
-+ W_REG(&di->d32txregs->control, XC_SE);
-+ SPINWAIT((status = (R_REG(&di->d32txregs->status) & XS_XS_MASK)) != XS_XS_DISABLED &&
-+ status != XS_XS_IDLE &&
-+ status != XS_XS_STOPPED,
-+ 10000);
++/* descriptor bumping macros */
++#define XXD(x, n) ((x) & ((n) - 1))
++#define TXD(x) XXD((x), di->ntxd)
++#define RXD(x) XXD((x), di->nrxd)
++#define NEXTTXD(i) TXD(i + 1)
++#define PREVTXD(i) TXD(i - 1)
++#define NEXTRXD(i) RXD(i + 1)
++#define NTXDACTIVE(h, t) TXD(t - h)
++#define NRXDACTIVE(h, t) RXD(t - h)
+
-+ W_REG(&di->d32txregs->control, 0);
-+ SPINWAIT((status = (R_REG(&di->d32txregs->status) & XS_XS_MASK)) != XS_XS_DISABLED,
-+ 10000);
++/* macros to convert between byte offsets and indexes */
++#define B2I(bytes, type) ((bytes) / sizeof(type))
++#define I2B(index, type) ((index) * sizeof(type))
+
-+ if (status != XS_XS_DISABLED) {
-+ DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name));
-+ }
++#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
++#define PCI32ADDR_HIGH_SHIFT 30
+
-+ /* wait for the last transaction to complete */
-+ OSL_DELAY(300);
-+}
+
-+static void
-+dma32_rxreset(dma_info_t *di)
-+{
-+ uint32 status;
++/* prototypes */
++static bool dma_isaddrext(dma_info_t *di);
++static bool dma_alloc(dma_info_t *di, uint direction);
+
-+ W_REG(&di->d32rxregs->control, 0);
-+ SPINWAIT((status = (R_REG(&di->d32rxregs->status) & RS_RS_MASK)) != RS_RS_DISABLED,
-+ 10000);
++static bool dma32_alloc(dma_info_t *di, uint direction);
++static void dma32_txreset(dma_info_t *di);
++static void dma32_rxreset(dma_info_t *di);
++static bool dma32_txsuspendedidle(dma_info_t *di);
++static int dma32_txfast(dma_info_t *di, void *p0, uint32 coreflags);
++static void* dma32_getnexttxp(dma_info_t *di, bool forceall);
++static void* dma32_getnextrxp(dma_info_t *di, bool forceall);
++static void dma32_txrotate(di_t *di);
+
-+ if (status != RS_RS_DISABLED) {
-+ DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name));
-+ }
-+}
++/* prototype or stubs */
++#ifdef BCMDMA64
++static bool dma64_alloc(dma_info_t *di, uint direction);
++static void dma64_txreset(dma_info_t *di);
++static void dma64_rxreset(dma_info_t *di);
++static bool dma64_txsuspendedidle(dma_info_t *di);
++static int dma64_txfast(dma_info_t *di, void *p0, uint32 coreflags);
++static void* dma64_getnexttxp(dma_info_t *di, bool forceall);
++static void* dma64_getnextrxp(dma_info_t *di, bool forceall);
++static void dma64_txrotate(di_t *di);
++#else
++static bool dma64_alloc(dma_info_t *di, uint direction) { return TRUE; }
++static void dma64_txreset(dma_info_t *di) {}
++static void dma64_rxreset(dma_info_t *di) {}
++static bool dma64_txsuspendedidle(dma_info_t *di) { return TRUE;}
++static int dma64_txfast(dma_info_t *di, void *p0, uint32 coreflags) { return 0; }
++static void* dma64_getnexttxp(dma_info_t *di, bool forceall) { return NULL; }
++static void* dma64_getnextrxp(dma_info_t *di, bool forceall) { return NULL; }
++static void dma64_txrotate(di_t *di) { return; }
++#endif
+
-+static bool
-+dma32_txsuspendedidle(dma_info_t *di)
-+{
-+ if (!(R_REG(&di->d32txregs->control) & XC_SE))
-+ return 0;
++/* old dmaregs struct for compatibility */
++typedef volatile struct {
++ /* transmit channel */
++ uint32 xmtcontrol; /* enable, et al */
++ uint32 xmtaddr; /* descriptor ring base address (4K aligned) */
++ uint32 xmtptr; /* last descriptor posted to chip */
++ uint32 xmtstatus; /* current active descriptor, et al */
+
-+ if ((R_REG(&di->d32txregs->status) & XS_XS_MASK) != XS_XS_IDLE)
-+ return 0;
-+
-+ OSL_DELAY(2);
-+ return ((R_REG(&di->d32txregs->status) & XS_XS_MASK) == XS_XS_IDLE);
-+}
++ /* receive channel */
++ uint32 rcvcontrol; /* enable, et al */
++ uint32 rcvaddr; /* descriptor ring base address (4K aligned) */
++ uint32 rcvptr; /* last descriptor posted to chip */
++ uint32 rcvstatus; /* current active descriptor, et al */
++} dmaregs_t;
+
-+/*
-+ * supports full 32bit dma engine buffer addressing so
-+ * dma buffers can cross 4 Kbyte page boundaries.
-+ */
-+static int
-+dma32_txfast(dma_info_t *di, void *p0, uint32 coreflags)
++void*
++dma_attach(void *drv, void *osh, char *name, dmaregs_t *regs, uint ntxd, uint nrxd,
++ uint rxbufsize, uint nrxpost, uint rxoffset, uint ddoffset, uint dataoffset, uint *msg_level)
+{
-+ void *p, *next;
-+ uchar *data;
-+ uint len;
-+ uint txout;
-+ uint32 ctrl;
-+ uint32 pa;
-+
-+ DMA_TRACE(("%s: dma_txfast\n", di->name));
++ dma_info_t *di;
++ uint size;
++ dma32regs_t *dmaregstx = regs;
++ dma32regs_t *dmaregsrx = dmaregstx + 1;
++
++ /* allocate private info structure */
++ if ((di = MALLOC(osh, sizeof (dma_info_t))) == NULL) {
++ return (NULL);
++ }
++ bzero((char*)di, sizeof (dma_info_t));
++ di->msg_level = msg_level ? msg_level : &dma_msg_level;
+
-+ txout = di->txout;
-+ ctrl = 0;
++ /* check arguments */
++ ASSERT(ISPOWEROF2(ntxd));
++ ASSERT(ISPOWEROF2(nrxd));
++ if (nrxd == 0)
++ ASSERT(dmaregsrx == NULL);
++ if (ntxd == 0)
++ ASSERT(dmaregstx == NULL);
+
-+ /*
-+ * Walk the chain of packet buffers
-+ * allocating and initializing transmit descriptor entries.
-+ */
-+ for (p = p0; p; p = next) {
-+ data = PKTDATA(di->osh, p);
-+ len = PKTLEN(di->osh, p);
-+ next = PKTNEXT(di->osh, p);
++ ASSERT(ntxd <= D32MAXDD);
++ ASSERT(nrxd <= D32MAXDD);
++ di->d32txregs = (dma32regs_t *)dmaregstx;
++ di->d32rxregs = (dma32regs_t *)dmaregsrx;
+
-+ /* return nonzero if out of tx descriptors */
-+ if (NEXTTXD(txout) == di->txin)
-+ goto outoftxd;
++ /* make a private copy of our callers name */
++ strncpy(di->name, name, MAXNAMEL);
++ di->name[MAXNAMEL-1] = '\0';
+
-+ if (len == 0)
-+ continue;
++ di->osh = osh;
++ di->sbh = NULL;
+
-+ /* get physical address of buffer start */
-+ pa = (uint32) DMA_MAP(di->osh, data, len, DMA_TX, p);
++ /* save tunables */
++ di->ntxd = ntxd;
++ di->nrxd = nrxd;
++ di->rxbufsize = rxbufsize;
++ di->nrxpost = nrxpost;
++ di->rxoffset = rxoffset;
+
-+ /* build the descriptor control value */
-+ ctrl = len & CTRL_BC_MASK;
++ di->ddoffsetlow = ddoffset;
++ di->dataoffsetlow = dataoffset;
++ di->ddoffsethigh = 0;
++ di->dataoffsethigh = 0;
++
++ di->addrext = 0;
++
++ DMA_TRACE(("%s: dma_attach: osh %p ntxd %d nrxd %d rxbufsize %d nrxpost %d rxoffset %d ddoffset 0x%x dataoffset 0x%x\n",
++ name, osh, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, di->ddoffsetlow, di->dataoffsetlow));
+
-+ ctrl |= coreflags;
-+
-+ if (p == p0)
-+ ctrl |= CTRL_SOF;
-+ if (next == NULL)
-+ ctrl |= (CTRL_IOC | CTRL_EOF);
-+ if (txout == (di->ntxd - 1))
-+ ctrl |= CTRL_EOT;
++ /* allocate tx packet pointer vector */
++ if (ntxd) {
++ size = ntxd * sizeof (void*);
++ if ((di->txp = MALLOC(osh, size)) == NULL) {
++ DMA_ERROR(("%s: dma_attach: out of tx memory, malloced %d bytes\n", di->name, MALLOCED(osh)));
++ goto fail;
++ }
++ bzero((char*)di->txp, size);
++ }
+
-+ if (DMA64_ENAB(di)) {
-+ dma64_dd_upd(di, di->txd64, pa, txout, &ctrl, len);
-+ } else {
-+ dma32_dd_upd(di, di->txd32, pa, txout, &ctrl);
++ /* allocate rx packet pointer vector */
++ if (nrxd) {
++ size = nrxd * sizeof (void*);
++ if ((di->rxp = MALLOC(osh, size)) == NULL) {
++ DMA_ERROR(("%s: dma_attach: out of rx memory, malloced %d bytes\n", di->name, MALLOCED(osh)));
++ goto fail;
+ }
++ bzero((char*)di->rxp, size);
++ }
+
-+ ASSERT(di->txp[txout] == NULL);
++ /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */
++ if (ntxd) {
++ if (!dma_alloc(di, DMA_TX))
++ goto fail;
++ }
+
-+ txout = NEXTTXD(txout);
++ /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */
++ if (nrxd) {
++ if (!dma_alloc(di, DMA_RX))
++ goto fail;
+ }
+
-+ /* if last txd eof not set, fix it */
-+ if (!(ctrl & CTRL_EOF))
-+ W_SM(&di->txd32[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
++ if ((di->ddoffsetlow == SB_PCI_DMA) && (di->txdpa > SB_PCI_DMA_SZ) && !di->addrext) {
++ DMA_ERROR(("%s: dma_attach: txdpa 0x%lx: addrext not supported\n", di->name, di->txdpa));
++ goto fail;
++ }
++ if ((di->ddoffsetlow == SB_PCI_DMA) && (di->rxdpa > SB_PCI_DMA_SZ) && !di->addrext) {
++ DMA_ERROR(("%s: dma_attach: rxdpa 0x%lx: addrext not supported\n", di->name, di->rxdpa));
++ goto fail;
++ }
+
-+ /* save the packet */
-+ di->txp[PREVTXD(txout)] = p0;
++ return ((void*)di);
+
-+ /* bump the tx descriptor index */
-+ di->txout = txout;
++fail:
++ dma_detach((void*)di);
++ return (NULL);
++}
+
-+ /* kick the chip */
++
++static bool
++dma_alloc(dma_info_t *di, uint direction)
++{
+ if (DMA64_ENAB(di)) {
-+ W_REG(&di->d64txregs->ptr, I2B(txout, dma64dd_t));
++ return dma64_alloc(di, direction);
+ } else {
-+ W_REG(&di->d32txregs->ptr, I2B(txout, dma32dd_t));
++ return dma32_alloc(di, direction);
+ }
-+
-+ /* tx flow control */
-+ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+
-+ return (0);
-+
-+ outoftxd:
-+ DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
-+ PKTFREE(di->osh, p0, TRUE);
-+ di->txavail = 0;
-+ di->hnddma.txnobuf++;
-+ return (-1);
+}
+
-+static void*
-+dma32_getnexttxp(dma_info_t *di, bool forceall)
++/* may be called with core in reset */
++void
++dma_detach(dma_info_t *di)
+{
-+ uint start, end, i;
-+ void *txp;
-+
-+ DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
-+
-+ txp = NULL;
-+
-+ start = di->txin;
-+ if (forceall)
-+ end = di->txout;
-+ else
-+ end = B2I(R_REG(&di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
-+
-+ if ((start == 0) && (end > di->txout))
-+ goto bogus;
-+
-+ for (i = start; i != end && !txp; i = NEXTTXD(i)) {
-+ DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->txd32[i].addr)) - di->dataoffsetlow),
-+ (BUS_SWAP32(R_SM(&di->txd32[i].ctrl)) & CTRL_BC_MASK), DMA_TX, di->txp[i]);
++ if (di == NULL)
++ return;
+
-+ W_SM(&di->txd32[i].addr, 0xdeadbeef);
-+ txp = di->txp[i];
-+ di->txp[i] = NULL;
-+ }
++ DMA_TRACE(("%s: dma_detach\n", di->name));
+
-+ di->txin = i;
++ /* shouldn't be here if descriptors are unreclaimed */
++ ASSERT(di->txin == di->txout);
++ ASSERT(di->rxin == di->rxout);
+
-+ /* tx flow control */
-+ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
++ /* free dma descriptor rings */
++ if (di->txd32)
++ DMA_FREE_CONSISTENT(di->osh, ((int8*)di->txd32 - di->txdalign), di->txdalloc, (di->txdpa - di->txdalign));
++ if (di->rxd32)
++ DMA_FREE_CONSISTENT(di->osh, ((int8*)di->rxd32 - di->rxdalign), di->rxdalloc, (di->rxdpa - di->rxdalign));
+
-+ return (txp);
++ /* free packet pointer vectors */
++ if (di->txp)
++ MFREE(di->osh, (void*)di->txp, (di->ntxd * sizeof (void*)));
++ if (di->rxp)
++ MFREE(di->osh, (void*)di->rxp, (di->nrxd * sizeof (void*)));
+
-+bogus:
-+/*
-+ DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
-+ start, end, di->txout, forceall));
-+*/
-+ return (NULL);
++ /* free our private info structure */
++ MFREE(di->osh, (void*)di, sizeof (dma_info_t));
+}
+
-+static void *
-+dma32_getnextrxp(dma_info_t *di, bool forceall)
++/* return TRUE if this dma engine supports DmaExtendedAddrChanges, otherwise FALSE */
++static bool
++dma_isaddrext(dma_info_t *di)
+{
-+ uint i;
-+ void *rxp;
-+
-+ /* if forcing, dma engine must be disabled */
-+ ASSERT(!forceall || !dma_rxenabled(di));
-+
-+ i = di->rxin;
-+
-+ /* return if no packets posted */
-+ if (i == di->rxout)
-+ return (NULL);
++ uint32 w;
+
-+ /* ignore curr if forceall */
-+ if (!forceall && (i == B2I(R_REG(&di->d32rxregs->status) & RS_CD_MASK, dma32dd_t)))
-+ return (NULL);
++ if (DMA64_ENAB(di)) {
++ OR_REG(&di->d64txregs->control, D64_XC_AE);
++ w = R_REG(&di->d32txregs->control);
++ AND_REG(&di->d32txregs->control, ~D64_XC_AE);
++ return ((w & XC_AE) == D64_XC_AE);
++ } else {
++ OR_REG(&di->d32txregs->control, XC_AE);
++ w = R_REG(&di->d32txregs->control);
++ AND_REG(&di->d32txregs->control, ~XC_AE);
++ return ((w & XC_AE) == XC_AE);
++ }
++}
+
-+ /* get the packet pointer that corresponds to the rx descriptor */
-+ rxp = di->rxp[i];
-+ ASSERT(rxp);
-+ di->rxp[i] = NULL;
++void
++dma_txreset(dma_info_t *di)
++{
++ DMA_TRACE(("%s: dma_txreset\n", di->name));
+
-+ /* clear this packet from the descriptor ring */
-+ DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->rxd32[i].addr)) - di->dataoffsetlow),
-+ di->rxbufsize, DMA_RX, rxp);
-+ W_SM(&di->rxd32[i].addr, 0xdeadbeef);
++ if (DMA64_ENAB(di))
++ dma64_txreset(di);
++ else
++ dma32_txreset(di);
++}
+
-+ di->rxin = NEXTRXD(i);
++void
++dma_rxreset(dma_info_t *di)
++{
++ DMA_TRACE(("%s: dma_rxreset\n", di->name));
+
-+ return (rxp);
++ if (DMA64_ENAB(di))
++ dma64_rxreset(di);
++ else
++ dma32_rxreset(di);
+}
+
++/* initialize descriptor table base address */
+static void
-+dma32_txrotate(di_t *di)
++dma_ddtable_init(dma_info_t *di, uint direction, ulong pa)
+{
-+ uint ad;
-+ uint nactive;
-+ uint rot;
-+ uint old, new;
-+ uint32 w;
-+ uint first, last;
-+
-+ ASSERT(dma_txsuspendedidle(di));
-+
-+ nactive = dma_txactive(di);
-+ ad = B2I(((R_REG(&di->d32txregs->status) & XS_AD_MASK) >> XS_AD_SHIFT), dma32dd_t);
-+ rot = TXD(ad - di->txin);
-+
-+ ASSERT(rot < di->ntxd);
-+
-+ /* full-ring case is a lot harder - don't worry about this */
-+ if (rot >= (di->ntxd - nactive)) {
-+ DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
-+ return;
++ if (DMA64_ENAB(di)) {
++ if (direction == DMA_TX) {
++ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow);
++ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh);
++ } else {
++ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow);
++ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh);
++ }
++ } else {
++ uint32 offset = di->ddoffsetlow;
++ if ((offset != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
++ if (direction == DMA_TX)
++ W_REG(&di->d32txregs->addr, (pa + offset));
++ else
++ W_REG(&di->d32rxregs->addr, (pa + offset));
++ } else {
++ /* dma32 address extension */
++ uint32 ae;
++ ASSERT(di->addrext);
++ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
++
++ if (direction == DMA_TX) {
++ W_REG(&di->d32txregs->addr, ((pa & ~PCI32ADDR_HIGH) + offset));
++ SET_REG(&di->d32txregs->control, XC_AE, (ae << XC_AE_SHIFT));
++ } else {
++ W_REG(&di->d32rxregs->addr, ((pa & ~PCI32ADDR_HIGH) + offset));
++ SET_REG(&di->d32rxregs->control, RC_AE, (ae << RC_AE_SHIFT));
++ }
++ }
+ }
++}
+
-+ first = di->txin;
-+ last = PREVTXD(di->txout);
-+
-+ /* move entries starting at last and moving backwards to first */
-+ for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
-+ new = TXD(old + rot);
-+
-+ /*
-+ * Move the tx dma descriptor.
-+ * EOT is set only in the last entry in the ring.
-+ */
-+ w = R_SM(&di->txd32[old].ctrl) & ~CTRL_EOT;
-+ if (new == (di->ntxd - 1))
-+ w |= CTRL_EOT;
-+ W_SM(&di->txd32[new].ctrl, w);
-+ W_SM(&di->txd32[new].addr, R_SM(&di->txd32[old].addr));
++/* init the tx or rx descriptor */
++static INLINE void
++dma32_dd_upd(dma_info_t *di, dma32dd_t *ddring, ulong pa, uint outidx, uint32 *ctrl)
++{
++ uint offset = di->dataoffsetlow;
+
-+ /* zap the old tx dma descriptor address field */
-+ W_SM(&di->txd32[old].addr, 0xdeadbeef);
++ if ((offset != SB_PCI_DMA) || !(pa & PCI32ADDR_HIGH)) {
++ W_SM(&ddring[outidx].addr, BUS_SWAP32(pa + offset));
++ W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*ctrl));
++ } else {
++ /* address extension */
++ uint32 ae;
++ ASSERT(di->addrext);
++ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
+
-+ /* move the corresponding txp[] entry */
-+ ASSERT(di->txp[new] == NULL);
-+ di->txp[new] = di->txp[old];
-+ di->txp[old] = NULL;
++ *ctrl |= (ae << CTRL_AE_SHIFT);
++ W_SM(&ddring[outidx].addr, BUS_SWAP32((pa & ~PCI32ADDR_HIGH) + offset));
++ W_SM(&ddring[outidx].ctrl, BUS_SWAP32(*ctrl));
+ }
-+
-+ /* update txin and txout */
-+ di->txin = ad;
-+ di->txout = TXD(di->txout + rot);
-+ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+
-+ /* kick the chip */
-+ W_REG(&di->d32txregs->ptr, I2B(di->txout, dma32dd_t));
+}
+
-+/*** 64 bits DMA non-inline functions ***/
-+
-+#ifdef BCMDMA64
-+
-+static bool
-+dma64_alloc(dma_info_t *di, uint direction)
++/* init the tx or rx descriptor */
++static INLINE void
++dma64_dd_upd(dma_info_t *di, dma64dd_t *ddring, ulong pa, uint outidx, uint32 *flags, uint32 bufcount)
+{
-+ uint size;
-+ uint ddlen;
-+ uint32 alignbytes;
-+ void *va;
-+
-+ ddlen = sizeof (dma64dd_t);
++ uint32 bufaddr_low = pa + di->dataoffsetlow;
++ uint32 bufaddr_high = 0 + di->dataoffsethigh;
+
-+ size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
++ uint32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
+
-+ alignbytes = di->dma64align;
++ W_SM(&ddring[outidx].addrlow, BUS_SWAP32(bufaddr_low));
++ W_SM(&ddring[outidx].addrhigh, BUS_SWAP32(bufaddr_high));
++ W_SM(&ddring[outidx].ctrl1, BUS_SWAP32(*flags));
++ W_SM(&ddring[outidx].ctrl2, BUS_SWAP32(ctrl2));
++}
+
-+ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, alignbytes))
-+ size += alignbytes;
++void
++dma_txinit(dma_info_t *di)
++{
++ DMA_TRACE(("%s: dma_txinit\n", di->name));
+
++ di->txin = di->txout = 0;
++ di->txavail = di->ntxd - 1;
+
-+ if (direction == DMA_TX) {
-+ if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->txdpa)) == NULL) {
-+ DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(ntxd) failed\n", di->name));
-+ return FALSE;
-+ }
++ /* clear tx descriptor ring */
++ if (DMA64_ENAB(di)) {
++ BZERO_SM((void*)di->txd64, (di->ntxd * sizeof (dma64dd_t)));
++ W_REG(&di->d64txregs->control, XC_XE);
++ dma_ddtable_init(di, DMA_TX, di->txdpa);
++ } else {
++ BZERO_SM((void*)di->txd32, (di->ntxd * sizeof (dma32dd_t)));
++ W_REG(&di->d32txregs->control, XC_XE);
++ dma_ddtable_init(di, DMA_TX, di->txdpa);
++ }
++}
+
-+ di->txd64 = (dma64dd_t*) ROUNDUP((uintptr)va, alignbytes);
-+ di->txdalign = (uint)((int8*)di->txd64 - (int8*)va);
-+ di->txdpa += di->txdalign;
-+ di->txdalloc = size;
-+ ASSERT(ISALIGNED((uintptr)di->txd64, alignbytes));
++bool
++dma_txenabled(dma_info_t *di)
++{
++ uint32 xc;
++
++ /* If the chip is dead, it is not enabled :-) */
++ if (DMA64_ENAB(di)) {
++ xc = R_REG(&di->d64txregs->control);
++ return ((xc != 0xffffffff) && (xc & D64_XC_XE));
+ } else {
-+ if ((va = DMA_ALLOC_CONSISTENT(di->osh, size, &di->rxdpa)) == NULL) {
-+ DMA_ERROR(("%s: dma_attach: DMA_ALLOC_CONSISTENT(nrxd) failed\n", di->name));
-+ return FALSE;
-+ }
-+ di->rxd64 = (dma64dd_t*) ROUNDUP((uintptr)va, alignbytes);
-+ di->rxdalign = (uint)((int8*)di->rxd64 - (int8*)va);
-+ di->rxdpa += di->rxdalign;
-+ di->rxdalloc = size;
-+ ASSERT(ISALIGNED((uintptr)di->rxd64, alignbytes));
++ xc = R_REG(&di->d32txregs->control);
++ return ((xc != 0xffffffff) && (xc & XC_XE));
+ }
++}
+
-+ return TRUE;
++void
++dma_txsuspend(dma_info_t *di)
++{
++ DMA_TRACE(("%s: dma_txsuspend\n", di->name));
++ if (DMA64_ENAB(di))
++ OR_REG(&di->d64txregs->control, D64_XC_SE);
++ else
++ OR_REG(&di->d32txregs->control, XC_SE);
+}
+
-+static void
-+dma64_txreset(dma_info_t *di)
++void
++dma_txresume(dma_info_t *di)
+{
-+ uint32 status;
++ DMA_TRACE(("%s: dma_txresume\n", di->name));
++ if (DMA64_ENAB(di))
++ AND_REG(&di->d64txregs->control, ~D64_XC_SE);
++ else
++ AND_REG(&di->d32txregs->control, ~XC_SE);
++}
+
-+ /* suspend tx DMA first */
-+ W_REG(&di->d64txregs->control, D64_XC_SE);
-+ SPINWAIT((status = (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED &&
-+ status != D64_XS0_XS_IDLE &&
-+ status != D64_XS0_XS_STOPPED,
-+ 10000);
++bool
++dma_txsuspendedidle(dma_info_t *di)
++{
++ if (DMA64_ENAB(di))
++ return dma64_txsuspendedidle(di);
++ else
++ return dma32_txsuspendedidle(di);
++}
+
-+ W_REG(&di->d64txregs->control, 0);
-+ SPINWAIT((status = (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) != D64_XS0_XS_DISABLED,
-+ 10000);
++bool
++dma_txsuspended(dma_info_t *di)
++{
++ if (DMA64_ENAB(di))
++ return ((R_REG(&di->d64txregs->control) & D64_XC_SE) == D64_XC_SE);
++ else
++ return ((R_REG(&di->d32txregs->control) & XC_SE) == XC_SE);
++}
+
-+ if (status != D64_XS0_XS_DISABLED) {
-+ DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name));
-+ }
++bool
++dma_txstopped(dma_info_t *di)
++{
++ if (DMA64_ENAB(di))
++ return ((R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK) == D64_XS0_XS_STOPPED);
++ else
++ return ((R_REG(&di->d32txregs->status) & XS_XS_MASK) == XS_XS_STOPPED);
++}
+
-+ /* wait for the last transaction to complete */
-+ OSL_DELAY(300);
++bool
++dma_rxstopped(dma_info_t *di)
++{
++ if (DMA64_ENAB(di))
++ return ((R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK) == D64_RS0_RS_STOPPED);
++ else
++ return ((R_REG(&di->d32rxregs->status) & RS_RS_MASK) == RS_RS_STOPPED);
++}
++
++void
++dma_fifoloopbackenable(dma_info_t *di)
++{
++ DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
++ if (DMA64_ENAB(di))
++ OR_REG(&di->d64txregs->control, D64_XC_LE);
++ else
++ OR_REG(&di->d32txregs->control, XC_LE);
+}
+
-+static void
-+dma64_rxreset(dma_info_t *di)
++void
++dma_rxinit(dma_info_t *di)
+{
-+ uint32 status;
++ DMA_TRACE(("%s: dma_rxinit\n", di->name));
+
-+ W_REG(&di->d64rxregs->control, 0);
-+ SPINWAIT((status = (R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK)) != D64_RS0_RS_DISABLED,
-+ 10000);
++ di->rxin = di->rxout = 0;
+
-+ if (status != D64_RS0_RS_DISABLED) {
-+ DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name));
++ /* clear rx descriptor ring */
++ if (DMA64_ENAB(di)) {
++ BZERO_SM((void*)di->rxd64, (di->nrxd * sizeof (dma64dd_t)));
++ dma_rxenable(di);
++ dma_ddtable_init(di, DMA_RX, di->rxdpa);
++ } else {
++ BZERO_SM((void*)di->rxd32, (di->nrxd * sizeof (dma32dd_t)));
++ dma_rxenable(di);
++ dma_ddtable_init(di, DMA_RX, di->rxdpa);
+ }
+}
+
-+static bool
-+dma64_txsuspendedidle(dma_info_t *di)
++void
++dma_rxenable(dma_info_t *di)
+{
-+
-+ if (!(R_REG(&di->d64txregs->control) & D64_XC_SE))
-+ return 0;
-+
-+ if ((R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK) == D64_XS0_XS_IDLE)
-+ return 1;
-+
-+ return 0;
++ DMA_TRACE(("%s: dma_rxenable\n", di->name));
++ if (DMA64_ENAB(di))
++ W_REG(&di->d64rxregs->control, ((di->rxoffset << D64_RC_RO_SHIFT) | D64_RC_RE));
++ else
++ W_REG(&di->d32rxregs->control, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
+}
+
-+/*
-+ * supports full 32bit dma engine buffer addressing so
-+ * dma buffers can cross 4 Kbyte page boundaries.
-+ */
-+static int
-+dma64_txfast(dma_info_t *di, void *p0, uint32 coreflags)
++bool
++dma_rxenabled(dma_info_t *di)
+{
-+ void *p, *next;
-+ uchar *data;
-+ uint len;
-+ uint txout;
-+ uint32 flags;
-+ uint32 pa;
-+
-+ DMA_TRACE(("%s: dma_txfast\n", di->name));
-+
-+ txout = di->txout;
-+ flags = 0;
-+
-+ /*
-+ * Walk the chain of packet buffers
-+ * allocating and initializing transmit descriptor entries.
-+ */
-+ for (p = p0; p; p = next) {
-+ data = PKTDATA(di->osh, p);
-+ len = PKTLEN(di->osh, p);
-+ next = PKTNEXT(di->osh, p);
-+
-+ /* return nonzero if out of tx descriptors */
-+ if (NEXTTXD(txout) == di->txin)
-+ goto outoftxd;
-+
-+ if (len == 0)
-+ continue;
-+
-+ /* get physical address of buffer start */
-+ pa = (uint32) DMA_MAP(di->osh, data, len, DMA_TX, p);
-+
-+ flags = coreflags;
-+
-+ if (p == p0)
-+ flags |= D64_CTRL1_SOF;
-+ if (next == NULL)
-+ flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
-+ if (txout == (di->ntxd - 1))
-+ flags |= D64_CTRL1_EOT;
-+
-+ dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
-+
-+ ASSERT(di->txp[txout] == NULL);
++ uint32 rc;
+
-+ txout = NEXTTXD(txout);
++ if (DMA64_ENAB(di)) {
++ rc = R_REG(&di->d64rxregs->control);
++ return ((rc != 0xffffffff) && (rc & D64_RC_RE));
++ } else {
++ rc = R_REG(&di->d32rxregs->control);
++ return ((rc != 0xffffffff) && (rc & RC_RE));
+ }
++}
+
-+ /* if last txd eof not set, fix it */
-+ if (!(flags & D64_CTRL1_EOF))
-+ W_SM(&di->txd64[PREVTXD(txout)].ctrl1, BUS_SWAP32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF));
-+
-+ /* save the packet */
-+ di->txp[PREVTXD(txout)] = p0;
-+
-+ /* bump the tx descriptor index */
-+ di->txout = txout;
-+
-+ /* kick the chip */
-+ W_REG(&di->d64txregs->ptr, I2B(txout, dma64dd_t));
-+
-+ /* tx flow control */
-+ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+
-+ return (0);
+
-+outoftxd:
-+ DMA_ERROR(("%s: dma_txfast: out of txds\n", di->name));
-+ PKTFREE(di->osh, p0, TRUE);
-+ di->txavail = 0;
-+ di->hnddma.txnobuf++;
-+ return (-1);
++/* !! tx entry routine */
++int
++dma_txfast(dma_info_t *di, void *p0, uint32 coreflags)
++{
++ if (DMA64_ENAB(di)) {
++ return dma64_txfast(di, p0, coreflags);
++ } else {
++ return dma32_txfast(di, p0, coreflags);
++ }
+}
+
-+static void*
-+dma64_getnexttxp(dma_info_t *di, bool forceall)
++/* !! rx entry routine, returns a pointer to the next frame received, or NULL if there are no more */
++void*
++dma_rx(dma_info_t *di)
+{
-+ uint start, end, i;
-+ void *txp;
-+
-+ DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, forceall ? "all" : ""));
-+
-+ txp = NULL;
++ void *p;
++ uint len;
++ int skiplen = 0;
+
-+ start = di->txin;
-+ if (forceall)
-+ end = di->txout;
-+ else
-+ end = B2I(R_REG(&di->d64txregs->status0) & D64_XS0_CD_MASK, dma64dd_t);
++ while ((p = dma_getnextrxp(di, FALSE))) {
++ /* skip giant packets which span multiple rx descriptors */
++ if (skiplen > 0) {
++ skiplen -= di->rxbufsize;
++ if (skiplen < 0)
++ skiplen = 0;
++ PKTFREE(di->osh, p, FALSE);
++ continue;
++ }
+
-+ if ((start == 0) && (end > di->txout))
-+ goto bogus;
++ len = ltoh16(*(uint16*)(PKTDATA(di->osh, p)));
++ DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
+
-+ for (i = start; i != end && !txp; i = NEXTTXD(i)) {
-+ DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->txd64[i].addrlow)) - di->dataoffsetlow),
-+ (BUS_SWAP32(R_SM(&di->txd64[i].ctrl2)) & D64_CTRL2_BC_MASK), DMA_TX, di->txp[i]);
++ /* bad frame length check */
++ if (len > (di->rxbufsize - di->rxoffset)) {
++ DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", di->name, len));
++ if (len > 0)
++ skiplen = len - (di->rxbufsize - di->rxoffset);
++ PKTFREE(di->osh, p, FALSE);
++ di->hnddma.rxgiants++;
++ continue;
++ }
+
-+ W_SM(&di->txd64[i].addrlow, 0xdeadbeef);
-+ W_SM(&di->txd64[i].addrhigh, 0xdeadbeef);
++ /* set actual length */
++ PKTSETLEN(di->osh, p, (di->rxoffset + len));
+
-+ txp = di->txp[i];
-+ di->txp[i] = NULL;
++ break;
+ }
+
-+ di->txin = i;
-+
-+ /* tx flow control */
-+ di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+
-+ return (txp);
-+
-+bogus:
-+/*
-+ DMA_ERROR(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n",
-+ start, end, di->txout, forceall));
-+*/
-+ return (NULL);
++ return (p);
+}
+
-+static void *
-+dma64_getnextrxp(dma_info_t *di, bool forceall)
++/* post receive buffers */
++void
++dma_rxfill(dma_info_t *di)
+{
++ void *p;
++ uint rxin, rxout;
++ uint32 ctrl;
++ uint n;
+ uint i;
-+ void *rxp;
++ uint32 pa;
++ uint rxbufsize;
+
-+ /* if forcing, dma engine must be disabled */
-+ ASSERT(!forceall || !dma_rxenabled(di));
++ /*
++ * Determine how many receive buffers we're lacking
++ * from the full complement, allocate, initialize,
++ * and post them, then update the chip rx lastdscr.
++ */
+
-+ i = di->rxin;
++ rxin = di->rxin;
++ rxout = di->rxout;
++ rxbufsize = di->rxbufsize;
+
-+ /* return if no packets posted */
-+ if (i == di->rxout)
-+ return (NULL);
++ n = di->nrxpost - NRXDACTIVE(rxin, rxout);
+
-+ /* ignore curr if forceall */
-+ if (!forceall && (i == B2I(R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK, dma64dd_t)))
-+ return (NULL);
++ DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
+
-+ /* get the packet pointer that corresponds to the rx descriptor */
-+ rxp = di->rxp[i];
-+ ASSERT(rxp);
-+ di->rxp[i] = NULL;
++ for (i = 0; i < n; i++) {
++ if ((p = PKTGET(di->osh, rxbufsize, FALSE)) == NULL) {
++ DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
++ di->hnddma.rxnobuf++;
++ break;
++ }
+
-+ /* clear this packet from the descriptor ring */
-+ DMA_UNMAP(di->osh, (BUS_SWAP32(R_SM(&di->rxd64[i].addrlow)) - di->dataoffsetlow),
-+ di->rxbufsize, DMA_RX, rxp);
++ /* Do a cached write instead of uncached write since DMA_MAP
++ * will flush the cache. */
++ *(uint32*)(PKTDATA(di->osh, p)) = 0;
++
++ pa = (uint32) DMA_MAP(di->osh, PKTDATA(di->osh, p), rxbufsize, DMA_RX, p);
++ ASSERT(ISALIGNED(pa, 4));
++
++ /* save the free packet pointer */
++ ASSERT(di->rxp[rxout] == NULL);
++ di->rxp[rxout] = p;
++
++ if (DMA64_ENAB(di)) {
++ /* prep the descriptor control value */
++ if (rxout == (di->nrxd - 1))
++ ctrl = CTRL_EOT;
+
-+ W_SM(&di->rxd64[i].addrlow, 0xdeadbeef);
-+ W_SM(&di->rxd64[i].addrhigh, 0xdeadbeef);
++ dma64_dd_upd(di, di->rxd64, pa, rxout, &ctrl, rxbufsize);
++ } else {
++ /* prep the descriptor control value */
++ ctrl = rxbufsize;
++ if (rxout == (di->nrxd - 1))
++ ctrl |= CTRL_EOT;
++ dma32_dd_upd(di, di->rxd32, pa, rxout, &ctrl);
++ }
+
-+ di->rxin = NEXTRXD(i);
++ rxout = NEXTRXD(rxout);
++ }
+
-+ return (rxp);
++ di->rxout = rxout;
++
++ /* update the chip lastdscr pointer */
++ if (DMA64_ENAB(di)) {
++ W_REG(&di->d64rxregs->ptr, I2B(rxout, dma64dd_t));
++ } else {
++ W_REG(&di->d32rxregs->ptr, I2B(rxout, dma32dd_t));
++ }
+}
+
-+static void
-+dma64_txrotate(di_t *di)
++void
++dma_txreclaim(dma_info_t *di, bool forceall)
+{
-+ uint ad;
-+ uint nactive;
-+ uint rot;
-+ uint old, new;
-+ uint32 w;
-+ uint first, last;
++ void *p;
+
-+ ASSERT(dma_txsuspendedidle(di));
++ DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
+
-+ nactive = dma_txactive(di);
-+ ad = B2I((R_REG(&di->d64txregs->status1) & D64_XS1_AD_MASK), dma64dd_t);
-+ rot = TXD(ad - di->txin);
++ while ((p = dma_getnexttxp(di, forceall)))
++ PKTFREE(di->osh, p, TRUE);
++}
+
-+ ASSERT(rot < di->ntxd);
++/*
++ * Reclaim next completed txd (txds if using chained buffers) and
++ * return associated packet.
++ * If 'force' is true, reclaim txd(s) and return associated packet
++ * regardless of the value of the hardware "curr" pointer.
++ */
++void*
++dma_getnexttxp(dma_info_t *di, bool forceall)
++{
++ if (DMA64_ENAB(di)) {
++ return dma64_getnexttxp(di, forceall);
++ } else {
++ return dma32_getnexttxp(di, forceall);
++ }
++}
++
++/* like getnexttxp but no reclaim */
++void*
++dma_peeknexttxp(dma_info_t *di)
++{
++ uint end, i;
+
-+ /* full-ring case is a lot harder - don't worry about this */
-+ if (rot >= (di->ntxd - nactive)) {
-+ DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
-+ return;
++ if (DMA64_ENAB(di)) {
++ end = B2I(R_REG(&di->d64txregs->status0) & D64_XS0_CD_MASK, dma64dd_t);
++ } else {
++ end = B2I(R_REG(&di->d32txregs->status) & XS_CD_MASK, dma32dd_t);
+ }
+
-+ first = di->txin;
-+ last = PREVTXD(di->txout);
++ for (i = di->txin; i != end; i = NEXTTXD(i))
++ if (di->txp[i])
++ return (di->txp[i]);
+
-+ /* move entries starting at last and moving backwards to first */
-+ for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
-+ new = TXD(old + rot);
++ return (NULL);
++}
+
-+ /*
-+ * Move the tx dma descriptor.
-+ * EOT is set only in the last entry in the ring.
-+ */
-+ w = R_SM(&di->txd64[old].ctrl1) & ~D64_CTRL1_EOT;
-+ if (new == (di->ntxd - 1))
-+ w |= D64_CTRL1_EOT;
-+ W_SM(&di->txd64[new].ctrl1, w);
++/*
++ * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
++ */
++void
++dma_txrotate(di_t *di)
++{
++ if (DMA64_ENAB(di)) {
++ dma64_txrotate(di);
++ } else {
++ &n