add cleanup and system code upgrade for brcm-2.6. pci seems to work, but spits out...
authorFelix Fietkau <nbd@openwrt.org>
Thu, 15 Dec 2005 22:33:10 +0000 (22:33 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 15 Dec 2005 22:33:10 +0000 (22:33 +0000)
SVN-Revision: 2689

openwrt/target/linux/linux-2.6/patches/brcm/001-bcm947xx.patch

index 32a4ed54cadc925a03d1a03f6b6dfd483663eefd..ade90a05a5cbec2cab1a1e4fb34739ec364a0ad2 100644 (file)
@@ -1,18 +1,76 @@
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/bcmsrom.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/bcmsrom.c     2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,685 @@
+diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
+--- linux.old/arch/mips/Kconfig        2005-12-15 13:26:49.758027500 +0100
++++ linux.dev/arch/mips/Kconfig        2005-12-15 12:57:27.889182500 +0100
+@@ -244,6 +244,17 @@
+        Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and
+        Olivetti M700-10 workstations.
++config BCM947XX
++      bool "Support for BCM947xx based boards"
++      select DMA_NONCOHERENT
++      select HW_HAS_PCI
++      select IRQ_CPU
++      select SYS_HAS_CPU_MIPS32_R1
++      select SYS_SUPPORTS_32BIT_KERNEL
++      select SYS_SUPPORTS_LITTLE_ENDIAN
++      help
++       Support for BCM947xx based boards
++
+ config LASAT
+       bool "Support for LASAT Networks platforms"
+       select DMA_NONCOHERENT
+diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
+--- linux.old/arch/mips/Makefile       2005-12-15 13:26:49.766024000 +0100
++++ linux.dev/arch/mips/Makefile       2005-12-15 12:57:27.921168500 +0100
+@@ -689,6 +689,13 @@
+ load-$(CONFIG_SIBYTE_BIGSUR)  := 0xffffffff80100000
+ #
++# Broadcom BCM47XX boards
++#
++core-$(CONFIG_BCM947XX)               += arch/mips/bcm947xx/ arch/mips/bcm947xx/broadcom/
++cflags-$(CONFIG_BCM947XX)     += -Iarch/mips/bcm947xx/include
++load-$(CONFIG_BCM947XX)               := 0xffffffff80001000
++
++#
+ # SNI RM200 PCI
+ #
+ core-$(CONFIG_SNI_RM200_PCI)  += arch/mips/sni/
+diff -urN 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      2005-12-15 14:32:03.580639500 +0100
+@@ -0,0 +1,6 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++
++obj-y := irq.o int-handler.o prom.o setup.o time.o pci.o
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/Makefile linux.dev/arch/mips/bcm947xx/broadcom/Makefile
+--- linux.old/arch/mips/bcm947xx/broadcom/Makefile     1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/Makefile     2005-12-15 16:59:40.571216500 +0100
+@@ -0,0 +1,6 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++ 
++obj-y   := sbutils.o linux_osl.o bcmsrom.o bcmutils.o sbmips.o sbpci.o sflash.o nvram.o
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/bcmsrom.c linux.dev/arch/mips/bcm947xx/broadcom/bcmsrom.c
+--- linux.old/arch/mips/bcm947xx/broadcom/bcmsrom.c    1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/bcmsrom.c    2005-12-15 17:35:21.719238750 +0100
+@@ -0,0 +1,483 @@
 +/*
-+ *  Misc useful routines to access NIC SROM
++ *  Misc useful routines to access NIC SROM/OTP .
 + *
-+ * Copyright 2001-2003, Broadcom Corporation
-+ * All Rights Reserved.
-+ * 
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ * $Id: bcmsrom.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
++ * 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>
@@ -21,76 +79,66 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc
 +#include <bcmsrom.h>
 +#include <bcmdevs.h>
 +#include <bcmendian.h>
-+#include <sbpcmcia.h>
 +#include <pcicfg.h>
++#include <sbutils.h>
 +
 +#include <proto/ethernet.h>   /* for sprom content groking */
 +
 +#define       VARS_MAX        4096    /* should be reduced */
 +
-+static int initvars_srom_pci(void *curmap, char **vars, int *count);
-+static int initvars_cis_pcmcia(void *osh, char **vars, int *count);
-+static int sprom_cmd_pcmcia(void *osh, uint8 cmd);
-+static int sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data);
-+static int sprom_write_pcmcia(void *osh, uint16 addr, uint16 data);
-+static int sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc);
++#define WRITE_ENABLE_DELAY    500     /* 500 ms after write enable/disable toggle */
++#define WRITE_WORD_DELAY      20      /* 20 ms between each word write */
++
++static int initvars_srom_pci(void *sbh, void *curmap, char **vars, int *count);
++static int sprom_read_pci(uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc);
++
++static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count);
 +
 +/*
-+ * Initialize the vars from the right source for this platform.
++ * Initialize local vars from the right source for this platform.
 + * Return 0 on success, nonzero on error.
 + */
 +int
-+srom_var_init(uint bus, void *curmap, void *osh, char **vars, int *count)
++srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, int *count)
 +{
-+      if (vars == NULL)
++      ASSERT(bustype == BUSTYPE(bustype));
++      if (vars == NULL || count == NULL)
 +              return (0);
 +
-+      switch (bus) {
-+      case SB_BUS:
-+              /* These two could be asserts ... */
-+              *vars = NULL;
-+              *count = 0;
-+              return(0);
++      switch (BUSTYPE(bustype)) {
 +
 +      case PCI_BUS:
 +              ASSERT(curmap); /* can not be NULL */
-+              return(initvars_srom_pci(curmap, vars, count));
-+
-+      case PCMCIA_BUS:
-+              return(initvars_cis_pcmcia(osh, vars, count));
-+
++              return initvars_srom_pci(sbh, curmap, vars, count);
 +
 +      default:
-+              ASSERT(0);
++              return 0;
 +      }
 +      return (-1);
 +}
 +
-+
 +/* support only 16-bit word read from srom */
 +int
-+srom_read(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
++srom_read(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
 +{
 +      void *srom;
-+      uint i, off, nw;
++      uint off, nw;
++
++      ASSERT(bustype == BUSTYPE(bustype));
 +
 +      /* check input - 16-bit access only */
 +      if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
 +              return 1;
 +
-+      if (bus == PCI_BUS) {
++      off = byteoff / 2;
++      nw = nbytes / 2;
++
++      if (BUSTYPE(bustype) == PCI_BUS) {
 +              if (!curmap)
 +                      return 1;
-+              srom = (void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
-+              if (sprom_read_pci(srom, byteoff, buf, nbytes, FALSE))
++              srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET;
++              if (sprom_read_pci(srom, off, buf, nw, FALSE))
 +                      return 1;
-+      } else if (bus == PCMCIA_BUS) {
-+              off = byteoff / 2;
-+              nw = nbytes / 2;
-+              for (i = 0; i < nw; i++) {
-+                      if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
-+                              return 1;
-+              }
 +      } else {
 +              return 1;
 +      }
@@ -100,7 +148,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc
 +
 +/* support only 16-bit word write into srom */
 +int
-+srom_write(uint bus, void *curmap, void *osh, uint byteoff, uint nbytes, uint16 *buf)
++srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
 +{
 +      uint16 *srom;
 +      uint i, off, nw, crc_range;
@@ -108,23 +156,25 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc
 +      uint8 crc;
 +      volatile uint32 val32;
 +
++      ASSERT(bustype == BUSTYPE(bustype));
++
 +      /* check input - 16-bit access only */
 +      if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
 +              return 1;
 +
-+      crc_range = ((bus == PCMCIA_BUS) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2;
++      crc_range = (((BUSTYPE(bustype) == SDIO_BUS)) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2;
 +
 +      /* if changes made inside crc cover range */
 +      if (byteoff < crc_range) {
 +              nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2;
 +              /* read data including entire first 64 words from srom */
-+              if (srom_read(bus, curmap, osh, 0, nw * 2, image))
++              if (srom_read(bustype, curmap, osh, 0, nw * 2, image))
 +                      return 1;
 +              /* make changes */
 +              bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
 +              /* calculate crc */
 +              htol16_buf(image, crc_range);
-+              crc = ~crc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
++              crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
 +              ltoh16_buf(image, crc_range);
 +              image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
 +              p = image;
@@ -135,343 +185,162 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc
 +              nw = nbytes / 2;
 +      }
 +
-+      if (bus == PCI_BUS) {
-+              srom = (uint16*)((uint)curmap + PCI_BAR0_SPROM_OFFSET);
++      if (BUSTYPE(bustype) == PCI_BUS) {
++              srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET);
 +              /* enable writes to the SPROM */
 +              val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
 +              val32 |= SPROM_WRITEEN;
 +              OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
-+              bcm_mdelay(500);
++              bcm_mdelay(WRITE_ENABLE_DELAY);
 +              /* write srom */
 +              for (i = 0; i < nw; i++) {
 +                      W_REG(&srom[off + i], p[i]);
-+                      bcm_mdelay(20);
++                      bcm_mdelay(WRITE_WORD_DELAY);
 +              }
 +              /* disable writes to the SPROM */
 +              OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN);
-+      } else if (bus == PCMCIA_BUS) {
-+              /* enable writes to the SPROM */
-+              if (sprom_cmd_pcmcia(osh, SROM_WEN))
-+                      return 1;
-+              bcm_mdelay(500);
-+              /* write srom */
-+              for (i = 0; i < nw; i++) {
-+                      sprom_write_pcmcia(osh, (uint16)(off + i), p[i]);
-+                      bcm_mdelay(20);
-+              }
-+              /* disable writes to the SPROM */
-+              if (sprom_cmd_pcmcia(osh, SROM_WDS))
-+                      return 1;
 +      } else {
 +              return 1;
 +      }
 +
-+      bcm_mdelay(500);
-+      return 0;
-+}
-+
-+
-+int
-+srom_parsecis(uint8 *cis, char **vars, int *count)
-+{
-+      char eabuf[32];
-+      char *vp, *base;
-+      uint8 tup, tlen, sromrev = 1;
-+      int i, j;
-+      uint varsize;
-+      bool ag_init = FALSE;
-+      uint16 w;
-+
-+      ASSERT(vars);
-+      ASSERT(count);
-+
-+      base = vp = MALLOC(VARS_MAX);
-+      ASSERT(vp);
-+
-+      i = 0;
-+      do {
-+              tup = cis[i++];
-+              tlen = cis[i++];
-+
-+              switch (tup) {
-+              case CISTPL_MANFID:
-+                      vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
-+                      vp++;
-+                      vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
-+                      vp++;
-+                      break;
-+
-+              case CISTPL_FUNCE:
-+                      if (cis[i] == LAN_NID) {
-+                              ASSERT(cis[i + 1] == ETHER_ADDR_LEN);
-+                              bcm_ether_ntoa((uchar*)&cis[i + 2], eabuf);
-+                              vp += sprintf(vp, "il0macaddr=%s", eabuf);
-+                              vp++;
-+                      }
-+                      break;
-+
-+              case CISTPL_CFTABLE:
-+                      vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
-+                      vp++;
-+                      break;
-+
-+              case CISTPL_BRCM_HNBU:
-+                      switch (cis[i]) {
-+                      case HNBU_CHIPID:
-+                              vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) + cis[i + 1]);
-+                              vp++;
-+                              vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) + cis[i + 3]);
-+                              vp++;
-+                              if (tlen == 7) {
-+                                      vp += sprintf(vp, "chiprev=%d", (cis[i + 6] << 8) + cis[i + 5]);
-+                                      vp++;
-+                              }
-+                              break;
-+
-+                      case HNBU_BOARDREV:
-+                              vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
-+                              vp++;
-+                              break;
-+
-+                      case HNBU_AA:
-+                              vp += sprintf(vp, "aa0=%d", cis[i + 1]);
-+                              vp++;
-+                              break;
-+
-+                      case HNBU_AG:
-+                              vp += sprintf(vp, "ag0=%d", cis[i + 1]);
-+                              vp++;
-+                              ag_init = TRUE;
-+                              break;
-+
-+                      case HNBU_CC:
-+                              vp += sprintf(vp, "cc=%d", cis[i + 1]);
-+                              vp++;
-+                              break;
-+
-+                      case HNBU_PAPARMS:
-+                              vp += sprintf(vp, "pa0maxpwr=%d", cis[i + tlen - 1]);
-+                              vp++;
-+                              if (tlen == 9) {
-+                                      /* New version */
-+                                      for (j = 0; j < 3; j++) {
-+                                              vp += sprintf(vp, "pa0b%d=%d", j,
-+                                                            (cis[i + (j * 2) + 2] << 8) + cis[i + (j * 2) + 1]);
-+                                              vp++;
-+                                      }
-+                                      vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
-+                                      vp++;
-+                              }
-+                              break;
-+
-+                      case HNBU_OEM:
-+                              vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
-+                                      cis[i + 1], cis[i + 2], cis[i + 3], cis[i + 4],
-+                                      cis[i + 5], cis[i + 6], cis[i + 7], cis[i + 8]);
-+                              vp++;
-+                              break;
-+                      case HNBU_BOARDFLAGS:
-+                              w = (cis[i + 2] << 8) + cis[i + 1];
-+                              if (w == 0xffff) w = 0;
-+                              vp += sprintf(vp, "boardflags=%d", w);
-+                              vp++;
-+                              break;
-+                      case HNBU_LED:
-+                              if (cis[i + 1] != 0xff) {
-+                                      vp += sprintf(vp, "wl0gpio0=%d", cis[i + 1]);
-+                                      vp++;
-+                              }
-+                              if (cis[i + 2] != 0xff) {
-+                                      vp += sprintf(vp, "wl0gpio1=%d", cis[i + 2]);
-+                                      vp++;
-+                              }
-+                              if (cis[i + 3] != 0xff) {
-+                                      vp += sprintf(vp, "wl0gpio2=%d", cis[i + 3]);
-+                                      vp++;
-+                              }
-+                              if (cis[i + 4] != 0xff) {
-+                                      vp += sprintf(vp, "wl0gpio3=%d", cis[i + 4]);
-+                                      vp++;
-+                              }
-+                              break;
-+                      }
-+                      break;
-+
-+              }
-+              i += tlen;
-+      } while (tup != 0xff);
-+
-+      /* Set the srom version */
-+      vp += sprintf(vp, "sromrev=%d", sromrev);
-+      vp++;
-+
-+      /* For now just set boardflags2 to zero */
-+      vp += sprintf(vp, "boardflags2=0");
-+      vp++;
-+
-+      /* if there is no antenna gain field, set default */
-+      if (ag_init == FALSE) {
-+              vp += sprintf(vp, "ag0=%d", 0xff);
-+              vp++;
-+      }
-+
-+      /* final nullbyte terminator */
-+      *vp++ = '\0';
-+      varsize = (uint)vp - (uint)base;
-+
-+      ASSERT(varsize < VARS_MAX);
-+
-+      if (varsize == VARS_MAX) {
-+              *vars = base;
-+      } else {
-+              vp = MALLOC(varsize);
-+              ASSERT(vp);
-+              bcopy(base, vp, varsize);
-+              MFREE(base, VARS_MAX);
-+              *vars = vp;
-+      }
-+      *count = varsize;
-+
-+      return (0);
-+}
-+
-+
-+/* set PCMCIA sprom command register */
-+static int
-+sprom_cmd_pcmcia(void *osh, uint8 cmd)
-+{
-+      uint8 status;
-+      uint wait_cnt = 1000;
-+
-+      /* write sprom command register */
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
-+
-+      /* wait status */
-+      while (wait_cnt--) {
-+              OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
-+              if (status & SROM_DONE)
-+                      return 0;
-+      }
-+      return 1;
-+}
-+
-+/* read a word from the PCMCIA srom */
-+static int
-+sprom_read_pcmcia(void *osh, uint16 addr, uint16 *data)
-+{
-+      uint8 addr_l, addr_h, data_l, data_h;
-+
-+      addr_l = (uint8)((addr * 2) & 0xff);
-+      addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
-+
-+      /* set address */
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
-+
-+      /* do read */
-+      if (sprom_cmd_pcmcia(osh, SROM_READ))
-+              return 1;
-+
-+      /* read data */
-+      OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
-+      OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
-+
-+      *data = (data_h << 8) | data_l;
++      bcm_mdelay(WRITE_ENABLE_DELAY);
 +      return 0;
 +}
 +
-+/* write a word to the PCMCIA srom */
-+static int
-+sprom_write_pcmcia(void *osh, uint16 addr, uint16 data)
-+{
-+      uint8 addr_l, addr_h, data_l, data_h;
-+
-+      addr_l = (uint8)((addr * 2) & 0xff);
-+      addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
-+      data_l = (uint8)(data & 0xff);
-+      data_h = (uint8)((data >> 8) & 0xff);
-+
-+      /* set address */
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
-+
-+      /* write data */
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
-+      OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
-+
-+      /* do write */
-+      return sprom_cmd_pcmcia(osh, SROM_WRITE);
-+}
 +
 +/*
 + * Read in and validate sprom.
 + * Return 0 on success, nonzero on error.
 + */
 +static int
-+sprom_read_pci(uint16 *sprom, uint byteoff, uint16 *buf, uint nbytes, bool check_crc)
++sprom_read_pci(uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc)
 +{
-+      int off, nw;
-+      uint8 chk8;
-+      int i;
-+
-+      off = byteoff / 2;
-+      nw = ROUNDUP(nbytes, 2) / 2;
++      int err = 0;
++      uint i;
 +
 +      /* read the sprom */
-+      for (i = 0; i < nw; i++)
-+              buf[i] = R_REG(&sprom[off + i]);
++      for (i = 0; i < nwords; i++)
++              buf[i] = R_REG(&sprom[wordoff + i]);
 +
 +      if (check_crc) {
 +              /* fixup the endianness so crc8 will pass */
-+              htol16_buf(buf, nw * 2);
-+              if ((chk8 = crc8((uchar*)buf, nbytes, CRC8_INIT_VALUE)) != CRC8_GOOD_VALUE)
-+                      return (1);
++              htol16_buf(buf, nwords * 2);
++              if (hndcrc8((uint8*)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE)
++                      err = 1;
 +              /* now correct the endianness of the byte array */
-+              ltoh16_buf(buf, nw * 2);
++              ltoh16_buf(buf, nwords * 2);
 +      }
++      
++      return err;
++}     
 +
-+      return (0);
++/*
++* Create variable table from memory.
++* Return 0 on success, nonzero on error.
++*/
++static int
++initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count)
++{
++      int c = (int)(end - start);
++
++      /* do it only when there is more than just the null string */
++      if (c > 1) {
++              char *vp = MALLOC(osh, c);
++              ASSERT(vp);
++              if (!vp)
++                      return BCME_NOMEM;
++              bcopy(start, vp, c);
++              *vars = vp;
++              *count = c;
++      }
++      else {
++              *vars = NULL;
++              *count = 0;
++      }
++      
++      return 0;
 +}
 +
 +/*
 + * Initialize nonvolatile variable table from sprom.
 + * Return 0 on success, nonzero on error.
 + */
-+
 +static int
-+initvars_srom_pci(void *curmap, char **vars, int *count)
++initvars_srom_pci(void *sbh, void *curmap, char **vars, int *count)
 +{
 +      uint16 w, b[64];
 +      uint8 sromrev;
 +      struct ether_addr ea;
 +      char eabuf[32];              
-+      int c, woff, i;
++      uint32 w32;
++      int woff, i;
 +      char *vp, *base;
++      osl_t *osh = sb_osh(sbh);
++      char name[SB_DEVPATH_BUFSZ+16], *value;
++      char devpath[SB_DEVPATH_BUFSZ];
++      int err;
 +
-+      if (sprom_read_pci((void *)((uint)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, sizeof (b), TRUE))
-+              return (-1);
++      /*
++      * Apply CRC over SROM content regardless SROM is present or not,
++      * and use variable <devpath>sromrev's existance in flash to decide
++      * if we should return an error when CRC fails or read SROM variables
++      * from flash.
++      */
++      sprom_read_pci((void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, sizeof(b)/sizeof(b[0]), TRUE);
 +
 +      /* top word of sprom contains version and crc8 */
 +      sromrev = b[63] & 0xff;
-+      if ((sromrev != 1) && (sromrev != 2)) {
++      /* bcm4401 sroms misprogrammed */
++      if (sromrev == 0x10)
++              sromrev = 1;
++      
++      /* srom version check */
++      if (sromrev > 3)
 +              return (-2);
-+      }
 +
 +      ASSERT(vars);
 +      ASSERT(count);
 +
-+      base = vp = MALLOC(VARS_MAX);
++      base = vp = MALLOC(osh, VARS_MAX);
 +      ASSERT(vp);
++      if (!vp)
++              return -2;
 +
 +      vp += sprintf(vp, "sromrev=%d", sromrev);
 +      vp++;
 +
-+      if (sromrev >= 2) {
-+              /* New section takes over the 4th hardware function space */
++      if (sromrev >= 3) {
++              /* New section takes over the 3th hardware function space */
++
++              /* Words 22+23 are 11a (mid) ofdm power offsets */
++              w32 = ((uint32)b[23] << 16) | b[22];
++              vp += sprintf(vp, "ofdmapo=%d", w32);
++              vp++;
++
++              /* Words 24+25 are 11a (low) ofdm power offsets */
++              w32 = ((uint32)b[25] << 16) | b[24];
++              vp += sprintf(vp, "ofdmalpo=%d", w32);
++              vp++;
++
++              /* Words 26+27 are 11a (high) ofdm power offsets */
++              w32 = ((uint32)b[27] << 16) | b[26];
++              vp += sprintf(vp, "ofdmahpo=%d", w32);
++              vp++;
++
++              /*GPIO LED Powersave duty cycle (oncount >> 24) (offcount >> 8)*/
++              w32 = ((uint32)b[43] << 24) | ((uint32)b[42] << 8);
++              vp += sprintf(vp, "gpiotimerval=%d", w32);
++
++              /*GPIO LED Powersave duty cycle (oncount >> 24) (offcount >> 8)*/
++              w32 = ((uint32)((unsigned char)(b[21] >> 8) & 0xFF) << 24) |  /* oncount*/
++                      ((uint32)((unsigned char)(b[21] & 0xFF)) << 8); /* offcount */
++              vp += sprintf(vp, "gpiotimerval=%d", w32);
 +
-+              /* Word 28 is boardflags2 */
-+              vp += sprintf(vp, "boardflags2=%d", b[28]);
 +              vp++;
++      }
++
++      if (sromrev >= 2) {
++              /* New section takes over the 4th hardware function space */
 +
 +              /* Word 29 is max power 11a high/low */
 +              w = b[29];
@@ -622,9 +491,13 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc
 +      vp++;
 +
 +      /* Word 57 is boardflags, if not programmed make it zero */
-+      w = b[57];
-+      if (w == 0xffff) w = 0;
-+      vp += sprintf(vp, "boardflags=%d", w);
++      w32 = (uint32)b[57];
++      if (w32 == 0xffff) w32 = 0;
++      if (sromrev > 1) {
++              /* Word 28 is the high bits of boardflags */
++              w32 |= (uint32)b[28] << 16;
++      }
++      vp += sprintf(vp, "boardflags=%d", w32);
 +      vp++;
 +
 +      /* Word 58 is antenna gain 0/1 */
@@ -643,72 +516,57 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.15-rc
 +                            ((b[61] >> 8) & 0xff), (b[61] & 0xff),
 +                            ((b[62] >> 8) & 0xff), (b[62] & 0xff));
 +              vp++;
++      } else if (sromrev == 2) {
++              /* Word 60 OFDM tx power offset from CCK level */
++              /* OFDM Power Offset - opo */
++              vp += sprintf(vp, "opo=%d", b[60] & 0xff);
++              vp++;
++      } else {
++              /* Word 60: cck power offsets */
++              vp += sprintf(vp, "cckpo=%d", b[60]);
++              vp++;
++
++              /* Words 61+62: 11g ofdm power offsets */
++              w32 = ((uint32)b[62] << 16) | b[61];
++              vp += sprintf(vp, "ofdmgpo=%d", w32);
++              vp++;
 +      }
 +
 +      /* final nullbyte terminator */
 +      *vp++ = '\0';
 +
-+      c = vp - base;
-+      ASSERT(c <= VARS_MAX);
-+
-+      if (c == VARS_MAX) {
-+              *vars = base;
-+      } else {
-+              vp = MALLOC(c);
-+              ASSERT(vp);
-+              bcopy(base, vp, c);
-+              MFREE(base, VARS_MAX);
-+              *vars = vp;
-+      }
-+      *count = c;
-+
-+      return (0);
-+}
-+
-+/*
-+ * Read the cis and call parsecis to initialize the vars.
-+ * Return 0 on success, nonzero on error.
-+ */
-+static int
-+initvars_cis_pcmcia(void *osh, char **vars, int *count)
-+{
-+      uint8 *cis = NULL;
-+      int rc;
-+
-+      if ((cis = MALLOC(CIS_SIZE)) == NULL)
-+              return (-1);
-+
-+      OSL_PCMCIA_READ_ATTR(osh, 0, cis, CIS_SIZE);
-+
-+      rc = srom_parsecis(cis, vars, count);
-+
-+      MFREE(cis, CIS_SIZE);
-+
-+      return (rc);
++      ASSERT((vp - base) <= VARS_MAX);
++      
++      err = initvars_table(osh, base, vp, vars, count);
++      
++      MFREE(osh, base, VARS_MAX);
++      return err;
 +}
 +
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/bcmutils.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmutils.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/bcmutils.c    2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,691 @@
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/bcmutils.c linux.dev/arch/mips/bcm947xx/broadcom/bcmutils.c
+--- linux.old/arch/mips/bcm947xx/broadcom/bcmutils.c   1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/bcmutils.c   2005-12-15 20:14:31.420035750 +0100
+@@ -0,0 +1,358 @@
 +/*
 + * Misc useful OS-independent routines.
 + *
-+ * Copyright 2001-2003, Broadcom Corporation   
-+ * All Rights Reserved.   
-+ *    
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY   
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM   
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS   
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.   
-+ * $Id: bcmutils.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
++ * 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 <bcmnvram.h>
 +#include <bcmutils.h>
 +#include <bcmendian.h>
-+#include <bcmnvram.h>
++#include <bcmdevs.h>
 +
 +unsigned char bcm_ctype[] = {
 +      _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,                        /* 0-7 */
@@ -807,104 +665,34 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.15-r
 +      return (n);
 +}
 +
-+void
-+deadbeef(char *p, uint len)
++/* return pointer to location of substring 'needle' in 'haystack' */
++char*
++bcmstrstr(char *haystack, char *needle)
 +{
-+      static uchar meat[] = { 0xde, 0xad, 0xbe, 0xef };
++      int len, nlen;
++      int i;
 +
-+      while (len-- > 0) {
-+              *p = meat[((uint)p) & 3];
-+              p++;
-+      }
-+}
++      if ((haystack == NULL) || (needle == NULL))
++              return (haystack);
 +
-+/* pretty hex print a contiguous buffer */
-+void
-+prhex(char *msg, uchar *buf, uint nbytes)
-+{
-+      char line[256];
-+      char* p;
-+      uint i;
-+
-+      if (msg && (msg[0] != '\0'))
-+              printf("%s: ", msg);
-+
-+      p = line;
-+      for (i = 0; i < nbytes; i++) {
-+              if (i % 16 == 0) {
-+                      p += sprintf(p, "%04d: ", i);   /* line prefix */
-+              }
-+              p += sprintf(p, "%02x ", buf[i]);
-+              if (i % 16 == 15) {
-+                      printf("%s\n", line);           /* flush line */
-+                      p = line;
-+              }
-+      }
-+
-+      /* flush last partial line */
-+      if (p != line)
-+              printf("%s\n", line);
-+}
-+
-+/* pretty hex print a pkt buffer chain */
-+void
-+prpkt(char *msg, void *drv, void *p0)
-+{
-+      void *p;
-+
-+      if (msg && (msg[0] != '\0'))
-+              printf("%s: ", msg);
-+
-+      for (p = p0; p; p = PKTNEXT(drv, p))
-+              prhex(NULL, PKTDATA(drv, p), PKTLEN(drv, p));
-+}
-+
-+/* copy a pkt buffer chain into a buffer */
-+uint
-+pktcopy(void *drv, 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(drv, p)) {
-+              if (offset < (uint)PKTLEN(drv, p))
-+                      break;
-+              offset -= PKTLEN(drv, p);
-+      }
-+
-+      if (!p)
-+              return 0;
++      nlen = strlen(needle);
++      len = strlen(haystack) - nlen + 1;
 +
-+      /* copy the data */
-+      for (; p && len; p = PKTNEXT(drv, p)) {
-+              n = MIN((uint)PKTLEN(drv, p) - offset, (uint)len);
-+              bcopy(PKTDATA(drv, p) + offset, buf, n);
-+              buf += n;
-+              len -= n;
-+              ret += n;
-+              offset = 0;
-+      }
-+
-+      return ret;
++      for (i = 0; i < len; i++)
++              if (bcmp(needle, &haystack[i], nlen) == 0)
++                      return (&haystack[i]);
++      return (NULL);
 +}
 +
-+/* return total length of buffer chain */
-+uint
-+pkttotlen(void *drv, void *p)
++char*
++bcmstrcat(char *dest, const char *src)
 +{
-+      uint total;
-+
-+      total = 0;
-+      for (; p; p = PKTNEXT(drv, p))
-+              total += PKTLEN(drv, p);
-+      return (total);
++      strcpy(&dest[strlen(dest)], src);
++      return (dest);
 +}
 +
 +
-+uchar*
++char*
 +bcm_ether_ntoa(char *ea, char *buf)
 +{
 +      sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
@@ -928,123 +716,113 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.15-r
 +      return (i == 6);
 +}
 +
-+/* 
-+ * 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)
++void
++bcm_mdelay(uint ms)
 +{
-+      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);
++      uint i;
 +
-+              elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
-+              totlen -= (len + 2);
++      for (i = 0; i < ms; i++) {
++              OSL_DELAY(1000);
 +      }
-+      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
++/*
++ * Search the name=value vars for a specific one and return its value.
++ * Returns NULL if not found.
 + */
-+bcm_tlv_t *
-+bcm_parse_tlvs(void *buf, int buflen, uint key)
++char*
++getvar(char *vars, char *name)
 +{
-+      bcm_tlv_t *elt;
-+      int totlen;
-+
-+      elt = (bcm_tlv_t*)buf;
-+      totlen = buflen;
++      char *s;
++      int len;
 +
-+      /* find tagged parameter */
-+      while (totlen >= 2) {
-+              int len = elt->len;
++      len = strlen(name);
 +
-+              /* validate remaining totlen */
-+              if ((elt->id == key) && (totlen >= (len + 2)))
-+                      return (elt);
++      /* first look in vars[] */
++      for (s = vars; s && *s; ) {
++              if ((bcmp(s, name, len) == 0) && (s[len] == '='))
++                      return (&s[len+1]);
 +
-+              elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
-+              totlen -= (len + 2);
++              while (*s++)
++                      ;
 +      }
-+      
-+      return NULL;
++
++      /* then query nvram */
++      return (BCMINIT(nvram_get)(name));
 +}
 +
-+void
-+pktqinit(struct pktq *q, int maxlen)
++/*
++ * Search the vars for a specific one and return its value as
++ * an integer. Returns 0 if not found.
++ */
++int
++getintvar(char *vars, char *name)
 +{
-+      q->head = q->tail = NULL;
-+      q->maxlen = maxlen;
-+      q->len = 0;
++      char *val;
++
++      if ((val = getvar(vars, name)) == NULL)
++              return (0);
++
++      return (bcm_strtoul(val, NULL, 0));
 +}
 +
-+void
-+pktenq(struct pktq *q, void *p, bool lifo)
-+{
-+      ASSERT(PKTLINK(p) == NULL);
 +
-+      PKTSETLINK(p, NULL);
++/* Search for token in comma separated token-string */
++static int
++findmatch(char *string, char *name)
++{
++      uint len;
++      char *c;
 +
-+      if (q->tail == NULL) {
-+              ASSERT(q->head == NULL);
-+              q->head = q->tail = p;
-+      }
-+      else {
-+              ASSERT(q->head);
-+              ASSERT(PKTLINK(q->tail) == NULL);
-+              if (lifo) {
-+                      PKTSETLINK(p, q->head);
-+                      q->head = p;
-+              } else {
-+                      PKTSETLINK(q->tail, p);
-+                      q->tail = p;
-+              }
++      len = strlen(name);
++      while ((c = strchr(string, ',')) != NULL) {
++              if (len == (uint)(c - string) && !strncmp(string, name, len))
++                      return 1;
++              string = c + 1;
 +      }
-+      q->len++;
++
++      return (!strcmp(string, name));
 +}
 +
-+void*
-+pktdeq(struct pktq *q)
++/* Return gpio pin number assigned to the named pin */
++/*
++* Variable should be in format:
++*
++*     gpio<N>=pin_name,pin_name
++*
++* This format allows multiple features to share the gpio with mutual
++* understanding.
++*
++* 'def_pin' is returned if a specific gpio is not defined for the requested functionality 
++* and if def_pin is not used by others.
++*/
++uint
++getgpiopin(char *vars, char *pin_name, uint def_pin)
 +{
-+      void *p;
++      char name[] = "gpioXXXX";
++      char *val;
++      uint pin;
 +
-+      if ((p = q->head)) {
-+              ASSERT(q->tail);
-+              q->head = PKTLINK(p);
-+              PKTSETLINK(p, NULL);
-+              q->len--;
-+              if (q->head == NULL)
-+                      q->tail = NULL;
++      /* Go thru all possibilities till a match in pin name */
++      for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
++              sprintf(name, "gpio%d", pin);
++              val = getvar(vars, name);
++              if (val && findmatch(val, pin_name))
++                      return pin;
 +      }
-+      else {
-+              ASSERT(q->tail == NULL);
++
++      if (def_pin != GPIO_PIN_NOTDEFINED) {
++              /* make sure the default pin is not used by someone else */
++              sprintf(name, "gpio%d", def_pin);
++              if (getvar(vars, name)) {
++                      def_pin =  GPIO_PIN_NOTDEFINED;
++              }
 +      }
 +
-+      return (p);
++      return def_pin;
 +}
 +
++
 +/*******************************************************************************
 + * crc8
 + *
@@ -1101,61 +879,11 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.15-r
 +    0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
 +};
 +
-+/*
-+ * Search the name=value vars for a specific one and return its value.
-+ * Returns NULL if not found.
-+ */
-+char*
-+getvar(char *vars, char *name)
-+{
-+      char *s;
-+      int len;
-+
-+      len = strlen(name);
-+
-+      /* first look in vars[] */
-+      for (s = vars; s && *s; ) {
-+              if ((bcmp(s, name, len) == 0) && (s[len] == '='))
-+                      return (&s[len+1]);
-+
-+              while (*s++)
-+                      ;
-+      }
-+
-+      /* then query nvram */
-+      return (nvram_get(name));
-+}
-+
-+/*
-+ * Search the vars for a specific one and return its value as
-+ * an integer. Returns 0 if not found.
-+ */
-+int
-+getintvar(char *vars, char *name)
-+{
-+      char *val;
-+
-+      if ((val = getvar(vars, name)) == NULL)
-+              return (0);
-+
-+      return (bcm_strtoul(val, NULL, 0));
-+}
-+
-+void
-+bcm_mdelay(uint ms)
-+{
-+      uint i;
-+
-+      for (i = 0; i < ms; i++) {
-+              OSL_DELAY(1000);
-+      }
-+}
-+
 +#define CRC_INNER_LOOP(n, c, x) \
 +    (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
 +
 +uint8
-+crc8(
++hndcrc8(
 +      uint8 *pdata,   /* pointer to array of data to process */
 +      uint  nbytes,   /* number of input data bytes to process */
 +      uint8 crc       /* either CRC8_INIT_VALUE or previous return value */
@@ -1169,228 +897,22 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.15-r
 +      return crc;
 +}
 +
-+/*******************************************************************************
-+ * crc16
-+ *
-+ * Computes a crc16 over the input data using the polynomial:
-+ *
-+ *       x^16 + x^12 +x^5 + 1
-+ *
-+ * The caller provides the initial value (either CRC16_INIT_VALUE
-+ * or the previous returned value) to allow for processing of 
-+ * discontiguous blocks of data.  When generating the CRC the
-+ * caller is responsible for complementing the final return value
-+ * and inserting it into the byte stream.  When checking, a final
-+ * return value of CRC16_GOOD_VALUE indicates a valid CRC.
-+ *
-+ * Reference: Dallas Semiconductor Application Note 27
-+ *   Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", 
-+ *     ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
-+ *     ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
-+ *
-+ ******************************************************************************/
-+
-+static uint16 crc16_table[256] = {
-+    0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
-+    0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
-+    0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
-+    0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
-+    0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
-+    0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
-+    0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
-+    0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
-+    0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
-+    0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
-+    0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
-+    0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
-+    0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
-+    0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
-+    0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
-+    0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
-+    0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
-+    0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
-+    0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
-+    0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
-+    0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
-+    0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
-+    0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
-+    0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
-+    0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
-+    0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
-+    0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
-+    0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
-+    0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
-+    0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
-+    0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
-+    0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
-+};
-+
-+uint16
-+crc16(
-+    uint8 *pdata,  /* pointer to array of data to process */
-+    uint nbytes, /* number of input data bytes to process */
-+    uint16 crc     /* either CRC16_INIT_VALUE or previous return value */
-+)
-+{
-+    while (nbytes-- > 0)
-+        CRC_INNER_LOOP(16, crc, *pdata++);
-+    return crc;
-+}
-+
-+static uint32 crc32_table[256] = {
-+    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
-+    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
-+    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
-+    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
-+    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
-+    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
-+    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
-+    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
-+    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
-+    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
-+    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
-+    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
-+    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
-+    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
-+    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
-+    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
-+    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
-+    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
-+    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
-+    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
-+    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
-+    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
-+    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
-+    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
-+    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
-+    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
-+    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
-+    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
-+    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
-+    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
-+    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
-+    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
-+    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
-+    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
-+    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
-+    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
-+    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
-+    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
-+    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
-+    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
-+    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
-+    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
-+    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
-+    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
-+    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
-+    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
-+    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
-+    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
-+    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
-+    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
-+    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
-+    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
-+    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
-+    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
-+    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
-+    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
-+    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
-+    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
-+    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
-+    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
-+    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
-+    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
-+    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
-+    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
-+};
-+
-+uint32
-+crc32(
-+    uint8 *pdata,  /* pointer to array of data to process */
-+    uint   nbytes, /* number of input data bytes to process */
-+    uint32 crc     /* either CRC32_INIT_VALUE or previous return value */
-+)
-+{
-+    uint8 *pend;
-+#ifdef __mips__
-+    uint8 tmp[4];
-+    ulong *tptr = (ulong *)tmp;
-+
-+      /* in case the beginning of the buffer isn't aligned */
-+      pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
-+      nbytes -= (pend - pdata);
-+      while (pdata < pend)
-+              CRC_INNER_LOOP(32, crc, *pdata++);
-+
-+    /* handle bulk of data as 32-bit words */
-+    pend = pdata + (nbytes & 0xfffffffc);
-+    while (pdata < pend) {
-+      *tptr = *((ulong *)pdata)++;
-+        CRC_INNER_LOOP(32, crc, tmp[0]);
-+        CRC_INNER_LOOP(32, crc, tmp[1]);
-+        CRC_INNER_LOOP(32, crc, tmp[2]);
-+        CRC_INNER_LOOP(32, crc, tmp[3]);
-+    }
-+
-+    /* 1-3 bytes at end of buffer */
-+    pend = pdata + (nbytes & 0x03);
-+    while (pdata < pend)
-+        CRC_INNER_LOOP(32, crc, *pdata++);
-+#else
-+    pend = pdata + nbytes;
-+    while (pdata < pend)
-+        CRC_INNER_LOOP(32, crc, *pdata++);
-+#endif
-+       
-+    return crc;
-+}
-+
 +#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
 +
 +
-+
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/hnddma.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/hnddma.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/hnddma.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/hnddma.c      2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,763 @@
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/linux_osl.c linux.dev/arch/mips/bcm947xx/broadcom/linux_osl.c
+--- linux.old/arch/mips/bcm947xx/broadcom/linux_osl.c  1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/linux_osl.c  2005-12-15 17:11:05.818041750 +0100
+@@ -0,0 +1,102 @@
 +/*
-+ * Generic Broadcom Home Networking Division (HND) DMA module.
-+ * This supports the following chips: BCM42xx, 44xx, 47xx .
++ * Linux OS Independent Layer
 + *
-+ * Copyright 2001-2003, Broadcom Corporation
++ * Copyright 2005, Broadcom Corporation
 + * All Rights Reserved.
 + * 
 + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
@@ -1398,2377 +920,284 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/hnddma.c linux-2.6.15-rc5
 + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
 + *
-+ * $Id: hnddma.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
++ * $Id$
 + */
 +
++#define LINUX_OSL
++
 +#include <typedefs.h>
-+#include <osl.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>
 +
-+struct dma_info;      /* forward declaration */
-+#define di_t struct dma_info
-+#include <hnddma.h>
-+
-+/* debug/trace */
-+#define       DMA_ERROR(args)
-+#define       DMA_TRACE(args)
-+
-+/* default dma message level(if input msg_level pointer is null in dma_attach()) */
-+static uint dma_msg_level = 0;
-+
-+#define       MAXNAMEL        8
-+#define       MAXDD           (DMAMAXRINGSZ / sizeof (dmadd_t))
-+
-+/* 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            *drv;           /* driver handle */
-+      void            *dev;           /* device handle */
-+      dmaregs_t       *regs;          /* dma engine registers */
-+
-+      dmadd_t         *txd;           /* pointer to chip-specific tx descriptor ring */
-+      uint            txin;           /* index of next descriptor to reclaim */
-+      uint            txout;          /* index of next descriptor to post */
-+      uint            txavail;        /* # free tx descriptors */
-+      void            *txp[MAXDD];    /* parallel array of pointers to packets */
-+      ulong           txdpa;          /* physical address of descriptor ring */
-+      uint            txdalign;       /* #bytes added to alloc'd mem to align txd */
-+
-+      dmadd_t         *rxd;           /* pointer to chip-specific rx descriptor ring */
-+      uint            rxin;           /* index of next descriptor to reclaim */
-+      uint            rxout;          /* index of next descriptor to post */
-+      void            *rxp[MAXDD];    /* parallel array of pointers to packets */
-+      ulong           rxdpa;          /* physical address of descriptor ring */
-+      uint            rxdalign;       /* #bytes added to alloc'd mem to align rxd */
-+
-+      /* tunables */
-+      uint            ntxd;           /* # tx descriptors */
-+      uint            nrxd;           /* # rx descriptors */
-+      uint            rxbufsize;      /* rx buffer size in bytes */
-+      uint            nrxpost;        /* # rx buffers to keep posted */
-+      uint            rxoffset;       /* rxcontrol offset */
-+      uint            ddoffset;       /* add to get dma address of descriptor ring */
-+      uint            dataoffset;     /* add to get dma address of data buffer */
-+} dma_info_t;
-+
-+/* descriptor bumping macros */
-+#define       NEXTTXD(i)      ((i + 1) & (di->ntxd - 1))
-+#define       PREVTXD(i)      ((i - 1) & (di->ntxd - 1))
-+#define       NEXTRXD(i)      ((i + 1) & (di->nrxd - 1))
-+#define       NTXDACTIVE(h, t)        ((t - h) & (di->ntxd - 1))
-+#define       NRXDACTIVE(h, t)        ((t - h) & (di->nrxd - 1))
-+
-+/* macros to convert between byte offsets and indexes */
-+#define       B2I(bytes)      ((bytes) / sizeof (dmadd_t))
-+#define       I2B(index)      ((index) * sizeof (dmadd_t))
++#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;
++};
 +
-+void*
-+dma_attach(void *drv, void *dev, char *name, dmaregs_t *regs, uint ntxd, uint nrxd,
-+      uint rxbufsize, uint nrxpost, uint rxoffset, uint ddoffset, uint dataoffset, uint *msg_level)
++uint32
++osl_pci_read_config(osl_t *osh, uint offset, uint size)
 +{
-+      dma_info_t *di;
-+      void *va;
-+
-+      ASSERT(ntxd <= MAXDD);
-+      ASSERT(nrxd <= MAXDD);
-+
-+      /* allocate private info structure */
-+      if ((di = MALLOC(sizeof (dma_info_t))) == NULL)
-+              return (NULL);
-+      bzero((char*)di, sizeof (dma_info_t));
-+
-+      /* set message level */
-+      di->msg_level = msg_level ? msg_level : &dma_msg_level;
-+
-+      DMA_TRACE(("%s: dma_attach: drv 0x%x dev 0x%x regs 0x%x ntxd %d nrxd %d rxbufsize %d nrxpost %d rxoffset %d ddoffset 0x%x dataoffset 0x%x\n", name, (uint)drv, (uint)dev, (uint)regs, ntxd, nrxd, rxbufsize, nrxpost, rxoffset, ddoffset, dataoffset));
-+
-+      /* make a private copy of our callers name */
-+      strncpy(di->name, name, MAXNAMEL);
-+      di->name[MAXNAMEL-1] = '\0';
-+
-+      di->drv = drv;
-+      di->dev = dev;
-+      di->regs = regs;
-+
-+      /* allocate transmit descriptor ring */
-+      if (ntxd) {
-+              if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->txdpa)) == NULL)
-+                      goto fail;
-+              di->txd = (dmadd_t*) ROUNDUP(va, DMARINGALIGN);
-+              di->txdalign = ((uint)di->txd - (uint)va);
-+              di->txdpa = di->txdpa + di->txdalign;
-+              ASSERT(ISALIGNED(di->txd, DMARINGALIGN));
-+      }
-+
-+      /* allocate receive descriptor ring */
-+      if (nrxd) {
-+              if ((va = DMA_ALLOC_CONSISTENT(dev, (DMAMAXRINGSZ + DMARINGALIGN), &di->rxdpa)) == NULL)
-+                      goto fail;
-+              di->rxd = (dmadd_t*) ROUNDUP(va, DMARINGALIGN);
-+              di->rxdalign = ((uint)di->rxd - (uint)va);
-+              di->rxdpa = di->rxdpa + di->rxdalign;
-+              ASSERT(ISALIGNED(di->rxd, DMARINGALIGN));
-+      }
-+
-+      /* save tunables */
-+      di->ntxd = ntxd;
-+      di->nrxd = nrxd;
-+      di->rxbufsize = rxbufsize;
-+      di->nrxpost = nrxpost;
-+      di->rxoffset = rxoffset;
-+      di->ddoffset = ddoffset;
-+      di->dataoffset = dataoffset;
-+
-+      return ((void*)di);
-+
-+fail:
-+      dma_detach((void*)di);
-+      return (NULL);
-+}
++      uint val;
++      uint retry=PCI_CFG_RETRY;        
 +
-+/* may be called with core in reset */
-+void
-+dma_detach(dma_info_t *di)
-+{
-+      if (di == NULL)
-+              return;
++      ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
 +
-+      DMA_TRACE(("%s: dma_detach\n", di->name));
++      /* only 4byte access supported */
++      ASSERT(size == 4);
 +
-+      /* shouldn't be here if descriptors are unreclaimed */
-+      ASSERT(di->txin == di->txout);
-+      ASSERT(di->rxin == di->rxout);
++      do {
++              pci_read_config_dword(osh->pdev, offset, &val);
++              if (val != 0xffffffff)
++                      break;
++      } while (retry--);
 +
-+      /* free dma descriptor rings */
-+      if (di->txd)
-+              DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->txd - di->txdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->txdpa);
-+      if (di->rxd)
-+              DMA_FREE_CONSISTENT(di->dev, (void *)((uint)di->rxd - di->rxdalign), (DMAMAXRINGSZ + DMARINGALIGN), di->rxdpa);
 +
-+      /* free our private info structure */
-+      MFREE((void*)di, sizeof (dma_info_t));
++      return (val);
 +}
 +
-+
 +void
-+dma_txreset(dma_info_t *di)
++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
 +{
-+      uint32 status;
-+
-+      DMA_TRACE(("%s: dma_txreset\n", di->name));
++      uint retry=PCI_CFG_RETRY;        
 +
-+      /* suspend tx DMA first */
-+      W_REG(&di->regs->xmtcontrol, XC_SE);
-+      SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED &&
-+               status != XS_XS_IDLE &&
-+               status != XS_XS_STOPPED,
-+               10000);
++      ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
 +
-+      W_REG(&di->regs->xmtcontrol, 0);
-+      SPINWAIT((status = (R_REG(&di->regs->xmtstatus) & XS_XS_MASK)) != XS_XS_DISABLED,
-+               10000);
++      /* only 4byte access supported */
++      ASSERT(size == 4);
 +
-+      if (status != XS_XS_DISABLED) {
-+              DMA_ERROR(("%s: dma_txreset: dma cannot be stopped\n", di->name));
-+      }
++      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--);
 +
-+      /* wait for the last transaction to complete */
-+      OSL_DELAY(300);
 +}
 +
 +void
-+dma_rxreset(dma_info_t *di)
++osl_delay(uint usec)
 +{
-+      uint32 status;
-+
-+      DMA_TRACE(("%s: dma_rxreset\n", di->name));
-+
-+      W_REG(&di->regs->rcvcontrol, 0);
-+      SPINWAIT((status = (R_REG(&di->regs->rcvstatus) & RS_RS_MASK)) != RS_RS_DISABLED,
-+               10000);
++      uint d;
 +
-+      if (status != RS_RS_DISABLED) {
-+              DMA_ERROR(("%s: dma_rxreset: dma cannot be stopped\n", di->name));
++      while (usec > 0) {
++              d = MIN(usec, 1000);
++              udelay(d);
++              usec -= d;
 +      }
 +}
 +
-+void
-+dma_txinit(dma_info_t *di)
-+{
-+      DMA_TRACE(("%s: dma_txinit\n", di->name));
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/nvram.c linux.dev/arch/mips/bcm947xx/broadcom/nvram.c
+--- linux.old/arch/mips/bcm947xx/broadcom/nvram.c      1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/nvram.c      2005-12-15 17:36:23.151078000 +0100
+@@ -0,0 +1,145 @@
++/*
++ * NVRAM variable manipulation (Linux kernel half)
++ *
++ * 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$
++ */
 +
-+      di->txin = di->txout = 0;
-+      di->txavail = di->ntxd - 1;
-+
-+      /* clear tx descriptor ring */
-+      BZERO_SM((void*)di->txd, (di->ntxd * sizeof (dmadd_t)));
-+
-+      W_REG(&di->regs->xmtcontrol, XC_XE);
-+      W_REG(&di->regs->xmtaddr, (di->txdpa + di->ddoffset));
-+}
-+
-+bool
-+dma_txenabled(dma_info_t *di)
-+{
-+      uint32 xc;
-+
-+      /* If the chip is dead, it is not enabled :-) */
-+      xc = R_REG(&di->regs->xmtcontrol);
-+      return ((xc != 0xffffffff) && (xc & XC_XE));
-+}
-+
-+void
-+dma_txsuspend(dma_info_t *di)
-+{
-+      DMA_TRACE(("%s: dma_txsuspend\n", di->name));
-+      OR_REG(&di->regs->xmtcontrol, XC_SE);
-+}
-+
-+void
-+dma_txresume(dma_info_t *di)
-+{
-+      DMA_TRACE(("%s: dma_txresume\n", di->name));
-+      AND_REG(&di->regs->xmtcontrol, ~XC_SE);
-+}
-+
-+bool
-+dma_txsuspended(dma_info_t *di)
-+{
-+      uint32 xc;
-+      uint32 xs;
-+
-+      xc = R_REG(&di->regs->xmtcontrol);
-+      if (xc & XC_SE) {
-+              xs = R_REG(&di->regs->xmtstatus);
-+              return ((xs & XS_XS_MASK) == XS_XS_IDLE);
-+      }
-+      return 0;
-+}
-+
-+bool
-+dma_txstopped(dma_info_t *di)
-+{
-+      return ((R_REG(&di->regs->xmtstatus) & XS_XS_MASK) == XS_XS_STOPPED);
-+}
-+
-+bool
-+dma_rxstopped(dma_info_t *di)
-+{
-+      return ((R_REG(&di->regs->rcvstatus) & RS_RS_MASK) == RS_RS_STOPPED);
-+}
-+
-+void
-+dma_fifoloopbackenable(dma_info_t *di)
-+{
-+      DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
-+      OR_REG(&di->regs->xmtcontrol, XC_LE);
-+}
-+
-+void
-+dma_rxinit(dma_info_t *di)
-+{
-+      DMA_TRACE(("%s: dma_rxinit\n", di->name));
-+
-+      di->rxin = di->rxout = 0;
-+
-+      /* clear rx descriptor ring */
-+      BZERO_SM((void*)di->rxd, (di->nrxd * sizeof (dmadd_t)));
-+
-+      dma_rxenable(di);
-+      W_REG(&di->regs->rcvaddr, (di->rxdpa + di->ddoffset));
-+}
-+
-+void
-+dma_rxenable(dma_info_t *di)
-+{
-+      DMA_TRACE(("%s: dma_rxenable\n", di->name));
-+      W_REG(&di->regs->rcvcontrol, ((di->rxoffset << RC_RO_SHIFT) | RC_RE));
-+}
-+
-+bool
-+dma_rxenabled(dma_info_t *di)
-+{
-+      uint32 rc;
-+
-+      rc = R_REG(&di->regs->rcvcontrol);
-+      return ((rc != 0xffffffff) && (rc & RC_RE));
-+}
-+
-+/*
-+ * The BCM47XX family supports full 32bit dma engine buffer addressing so
-+ * dma buffers can cross 4 Kbyte page boundaries.
-+ */
-+int
-+dma_txfast(dma_info_t *di, void *p0, uint32 coreflags)
-+{
-+      void *p, *next;
-+      uchar *data;
-+      uint len;
-+      uint txout;
-+      uint32 ctrl;
-+      uint32 pa;
-+
-+      DMA_TRACE(("%s: dma_txfast\n", di->name));
-+
-+      txout = di->txout;
-+      ctrl = 0;
-+
-+      /*
-+       * Walk the chain of packet buffers
-+       * allocating and initializing transmit descriptor entries.
-+       */
-+      for (p = p0; p; p = next) {
-+              data = PKTDATA(di->drv, p);
-+              len = PKTLEN(di->drv, p);
-+              next = PKTNEXT(di->drv, 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->dev, data, len, DMA_TX, p);
-+
-+              /* build the descriptor control value */
-+              ctrl = len & CTRL_BC_MASK;
-+
-+              ctrl |= coreflags;
-+              
-+              if (p == p0)
-+                      ctrl |= CTRL_SOF;
-+              if (next == NULL)
-+                      ctrl |= (CTRL_IOC | CTRL_EOF);
-+              if (txout == (di->ntxd - 1))
-+                      ctrl |= CTRL_EOT;
-+
-+              /* init the tx descriptor */
-+              W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
-+              W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));
-+
-+              ASSERT(di->txp[txout] == NULL);
-+
-+              txout = NEXTTXD(txout);
-+      }
-+
-+      /* if last txd eof not set, fix it */
-+      if (!(ctrl & CTRL_EOF))
-+              W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
-+
-+      /* save the packet */
-+      di->txp[PREVTXD(txout)] = p0;
-+
-+      /* bump the tx descriptor index */
-+      di->txout = txout;
-+
-+      /* kick the chip */
-+      W_REG(&di->regs->xmtptr, I2B(txout));
-+
-+      /* 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->drv, p0, TRUE);
-+      di->txavail = 0;
-+      di->hnddma.txnobuf++;
-+      return (-1);
-+}
-+
-+#define       PAGESZ          4096
-+#define       PAGEBASE(x)     ((uint)(x) & ~4095)
-+
-+/*
-+ * Just like above except go through the extra effort of splitting
-+ * buffers that cross 4Kbyte boundaries into multiple tx descriptors.
-+ */
-+int
-+dma_tx(dma_info_t *di, void *p0, uint32 coreflags)
-+{
-+      void *p, *next;
-+      uchar *data;
-+      uint plen, len;
-+      uchar *page, *start, *end;
-+      uint txout;
-+      uint32 ctrl;
-+      uint32 pa;
-+
-+      DMA_TRACE(("%s: dma_tx\n", di->name));
-+
-+      txout = di->txout;
-+      ctrl = 0;
-+
-+      /*
-+       * Walk the chain of packet buffers
-+       * splitting those that cross 4 Kbyte boundaries
-+       * allocating and initializing transmit descriptor entries.
-+       */
-+      for (p = p0; p; p = next) {
-+              data = PKTDATA(di->drv, p);
-+              plen = PKTLEN(di->drv, p);
-+              next = PKTNEXT(di->drv, p);
-+
-+              if (plen == 0)
-+                      continue;
-+
-+              for (page = (uchar*)PAGEBASE(data);
-+                      page <= (uchar*)PAGEBASE(data + plen - 1);
-+                      page += PAGESZ) {
-+
-+                      /* return nonzero if out of tx descriptors */
-+                      if (NEXTTXD(txout) == di->txin)
-+                              goto outoftxd;
-+
-+                      start = (page == (uchar*)PAGEBASE(data))?  data: page;
-+                      end = (page == (uchar*)PAGEBASE(data + plen))?
-+                              (data + plen): (page + PAGESZ);
-+                      len = end - start;
-+
-+                      /* build the descriptor control value */
-+                      ctrl = len & CTRL_BC_MASK;
-+
-+                      ctrl |= coreflags;
-+
-+                      if ((p == p0) && (start == data))
-+                              ctrl |= CTRL_SOF;
-+                      if ((next == NULL) && (end == (data + plen)))
-+                              ctrl |= (CTRL_IOC | CTRL_EOF);
-+                      if (txout == (di->ntxd - 1))
-+                              ctrl |= CTRL_EOT;
-+
-+                      /* get physical address of buffer start */
-+                      pa = (uint32) DMA_MAP(di->dev, start, len, DMA_TX, p);
-+
-+                      /* init the tx descriptor */
-+                      W_SM(&di->txd[txout].ctrl, BUS_SWAP32(ctrl));
-+                      W_SM(&di->txd[txout].addr, BUS_SWAP32(pa + di->dataoffset));
-+
-+                      ASSERT(di->txp[txout] == NULL);
-+
-+                      txout = NEXTTXD(txout);
-+              }
-+      }
-+
-+      /* if last txd eof not set, fix it */
-+      if (!(ctrl & CTRL_EOF))
-+              W_SM(&di->txd[PREVTXD(txout)].ctrl, BUS_SWAP32(ctrl | CTRL_IOC | CTRL_EOF));
-+
-+      /* save the packet */
-+      di->txp[PREVTXD(txout)] = p0;
-+
-+      /* bump the tx descriptor index */
-+      di->txout = txout;
-+
-+      /* kick the chip */
-+      W_REG(&di->regs->xmtptr, I2B(txout));
-+
-+      /* tx flow control */
-+      di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+
-+      return (0);
-+
-+outoftxd:
-+      DMA_ERROR(("%s: dma_tx: out of txds\n", di->name));
-+      PKTFREE(di->drv, p0, TRUE);
-+      di->txavail = 0;
-+      di->hnddma.txnobuf++;
-+      return (-1);
-+}
-+
-+/* returns a pointer to the next frame received, or NULL if there are no more */
-+void*
-+dma_rx(dma_info_t *di)
-+{
-+      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->drv, p, FALSE);
-+                      continue;
-+              }
-+
-+              len = ltoh16(*(uint16*)(PKTDATA(di->drv, p)));
-+              DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
-+
-+              /* 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->drv, p, FALSE);
-+                      di->hnddma.rxgiants++;
-+                      continue;
-+              }
-+
-+              /* set actual length */
-+              PKTSETLEN(di->drv, p, (di->rxoffset + len));
-+
-+              break;
-+      }
-+
-+      return (p);
-+}
-+
-+/* post receive buffers */
-+void
-+dma_rxfill(dma_info_t *di)
-+{
-+      void *p;
-+      uint rxin, rxout;
-+      uint ctrl;
-+      uint n;
-+      uint i;
-+      uint32 pa;
-+      uint rxbufsize;
-+
-+      /*
-+       * Determine how many receive buffers we're lacking
-+       * from the full complement, allocate, initialize,
-+       * and post them, then update the chip rx lastdscr.
-+       */
-+
-+      rxin = di->rxin;
-+      rxout = di->rxout;
-+      rxbufsize = di->rxbufsize;
-+
-+      n = di->nrxpost - NRXDACTIVE(rxin, rxout);
-+
-+      DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
-+
-+      for (i = 0; i < n; i++) {
-+              if ((p = PKTGET(di->drv, rxbufsize, FALSE)) == NULL) {
-+                      DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", di->name));
-+                      di->hnddma.rxnobuf++;
-+                      break;
-+              }
-+
-+              *(uint32*)(OSL_UNCACHED(PKTDATA(di->drv, p))) = 0;
-+
-+              pa = (uint32) DMA_MAP(di->dev, PKTDATA(di->drv, p), rxbufsize, DMA_RX, p);
-+              ASSERT(ISALIGNED(pa, 4));
-+
-+              /* save the free packet pointer */
-+              ASSERT(di->rxp[rxout] == NULL);
-+              di->rxp[rxout] = p;
-+
-+              /* prep the descriptor control value */
-+              ctrl = rxbufsize;
-+              if (rxout == (di->nrxd - 1))
-+                      ctrl |= CTRL_EOT;
-+
-+              /* init the rx descriptor */
-+              W_SM(&di->rxd[rxout].ctrl, BUS_SWAP32(ctrl));
-+              W_SM(&di->rxd[rxout].addr, BUS_SWAP32(pa + di->dataoffset));
-+
-+              rxout = NEXTRXD(rxout);
-+      }
-+
-+      di->rxout = rxout;
-+
-+      /* update the chip lastdscr pointer */
-+      W_REG(&di->regs->rcvptr, I2B(rxout));
-+}
-+
-+void
-+dma_txreclaim(dma_info_t *di, bool forceall)
-+{
-+      void *p;
-+
-+      DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, forceall ? "all" : ""));
-+
-+      while ((p = dma_getnexttxp(di, forceall)))
-+              PKTFREE(di->drv, p, TRUE);
-+}
-+
-+/*
-+ * 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)
-+{
-+      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->regs->xmtstatus) & XS_CD_MASK);
-+
-+      if ((start == 0) && (end > di->txout))
-+              goto bogus;
-+
-+      for (i = start; i != end && !txp; i = NEXTTXD(i)) {
-+              DMA_UNMAP(di->dev, (BUS_SWAP32(R_SM(&di->txd[i].addr)) - di->dataoffset),
-+                        (BUS_SWAP32(R_SM(&di->txd[i].ctrl)) & CTRL_BC_MASK), DMA_TX, di->txp[i]);
-+              W_SM(&di->txd[i].addr, 0xdeadbeef);
-+              txp = di->txp[i];
-+              di->txp[i] = NULL;
-+      }
-+
-+      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);
-+}
-+
-+void
-+dma_rxreclaim(dma_info_t *di)
-+{
-+      void *p;
-+
-+      DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
-+
-+      while ((p = dma_getnextrxp(di, TRUE)))
-+              PKTFREE(di->drv, p, FALSE);
-+}
-+
-+void *
-+dma_getnextrxp(dma_info_t *di, bool forceall)
-+{
-+      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);
-+
-+      /* ignore curr if forceall */
-+      if (!forceall && (i == B2I(R_REG(&di->regs->rcvstatus) & RS_CD_MASK)))
-+              return (NULL);
-+
-+      /* get the packet pointer that corresponds to the rx descriptor */
-+      rxp = di->rxp[i];
-+      ASSERT(rxp);
-+      di->rxp[i] = NULL;
-+
-+      /* clear this packet from the descriptor ring */
-+      DMA_UNMAP(di->dev, (BUS_SWAP32(R_SM(&di->rxd[i].addr)) - di->dataoffset),
-+                di->rxbufsize, DMA_RX, rxp);
-+      W_SM(&di->rxd[i].addr, 0xdeadbeef);
-+
-+      di->rxin = NEXTRXD(i);
-+
-+      return (rxp);
-+}
-+
-+char*
-+dma_dumptx(dma_info_t *di, char *buf)
-+{
-+      buf += sprintf(buf, "txd 0x%lx txdpa 0x%lx txp 0x%lx txin %d txout %d txavail %d\n",
-+              (ulong)di->txd, di->txdpa, (ulong)di->txp, di->txin, di->txout, di->txavail);
-+      buf += sprintf(buf, "xmtcontrol 0x%x xmtaddr 0x%x xmtptr 0x%x xmtstatus 0x%x\n",
-+              R_REG(&di->regs->xmtcontrol),
-+              R_REG(&di->regs->xmtaddr),
-+              R_REG(&di->regs->xmtptr),
-+              R_REG(&di->regs->xmtstatus));
-+      return (buf);
-+}
-+
-+char*
-+dma_dumprx(dma_info_t *di, char *buf)
-+{
-+      buf += sprintf(buf, "rxd 0x%lx rxdpa 0x%lx rxp 0x%lx rxin %d rxout %d\n",
-+              (ulong)di->rxd, di->rxdpa, (ulong)di->rxp, di->rxin, di->rxout);
-+      buf += sprintf(buf, "rcvcontrol 0x%x rcvaddr 0x%x rcvptr 0x%x rcvstatus 0x%x\n",
-+              R_REG(&di->regs->rcvcontrol),
-+              R_REG(&di->regs->rcvaddr),
-+              R_REG(&di->regs->rcvptr),
-+              R_REG(&di->regs->rcvstatus));
-+      return (buf);
-+}
-+
-+char*
-+dma_dump(dma_info_t *di, char *buf)
-+{
-+      buf = dma_dumptx(di, buf);
-+      buf = dma_dumprx(di, buf);
-+      return (buf);
-+}
-+
-+uint
-+dma_getvar(dma_info_t *di, char *name)
-+{
-+      if (!strcmp(name, "&txavail"))
-+              return ((uint) &di->txavail);
-+      else {
-+              ASSERT(0);
-+      }
-+      return (0);
-+}
-+
-+void
-+dma_txblock(dma_info_t *di)
-+{
-+      di->txavail = 0;
-+}
-+
-+void
-+dma_txunblock(dma_info_t *di)
-+{
-+      di->txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-+}
-+
-+uint
-+dma_txactive(dma_info_t *di)
-+{
-+      return (NTXDACTIVE(di->txin, di->txout));
-+}
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/linux_osl.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/linux_osl.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/linux_osl.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/linux_osl.c   2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,420 @@
-+/*
-+ * Linux OS Independent Layer
-+ *
-+ * Copyright 2001-2003, Broadcom Corporation
-+ * All Rights Reserved.
-+ * 
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id: linux_osl.c,v 1.2 2005/02/28 13:34:25 jolt Exp $
-+ */
-+
-+#define LINUX_OSL
-+
-+#include <typedefs.h>
-+#include <bcmendian.h>
-+#include <linuxver.h>
-+#include <linux_osl.h>
-+#include <bcmutils.h>
-+#include <linux/delay.h>
-+#ifdef mips
-+#include <asm/paccess.h>
-+#endif
-+#include <pcicfg.h>
-+
-+#define PCI_CFG_RETRY 10      
-+
-+void*
-+osl_pktget(void *drv, 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(void *loc, uint offset, uint size)
-+{
-+      struct pci_dev *pdev;
-+      uint val;
-+      uint retry=PCI_CFG_RETRY;        
-+
-+      /* only 4byte access supported */
-+      ASSERT(size == 4);
-+
-+      pdev = (struct pci_dev*)loc;
-+      do {
-+              pci_read_config_dword(pdev, offset, &val);
-+              if (val != 0xffffffff)
-+                      break;
-+      } while (retry--);
-+
-+
-+      return (val);
-+}
-+
-+void
-+osl_pci_write_config(void *loc, uint offset, uint size, uint val)
-+{
-+      struct pci_dev *pdev;
-+      uint retry=PCI_CFG_RETRY;        
-+
-+      /* only 4byte access supported */
-+      ASSERT(size == 4);
-+
-+      pdev = (struct pci_dev*)loc;
-+
-+      do {
-+              pci_write_config_dword(pdev, offset, val);
-+              if (offset!=PCI_BAR0_WIN)
-+                      break;
-+              if (osl_pci_read_config(loc,offset,size) == val) 
-+                      break;
-+      } while (retry--);
-+
-+}
-+
-+void
-+osl_pcmcia_read_attr(void *osh, uint offset, void *buf, int size)
-+{
-+      ASSERT(0);
-+}
-+
-+void
-+osl_pcmcia_write_attr(void *osh, uint offset, void *buf, int size)
-+{
-+      ASSERT(0);
-+}
-+
-+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);
-+}
-+
-+/*
-+ * 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(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);
-+}
-+
-+void*
-+osl_malloc(uint size)
-+{
-+      return (kmalloc(size, GFP_ATOMIC));
-+}
-+
-+void
-+osl_mfree(void *addr, uint size)
-+{
-+      kfree(addr);
-+}
-+
-+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
-+}
-+
-+void*
-+osl_dma_alloc_consistent(void *dev, uint size, ulong *pap)
-+{
-+      return (pci_alloc_consistent((struct pci_dev*)dev, size, (dma_addr_t*)pap));
-+}
-+
-+void
-+osl_dma_free_consistent(void *dev, void *va, uint size, ulong pa)
-+{
-+      pci_free_consistent((struct pci_dev*)dev, size, va, (dma_addr_t)pa);
-+}
-+
-+uint
-+osl_dma_map(void *dev, void *va, uint size, int direction)
-+{
-+      int dir;
-+
-+      dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
-+      return (pci_map_single(dev, va, size, dir));
-+}
-+
-+void
-+osl_dma_unmap(void *dev, uint pa, uint size, int direction)
-+{
-+      int dir;
-+
-+      dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
-+      pci_unmap_single(dev, (uint32)pa, size, dir);
-+}
-+
-+void
-+osl_delay(uint usec)
-+{
-+      udelay(usec);
-+}
-+
-+uchar*
-+osl_pktdata(void *drv, void *skb)
-+{
-+      return (((struct sk_buff*)skb)->data);
-+}
-+
-+uint
-+osl_pktlen(void *drv, void *skb)
-+{
-+      return (((struct sk_buff*)skb)->len);
-+}
-+
-+void*
-+osl_pktnext(void *drv, 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(void *drv, void *skb, uint len)
-+{
-+      __skb_trim((struct sk_buff*)skb, len);
-+}
-+
-+uchar*
-+osl_pktpush(void *drv, void *skb, int bytes)
-+{
-+      return (skb_push((struct sk_buff*)skb, bytes));
-+}
-+
-+uchar*
-+osl_pktpull(void *drv, void *skb, int bytes)
-+{
-+      return (skb_pull((struct sk_buff*)skb, bytes));
-+}
-+
-+void*
-+osl_pktdup(void *drv, 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;
-+}
-+
-+#endif
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/Makefile linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/Makefile
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/Makefile      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/Makefile      2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,7 @@
-+#
-+# Makefile for the BCM47xx specific kernel interface routines
-+# under Linux.
-+#
-+
-+obj-y   := sbutils.o linux_osl.o bcmsrom.o bcmutils.o sbmips.o sbpci.o hnddma.o
-+#obj-y   := nvram.o nvram_linux.o
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/nvram.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/nvram.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/nvram.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/nvram.c       2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,321 @@
-+/*
-+ * NVRAM variable manipulation (common)
-+ *
-+ * 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$
-+ */
-+
-+#include <typedefs.h>
-+#include <osl.h>
-+#include <bcmendian.h>
-+#include <bcmnvram.h>
-+#include <bcmutils.h>
-+#include <sbsdram.h>
-+
-+extern struct nvram_tuple * BCMINIT(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value);
-+extern void BCMINIT(_nvram_free)(struct nvram_tuple *t);
-+extern int BCMINIT(_nvram_read)(void *buf);
-+
-+char * BCMINIT(_nvram_get)(const char *name);
-+int BCMINIT(_nvram_set)(const char *name, const char *value);
-+int BCMINIT(_nvram_unset)(const char *name);
-+int BCMINIT(_nvram_getall)(char *buf, int count);
-+int BCMINIT(_nvram_commit)(struct nvram_header *header);
-+int BCMINIT(_nvram_init)(void);
-+void BCMINIT(_nvram_exit)(void);
-+
-+static struct nvram_tuple * BCMINITDATA(nvram_hash)[257];
-+static struct nvram_tuple * nvram_dead;
-+
-+/* Free all tuples. Should be locked. */
-+static void  
-+BCMINITFN(nvram_free)(void)
-+{
-+      uint i;
-+      struct nvram_tuple *t, *next;
-+
-+      /* Free hash table */
-+      for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
-+              for (t = BCMINIT(nvram_hash)[i]; t; t = next) {
-+                      next = t->next;
-+                      BCMINIT(_nvram_free)(t);
-+              }
-+              BCMINIT(nvram_hash)[i] = NULL;
-+      }
-+
-+      /* Free dead table */
-+      for (t = nvram_dead; t; t = next) {
-+              next = t->next;
-+              BCMINIT(_nvram_free)(t);
-+      }
-+      nvram_dead = NULL;
-+
-+      /* Indicate to per-port code that all tuples have been freed */
-+      BCMINIT(_nvram_free)(NULL);
-+}
-+
-+/* String hash */
-+static INLINE uint
-+hash(const char *s)
-+{
-+      uint hash = 0;
-+
-+      while (*s)
-+              hash = 31 * hash + *s++;
-+
-+      return hash;
-+}
-+
-+/* (Re)initialize the hash table. Should be locked. */
-+static int 
-+BCMINITFN(nvram_rehash)(struct nvram_header *header)
-+{
-+      char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
-+
-+      /* (Re)initialize hash table */
-+      BCMINIT(nvram_free)();
-+
-+      /* Parse and set "name=value\0 ... \0\0" */
-+      name = (char *) &header[1];
-+      end = (char *) header + NVRAM_SPACE - 2;
-+      end[0] = end[1] = '\0';
-+      for (; *name; name = value + strlen(value) + 1) {
-+              if (!(eq = strchr(name, '=')))
-+                      break;
-+              *eq = '\0';
-+              value = eq + 1;
-+              BCMINIT(_nvram_set)(name, value);
-+              *eq = '=';
-+      }
-+
-+      /* Set special SDRAM parameters */
-+      if (!BCMINIT(_nvram_get)("sdram_init")) {
-+              sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
-+              BCMINIT(_nvram_set)("sdram_init", buf);
-+      }
-+      if (!BCMINIT(_nvram_get)("sdram_config")) {
-+              sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
-+              BCMINIT(_nvram_set)("sdram_config", buf);
-+      }
-+      if (!BCMINIT(_nvram_get)("sdram_refresh")) {
-+              sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
-+              BCMINIT(_nvram_set)("sdram_refresh", buf);
-+      }
-+      if (!BCMINIT(_nvram_get)("sdram_ncdl")) {
-+              sprintf(buf, "0x%08X", header->config_ncdl);
-+              BCMINIT(_nvram_set)("sdram_ncdl", buf);
-+      }
-+
-+      return 0;
-+}
-+
-+/* Get the value of an NVRAM variable. Should be locked. */
-+char * 
-+BCMINITFN(_nvram_get)(const char *name)
-+{
-+      uint i;
-+      struct nvram_tuple *t;
-+      char *value;
-+
-+      if (!name)
-+              return NULL;
-+
-+      /* Hash the name */
-+      i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
-+
-+      /* Find the associated tuple in the hash table */
-+      for (t = BCMINIT(nvram_hash)[i]; t && strcmp(t->name, name); t = t->next);
-+
-+      value = t ? t->value : NULL;
-+
-+      return value;
-+}
-+
-+/* Get the value of an NVRAM variable. Should be locked. */
-+int 
-+BCMINITFN(_nvram_set)(const char *name, const char *value)
-+{
-+      uint i;
-+      struct nvram_tuple *t, *u, **prev;
-+
-+      /* Hash the name */
-+      i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
-+
-+      /* Find the associated tuple in the hash table */
-+      for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
-+
-+      /* (Re)allocate tuple */
-+      if (!(u = BCMINIT(_nvram_realloc)(t, name, value)))
-+              return -12; /* -ENOMEM */
-+
-+      /* Value reallocated */
-+      if (t && t == u)
-+              return 0;
-+
-+      /* Move old tuple to the dead table */
-+      if (t) {
-+              *prev = t->next;
-+              t->next = nvram_dead;
-+              nvram_dead = t;
-+      }
-+
-+      /* Add new tuple to the hash table */
-+      u->next = BCMINIT(nvram_hash)[i];
-+      BCMINIT(nvram_hash)[i] = u;
-+
-+      return 0;
-+}
-+
-+/* Unset the value of an NVRAM variable. Should be locked. */
-+int 
-+BCMINITFN(_nvram_unset)(const char *name)
-+{
-+      uint i;
-+      struct nvram_tuple *t, **prev;
-+
-+      if (!name)
-+              return 0;
-+
-+      /* Hash the name */
-+      i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
-+
-+      /* Find the associated tuple in the hash table */
-+      for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
-+
-+      /* Move it to the dead table */
-+      if (t) {
-+              *prev = t->next;
-+              t->next = nvram_dead;
-+              nvram_dead = t;
-+      }
-+
-+      return 0;
-+}
-+
-+/* Get all NVRAM variables. Should be locked. */
-+int 
-+BCMINITFN(_nvram_getall)(char *buf, int count)
-+{
-+      uint i;
-+      struct nvram_tuple *t;
-+      int len = 0;
-+
-+      bzero(buf, count);
-+
-+      /* Write name=value\0 ... \0\0 */
-+      for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
-+              for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
-+                      if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
-+                              len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
-+                      else
-+                              break;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/* Regenerate NVRAM. Should be locked. */
-+int
-+BCMINITFN(_nvram_commit)(struct nvram_header *header)
-+{
-+      char *init, *config, *refresh, *ncdl;
-+      char *ptr, *end;
-+      int i;
-+      struct nvram_tuple *t;
-+      struct nvram_header tmp;
-+      uint8 crc;
-+
-+      /* Regenerate header */
-+      header->magic = NVRAM_MAGIC;
-+      header->crc_ver_init = (NVRAM_VERSION << 8);
-+      if (!(init = BCMINIT(_nvram_get)("sdram_init")) ||
-+          !(config = BCMINIT(_nvram_get)("sdram_config")) ||
-+          !(refresh = BCMINIT(_nvram_get)("sdram_refresh")) ||
-+          !(ncdl = BCMINIT(_nvram_get)("sdram_ncdl"))) {
-+              header->crc_ver_init |= SDRAM_INIT << 16;
-+              header->config_refresh = SDRAM_CONFIG;
-+              header->config_refresh |= SDRAM_REFRESH << 16;
-+              header->config_ncdl = 0;
-+      } else {
-+              header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
-+              header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
-+              header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
-+              header->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
-+      }
-+
-+      /* Clear data area */
-+      ptr = (char *) header + sizeof(struct nvram_header);
-+      bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
-+
-+      /* Leave space for a double NUL at the end */
-+      end = (char *) header + NVRAM_SPACE - 2;
-+
-+      /* Write out all tuples */
-+      for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
-+              for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
-+                      if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
-+                              break;
-+                      ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
-+              }
-+      }
-+
-+      /* End with a double NUL */
-+      ptr += 2;
-+
-+      /* Set new length */
-+      header->len = ROUNDUP(ptr - (char *) header, 4);
-+
-+      /* Little-endian CRC8 over the last 11 bytes of the header */
-+      tmp.crc_ver_init = htol32(header->crc_ver_init);
-+      tmp.config_refresh = htol32(header->config_refresh);
-+      tmp.config_ncdl = htol32(header->config_ncdl);
-+      crc = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
-+
-+      /* Continue CRC8 over data bytes */
-+      crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
-+
-+      /* Set new CRC8 */
-+      header->crc_ver_init |= crc;
-+
-+      /* Reinitialize hash table */
-+      return BCMINIT(nvram_rehash)(header);
-+}
-+
-+/* Initialize hash table. Should be locked. */
-+int 
-+BCMINITFN(_nvram_init)(void)
-+{
-+      struct nvram_header *header;
-+      int ret;
-+      void *osh;
-+
-+      /* get kernel osl handler */
-+      osh = osl_attach(NULL);
-+
-+      if (!(header = (struct nvram_header *) MALLOC(osh, NVRAM_SPACE))) {
-+              printf("nvram_init: out of memory, malloced %d bytes\n", MALLOCED(osh));
-+              return -12; /* -ENOMEM */
-+      }
-+
-+      if ((ret = BCMINIT(_nvram_read)(header)) == 0 &&
-+          header->magic == NVRAM_MAGIC)
-+              BCMINIT(nvram_rehash)(header);
-+
-+      MFREE(osh, header, NVRAM_SPACE);
-+      return ret;
-+}
-+
-+/* Free hash table. Should be locked. */
-+void 
-+BCMINITFN(_nvram_exit)(void)
-+{
-+      BCMINIT(nvram_free)();
-+}
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/nvram_linux.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/nvram_linux.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/nvram_linux.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/nvram_linux.c 2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,633 @@
-+/*
-+ * NVRAM variable manipulation (Linux kernel half)
-+ *
-+ * 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 <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/interrupt.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+#include <linux/bootmem.h>
-+#include <linux/wrapper.h>
-+#include <linux/fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/mtd/mtd.h>
-+#include <asm/addrspace.h>
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+
-+#include <typedefs.h>
-+#include <bcmendian.h>
-+#include <bcmnvram.h>
-+#include <bcmutils.h>
-+#include <sbconfig.h>
-+#include <sbchipc.h>
-+#include <sbutils.h>
-+#include <sbmips.h>
-+#include <sflash.h>
-+
-+/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
-+static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
-+
-+#ifdef MODULE
-+
-+#define early_nvram_get(name) nvram_get(name)
-+
-+#else /* !MODULE */
-+
-+/* Global SB handle */
-+extern void *bcm947xx_sbh;
-+extern spinlock_t bcm947xx_sbh_lock;
-+
-+/* Convenience */
-+#define sbh bcm947xx_sbh
-+#define sbh_lock bcm947xx_sbh_lock
-+#define KB * 1024
-+#define MB * 1024 * 1024
-+
-+/* Probe for NVRAM header */
-+static void __init
-+early_nvram_init(void)
-+{
-+      struct nvram_header *header;
-+      chipcregs_t *cc;
-+      struct sflash *info = NULL;
-+      int i;
-+      uint32 base, off, lim;
-+      u32 *src, *dst;
-+
-+      if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
-+              base = KSEG1ADDR(SB_FLASH2);
-+              switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
-+              case PFLASH:
-+                      lim = SB_FLASH2_SZ;
-+                      break;
-+
-+              case SFLASH_ST:
-+              case SFLASH_AT:
-+                      if ((info = sflash_init(cc)) == NULL)
-+                              return;
-+                      lim = info->size;
-+                      break;
-+
-+              case FLASH_NONE:
-+              default:
-+                      return;
-+              }
-+      } else {
-+              /* extif assumed, Stop at 4 MB */
-+              base = KSEG1ADDR(SB_FLASH1);
-+              lim = SB_FLASH1_SZ;
-+      }
-+
-+      off = FLASH_MIN;
-+      while (off <= lim) {
-+              /* Windowed flash access */
-+              header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
-+              if (header->magic == NVRAM_MAGIC)
-+                      goto found;
-+              off <<= 1;
-+      }
-+
-+      /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
-+      header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
-+      if (header->magic == NVRAM_MAGIC)
-+              goto found;
-+      
-+      header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
-+      if (header->magic == NVRAM_MAGIC)
-+              goto found;
-+      
-+      printk("early_nvram_init: NVRAM not found\n");
-+      return;
-+
-+found:
-+      src = (u32 *) header;
-+      dst = (u32 *) nvram_buf;
-+      for (i = 0; i < sizeof(struct nvram_header); i += 4)
-+              *dst++ = *src++;
-+      for (; i < header->len && i < NVRAM_SPACE; i += 4)
-+              *dst++ = ltoh32(*src++);
-+}
-+
-+/* Early (before mm or mtd) read-only access to NVRAM */
-+static char * __init
-+early_nvram_get(const char *name)
-+{
-+      char *var, *value, *end, *eq;
-+
-+      if (!name)
-+              return NULL;
-+
-+      /* Too early? */
-+      if (sbh == NULL)
-+              return NULL;
-+
-+      if (!nvram_buf[0])
-+              early_nvram_init();
-+
-+      /* Look for name=value and return value */
-+      var = &nvram_buf[sizeof(struct nvram_header)];
-+      end = nvram_buf + sizeof(nvram_buf) - 2;
-+      end[0] = end[1] = '\0';
-+      for (; *var; var = value + strlen(value) + 1) {
-+              if (!(eq = strchr(var, '=')))
-+                      break;
-+              value = eq + 1;
-+              if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
-+                      return value;
-+      }
-+
-+      return NULL;
-+}
-+
-+#endif /* !MODULE */
-+
-+extern char * _nvram_get(const char *name);
-+extern int _nvram_set(const char *name, const char *value);
-+extern int _nvram_unset(const char *name);
-+extern int _nvram_getall(char *buf, int count);
-+extern int _nvram_commit(struct nvram_header *header);
-+extern int _nvram_init(void);
-+extern void _nvram_exit(void);
-+
-+/* Globals */
-+static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
-+static struct semaphore nvram_sem;
-+static unsigned long nvram_offset = 0;
-+static int nvram_major = -1;
-+static devfs_handle_t nvram_handle = NULL;
-+static struct mtd_info *nvram_mtd = NULL;
-+
-+int
-+_nvram_read(char *buf)
-+{
-+      struct nvram_header *header = (struct nvram_header *) buf;
-+      size_t len;
-+
-+      if (!nvram_mtd ||
-+          MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
-+          len != NVRAM_SPACE ||
-+          header->magic != NVRAM_MAGIC) {
-+              /* Maybe we can recover some data from early initialization */
-+              memcpy(buf, nvram_buf, NVRAM_SPACE);
-+      }
-+
-+      return 0;
-+}
-+
-+struct nvram_tuple *
-+_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
-+{
-+      if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
-+              return NULL;
-+
-+      if (!t) {
-+              if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
-+                      return NULL;
-+
-+              /* Copy name */
-+              t->name = (char *) &t[1];
-+              strcpy(t->name, name);
-+
-+              t->value = NULL;
-+      }
-+
-+      /* Copy value */
-+      if (!t->value || strcmp(t->value, value)) {
-+              t->value = &nvram_buf[nvram_offset];
-+              strcpy(t->value, value);
-+              nvram_offset += strlen(value) + 1;
-+      }
-+
-+      return t;
-+}
-+
-+void
-+_nvram_free(struct nvram_tuple *t)
-+{
-+      if (!t)
-+              nvram_offset = 0;
-+      else
-+              kfree(t);
-+}
-+
-+int
-+nvram_set(const char *name, const char *value)
-+{
-+      unsigned long flags;
-+      int ret;
-+      struct nvram_header *header;
-+
-+      spin_lock_irqsave(&nvram_lock, flags);
-+      if ((ret = _nvram_set(name, value))) {
-+              /* Consolidate space and try again */
-+              if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
-+                      if (_nvram_commit(header) == 0)
-+                              ret = _nvram_set(name, value);
-+                      kfree(header);
-+              }
-+      }
-+      spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+      return ret;
-+}
-+
-+char *
-+real_nvram_get(const char *name)
-+{
-+      unsigned long flags;
-+      char *value;
-+
-+      spin_lock_irqsave(&nvram_lock, flags);
-+      value = _nvram_get(name);
-+      spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+      return value;
-+}
-+
-+char *
-+nvram_get(const char *name)
-+{
-+      if (nvram_major >= 0)
-+              return real_nvram_get(name);
-+      else
-+              return early_nvram_get(name);
-+}
-+
-+int
-+nvram_unset(const char *name)
-+{
-+      unsigned long flags;
-+      int ret;
-+
-+      spin_lock_irqsave(&nvram_lock, flags);
-+      ret = _nvram_unset(name);
-+      spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+      return ret;
-+}
-+
-+static void
-+erase_callback(struct erase_info *done)
-+{
-+      wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
-+      wake_up(wait_q);
-+}
-+
-+int
-+nvram_commit(void)
-+{
-+      char *buf;
-+      size_t erasesize, len;
-+      unsigned int i;
-+      int ret;
-+      struct nvram_header *header;
-+      unsigned long flags;
-+      u_int32_t offset;
-+      DECLARE_WAITQUEUE(wait, current);
-+      wait_queue_head_t wait_q;
-+      struct erase_info erase;
-+
-+      if (!nvram_mtd) {
-+              printk("nvram_commit: NVRAM not found\n");
-+              return -ENODEV;
-+      }
-+
-+      if (in_interrupt()) {
-+              printk("nvram_commit: not committing in interrupt\n");
-+              return -EINVAL;
-+      }
-+
-+      /* Backup sector blocks to be erased */
-+      erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
-+      if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
-+              printk("nvram_commit: out of memory\n");
-+              return -ENOMEM;
-+      }
-+
-+      down(&nvram_sem);
-+
-+      if ((i = erasesize - NVRAM_SPACE) > 0) {
-+              offset = nvram_mtd->size - erasesize;
-+              len = 0;
-+              ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
-+              if (ret || len != i) {
-+                      printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
-+                      ret = -EIO;
-+                      goto done;
-+              }
-+              header = (struct nvram_header *)(buf + i);
-+      } else {
-+              offset = nvram_mtd->size - NVRAM_SPACE;
-+              header = (struct nvram_header *)buf;
-+      }
-+
-+      /* Regenerate NVRAM */
-+      spin_lock_irqsave(&nvram_lock, flags);
-+      ret = _nvram_commit(header);
-+      spin_unlock_irqrestore(&nvram_lock, flags);
-+      if (ret)
-+              goto done;
-+
-+      /* Erase sector blocks */
-+      init_waitqueue_head(&wait_q);
-+      for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) {
-+              erase.mtd = nvram_mtd;
-+              erase.addr = offset;
-+              erase.len = nvram_mtd->erasesize;
-+              erase.callback = erase_callback;
-+              erase.priv = (u_long) &wait_q;
-+
-+              set_current_state(TASK_INTERRUPTIBLE);
-+              add_wait_queue(&wait_q, &wait);
-+
-+              /* Unlock sector blocks */
-+              if (nvram_mtd->unlock)
-+                      nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
-+
-+              if ((ret = MTD_ERASE(nvram_mtd, &erase))) {
-+                      set_current_state(TASK_RUNNING);
-+                      remove_wait_queue(&wait_q, &wait);
-+                      printk("nvram_commit: erase error\n");
-+                      goto done;
-+              }
-+
-+              /* Wait for erase to finish */
-+              schedule();
-+              remove_wait_queue(&wait_q, &wait);
-+      }
-+
-+      /* Write partition up to end of data area */
-+      offset = nvram_mtd->size - erasesize;
-+      i = erasesize - NVRAM_SPACE + header->len;
-+      ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf);
-+      if (ret || len != i) {
-+              printk("nvram_commit: write error\n");
-+              ret = -EIO;
-+              goto done;
-+      }
-+
-+      offset = nvram_mtd->size - erasesize;
-+      ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
-+
-+ done:
-+      up(&nvram_sem);
-+      kfree(buf);
-+      return ret;
-+}
-+
-+int
-+nvram_getall(char *buf, int count)
-+{
-+      unsigned long flags;
-+      int ret;
-+
-+      spin_lock_irqsave(&nvram_lock, flags);
-+      ret = _nvram_getall(buf, count);
-+      spin_unlock_irqrestore(&nvram_lock, flags);
-+
-+      return ret;
-+}
-+
-+EXPORT_SYMBOL(nvram_get);
-+EXPORT_SYMBOL(nvram_getall);
-+EXPORT_SYMBOL(nvram_set);
-+EXPORT_SYMBOL(nvram_unset);
-+EXPORT_SYMBOL(nvram_commit);
-+
-+/* User mode interface below */
-+
-+static ssize_t
-+dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-+{
-+      char tmp[100], *name = tmp, *value;
-+      ssize_t ret;
-+      unsigned long off;
-+
-+      if (count > sizeof(tmp)) {
-+              if (!(name = kmalloc(count, GFP_KERNEL)))
-+                      return -ENOMEM;
-+      }
-+
-+      if (copy_from_user(name, buf, count)) {
-+              ret = -EFAULT;
-+              goto done;
-+      }
-+
-+      if (*name == '\0') {
-+              /* Get all variables */
-+              ret = nvram_getall(name, count);
-+              if (ret == 0) {
-+                      if (copy_to_user(buf, name, count)) {
-+                              ret = -EFAULT;
-+                              goto done;
-+                      }
-+                      ret = count;
-+              }
-+      } else {
-+              if (!(value = nvram_get(name))) {
-+                      ret = 0;
-+                      goto done;
-+              }
-+
-+              /* Provide the offset into mmap() space */
-+              off = (unsigned long) value - (unsigned long) nvram_buf;
-+
-+              if (put_user(off, (unsigned long *) buf)) {
-+                      ret = -EFAULT;
-+                      goto done;
-+              }
-+
-+              ret = sizeof(unsigned long);
-+      }
-+
-+      flush_cache_all();      
-+ 
-+done:
-+      if (name != tmp)
-+              kfree(name);
-+
-+      return ret;
-+}
-+
-+static ssize_t
-+dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-+{
-+      char tmp[100], *name = tmp, *value;
-+      ssize_t ret;
-+
-+      if (count > sizeof(tmp)) {
-+              if (!(name = kmalloc(count, GFP_KERNEL)))
-+                      return -ENOMEM;
-+      }
-+
-+      if (copy_from_user(name, buf, count)) {
-+              ret = -EFAULT;
-+              goto done;
-+      }
-+
-+      value = name;
-+      name = strsep(&value, "=");
-+      if (value)
-+              ret = nvram_set(name, value) ? : count;
-+      else
-+              ret = nvram_unset(name) ? : count;
-+
-+ done:
-+      if (name != tmp)
-+              kfree(name);
-+
-+      return ret;
-+}     
-+
-+static int
-+dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+      if (cmd != NVRAM_MAGIC)
-+              return -EINVAL;
-+      return nvram_commit();
-+}
-+
-+static int
-+dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
-+{
-+      unsigned long offset = virt_to_phys(nvram_buf);
-+
-+      if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
-+                           vma->vm_page_prot))
-+              return -EAGAIN;
-+
-+      return 0;
-+}
-+
-+static int
-+dev_nvram_open(struct inode *inode, struct file * file)
-+{
-+      MOD_INC_USE_COUNT;
-+      return 0;
-+}
-+
-+static int
-+dev_nvram_release(struct inode *inode, struct file * file)
-+{
-+      MOD_DEC_USE_COUNT;
-+      return 0;
-+}
-+
-+static struct file_operations dev_nvram_fops = {
-+      owner:          THIS_MODULE,
-+      open:           dev_nvram_open,
-+      release:        dev_nvram_release,
-+      read:           dev_nvram_read,
-+      write:          dev_nvram_write,
-+      ioctl:          dev_nvram_ioctl,
-+      mmap:           dev_nvram_mmap,
-+};
-+
-+static void
-+dev_nvram_exit(void)
-+{
-+      int order = 0;
-+      struct page *page, *end;
-+
-+      if (nvram_handle)
-+              devfs_unregister(nvram_handle);
-+
-+      if (nvram_major >= 0)
-+              devfs_unregister_chrdev(nvram_major, "nvram");
-+
-+      if (nvram_mtd)
-+              put_mtd_device(nvram_mtd);
-+
-+      while ((PAGE_SIZE << order) < NVRAM_SPACE)
-+              order++;
-+      end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
-+      for (page = virt_to_page(nvram_buf); page <= end; page++)
-+              mem_map_unreserve(page);
-+
-+      _nvram_exit();
-+}
-+
-+static int __init
-+dev_nvram_init(void)
-+{
-+      int order = 0, ret = 0;
-+      struct page *page, *end;
-+      unsigned int i;
-+
-+      /* Allocate and reserve memory to mmap() */
-+      while ((PAGE_SIZE << order) < NVRAM_SPACE)
-+              order++;
-+      end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
-+      for (page = virt_to_page(nvram_buf); page <= end; page++)
-+              mem_map_reserve(page);
-+
-+#ifdef CONFIG_MTD
-+      /* Find associated MTD device */
-+      for (i = 0; i < MAX_MTD_DEVICES; i++) {
-+              nvram_mtd = get_mtd_device(NULL, i);
-+              if (nvram_mtd) {
-+                      if (!strcmp(nvram_mtd->name, "nvram") &&
-+                          nvram_mtd->size >= NVRAM_SPACE)
-+                              break;
-+                      put_mtd_device(nvram_mtd);
-+              }
-+      }
-+      if (i >= MAX_MTD_DEVICES)
-+              nvram_mtd = NULL;
-+#endif
-+
-+      /* Initialize hash table lock */
-+      spin_lock_init(&nvram_lock);
-+
-+      /* Initialize commit semaphore */
-+      init_MUTEX(&nvram_sem);
-+
-+      /* Register char device */
-+      if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
-+              ret = nvram_major;
-+              goto err;
-+      }
-+
-+      /* Initialize hash table */
-+      _nvram_init();
-+
-+      /* Create /dev/nvram handle */
-+      nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0,
-+                                    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL);
-+
-+      /* Set the SDRAM NCDL value into NVRAM if not already done */
-+      if (getintvar(NULL, "sdram_ncdl") == 0) {
-+              unsigned int ncdl;
-+              char buf[] = "0x00000000";
-+
-+              if ((ncdl = sb_memc_get_ncdl(sbh))) {
-+                      sprintf(buf, "0x%08x", ncdl);
-+                      nvram_set("sdram_ncdl", buf);
-+                      nvram_commit();
-+              }
-+      }
-+
-+      return 0;
-+
-+ err:
-+      dev_nvram_exit();
-+      return ret;
-+}
-+
-+module_init(dev_nvram_init);
-+module_exit(dev_nvram_exit);
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/sbmips.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/sbmips.c      2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,950 @@
-+/*
-+ * BCM47XX Sonics SiliconBackplane MIPS core routines
-+ *
-+ * Copyright 2001-2003, Broadcom Corporation
-+ * All Rights Reserved.
-+ * 
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id: sbmips.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
-+ */
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/bootmem.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
 +
 +#include <typedefs.h>
-+#include <osl.h>
-+#include <sbutils.h>
-+#include <bcmdevs.h>
++#include <bcmendian.h>
 +#include <bcmnvram.h>
 +#include <bcmutils.h>
-+#include <hndmips.h>
 +#include <sbconfig.h>
-+#include <sbextif.h>
 +#include <sbchipc.h>
-+#include <sbmemc.h>
++#include <sbutils.h>
++#include <sbmips.h>
++#include <sflash.h>
 +
-+/*
-+ * Memory segments (32bit kernel mode addresses)
-+ */
-+#undef KUSEG
-+#undef KSEG0
-+#undef KSEG1
-+#undef KSEG2
-+#undef KSEG3
-+#define KUSEG         0x00000000
-+#define KSEG0         0x80000000
-+#define KSEG1         0xa0000000
-+#define KSEG2         0xc0000000
-+#define KSEG3         0xe0000000
++/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
++static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
 +
-+/*
-+ * Map an address to a certain kernel segment
-+ */
-+#undef KSEG0ADDR
-+#undef KSEG1ADDR
-+#undef KSEG2ADDR
-+#undef KSEG3ADDR
-+#define KSEG0ADDR(a)          (((a) & 0x1fffffff) | KSEG0)
-+#define KSEG1ADDR(a)          (((a) & 0x1fffffff) | KSEG1)
-+#define KSEG2ADDR(a)          (((a) & 0x1fffffff) | KSEG2)
-+#define KSEG3ADDR(a)          (((a) & 0x1fffffff) | KSEG3)
++/* Global SB handle */
++extern void *sbh;
++extern spinlock_t bcm947xx_sbh_lock;
 +
-+/*
-+ * The following macros are especially useful for __asm__
-+ * inline assembler.
-+ */
-+#ifndef __STR
-+#define __STR(x) #x
-+#endif
-+#ifndef STR
-+#define STR(x) __STR(x)
-+#endif
++/* Convenience */
++#define sbh_lock bcm947xx_sbh_lock
++#define KB * 1024
++#define MB * 1024 * 1024
 +
-+/*  *********************************************************************
-+    *  CP0 Registers 
-+    ********************************************************************* */
++/* Probe for NVRAM header */
++static void __init
++early_nvram_init(void)
++{
++      struct nvram_header *header;
++      chipcregs_t *cc;
++      struct sflash *info = NULL;
++      int i;
++      uint32 base, off, lim;
++      u32 *src, *dst;
 +
-+#define C0_INX                0               /* CP0: TLB Index */
-+#define C0_RAND               1               /* CP0: TLB Random */
-+#define C0_TLBLO0     2               /* CP0: TLB EntryLo0 */
-+#define C0_TLBLO      C0_TLBLO0       /* CP0: TLB EntryLo0 */
-+#define C0_TLBLO1     3               /* CP0: TLB EntryLo1 */
-+#define C0_CTEXT      4               /* CP0: Context */
-+#define C0_PGMASK     5               /* CP0: TLB PageMask */
-+#define C0_WIRED      6               /* CP0: TLB Wired */
-+#define C0_BADVADDR   8               /* CP0: Bad Virtual Address */
-+#define C0_COUNT      9               /* CP0: Count */
-+#define C0_TLBHI      10              /* CP0: TLB EntryHi */
-+#define C0_COMPARE    11              /* CP0: Compare */
-+#define C0_SR         12              /* CP0: Processor Status */
-+#define C0_STATUS     C0_SR           /* CP0: Processor Status */
-+#define C0_CAUSE      13              /* CP0: Exception Cause */
-+#define C0_EPC                14              /* CP0: Exception PC */
-+#define C0_PRID               15              /* CP0: Processor Revision Indentifier */
-+#define C0_CONFIG     16              /* CP0: Config */
-+#define C0_LLADDR     17              /* CP0: LLAddr */
-+#define C0_WATCHLO    18              /* CP0: WatchpointLo */
-+#define C0_WATCHHI    19              /* CP0: WatchpointHi */
-+#define C0_XCTEXT     20              /* CP0: XContext */
-+#define C0_DIAGNOSTIC 22              /* CP0: Diagnostic */
-+#define C0_BROADCOM   C0_DIAGNOSTIC   /* CP0: Broadcom Register */
-+#define C0_ECC                26              /* CP0: ECC */
-+#define C0_CACHEERR   27              /* CP0: CacheErr */
-+#define C0_TAGLO      28              /* CP0: TagLo */
-+#define C0_TAGHI      29              /* CP0: TagHi */
-+#define C0_ERREPC     30              /* CP0: ErrorEPC */
++      if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
++              base = KSEG1ADDR(SB_FLASH2);
++              switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
++              case PFLASH:
++                      lim = SB_FLASH2_SZ;
++                      break;
 +
-+/*
-+ * Macros to access the system control coprocessor
-+ */
++              case SFLASH_ST:
++              case SFLASH_AT:
++                      if ((info = sflash_init(cc)) == NULL)
++                              return;
++                      lim = info->size;
++                      break;
 +
-+#define MFC0(source, sel)                                     \
-+({                                                            \
-+      int __res;                                              \
-+      __asm__ __volatile__(                                   \
-+      ".set\tnoreorder\n\t"                                   \
-+      ".set\tnoat\n\t"                                        \
-+      ".word\t"STR(0x40010000 | ((source)<<11) | (sel))"\n\t" \
-+      "move\t%0,$1\n\t"                                       \
-+      ".set\tat\n\t"                                          \
-+      ".set\treorder"                                         \
-+      :"=r" (__res)                                           \
-+      :                                                       \
-+      :"$1");                                                 \
-+      __res;                                                  \
-+})
++              case FLASH_NONE:
++              default:
++                      return;
++              }
++      } else {
++              /* extif assumed, Stop at 4 MB */
++              base = KSEG1ADDR(SB_FLASH1);
++              lim = SB_FLASH1_SZ;
++      }
 +
-+#define MTC0(source, sel, value)                              \
-+do {                                                          \
-+      __asm__ __volatile__(                                   \
-+      ".set\tnoreorder\n\t"                                   \
-+      ".set\tnoat\n\t"                                        \
-+      "move\t$1,%z0\n\t"                                      \
-+      ".word\t"STR(0x40810000 | ((source)<<11) | (sel))"\n\t" \
-+      ".set\tat\n\t"                                          \
-+      ".set\treorder"                                         \
-+      :                                                       \
-+      :"Jr" (value)                                           \
-+      :"$1");                                                 \
-+} while (0)
++      off = FLASH_MIN;
++      while (off <= lim) {
++              /* Windowed flash access */
++              header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
++              if (header->magic == NVRAM_MAGIC)
++                      goto found;
++              off <<= 1;
++      }
++
++      /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
++      header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
++      if (header->magic == NVRAM_MAGIC)
++              goto found;
++      
++      header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
++      if (header->magic == NVRAM_MAGIC)
++              goto found;
++      
++      printk("early_nvram_init: NVRAM not found\n");
++      return;
 +
-+/*
-+ * R4x00 interrupt enable / cause bits
-+ */
-+#undef IE_SW0
-+#undef IE_SW1
-+#undef IE_IRQ0
-+#undef IE_IRQ1
-+#undef IE_IRQ2
-+#undef IE_IRQ3
-+#undef IE_IRQ4
-+#undef IE_IRQ5
-+#define IE_SW0                (1<< 8)
-+#define IE_SW1                (1<< 9)
-+#define IE_IRQ0               (1<<10)
-+#define IE_IRQ1               (1<<11)
-+#define IE_IRQ2               (1<<12)
-+#define IE_IRQ3               (1<<13)
-+#define IE_IRQ4               (1<<14)
-+#define IE_IRQ5               (1<<15)
++found:
++      src = (u32 *) header;
++      dst = (u32 *) nvram_buf;
++      for (i = 0; i < sizeof(struct nvram_header); i += 4)
++              *dst++ = *src++;
++      for (; i < header->len && i < NVRAM_SPACE; i += 4)
++              *dst++ = ltoh32(*src++);
++}
 +
-+/*
-+ * Bitfields in the R4xx0 cp0 status register
-+ */
-+#define ST0_IE                        0x00000001
-+#define ST0_EXL                       0x00000002
-+#define ST0_ERL                       0x00000004
-+#define ST0_KSU                       0x00000018
-+#  define KSU_USER            0x00000010
-+#  define KSU_SUPERVISOR      0x00000008
-+#  define KSU_KERNEL          0x00000000
-+#define ST0_UX                        0x00000020
-+#define ST0_SX                        0x00000040
-+#define ST0_KX                        0x00000080
-+#define ST0_DE                        0x00010000
-+#define ST0_CE                        0x00020000
++/* Early (before mm or mtd) read-only access to NVRAM */
++char * __init nvram_get(const char *name)
++{
++      char *var, *value, *end, *eq;
 +
-+/*
-+ * Status register bits available in all MIPS CPUs.
-+ */
-+#define ST0_IM                        0x0000ff00
-+#define ST0_CH                        0x00040000
-+#define ST0_SR                        0x00100000
-+#define ST0_TS                        0x00200000
-+#define ST0_BEV                       0x00400000
-+#define ST0_RE                        0x02000000
-+#define ST0_FR                        0x04000000
-+#define ST0_CU                        0xf0000000
-+#define ST0_CU0                       0x10000000
-+#define ST0_CU1                       0x20000000
-+#define ST0_CU2                       0x40000000
-+#define ST0_CU3                       0x80000000
-+#define ST0_XX                        0x80000000      /* MIPS IV naming */
++      if (!name)
++              return NULL;
 +
-+/*
-+ * Cache Operations
-+ */
++      /* Too early? */
++      if (sbh == NULL)
++              return NULL;
 +
-+#ifndef Fill_I
-+#define Fill_I                        0x14
-+#endif
++      if (!nvram_buf[0])
++              early_nvram_init();
 +
-+#define cache_unroll(base,op)                 \
-+      __asm__ __volatile__("                  \
-+              .set noreorder;                 \
-+              .set mips3;                     \
-+              cache %1, (%0);                 \
-+              .set mips0;                     \
-+              .set reorder"                   \
-+              :                               \
-+              : "r" (base),                   \
-+                "i" (op));
++      /* Look for name=value and return value */
++      var = &nvram_buf[sizeof(struct nvram_header)];
++      end = nvram_buf + sizeof(nvram_buf) - 2;
++      end[0] = end[1] = '\0';
++      for (; *var; var = value + strlen(value) + 1) {
++              if (!(eq = strchr(var, '=')))
++                      break;
++              value = eq + 1;
++              if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
++                      return value;
++      }
 +
-+/* 
-+ * These are the UART port assignments, expressed as offsets from the base
-+ * register.  These assignments should hold for any serial port based on
-+ * a 8250, 16450, or 16550(A).
++      return NULL;
++}
++
++EXPORT_SYMBOL(nvram_get);
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/sbmips.c linux.dev/arch/mips/bcm947xx/broadcom/sbmips.c
+--- linux.old/arch/mips/bcm947xx/broadcom/sbmips.c     1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/sbmips.c     2005-12-15 16:46:31.122961250 +0100
+@@ -0,0 +1,1038 @@
++/*
++ * BCM47XX Sonics SiliconBackplane MIPS core 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$
 + */
 +
-+#define UART_MCR      4       /* Out: Modem Control Register */
-+#define UART_MSR      6       /* In:  Modem Status Register */
-+#define UART_MCR_LOOP 0x10    /* Enable loopback test mode */
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmdevs.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <hndmips.h>
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbchipc.h>
++#include <sbmemc.h>
++#include <mipsinc.h>
++#include <sbutils.h>
 +
-+/* 
++/*
 + * Returns TRUE if an external UART exists at the given base
 + * register.
 + */
 +static bool
-+serial_exists(uint8 *regs)
++BCMINITFN(serial_exists)(uint8 *regs)
 +{
 +      uint8 save_mcr, status1;
 +
@@ -3780,12 +1209,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      return (status1 == 0x90);
 +}
 +
-+/* 
++/*
 + * Initializes UART access. The callback function will be called once
 + * per found UART.
-+*/
++ */
 +void
-+sb_serial_init(void *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
++BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
 +{
 +      void *regs;
 +      ulong base;
@@ -3811,7 +1240,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              n = 2;
 +              for (i = 0; i < 2; i++) {
 +                      regs = (void *) REG_MAP(base + (i * 8), 8);
-+                      if (serial_exists(regs)) {
++                      if (BCMINIT(serial_exists)(regs)) {
 +                              /* Set GPIO 1 to be the external UART IRQ */
 +                              W_REG(&eir->gpiointmask, 2);
 +                              if (add)
@@ -3841,27 +1270,35 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +                                                R_REG(&cc->clockcontrol_n),
 +                                                R_REG(&cc->clockcontrol_m2));
 +                      div = 1;
-+              } else if (rev >= 3) {
-+                      /* Internal backplane clock */
-+                      baud_base = sb_clock_rate(pll,
-+                                                R_REG(&cc->clockcontrol_n),
-+                                                R_REG(&cc->clockcontrol_sb));
-+                      div = 2;        /* Minimum divisor */
-+                      W_REG(&cc->uart_clkdiv, div);
 +              } else {
-+                      /* Fixed internal backplane clock */
-+                      baud_base = 88000000;
-+                      div = 48;
-+              }
-+
-+              /* Clock source depends on strapping if UartClkOverride is unset */
-+              if ((rev > 0) && ((R_REG(&cc->corecontrol) & CC_UARTCLKO) == 0)) {
-+                      if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
-+                              /* Internal divided backplane clock */
-+                              baud_base /= div;
++                      if (rev >= 11) {
++                              /* Fixed ALP clock */
++                              baud_base = 20000000;
++                              div = 1;
++                              /* Set the override bit so we don't divide it */
++                              W_REG(&cc->corecontrol, CC_UARTCLKO);
++                      } else if (rev >= 3) {
++                              /* Internal backplane clock */
++                              baud_base = sb_clock(sbh);
++                              div = 2;        /* Minimum divisor */
++                              W_REG(&cc->clkdiv,
++                                    ((R_REG(&cc->clkdiv) & ~CLKD_UART) | div));
 +                      } else {
-+                              /* Assume external clock of 1.8432 MHz */
-+                              baud_base = 1843200;
++                              /* Fixed internal backplane clock */
++                              baud_base = 88000000;
++                              div = 48;
++                      }
++
++                      /* Clock source depends on strapping if UartClkOverride is unset */
++                      if ((rev > 0) &&
++                          ((R_REG(&cc->corecontrol) & CC_UARTCLKO) == 0)) {
++                              if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
++                                      /* Internal divided backplane clock */
++                                      baud_base /= div;
++                              } else {
++                                      /* Assume external clock of 1.8432 MHz */
++                                      baud_base = 1843200;
++                              }
 +                      }
 +              }
 +
@@ -3880,9 +1317,90 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      }
 +}
 +
++/*
++ * Initialize jtag master and return handle for
++ * jtag_rwreg. Returns NULL on failure.
++ */
++void *
++sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap)
++{
++      void *regs;
++
++      if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) {
++              chipcregs_t *cc = (chipcregs_t *) regs;
++              uint32 tmp;
++
++              /*
++               * Determine jtagm availability from
++               * core revision and capabilities.
++               */
++              tmp = sb_corerev(sbh);
++              /*
++               * Corerev 10 has jtagm, but the only chip
++               * with it does not have a mips, and
++               * the layout of the jtagcmd register is
++               * different. We'll only accept >= 11.
++               */
++              if (tmp < 11)
++                      return (NULL);
++
++              tmp = R_REG(&cc->capabilities);
++              if ((tmp & CAP_JTAGP) == 0)
++                      return (NULL);
++
++              /* Set clock divider if requested */
++              if (clkd != 0) {
++                      tmp = R_REG(&cc->clkdiv);
++                      tmp = (tmp & ~CLKD_JTAG) |
++                              ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG);
++                      W_REG(&cc->clkdiv, tmp);
++              }
++
++              /* Enable jtagm */
++              tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
++              W_REG(&cc->jtagctrl, tmp);
++      }
++
++      return (regs);
++}
++
++void
++sb_jtagm_disable(void *h)
++{
++      chipcregs_t *cc = (chipcregs_t *)h;
++
++      W_REG(&cc->jtagctrl, R_REG(&cc->jtagctrl) & ~JCTRL_EN);
++}
++
++/*
++ * Read/write a jtag register. Assumes a target with
++ * 8 bit IR and 32 bit DR.
++ */
++#define       IRWIDTH         8
++#define       DRWIDTH         32
++uint32
++jtag_rwreg(void *h, uint32 ir, uint32 dr)
++{
++      chipcregs_t *cc = (chipcregs_t *) h;
++      uint32 tmp;
++
++      W_REG(&cc->jtagir, ir);
++      W_REG(&cc->jtagdr, dr);
++      tmp = JCMD_START | JCMD_ACC_IRDR |
++              ((IRWIDTH - 1) << JCMD_IRW_SHIFT) |
++              (DRWIDTH - 1);
++      W_REG(&cc->jtagcmd, tmp);
++      while (((tmp = R_REG(&cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) {
++              /* OSL_DELAY(1); */
++      }
++
++      tmp = R_REG(&cc->jtagdr);
++      return (tmp);
++}
++
 +/* Returns the SB interrupt flag of the current core. */
 +uint32
-+sb_flag(void *sbh)
++sb_flag(sb_t *sbh)
 +{
 +      void *regs;
 +      sbconfig_t *sb;
@@ -3909,12 +1427,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      SBIPS_INT4_SHIFT
 +};
 +
-+/* 
++/*
 + * Returns the MIPS IRQ assignment of the current core. If unassigned,
 + * 0 is returned.
 + */
 +uint
-+sb_irq(void *sbh)
++sb_irq(sb_t *sbh)
 +{
 +      uint idx;
 +      void *regs;
@@ -3947,7 +1465,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +
 +/* Clears the specified MIPS IRQ. */
 +static void
-+sb_clearirq(void *sbh, uint irq)
++BCMINITFN(sb_clearirq)(sb_t *sbh, uint irq)
 +{
 +      void *regs;
 +      sbconfig_t *sb;
@@ -3963,12 +1481,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
 +}
 +
-+/* 
++/*
 + * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
 + * IRQ 0 may be assigned more than once.
 + */
 +static void
-+sb_setirq(void *sbh, uint irq, uint coreid, uint coreunit)
++BCMINITFN(sb_setirq)(sb_t *sbh, uint irq, uint coreid, uint coreunit)
 +{
 +      void *regs;
 +      sbconfig_t *sb;
@@ -3991,14 +1509,14 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              flag |= R_REG(&sb->sbipsflag) & ~sbips_int_mask[irq];
 +              W_REG(&sb->sbipsflag, flag);
 +      }
-+}     
++}
 +
-+/* 
++/*
 + * Initializes clocks and interrupts. SB and NVRAM access must be
 + * initialized prior to calling.
 + */
 +void
-+sb_mips_init(void *sbh)
++BCMINITFN(sb_mips_init)(sb_t *sbh)
 +{
 +      ulong hz, ns, tmp;
 +      extifregs_t *eir;
@@ -4033,45 +1551,66 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              tmp = CEIL(10, ns) << FW_W3_SHIFT;      /* W3 = 10nS */
 +              tmp |= CEIL(10, ns) << FW_W1_SHIFT;     /* W1 = 10nS */
 +              tmp |= CEIL(120, ns);                   /* W0 = 120nS */
-+              W_REG(&cc->parallelflashwaitcnt, tmp);
++              
++              // Added by Chen-I for 5365
++              if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++              {
++                      W_REG(&cc->flash_waitcount, tmp);
++                      W_REG(&cc->pcmcia_memwait, tmp);
++              }
++              else
++              {
++                      if (sb_corerev(sbh) < 9)
++                              W_REG(&cc->flash_waitcount, tmp);
 +
-+              W_REG(&cc->cs01memwaitcnt, tmp);
++                      if ((sb_corerev(sbh) < 9) ||
++                       ((BCMINIT(sb_chip)(sbh) == BCM5350_DEVICE_ID) && BCMINIT(sb_chiprev)(sbh) == 0)) {
++                              W_REG(&cc->pcmcia_memwait, tmp);
++                      }
++              }
 +      }
 +
 +      /* Chip specific initialization */
-+      switch (sb_chip(sbh)) {
++      switch (BCMINIT(sb_chip)(sbh)) {
 +      case BCM4710_DEVICE_ID:
 +              /* Clear interrupt map */
 +              for (irq = 0; irq <= 4; irq++)
-+                      sb_clearirq(sbh, irq);
-+              sb_setirq(sbh, 0, SB_CODEC, 0);
-+              sb_setirq(sbh, 0, SB_EXTIF, 0);
-+              sb_setirq(sbh, 2, SB_ENET, 1);
-+              sb_setirq(sbh, 3, SB_ILINE20, 0);
-+              sb_setirq(sbh, 4, SB_PCI, 0);
++                      BCMINIT(sb_clearirq)(sbh, irq);
++              BCMINIT(sb_setirq)(sbh, 0, SB_CODEC, 0);
++              BCMINIT(sb_setirq)(sbh, 0, SB_EXTIF, 0);
++              BCMINIT(sb_setirq)(sbh, 2, SB_ENET, 1);
++              BCMINIT(sb_setirq)(sbh, 3, SB_ILINE20, 0);
++              BCMINIT(sb_setirq)(sbh, 4, SB_PCI, 0);
 +              ASSERT(eir);
-+              value = nvram_get("et0phyaddr");
++              value = BCMINIT(nvram_get)("et0phyaddr");
 +              if (value && !strcmp(value, "31")) {
 +                      /* Enable internal UART */
 +                      W_REG(&eir->corecontrol, CC_UE);
 +                      /* Give USB its own interrupt */
-+                      sb_setirq(sbh, 1, SB_USB, 0);
++                      BCMINIT(sb_setirq)(sbh, 1, SB_USB, 0);
 +              } else {
 +                      /* Disable internal UART */
 +                      W_REG(&eir->corecontrol, 0);
 +                      /* Give Ethernet its own interrupt */
-+                      sb_setirq(sbh, 1, SB_ENET, 0);
-+                      sb_setirq(sbh, 0, SB_USB, 0);
++                      BCMINIT(sb_setirq)(sbh, 1, SB_ENET, 0);
++                      BCMINIT(sb_setirq)(sbh, 0, SB_USB, 0);
 +              }
 +              break;
-+      case BCM4310_DEVICE_ID:
-+              MTC0(C0_BROADCOM, 0, MFC0(C0_BROADCOM, 0) & ~(1 << 22));
++      case BCM5350_DEVICE_ID:
++              /* Clear interrupt map */
++              for (irq = 0; irq <= 4; irq++)
++                      BCMINIT(sb_clearirq)(sbh, irq);
++              BCMINIT(sb_setirq)(sbh, 0, SB_CC, 0);
++              BCMINIT(sb_setirq)(sbh, 1, SB_D11, 0);
++              BCMINIT(sb_setirq)(sbh, 2, SB_ENET, 0);
++              BCMINIT(sb_setirq)(sbh, 3, SB_PCI, 0);
++              BCMINIT(sb_setirq)(sbh, 4, SB_USB, 0);
 +              break;
 +      }
 +}
 +
 +uint32
-+sb_mips_clock(void *sbh)
++BCMINITFN(sb_mips_clock)(sb_t *sbh)
 +{
 +      extifregs_t *eir;
 +      chipcregs_t *cc;
@@ -4090,18 +1629,35 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      } 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_TYPE2) || (pll_type == PLL_TYPE4))
++              if ((pll_type == PLL_TYPE2) ||
++                  (pll_type == PLL_TYPE4) ||
++                  (pll_type == PLL_TYPE6) ||
++                  (pll_type == PLL_TYPE7))
 +                      m = R_REG(&cc->clockcontrol_mips);
-+              else if (pll_type == PLL_TYPE3) {
++              else if (pll_type == PLL_TYPE5) {
 +                      rate = 200000000;
 +                      goto out;
++              }
++              else if (pll_type == PLL_TYPE3) {
++                      if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID) { /* 5365 is also type3 */
++                              rate = 200000000;
++                              goto out;
++                      } else
++                              m = R_REG(&cc->clockcontrol_m2); /* 5350 uses m2 to control mips */
 +              } else
 +                      m = R_REG(&cc->clockcontrol_sb);
 +      } else
 +              goto out;
 +
-+      /* calculate rate */
-+      rate = sb_clock_rate(pll_type, n, m);
++      // 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_TYPE6)
++              rate = SB2MIPS_T6(rate);
 +
 +out:
 +      /* switch back to previous core */
@@ -4110,26 +1666,10 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      return rate;
 +}
 +
-+static void
-+icache_probe(int *size, int *lsize)
-+{
-+      uint32 config1;
-+      uint sets, ways;
-+
-+      config1 = MFC0(C0_CONFIG, 1);
-+
-+      /* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
-+      if ((*lsize = ((config1 >> 19) & 7)))
-+              *lsize = 2 << *lsize;
-+      sets = 64 << ((config1 >> 22) & 7);
-+      ways = 1 + ((config1 >> 16) & 7);
-+      *size = *lsize * sets * ways;
-+}
-+
 +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
 +
 +static void
-+handler(void)
++BCMINITFN(handler)(void)
 +{
 +      /* Step 11 */
 +      __asm__ (
@@ -4139,7 +1679,9 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      /* Disable interrupts */
 +      /*      MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
 +              "mfc0 $15, $12\n\t"
-+              "and $15, $15, -31746\n\t"
++      /* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
++              "li $14, -31746\n\t"
++              "and $15, $15, $14\n\t"
 +              "mtc0 $15, $12\n\t"
 +              "eret\n\t"
 +              "nop\n\t"
@@ -4150,7 +1692,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +
 +/* The following MUST come right after handler() */
 +static void
-+afterhandler(void)
++BCMINITFN(afterhandler)(void)
 +{
 +}
 +
@@ -4158,22 +1700,24 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 + * Set the MIPS, backplane and PCI clocks as closely as possible.
 + */
 +bool
-+sb_mips_setclock(void *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
++BCMINITFN(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
 +{
 +      extifregs_t *eir = NULL;
 +      chipcregs_t *cc = NULL;
 +      mipsregs_t *mipsr = NULL;
-+      volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci;
-+      uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, new_ratio;
++      volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
++      uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
 +      uint32 pll_type, sync_mode;
++      uint ic_size, ic_lsize;
 +      uint idx, i;
-+      struct {
++      typedef struct {
 +              uint32 mipsclock;
 +              uint16 n;
 +              uint32 sb;
 +              uint32 pci33;
 +              uint32 pci25;
-+      } type1_table[] = {
++      } n3m_table_t;
++      static n3m_table_t BCMINITDATA(type1_table)[] = {
 +              {  96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /*  96.000 32.000 24.000 */
 +              { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
 +              { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
@@ -4197,56 +1741,91 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      };
 +      typedef struct {
 +              uint32 mipsclock;
++              uint16 n;
++              uint32 m2; /* that is the clockcontrol_m2 */
++      } type3_table_t;
++      static type3_table_t type3_table[] = { /* for 5350, mips clock is always double sb clock */
++              { 150000000, 0x311, 0x4020005 },
++              { 200000000, 0x311, 0x4020003 },
++      };
++      typedef struct {
++              uint32 mipsclock;
 +              uint32 sbclock;
 +              uint16 n;
 +              uint32 sb;
 +              uint32 pci33;
 +              uint32 m2;
 +              uint32 m3;
-+              uint32 ratio;
++              uint32 ratio_cfg;
 +              uint32 ratio_parm;
 +      } n4m_table_t;
 +
-+      n4m_table_t type2_table[] = {
-+              { 180000000,  80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+              { 180000000,  90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
-+              { 200000000, 100000000, 0x0303, 0x01000000, 0x01000600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
-+              { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+              { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+              { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+              { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+              { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+              { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 },
-+              { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 0x21, 0x0aaa0555 },
-+              { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+              { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+              { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
-+              { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+              { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 0x21, 0x0aaa0555 },
-+              { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 0x94, 0x012a0115 },
-+              { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 0x21, 0x0aaa0555 }
++      static n4m_table_t BCMINITDATA(type2_table)[] = {
++              { 180000000,  80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100,  8, 0x012a00a9 },
++              { 180000000,  90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 11, 0x0aaa0555 },
++              { 200000000, 100000000, 0x0303, 0x02010000, 0x02040001, 0x02010000, 0x06000001, 11, 0x0aaa0555 },
++              { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++              { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++              { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++              { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100,  8, 0x012a00a9 },
++              { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++              { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 11, 0x0aaa0555 },
++              { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++              { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100,  8, 0x012a00a9 },
++              { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100,  8, 0x012a00a9 },
++              { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11, 0x0aaa0555 },
++              { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100,  8, 0x012a00a9 },
++              { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11, 0x0aaa0555 },
++              { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100,  8, 0x012a00a9 },
++              { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 11, 0x0aaa0555 }
++      };
++
++      static n4m_table_t BCMINITDATA(type4_table)[] = {
++              { 192000000,  96000000, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
++              { 198000000,  99000000, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11, 0x0aaa0555 },
++              { 204000000, 102000000, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 208000000, 104000000, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
++              { 210000000, 105000000, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 216000000, 108000000, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 224000000, 112000000, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
++              { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005,  8, 0x012a00a9 },
++              { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 240000000, 102857143, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003, 13, 0x254a14a9 },
++              { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
++              { 252000000, 100800000, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002,  9, 0x02520129 },
++              { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11, 0x0aaa0555 },
++              { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11, 0x0aaa0555 },
++              { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 13, 0x254a14a9 },
++              { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13, 0x254a14a9 },
++              { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13, 0x254a14a9 },
++              { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002,  9, 0x02520129 },
++              { 300000000, 150000000, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002, 11, 0x0aaa0555 }
 +      };
 +
-+      n4m_table_t type4_table[] = {
-+              { 192000000,  96000000, 0x0702, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
-+              { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 0x21, 0x0aaa0555 },
-+              { 216000000, 108000000, 0x0211, 0x11020005, 0x11030303, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
-+              { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x11030305, 0x04000005, 0x94, 0x012a00a9 },
-+              { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 0x21, 0x0aaa0555 },
-+              { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 0x21, 0x0aaa0555 },
-+              { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
-+              { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 0x21, 0x0aaa0555 },
-+              { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
-+              { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
-+              { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 0x73, 0x254a14a9 },
-+              { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 0x52, 0x02520129 }
++      static n4m_table_t BCMINITDATA(type7_table)[] = {
++              { 183333333,  91666666, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
++              { 187500000,  93750000, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
++              { 196875000,  98437500, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 200000000, 100000000, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003, 11, 0x0aaa0555 },
++              { 200000000, 100000000, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11, 0x0aaa0555 },
++              { 206250000, 103125000, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 212500000, 106250000, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 215625000, 107812500, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 216666666, 108333333, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
++              { 225000000, 112500000, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
++              { 233333333, 116666666, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
++              { 237500000, 118750000, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++              { 240000000, 120000000, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009, 11, 0x0aaa0555 },
++              { 250000000, 125000000, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003, 11, 0x0aaa0555 }
 +      };
-+      uint icache_size, ic_lsize;
++
 +      ulong start, end, dst;
 +      bool ret = FALSE;
 +
 +      /* get index of the current core */
 +      idx = sb_coreidx(sbh);
++      clockcontrol_m2 = NULL;
 +
 +      /* switch to extif or chipc core */
 +      if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
@@ -4254,18 +1833,31 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              clockcontrol_n = &eir->clockcontrol_n;
 +              clockcontrol_sb = &eir->clockcontrol_sb;
 +              clockcontrol_pci = &eir->clockcontrol_pci;
++              clockcontrol_m2 = &cc->clockcontrol_m2;
 +      } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
 +              pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
-+              clockcontrol_n = &cc->clockcontrol_n;
-+              clockcontrol_sb = &cc->clockcontrol_sb;
-+              clockcontrol_pci = &cc->clockcontrol_pci;
++              if (pll_type == PLL_TYPE6) {
++                      clockcontrol_n = NULL;
++                      clockcontrol_sb = NULL;
++                      clockcontrol_pci = NULL;
++              } else {
++                      clockcontrol_n = &cc->clockcontrol_n;
++                      clockcontrol_sb = &cc->clockcontrol_sb;
++                      clockcontrol_pci = &cc->clockcontrol_pci;
++                      clockcontrol_m2 = &cc->clockcontrol_m2;
++              }
 +      } else
 +              goto done;
 +
-+      /* Store the current clock register values */
-+      orig_n = R_REG(clockcontrol_n);
-+      orig_sb = R_REG(clockcontrol_sb);
-+      orig_pci = R_REG(clockcontrol_pci);
++      if (pll_type == PLL_TYPE6) {
++              /* Silence compilers */
++              orig_n = orig_sb = orig_pci = 0;
++      } else {
++              /* Store the current clock register values */
++              orig_n = R_REG(clockcontrol_n);
++              orig_sb = R_REG(clockcontrol_sb);
++              orig_pci = R_REG(clockcontrol_pci);
++      }
 +
 +      if (pll_type == PLL_TYPE1) {
 +              /* Keep the current PCI clock if not specified */
@@ -4275,10 +1867,10 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              }
 +
 +              /* Search for the closest MIPS clock less than or equal to a preferred value */
-+              for (i = 0; i < ARRAYSIZE(type1_table); i++) {
-+                      ASSERT(type1_table[i].mipsclock ==
-+                             sb_clock_rate(pll_type, type1_table[i].n, type1_table[i].sb));
-+                      if (type1_table[i].mipsclock > mipsclock)
++              for (i = 0; i < ARRAYSIZE(BCMINIT(type1_table)); i++) {
++                      ASSERT(BCMINIT(type1_table)[i].mipsclock ==
++                             sb_clock_rate(pll_type, BCMINIT(type1_table)[i].n, BCMINIT(type1_table)[i].sb));
++                      if (BCMINIT(type1_table)[i].mipsclock > mipsclock)
 +                              break;
 +              }
 +              if (i == 0) {
@@ -4288,35 +1880,99 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +                      ret = TRUE;
 +                      i--;
 +              }
-+              ASSERT(type1_table[i].mipsclock <= mipsclock);
++              ASSERT(BCMINIT(type1_table)[i].mipsclock <= mipsclock);
 +
 +              /* No PLL change */
-+              if ((orig_n == type1_table[i].n) &&
-+                  (orig_sb == type1_table[i].sb) &&
-+                  (orig_pci == type1_table[i].pci33))
++              if ((orig_n == BCMINIT(type1_table)[i].n) &&
++                  (orig_sb == BCMINIT(type1_table)[i].sb) &&
++                  (orig_pci == BCMINIT(type1_table)[i].pci33))
 +                      goto done;
 +
 +              /* Set the PLL controls */
-+              W_REG(clockcontrol_n, type1_table[i].n);
-+              W_REG(clockcontrol_sb, type1_table[i].sb);
++              W_REG(clockcontrol_n, BCMINIT(type1_table)[i].n);
++              W_REG(clockcontrol_sb, BCMINIT(type1_table)[i].sb);
 +              if (pciclock == 25000000)
-+                      W_REG(clockcontrol_pci, type1_table[i].pci25);
++                      W_REG(clockcontrol_pci, BCMINIT(type1_table)[i].pci25);
 +              else
-+                      W_REG(clockcontrol_pci, type1_table[i].pci33);
++                      W_REG(clockcontrol_pci, BCMINIT(type1_table)[i].pci33);
++
++              /* Reset */
++              sb_watchdog(sbh, 1);
++
++              while (1);
++      } else if ((pll_type == PLL_TYPE3) &&
++                 (BCMINIT(sb_chip)(sbh) != BCM5365_DEVICE_ID)) {
++              /* 5350 */
++              /* Search for the closest MIPS clock less than or equal to a preferred value */
++
++              for (i = 0; i < ARRAYSIZE(type3_table); i++) {
++                      if (type3_table[i].mipsclock > mipsclock)
++                              break;
++              }
++              if (i == 0) {
++                      ret = FALSE;
++                      goto done;
++              } else {
++                      ret = TRUE;
++                      i--;
++              }
++              ASSERT(type3_table[i].mipsclock <= mipsclock);
++
++              /* No PLL change */
++              orig_m2 = R_REG(&cc->clockcontrol_m2);
++              if ((orig_n == type3_table[i].n) &&
++                  (orig_m2 == type3_table[i].m2)) {
++                      goto done;
++              }
++
++              /* Set the PLL controls */
++              W_REG(clockcontrol_n, type3_table[i].n);
++              W_REG(clockcontrol_m2, type3_table[i].m2);
 +
 +              /* Reset */
 +              sb_watchdog(sbh, 1);
 +              while (1);
-+      } else if ((pll_type == PLL_TYPE2) || (pll_type == PLL_TYPE4)) {
-+              n4m_table_t *table = (pll_type == PLL_TYPE2) ? type2_table : type4_table;
-+              uint tabsz = (pll_type == PLL_TYPE2) ? ARRAYSIZE(type2_table) : ARRAYSIZE(type4_table);
++      } else if ((pll_type == PLL_TYPE2) ||
++                 (pll_type == PLL_TYPE4) ||
++                 (pll_type == PLL_TYPE6) ||
++                 (pll_type == PLL_TYPE7)) {
++              n4m_table_t *table = NULL, *te;
++              uint tabsz = 0;
 +
 +              ASSERT(cc);
 +
++              orig_mips = R_REG(&cc->clockcontrol_mips);
++
++              if (pll_type == PLL_TYPE6) {
++                      uint32 new_mips = 0;
++
++                      ret = TRUE;
++                      if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
++                              new_mips = CC_T6_MMASK;
++
++                      if (orig_mips == new_mips)
++                              goto done;
++
++                      W_REG(&cc->clockcontrol_mips, new_mips);
++                      goto end_fill;
++              }
++
++              if (pll_type == PLL_TYPE2) {
++                      table = BCMINIT(type2_table);
++                      tabsz = ARRAYSIZE(BCMINIT(type2_table));
++              } else if (pll_type == PLL_TYPE4) {
++                      table = BCMINIT(type4_table);
++                      tabsz = ARRAYSIZE(BCMINIT(type4_table));
++              } else if (pll_type == PLL_TYPE7) {
++                      table = BCMINIT(type7_table);
++                      tabsz = ARRAYSIZE(BCMINIT(type7_table));
++              } else
++                      ASSERT("No table for plltype" == NULL);
++
 +              /* Store the current clock register values */
 +              orig_m2 = R_REG(&cc->clockcontrol_m2);
-+              orig_mips = R_REG(&cc->clockcontrol_mips);
 +              orig_ratio_parm = 0;
++              orig_ratio_cfg = 0;
 +
 +              /* Look up current ratio */
 +              for (i = 0; i < tabsz; i++) {
@@ -4326,6 +1982,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +                          (orig_m2 == table[i].m2) &&
 +                          (orig_mips == table[i].m3)) {
 +                              orig_ratio_parm = table[i].ratio_parm;
++                              orig_ratio_cfg = table[i].ratio_cfg;
 +                              break;
 +                      }
 +              }
@@ -4342,50 +1999,55 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +                      ret = FALSE;
 +                      goto done;
 +              } else {
++                      te = &table[i];
 +                      ret = TRUE;
 +              }
 +
 +              /* No PLL change */
-+              if ((orig_n == table[i].n) &&
-+                  (orig_sb == table[i].sb) &&
-+                  (orig_pci == table[i].pci33) &&
-+                  (orig_m2 == table[i].m2) &&
-+                  (orig_mips == table[i].m3))
++              if ((orig_n == te->n) &&
++                  (orig_sb == te->sb) &&
++                  (orig_pci == te->pci33) &&
++                  (orig_m2 == te->m2) &&
++                  (orig_mips == te->m3))
 +                      goto done;
 +
 +              /* Set the PLL controls */
-+              W_REG(clockcontrol_n, table[i].n);
-+              W_REG(clockcontrol_sb, table[i].sb);
-+              W_REG(clockcontrol_pci, table[i].pci33);
-+              W_REG(&cc->clockcontrol_m2, table[i].m2);
-+              W_REG(&cc->clockcontrol_mips, table[i].m3);
++              W_REG(clockcontrol_n, te->n);
++              W_REG(clockcontrol_sb, te->sb);
++              W_REG(clockcontrol_pci, te->pci33);
++              W_REG(&cc->clockcontrol_m2, te->m2);
++              W_REG(&cc->clockcontrol_mips, te->m3);
++
++              /* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
++              if ((pll_type == PLL_TYPE7) &&
++                  (te->sb != te->m2) &&
++                  (sb_clock_rate(pll_type, te->n, te->m2) == 120000000))
++                      W_REG(&cc->chipcontrol, R_REG(&cc->chipcontrol) | 0x100);
 +
 +              /* No ratio change */
-+              if (orig_ratio_parm == table[i].ratio_parm)
++              if (orig_ratio_parm == te->ratio_parm)
 +                      goto end_fill;
 +
-+              new_ratio = table[i].ratio_parm;
-+
-+              icache_probe(&icache_size, &ic_lsize);
++              icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
 +
 +              /* Preload the code into the cache */
 +              start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
 +              end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
 +              while (start < end) {
-+                      cache_unroll(start, Fill_I);
++                      cache_op(start, Fill_I);
 +                      start += ic_lsize;
 +              }
 +
 +              /* Copy the handler */
-+              start = (ulong) &handler;
-+              end = (ulong) &afterhandler;
++              start = (ulong) &BCMINIT(handler);
++              end = (ulong) &BCMINIT(afterhandler);
 +              dst = KSEG1ADDR(0x180);
 +              for (i = 0; i < (end - start); i += 4)
 +                      *((ulong *)(dst + i)) = *((ulong *)(start + i));
-+              
++
 +              /* Preload handler into the cache one line at a time */
 +              for (i = 0; i < (end - start); i += 4)
-+                      cache_unroll(dst + i, Fill_I);
++                      cache_op(dst + i, Fill_I);
 +
 +              /* Clear BEV bit */
 +              MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
@@ -4401,8 +2063,8 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +
 +      start_fill:
 +              /* step 1, set clock ratios */
-+              MTC0(C0_BROADCOM, 3, new_ratio);
-+              MTC0(C0_BROADCOM, 1, 8);
++              MTC0(C0_BROADCOM, 3, te->ratio_parm);
++              MTC0(C0_BROADCOM, 1, te->ratio_cfg);
 +
 +              /* step 2: program timer intr */
 +              W_REG(&mipsr->timer, 100);
@@ -4416,7 +2078,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              MTC0(C0_BROADCOM, 2, 0x9);
 +
 +
-+              /* steps 5 & 6 */ 
++              /* steps 5 & 6 */
 +              __asm__ __volatile__ (
 +                      ".set\tmips3\n\t"
 +                      "wait\n\t"
@@ -4425,7 +2087,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +
 +              /* step 7, clear cfg_active */
 +              MTC0(C0_BROADCOM, 2, 0);
-+              
++
 +              /* Additional Step: set back to orig sync mode */
 +              MTC0(C0_BROADCOM, 4, sync_mode);
 +
@@ -4447,17 +2109,56 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +              while (1);
 +      }
 +
-+done:
-+      /* switch back to previous core */
-+      sb_setcoreidx(sbh, idx);
++done:
++      /* switch back to previous core */
++      sb_setcoreidx(sbh, idx);
++
++      return ret;
++}
++
++/*
++ *  This also must be run from the cache on 47xx
++ *  so there are no mips core BIU ops in progress
++ *  when the PFC is enabled.
++ */
++
++static void
++BCMINITFN(_enable_pfc)(uint32 mode)
++{
++      /* write range */
++      *(volatile uint32 *)PFC_CR1 = 0xffff0000;
++
++      /* enable */
++      *(volatile uint32 *)PFC_CR0 = mode;
++}
++
++void
++BCMINITFN(enable_pfc)(uint32 mode)
++{
++      ulong start, end;
++      int i;
++
++      /* If auto then choose the correct mode for this
++         platform, currently we only ever select one mode */
++      if (mode == PFC_AUTO)
++              mode = PFC_INST;
++
++      /* enable prefetch cache if available */
++      if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
++              start = (ulong) &BCMINIT(_enable_pfc);
++              end = (ulong) &BCMINIT(enable_pfc);
++
++              /* Preload handler into the cache one line at a time */
++              for (i = 0; i < (end - start); i += 4)
++                      cache_op(start + i, Fill_I);
 +
-+      return ret;
++              BCMINIT(_enable_pfc)(mode);
++      }
 +}
 +
-+
 +/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
 +uint32
-+sb_memc_get_ncdl(void *sbh)
++BCMINITFN(sb_memc_get_ncdl)(sb_t *sbh)
 +{
 +      sbmemcregs_t *memc;
 +      uint32 ret = 0;
@@ -4479,7 +2180,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +      dqsg = R_REG(&memc->dqsgatencdl);
 +
 +      rd &= MEMC_RDNCDLCOR_RD_MASK;
-+      wr &= MEMC_WRNCDLCOR_WR_MASK; 
++      wr &= MEMC_WRNCDLCOR_WR_MASK;
 +      dqsg &= MEMC_DQSGATENCDL_G_MASK;
 +
 +      if (config & MEMC_CONFIG_DDR) {
@@ -4500,14 +2201,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.15-rc5
 +
 +      return ret;
 +}
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/sbpci.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/sbpci.c       2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,530 @@
++
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/sbpci.c linux.dev/arch/mips/bcm947xx/broadcom/sbpci.c
+--- linux.old/arch/mips/bcm947xx/broadcom/sbpci.c      1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/sbpci.c      2005-12-15 20:09:46.562233250 +0100
+@@ -0,0 +1,529 @@
 +/*
 + * Low-Level PCI and SB support for BCM47xx
 + *
-+ * Copyright 2001-2003, Broadcom Corporation
++ * Copyright 2005, Broadcom Corporation
 + * All Rights Reserved.
 + * 
 + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
@@ -4515,18 +2217,18 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
 + *
-+ * $Id: sbpci.c,v 1.2 2005/02/28 13:34:25 jolt Exp $
++ * $Id$
 + */
 +
 +#include <typedefs.h>
 +#include <pcicfg.h>
 +#include <bcmdevs.h>
 +#include <sbconfig.h>
-+#include <sbpci.h>
 +#include <osl.h>
++#include <sbutils.h>
++#include <sbpci.h>
 +#include <bcmendian.h>
 +#include <bcmutils.h>
-+#include <sbutils.h>
 +#include <bcmnvram.h>
 +#include <hndmips.h>
 +
@@ -4545,6 +2247,9 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +/* CardBus mode */
 +static bool cardbus = FALSE;
 +
++/* Disable PCI host core */
++static bool pci_disabled = FALSE;
++
 +/*
 + * Functions for accessing external PCI configuration space
 + */
@@ -4553,7 +2258,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +#define PCI_SLOT_MAX 16
 +
 +static uint32
-+config_cmd(void *sbh, uint bus, uint dev, uint func, uint off)
++config_cmd(sb_t *sbh, uint bus, uint dev, uint func, uint off)
 +{
 +      uint coreidx;
 +      sbpciregs_t *regs;
@@ -4589,12 +2294,13 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +}
 +
 +static int
-+extpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++extpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
 +{
 +      uint32 addr, *reg = NULL, val;
 +      int ret = 0;
 +
-+      if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
++      if (pci_disabled ||
++          !(addr = config_cmd(sbh, bus, dev, func, off)) ||
 +          !(reg = (uint32 *) REG_MAP(addr, len)) ||
 +          BUSPROBE(val, reg))
 +              val = 0xffffffff;
@@ -4616,12 +2322,13 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +}
 +
 +static int
-+extpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++extpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
 +{
 +      uint32 addr, *reg = NULL, val;
 +      int ret = 0;
 +
-+      if (!(addr = config_cmd(sbh, bus, dev, func, off)) ||
++      if (pci_disabled ||
++          !(addr = config_cmd(sbh, bus, dev, func, off)) ||
 +          !(reg = (uint32 *) REG_MAP(addr, len)) ||
 +          BUSPROBE(val, reg))
 +              goto done;
@@ -4651,7 +2358,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 + */
 +
 +static int
-+sb_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++sb_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
 +{
 +      pci_config_regs *cfg;
 +
@@ -4660,7 +2367,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +      cfg = &sb_config_regs[dev];
 +
 +      ASSERT(ISALIGNED(off, len));
-+      ASSERT(ISALIGNED(buf, len));
++      ASSERT(ISALIGNED((uintptr)buf, len));
 +
 +      if (len == 4)
 +              *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
@@ -4675,7 +2382,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +}
 +
 +static int
-+sb_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++sb_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
 +{
 +      uint coreidx, n;
 +      void *regs;
@@ -4687,7 +2394,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +      cfg = &sb_config_regs[dev];
 +
 +      ASSERT(ISALIGNED(off, len));
-+      ASSERT(ISALIGNED(buf, len));
++      ASSERT(ISALIGNED((uintptr)buf, len));
 +
 +      /* Emulate BAR sizing */
 +      if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
@@ -4699,12 +2406,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +                      n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
 +                      if (off == OFFSETOF(pci_config_regs, base[0]))
 +                              cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
-+                      /*else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
++                      else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
 +                              cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
 +                      else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
 +                              cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
 +                      else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
-+                              cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);*/
++                              cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);
 +              }
 +              sb_setcoreidx(sbh, coreidx);
 +              return 0;
@@ -4723,7 +2430,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +}
 +
 +int
-+sbpci_read_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
 +{
 +      if (bus == 0)
 +              return sb_read_config(sbh, bus, dev, func, off, buf, len);
@@ -4732,7 +2439,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +}
 +
 +int
-+sbpci_write_config(void *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
 +{
 +      if (bus == 0)
 +              return sb_write_config(sbh, bus, dev, func, off, buf, len);
@@ -4747,33 +2454,49 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +              pci_ban[pci_banned++] = core;
 +}
 +
-+int __init
-+sbpci_init(void *sbh)
++static int
++sbpci_init_pci(sb_t *sbh)
 +{
-+      uint chip, chiprev, chippkg, coreidx, host, i;
++      uint chip, chiprev, chippkg, host;
++      uint32 boardflags;
 +      sbpciregs_t *pci;
 +      sbconfig_t *sb;
-+      pci_config_regs *cfg;
-+      void *regs;
-+      char varname[8];
-+      uint wlidx = 0;
-+      uint16 vendor, core;
-+      uint8 class, subclass, progif;
 +      uint32 val;
-+      uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
-+      uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
 +
 +      chip = sb_chip(sbh);
 +      chiprev = sb_chiprev(sbh);
 +      chippkg = sb_chippkg(sbh);
-+      coreidx = sb_coreidx(sbh);
 +
-+      if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0)))
++      if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0))) {
++              printf("PCI: no core\n");
++              pci_disabled = TRUE;
 +              return -1;
++      }
 +      sb_core_reset(sbh, 0);
 +
-+      if (((chip == BCM4310_DEVICE_ID) && (chiprev == 0)) ||
-+          ((chip == BCM4712_DEVICE_ID) && (chippkg == BCM4712SMALL_PKG_ID)))
++      boardflags = (uint32) getintvar(NULL, "boardflags");
++
++      if ((chip == BCM4310_DEVICE_ID) && (chiprev == 0))
++              pci_disabled = TRUE;
++
++      /*
++       * The 200-pin BCM4712 package does not bond out PCI. Even when
++       * PCI is bonded out, some boards may leave the pins
++       * floating.
++       */
++      if (((chip == BCM4712_DEVICE_ID) &&
++           ((chippkg == BCM4712SMALL_PKG_ID) ||
++            (chippkg == BCM4712MID_PKG_ID))) ||
++          (boardflags & BFL_NOPCI))
++              pci_disabled = TRUE;
++
++      /*
++       * If the PCI core should not be touched (disabled, not bonded
++       * out, or pins floating), do not even attempt to access core
++       * registers. Otherwise, try to determine if it is in host
++       * mode.
++       */
++      if (pci_disabled)
 +              host = 0;
 +      else
 +              host = !BUSPROBE(val, &pci->control);
@@ -4790,7 +2513,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +              /* Reset the external PCI bus and enable the clock */
 +              W_REG(&pci->control, 0x5);              /* enable the tristate drivers */
 +              W_REG(&pci->control, 0xd);              /* enable the PCI clock */
-+              OSL_DELAY(100);                         /* delay 100 us */
++              OSL_DELAY(150);                         /* delay > 100 us */
 +              W_REG(&pci->control, 0xf);              /* deassert PCI reset */
 +              W_REG(&pci->arbcontrol, PCI_INT_ARB);   /* use internal arbiter */
 +              OSL_DELAY(1);                           /* delay 1 us */
@@ -4800,8 +2523,8 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +              if (cardbus) {
 +                      printf("PCI: Enabling CardBus\n");
 +                      /* GPIO 1 resets the CardBus device on bcm94710ap */
-+                      sb_gpioout(sbh, 1, 1);
-+                      sb_gpioouten(sbh, 1, 1);
++                      sb_gpioout(sbh, 1, 1, GPIO_DRV_PRIORITY);
++                      sb_gpioouten(sbh, 1, 1, GPIO_DRV_PRIORITY);
 +                      W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
 +              }
 +
@@ -4819,6 +2542,29 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +              /* Enable PCI interrupts */
 +              W_REG(&pci->intmask, PCI_INTA);
 +      }
++      
++      return 0;
++}
++
++static int
++sbpci_init_cores(sb_t *sbh)
++{
++      uint chip, chiprev, chippkg, coreidx, i;
++      sbconfig_t *sb;
++      pci_config_regs *cfg;
++      void *regs;
++      char varname[8];
++      uint wlidx = 0;
++      uint16 vendor, core;
++      uint8 class, subclass, progif;
++      uint32 val;
++      uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
++      uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
++
++      chip = sb_chip(sbh);
++      chiprev = sb_chiprev(sbh);
++      chippkg = sb_chippkg(sbh);
++      coreidx = sb_coreidx(sbh);
 +
 +      /* Scan the SB bus */
 +      bzero(sb_config_regs, sizeof(sb_config_regs));
@@ -4873,7 +2619,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +              case SB_PCI:
 +                      class = PCI_CLASS_BRIDGE;
 +                      subclass = PCI_BRIDGE_PCI;
-+                      //break;
++                      break;
 +              case SB_MIPS:
 +              case SB_MIPS33:
 +                      class = PCI_CLASS_CPU;
@@ -4906,6 +2652,11 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +                      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;
@@ -4943,9 +2694,9 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +              cfg->sub_class = subclass;
 +              cfg->base_class = class;
 +              cfg->base[0] = htol32(sb_base(R_REG(&sb->sbadmatch0)));
-+              cfg->base[1] = 0/*htol32(sb_base(R_REG(&sb->sbadmatch1)))*/;
-+              cfg->base[2] = 0/*htol32(sb_base(R_REG(&sb->sbadmatch2)))*/;
-+              cfg->base[3] = 0/*htol32(sb_base(R_REG(&sb->sbadmatch3)))*/;
++              cfg->base[1] = htol32(sb_base(R_REG(&sb->sbadmatch1)));
++              cfg->base[2] = htol32(sb_base(R_REG(&sb->sbadmatch2)));
++              cfg->base[3] = htol32(sb_base(R_REG(&sb->sbadmatch3)));
 +              cfg->base[4] = 0;
 +              cfg->base[5] = 0;
 +              if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI)
@@ -4976,110 +2727,56 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.15-rc5-
 +      return 0;
 +}
 +
-+void
-+sbpci_check(void *sbh)
++int __init
++sbpci_init(sb_t *sbh)
 +{
-+      uint coreidx;
-+      sbpciregs_t *pci;
-+      uint32 sbtopci1;
-+      uint32 buf[64], *ptr, i;
-+      ulong pa;
-+      volatile uint j;
-+
-+      coreidx = sb_coreidx(sbh);
-+      pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
-+
-+      /* Clear the test array */
-+      pa = (ulong) DMA_MAP(NULL, buf, sizeof(buf), DMA_RX, NULL);
-+      ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
-+      memset(ptr, 0, sizeof(buf));
-+
-+      /* Point PCI window 1 to memory */
-+      sbtopci1 = R_REG(&pci->sbtopci1);
-+      W_REG(&pci->sbtopci1, SBTOPCI_MEM | (pa & SBTOPCI1_MASK));
-+
-+      /* Fill the test array via PCI window 1 */
-+      ptr = (uint32 *) REG_MAP(SB_PCI_CFG + (pa & ~SBTOPCI1_MASK), sizeof(buf));
-+      for (i = 0; i < ARRAYSIZE(buf); i++) {
-+              for (j = 0; j < 2; j++);
-+              W_REG(&ptr[i], i);
-+      }
-+      REG_UNMAP(ptr);
-+
-+      /* Restore PCI window 1 */
-+      W_REG(&pci->sbtopci1, sbtopci1);
-+
-+      /* Check the test array */
-+      DMA_UNMAP(NULL, pa, sizeof(buf), DMA_RX, NULL);
-+      ptr = (uint32 *) OSL_UNCACHED(&buf[0]);
-+      for (i = 0; i < ARRAYSIZE(buf); i++) {
-+              if (ptr[i] != i)
-+                      break;
-+      }
-+
-+      /* Change the clock if the test fails */
-+      if (i < ARRAYSIZE(buf)) {
-+              uint32 req, cur;
-+
-+              cur = sb_clock(sbh);
-+              printf("PCI: Test failed at %d MHz\n", (cur + 500000) / 1000000);
-+              for (req = 104000000; req < 176000000; req += 4000000) {
-+                      printf("PCI: Resetting to %d MHz\n", (req + 500000) / 1000000);
-+                      /* This will only reset if the clocks are valid and have changed */
-+                      sb_mips_setclock(sbh, req, 0, 0);
-+              }
-+              /* Should not reach here */
-+              ASSERT(0);
-+      }
-+
-+      sb_setcoreidx(sbh, coreidx);
++      sbpci_init_pci(sbh);
++      sbpci_init_cores(sbh);
++      return 0;
 +}
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/sbutils.c
---- linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/broadcom/sbutils.c     2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,1895 @@
++
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/sbutils.c linux.dev/arch/mips/bcm947xx/broadcom/sbutils.c
+--- linux.old/arch/mips/bcm947xx/broadcom/sbutils.c    1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/sbutils.c    2005-12-15 17:31:12.211645500 +0100
+@@ -0,0 +1,2407 @@
 +/*
 + * Misc utility routines for accessing chip-specific features
 + * of the SiliconBackplane-based Broadcom chips.
 + *
-+ * Copyright 2001-2003, Broadcom Corporation
++ * 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: sbutils.c,v 1.1 2005/02/28 13:33:32 jolt Exp $
++ * $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 <pcicfg.h>
-+#include <sbpcmcia.h>
 +#include <sbextif.h>
-+#include <sbutils.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 {
-+      uint    chip;                   /* chip number */
-+      uint    chiprev;                /* chip revision */
-+      uint    chippkg;                /* chip package option */
-+      uint    boardtype;              /* board type */
-+      uint    boardvendor;            /* board vendor id */
-+      uint    bus;                    /* what bus type we are going through */
++
++      struct sb_pub   sb;                     /* back plane public state(must be first field of sb_info */
 +
 +      void    *osh;                   /* osl os handle */
 +      void    *sdh;                   /* bcmsdh handle */
@@ -5089,14 +2786,6 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +      uint    curidx;                 /* current core index */
 +      uint    dev_coreid;             /* the core provides driver functions */
-+      uint    pciidx;                 /* pci core index */
-+      uint    pcirev;                 /* pci core rev */
-+
-+      uint    pcmciaidx;              /* pcmcia core index */
-+      uint    pcmciarev;              /* pcmcia core rev */
-+      bool    memseg;                 /* flag to toggle MEM_SEG register */
-+
-+      uint    ccrev;                  /* chipc core rev */
 +
 +      uint    gpioidx;                /* gpio control core index */
 +      uint    gpioid;                 /* gpio control coretype */
@@ -5107,32 +2796,49 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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 void* sb_doattach(sb_info_t *si, uint devid, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz);
-+static void sb_scan(sb_info_t *si);
-+static uint sb_corereg(void *sbh, uint coreidx, uint regoff, uint mask, uint val);
-+static uint _sb_coreidx(void *sbh);
-+static uint sb_findcoreidx(void *sbh, uint coreid, uint coreunit);
-+static uint sb_pcidev2chip(uint pcidev);
-+static uint sb_chip2numcores(uint chip);
++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 int sb_pci_fixcfg(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(regs, SB_CORE_SIZE))
-+#define       REGS2SB(va)     (sbconfig_t*) ((uint)(va) + SBCONFIGOFF)
++#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)) 
++
++/* 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.
 + */
@@ -5143,173 +2849,98 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) {  \
 +              (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }
 +
-+/* power control defines */
-+#define       PLL_DELAY       150                     /* 150us pll on delay */
-+#define       FREF_DELAY      15                      /* 15us fref change delay */
++/* dynamic clock control defines */
 +#define       LPOMINFREQ      25000                   /* low power oscillator min */
 +#define       LPOMAXFREQ      43000                   /* low power oscillator max */
-+#define       XTALMINFREQ     19800000                /* 20mhz - 1% */
-+#define       XTALMAXFREQ     20200000                /* 20mhz + 1% */
-+#define       PCIMINFREQ      25000000                /* 25mhz */
-+#define       PCIMAXFREQ      34000000                /* 33mhz + fudge */
-+
-+#define SCC_LOW2FAST_LIMIT    5000    /* turn on fast clock time, in unit of ms */
++#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 */
 +
-+static uint32
-+sb_read_sbreg(void *sbh, volatile uint32 *sbr)
-+{
-+      sb_info_t *si;
-+      uint8 tmp;
-+      uint32 val, intr_val = 0;
++#define MIN_DUMPBUFLEN  32    /* debug */
 +
-+      si = SB_INFO(sbh);
++/* GPIO Based LED powersave defines */
++#define DEFAULT_GPIO_ONTIME   10
++#define DEFAULT_GPIO_OFFTIME  90
 +
-+      /* 
-+       * 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);
-+              (uint32)sbr &= ~(1 << 11);      /* mask out bit 11*/
-+      }
++#define DEFAULT_GPIOTIMERVAL  ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
 +
-+      val = R_REG(sbr);
-+      
-+      if(si->memseg) {
-+              tmp = 0;
-+              OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
-+              INTR_RESTORE(si, intr_val);
-+      }
++static uint32
++sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr)
++{
++      uint32 val = R_REG(sbr);
 +
 +      return (val);
 +}
 +
 +static void
-+sb_write_sbreg(void *sbh, volatile uint32 *sbr, uint32 v)
++sb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v)
 +{
-+      sb_info_t *si;
-+      uint8 tmp;
-+      volatile uint32 dummy;
-+      uint32 intr_val = 0;
-+
-+      si = SB_INFO(sbh);
-+
-+      /* 
-+       * 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);
-+              (uint32)sbr &= ~(1 << 11);      /* mask out bit 11 */
-+      }
-+
-+      if ((si->bus == PCMCIA_BUS) || (si->bus == PCI_BUS)) {
-+#ifdef IL_BIGENDIAN
-+              dummy = R_REG(sbr);
-+              W_REG((volatile uint16 *)((uint32)sbr + 2), (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 *)((uint32)sbr + 2), (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);
-+      }
++      W_REG(sbr, v);
 +}
 +
-+/*
-+ * 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
-+ */
-+void*
-+sb_attach(uint devid, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz)
-+{
-+      sb_info_t *si;
-+
-+      /* alloc sb_info_t */
-+      if ((si = MALLOC(sizeof (sb_info_t))) == NULL) {
-+              SB_ERROR(("sb_attach: malloc failed!\n"));
-+              return (NULL);
-+      }
-+
-+      return (sb_doattach(si, devid, osh, regs, bustype, sdh, vars, varsz));
-+}
++/* 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() */
-+void*
-+sb_kattach()
++sb_t * 
++BCMINITFN(sb_kattach)()
 +{
 +      uint32 *regs;
-+      char *unused;
-+      int varsz;
 +
 +      if (ksi.curmap == NULL) {
 +              uint32 cid;
++
 +              regs = (uint32 *)REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE);
 +              cid = R_REG((uint32 *)regs);
-+              if ((cid == 0x08104712) || (cid == 0x08114712)) {
++              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 *)((uint32)regs + OFFSETOF(chipcregs_t, slow_clk_ctl));
++                      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);
 +              }
 +
-+              sb_doattach(&ksi, BCM4710_DEVICE_ID, NULL, (void*)regs,
-+                          SB_BUS, NULL, &unused, &varsz);
++              if (BCMINIT(sb_doattach)(&ksi, BCM4710_DEVICE_ID, NULL, (void*)regs,
++                      SB_BUS, NULL, NULL, NULL) == NULL) {
++                      return NULL;
++              }
 +      }
 +
-+      return &ksi;
++      return (sb_t *)&ksi;
 +}
++#endif
 +
-+static void*
-+sb_doattach(sb_info_t *si, uint devid, void *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz)
++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->pciidx = si->gpioidx = BADIDX;
++      si->sb.buscoreidx = si->gpioidx = BADIDX;
 +
 +      si->osh = osh;
 +      si->curmap = regs;
 +      si->sdh = sdh;
 +
-+      /* 4317A0 PCMCIA is no longer supported */ 
-+      if ((bustype == PCMCIA_BUS) && (R_REG((uint32 *)regs) == 0x04104317))
-+              return NULL;
-+
 +      /* 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)
@@ -5318,142 +2949,149 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +                      bustype = PCI_BUS;
 +      }
 +
-+      si->bus = bustype;
++      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;
++      }
 +
 +      /* kludge to enable the clock on the 4306 which lacks a slowclock */
-+      if (si->bus == PCI_BUS)
-+              sb_pwrctl_xtal((void*)si, XTAL|PLL, ON);
++      if (BUSTYPE(si->sb.bustype) == PCI_BUS)
++              sb_clkctl_xtal(&si->sb, XTAL|PLL, ON);
 +
-+      /* clear any previous epidiag-induced target abort */
-+      sb_taclear((void*)si);
++      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((void*)si);
++      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 (si->bus == SB_BUS)
++      if (BUSTYPE(si->sb.bustype) == SB_BUS)
 +              si->regs[origidx] = regs;
 +
-+      /* initialize the vars */
-+      if (srom_var_init(si->bus, si->curmap, osh, vars, varsz)) {
-+              SB_ERROR(("sb_attach: srom_var_init failed\n"));
-+              goto bad;
-+      }
-+      
-+      if (si->bus == PCMCIA_BUS) {
-+              w = getintvar(*vars, "regwindowsz");
-+              si->memseg = (w <= CFTABLE_REGWIN_2K) ? TRUE : FALSE;
-+      }
-+
 +      /* is core-0 a chipcommon core? */
 +      si->numcores = 1;
-+      cc = (chipcregs_t*) sb_setcoreidx((void*)si, 0);
-+      if (sb_coreid((void*)si) != SB_CC)
++      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->chip = R_REG(&cc->chipid) & CID_ID_MASK;
-+              si->chiprev = (R_REG(&cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT;
-+              si->chippkg = (R_REG(&cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT;
++              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 {
-+              /* without chip common core, get devid for PCMCIA */
-+              if (si->bus == PCMCIA_BUS)
-+                      devid = getintvar(*vars, "devid");
-+
 +              /* no chip common core -- must convert device id to chip id */
-+              if ((si->chip = sb_pcidev2chip(devid)) == 0) {
-+                      SB_ERROR(("sb_attach: unrecognized device id 0x%04x\n", devid));
-+                      goto bad;
++              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;
 +              }
-+
-+              /*
-+               * 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 (si->bus == PCMCIA_BUS) {
-+                      ASSERT(vars);
-+                      si->chiprev = getintvar(*vars, "chiprev");
-+              } else if (si->bus == PCI_BUS) {
-+                      w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_REV, sizeof (uint32));
-+                      si->chiprev = w & 0xff;
-+              } else
-+                      si->chiprev = 0;
 +      }
 +
 +      /* get chipcommon rev */
-+      si->ccrev = cc? sb_corerev((void*)si) : 0;
-+      
++      si->sb.ccrev = cc ? (int)sb_corerev(&si->sb) : NOREV;
++
 +      /* determine numcores */
-+      if ((si->ccrev == 4) || (si->ccrev >= 6))
++      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 = sb_chip2numcores(si->chip);
++              si->numcores = BCMINIT(sb_chip2numcores)(si->sb.chip);
 +
 +      /* return to original core */
-+      sb_setcoreidx((void*)si, origidx);
++      sb_setcoreidx(&si->sb, origidx);
 +
 +      /* sanity checks */
-+      ASSERT(si->chip);
-+      /* 4704A1 is chiprev 8 :-( */
-+      ASSERT((si->chiprev < 8) ||
-+             ((si->chip == BCM4704_DEVICE_ID) && ((si->chiprev == 8))));
++      ASSERT(si->sb.chip);
 +
 +      /* scan for cores */
-+      sb_scan(si);
++      BCMINIT(sb_scan)(si);
 +
-+      /* pci core is required */
-+      if (!GOODIDX(si->pciidx)) {
-+              SB_ERROR(("sb_attach: pci core not found\n"));
-+              goto bad;
++      /* 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.
++               */
++              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;
 +      }
 +
 +      /* gpio control core is required */
 +      if (!GOODIDX(si->gpioidx)) {
-+              SB_ERROR(("sb_attach: gpio control core not found\n"));
-+              goto bad;
++              SB_ERROR(("sb_doattach: gpio control core not found\n"));
++              return NULL;
 +      }
 +
 +      /* get boardtype and boardrev */
-+      switch (si->bus) {
++      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->boardvendor = w & 0xffff;
-+              si->boardtype = (w >> 16) & 0xffff;
-+              break;
-+
-+      case PCMCIA_BUS:
-+      case SDIO_BUS:
-+              si->boardvendor = getintvar(*vars, "manfid");
-+              si->boardtype = getintvar(*vars, "prodid");
++              si->sb.boardvendor = w & 0xffff;
++              si->sb.boardtype = (w >> 16) & 0xffff;
 +              break;
 +
 +      case SB_BUS:
-+              si->boardvendor = VENDOR_BROADCOM;
-+              si->boardtype = 0xffff;
++      case JTAG_BUS:
++              si->sb.boardvendor = VENDOR_BROADCOM;
++              if ((si->sb.boardtype = getintvar(NULL, "boardtype")) == 0)
++                      si->sb.boardtype = 0xffff;
 +              break;
 +      }
 +
-+      if (si->boardtype == 0) {
-+              SB_ERROR(("sb_attach: unknown board type\n"));
-+              ASSERT(si->boardtype);
++      if (si->sb.boardtype == 0) {
++              SB_ERROR(("sb_doattach: unknown board type\n"));
++              ASSERT(si->sb.boardtype);
 +      }
 +
-+      return ((void*)si);
++      /* 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);
++      }
 +
-+bad:
-+      MFREE(si, sizeof (sb_info_t));
-+      return (NULL);
++
++      return (si);
 +}
 +
 +uint
-+sb_coreid(void *sbh)
++sb_coreid(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -5461,11 +3099,11 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      si = SB_INFO(sbh);
 +      sb = REGS2SB(si->curmap);
 +
-+      return ((R_SBREG(sbh, &(sb)->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
++      return ((R_SBREG(si, &(sb)->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
 +}
 +
 +uint
-+sb_coreidx(void *sbh)
++sb_coreidx(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +
@@ -5475,46 +3113,41 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* return current index of core */
 +static uint
-+_sb_coreidx(void *sbh)
++_sb_coreidx(sb_info_t *si)
 +{
-+      sb_info_t *si;
 +      sbconfig_t *sb;
 +      uint32 sbaddr = 0;
 +
-+      si = SB_INFO(sbh);
 +      ASSERT(si);
 +
-+      switch (si->bus) {
++      switch (BUSTYPE(si->sb.bustype)) {
 +      case SB_BUS:
 +              sb = REGS2SB(si->curmap);
-+              sbaddr = sb_base(R_SBREG(sbh, &sb->sbadmatch0));
++              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;
-+
-+              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;
++#ifdef BCMJTAG
++      case JTAG_BUS:
++              sbaddr = (uint32)si->curmap;
 +              break;
-+      }
++#endif        /* BCMJTAG */
++
 +      default:
 +              ASSERT(0);
 +      }
 +
-+      ASSERT(GOODCOREADDR(sbaddr));
-+      return ((sbaddr - SB_ENUM_BASE)/SB_CORE_SIZE);
++      if (!GOODCOREADDR(sbaddr))
++              return BADIDX;
++
++      return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE);
 +}
 +
 +uint
-+sb_corevendor(void *sbh)
++sb_corevendor(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -5522,26 +3155,37 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      si = SB_INFO(sbh);
 +      sb = REGS2SB(si->curmap);
 +
-+      return ((R_SBREG(sbh, &(sb)->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
++      return ((R_SBREG(si, &(sb)->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
 +}
 +
 +uint
-+sb_corerev(void *sbh)
++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;
 +
-+      return (R_SBREG(sbh, &(sb)->sbidhigh) & SBIDH_RC_MASK);
++      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(void *sbh, uint32 mask, uint32 val)
++sb_coreflags(sb_t *sbh, uint32 mask, uint32 val)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -5555,17 +3199,17 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +      /* mask and set */
 +      if (mask || val) {
-+              w = (R_SBREG(sbh, &sb->sbtmstatelow) & ~mask) | val;
-+              W_SBREG(sbh, &sb->sbtmstatelow, w);
++              w = (R_SBREG(si, &sb->sbtmstatelow) & ~mask) | val;
++              W_SBREG(si, &sb->sbtmstatelow, w);
 +      }
 +
 +      /* return the new value */
-+      return (R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_ALLOW);
++      return (R_SBREG(si, &sb->sbtmstatelow) & SBTML_ALLOW);
 +}
 +
 +/* set/clear sbtmstatehigh core-specific flags */
 +uint32
-+sb_coreflagshi(void *sbh, uint32 mask, uint32 val)
++sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -5579,16 +3223,45 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +      /* mask and set */
 +      if (mask || val) {
-+              w = (R_SBREG(sbh, &sb->sbtmstatehigh) & ~mask) | val;
-+              W_SBREG(sbh, &sb->sbtmstatehigh, w);
++              w = (R_SBREG(si, &sb->sbtmstatehigh) & ~mask) | val;
++              W_SBREG(si, &sb->sbtmstatehigh, w);
 +      }
 +
 +      /* return the new value */
-+      return (R_SBREG(sbh, &sb->sbtmstatehigh) & SBTMH_FL_MASK);
++      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(void *sbh)
++sb_iscoreup(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -5596,7 +3269,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      si = SB_INFO(sbh);
 +      sb = REGS2SB(si->curmap);
 +
-+      return ((R_SBREG(sbh, &(sb)->sbtmstatelow) & (SBTML_RESET | SBTML_REJ | SBTML_CLK)) == SBTML_CLK);
++      return ((R_SBREG(si, &(sb)->sbtmstatelow) & (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK);
 +}
 +
 +/*
@@ -5604,9 +3277,8 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 + * switch back to the original core, and return the new value.
 + */
 +static uint
-+sb_corereg(void *sbh, uint coreidx, uint regoff, uint mask, uint val)
++sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val)
 +{
-+      sb_info_t *si;
 +      uint origidx;
 +      uint32 *r;
 +      uint w;
@@ -5616,20 +3288,19 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      ASSERT(regoff < SB_CORE_SIZE);
 +      ASSERT((val & ~mask) == 0);
 +
-+      si = SB_INFO(sbh);
++      INTR_OFF(si, intr_val);
 +
 +      /* save current core index */
-+      origidx = sb_coreidx(sbh);
++      origidx = sb_coreidx(&si->sb);
 +
 +      /* switch core */
-+      INTR_OFF(si, intr_val);
-+      r = (uint32*) ((uint) sb_setcoreidx(sbh, coreidx) + regoff);
++      r = (uint32*) ((uchar*) sb_setcoreidx(&si->sb, coreidx) + regoff);
 +
 +      /* mask and set */
 +      if (mask || val) {
 +              if (regoff >= SBCONFIGOFF) {
-+                      w = (R_SBREG(sbh, r) & ~mask) | val;
-+                      W_SBREG(sbh, r, w);
++                      w = (R_SBREG(si, r) & ~mask) | val;
++                      W_SBREG(si, r, w);
 +              } else {
 +                      w = (R_REG(r) & ~mask) | val;
 +                      W_REG(r, w);
@@ -5637,50 +3308,78 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      }
 +
 +      /* readback */
-+      w = R_SBREG(sbh, r);
++      if (regoff >= SBCONFIGOFF)
++              w = R_SBREG(si, r);
++      else
++              w = R_REG(r);
 +
 +      /* restore core index */
 +      if (origidx != coreidx)
-+              sb_setcoreidx(sbh, origidx);
++              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)
++
++
 +/* scan the sb enumerated space to identify all cores */
 +static void
-+sb_scan(sb_info_t *si)
++BCMINITFN(sb_scan)(sb_info_t *si)
 +{
-+      void *sbh;
 +      uint origidx;
 +      uint i;
++      bool pci;
++      uint pciidx;
++      uint pcirev;
++
 +
-+      sbh = (void*) si;
 +
 +      /* numcores should already be set */
 +      ASSERT((si->numcores > 0) && (si->numcores <= SB_MAXCORES));
 +
 +      /* save current core index */
-+      origidx = sb_coreidx(sbh);
++      origidx = sb_coreidx(&si->sb);
 +
-+      si->pciidx = si->gpioidx = BADIDX;
++      si->sb.buscorerev = NOREV;
++      si->sb.buscoreidx = BADIDX;
 +
-+      for (i = 0; i < si->numcores; i++) {
-+              sb_setcoreidx(sbh, i);
-+              si->coreid[i] = sb_coreid(sbh);
++      si->gpioidx = BADIDX;
 +
-+              if (si->coreid[i] == SB_CC)
-+                      si->ccrev = sb_corerev(sbh);
++      pci = FALSE;
++      pcirev = NOREV;
++      pciidx = BADIDX;
 +
-+              else if (si->coreid[i] == SB_PCI) {
-+                      si->pciidx = i;
-+                      si->pcirev = sb_corerev(sbh);
++      for (i = 0; i < si->numcores; i++) {
++              sb_setcoreidx(&si->sb, i);
++              si->coreid[i] = sb_coreid(&si->sb);
 +
-+              }else if (si->coreid[i] == SB_PCMCIA){
-+                      si->pcmciaidx = i;
-+                      si->pcmciarev = sb_corerev(sbh);
++              if (si->coreid[i] == SB_PCI) { 
++                      pciidx = i;
++                      pcirev = sb_corerev(&si->sb);
++                      pci = TRUE;
 +              }
 +      }
++      if (pci) {
++              si->sb.buscoretype = SB_PCI;
++              si->sb.buscorerev = pcirev; 
++              si->sb.buscoreidx = pciidx; 
++      }
 +
 +      /*
 +       * Find the gpio "controlling core" type and index.
@@ -5689,24 +3388,25 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +       * - 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(sbh, SB_CC, 0))) {
-+              si->gpioidx = sb_findcoreidx(sbh, SB_CC, 0);
++      if (GOODIDX(sb_findcoreidx(si, SB_CC, 0))) {
++              si->gpioidx = sb_findcoreidx(si, SB_CC, 0);
 +              si->gpioid = SB_CC;
-+      } else if (GOODIDX(si->pciidx) && (si->pcirev >= 2)) {
-+              si->gpioidx = si->pciidx;
++      } else if (PCI(si) && (si->sb.buscorerev >= 2)) {
++              si->gpioidx = si->sb.buscoreidx;
 +              si->gpioid = SB_PCI;
-+      } else if (sb_findcoreidx(sbh, SB_EXTIF, 0)) {
-+              si->gpioidx = sb_findcoreidx(sbh, SB_EXTIF, 0);
++      } 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(sbh, origidx);
++      sb_setcoreidx(&si->sb, origidx);
 +}
 +
 +/* may be called with core in reset */
 +void
-+sb_detach(void *sbh)
++sb_detach(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      uint idx;
@@ -5716,26 +3416,27 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      if (si == NULL)
 +              return;
 +
-+      if (si->bus == SB_BUS)
++      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;
 +                      }
 +
-+      MFREE(si, sizeof (sb_info_t));
++      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
-+sb_pcidev2chip(uint pcidev)
++BCMINITFN(sb_pcidev2chip)(uint pcidev)
 +{
 +      if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID))
 +              return (BCM4710_DEVICE_ID);
-+      if ((pcidev >= BCM4610_DEVICE_ID) && (pcidev <= BCM4610_USB_ID))
-+              return (BCM4610_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)
@@ -5746,23 +3447,19 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* convert chip number to number of i/o cores */
 +static uint
-+sb_chip2numcores(uint chip)
++BCMINITFN(sb_chip2numcores)(uint chip)
 +{
-+      if (chip == 0x4710)
++      if (chip == BCM4710_DEVICE_ID)
 +              return (9);
-+      if (chip == 0x4610)
-+              return (9);
-+      if (chip == 0x4402)
++      if (chip == BCM4402_DEVICE_ID)
 +              return (3);
-+      if ((chip == 0x4307) || (chip == 0x4301))
++      if ((chip == BCM4301_DEVICE_ID) || (chip == BCM4307_DEVICE_ID))
 +              return (5);
-+      if (chip == 0x4310)
-+              return (8);
-+      if (chip == 0x4306)     /* < 4306c0 */
++      if (chip == BCM4306_DEVICE_ID)  /* < 4306c0 */
 +              return (6);
-+      if (chip == 0x4704)
++      if (chip == BCM4704_DEVICE_ID)
 +              return (9);
-+      if (chip == 0x5365)
++      if (chip == BCM5365_DEVICE_ID)
 +              return (7);
 +
 +      SB_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", chip));
@@ -5772,13 +3469,11 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* return index of coreid or BADIDX if not found */
 +static uint
-+sb_findcoreidx(void *sbh, uint coreid, uint coreunit)
++sb_findcoreidx( sb_info_t *si, uint coreid, uint coreunit)
 +{
-+      sb_info_t *si;
 +      uint found;
 +      uint i;
 +
-+      si = SB_INFO(sbh);
 +      found = 0;
 +
 +      for (i = 0; i < si->numcores; i++)
@@ -5791,28 +3486,31 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      return (BADIDX);
 +}
 +
-+/* change logical "focus" to the indiciated core */
++/* 
++ * 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(void *sbh, uint coreidx)
++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->imf == NULL) || !(*si->imf)(si->imfarg));
++      ASSERT((si->intrsenabled_fn == NULL) || !(*(si)->intrsenabled_fn)((si)->intr_arg));
 +
 +      sbaddr = SB_ENUM_BASE + (coreidx * SB_CORE_SIZE);
 +
-+      switch (si->bus) {
++      switch (BUSTYPE(si->sb.bustype)) {
 +      case SB_BUS:
 +              /* map new one */
 +              if (!si->regs[coreidx]) {
@@ -5827,14 +3525,16 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              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);
++#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;
@@ -5842,16 +3542,19 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      return (si->curmap);
 +}
 +
-+/* change logical "focus" to the indicated core */
++/* 
++ * 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(void *sbh, uint coreid, uint coreunit)
++sb_setcore(sb_t *sbh, uint coreid, uint coreunit)
 +{
 +      sb_info_t *si;
 +      uint idx;
 +
 +      si = SB_INFO(sbh);
-+
-+      idx = sb_findcoreidx(sbh, coreid, coreunit);
++      idx = sb_findcoreidx(si, coreid, coreunit);
 +      if (!GOODIDX(idx))
 +              return (NULL);
 +
@@ -5860,125 +3563,145 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* return chip number */
 +uint
-+sb_chip(void *sbh)
++BCMINITFN(sb_chip)(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +
 +      si = SB_INFO(sbh);
-+      return (si->chip);
++      return (si->sb.chip);
 +}
 +
 +/* return chip revision number */
 +uint
-+sb_chiprev(void *sbh)
++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->chiprev);
++      return (si->sb.ccrev);
 +}
 +
 +/* return chip package option */
 +uint
-+sb_chippkg(void *sbh)
++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 (si->chippkg);
++
++      return (PCI(si) && (si->sb.buscorerev <= 10));
 +}
 +
 +/* return board vendor id */
 +uint
-+sb_boardvendor(void *sbh)
++BCMINITFN(sb_boardvendor)(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +
 +      si = SB_INFO(sbh);
-+      return (si->boardvendor);
++      return (si->sb.boardvendor);
 +}
 +
 +/* return boardtype */
 +uint
-+sb_boardtype(void *sbh)
++BCMINITFN(sb_boardtype)(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      char *var;
 +
 +      si = SB_INFO(sbh);
 +
-+      if (si->bus == SB_BUS && si->boardtype == 0xffff) {
++      if (BUSTYPE(si->sb.bustype) == SB_BUS && si->sb.boardtype == 0xffff) {
 +              /* boardtype format is a hex string */
-+              si->boardtype = getintvar(NULL, "boardtype");
++              si->sb.boardtype = getintvar(NULL, "boardtype");
 +
 +              /* backward compatibility for older boardtype string format */
-+              if ((si->boardtype == 0) && (var = getvar(NULL, "boardtype"))) {
++              if ((si->sb.boardtype == 0) && (var = getvar(NULL, "boardtype"))) {
 +                      if (!strcmp(var, "bcm94710dev"))
-+                              si->boardtype = BCM94710D_BOARD;
++                              si->sb.boardtype = BCM94710D_BOARD;
 +                      else if (!strcmp(var, "bcm94710ap"))
-+                              si->boardtype = BCM94710AP_BOARD;
-+                      else if (!strcmp(var, "bcm94310u"))
-+                              si->boardtype = BCM94310U_BOARD;
-+                      else if (!strcmp(var, "bu4711"))
-+                              si->boardtype = BU4711_BOARD;
++                              si->sb.boardtype = BCM94710AP_BOARD;
 +                      else if (!strcmp(var, "bu4710"))
-+                              si->boardtype = BU4710_BOARD;
++                              si->sb.boardtype = BU4710_BOARD;
 +                      else if (!strcmp(var, "bcm94702mn"))
-+                              si->boardtype = BCM94702MN_BOARD;
++                              si->sb.boardtype = BCM94702MN_BOARD;
 +                      else if (!strcmp(var, "bcm94710r1"))
-+                              si->boardtype = BCM94710R1_BOARD;
++                              si->sb.boardtype = BCM94710R1_BOARD;
 +                      else if (!strcmp(var, "bcm94710r4"))
-+                              si->boardtype = BCM94710R4_BOARD;
++                              si->sb.boardtype = BCM94710R4_BOARD;
 +                      else if (!strcmp(var, "bcm94702cpci"))
-+                              si->boardtype = BCM94702CPCI_BOARD;
++                              si->sb.boardtype = BCM94702CPCI_BOARD;
 +                      else if (!strcmp(var, "bcm95380_rr"))
-+                              si->boardtype = BCM95380RR_BOARD; 
++                              si->sb.boardtype = BCM95380RR_BOARD;
 +              }
 +      }
 +
-+      return (si->boardtype);
++      return (si->sb.boardtype);
 +}
 +
-+/* return board bus style */
++/* return bus type of sbh device */
 +uint
-+sb_boardstyle(void *sbh)
++sb_bus(sb_t *sbh)
 +{
 +      sb_info_t *si;
-+      uint16 w;
 +
 +      si = SB_INFO(sbh);
++      return (si->sb.bustype);
++}
 +
-+      if (si->bus == PCMCIA_BUS)
-+              return (BOARDSTYLE_PCMCIA);
-+
-+      if (si->bus == SB_BUS)
-+              return (BOARDSTYLE_SOC);
-+
-+      /* bus is PCI */
-+
-+      if (OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_CIS, sizeof (uint32)) != 0)
-+              return (BOARDSTYLE_CARDBUS);
++/* return bus core type */
++uint
++sb_buscoretype(sb_t *sbh)
++{
++      sb_info_t *si;
 +
-+      if ((srom_read(si->bus, si->curmap, si->osh, (SPROM_SIZE - 1) * 2, 2, &w) == 0) &&
-+          (w == 0x0313))
-+              return (BOARDSTYLE_CARDBUS);
++      si = SB_INFO(sbh);
 +
-+      return (BOARDSTYLE_PCI);
++      return (si->sb.buscoretype);
 +}
 +
-+/* return boolean if sbh device is in pci hostmode or client mode */
++/* return bus core revision */
 +uint
-+sb_bus(void *sbh)
++sb_buscorerev(sb_t *sbh)
 +{
 +      sb_info_t *si;
-+
 +      si = SB_INFO(sbh);
-+      return (si->bus);
++
++      return (si->sb.buscorerev);
 +}
 +
 +/* return list of found cores */
 +uint
-+sb_corelist(void *sbh, uint coreid[])
++sb_corelist(sb_t *sbh, uint coreid[])
 +{
 +      sb_info_t *si;
 +
@@ -5990,7 +3713,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* return current register mapping */
 +void *
-+sb_coreregs(void *sbh)
++sb_coreregs(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +
@@ -6000,49 +3723,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      return (si->curmap);
 +}
 +
-+/* Check if a target abort has happened and clear it */
-+bool
-+sb_taclear(void *sbh)
-+{
-+      sb_info_t *si;
-+      bool rc = FALSE;
-+      sbconfig_t *sb;
-+
-+      si = SB_INFO(sbh);
-+      sb = REGS2SB(si->curmap);
-+
-+      if (si->bus == PCI_BUS) {
-+              uint32 stcmd;
-+
-+              stcmd = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_CMD, sizeof(stcmd));
-+              rc = (stcmd & 0x08000000) != 0;
-+
-+              if (rc) {
-+                      /* Target abort bit is set, clear it */
-+                      OSL_PCI_WRITE_CONFIG(si->osh, PCI_CFG_CMD, sizeof(stcmd), stcmd);
-+              }
-+      } else if (si->bus == PCMCIA_BUS) {
-+              rc = FALSE;
-+      }
-+      else if (si->bus == SDIO_BUS) {
-+              /* due to 4317 A0 HW bug, sdio core wedged on target abort, 
-+                 just clear SBSErr bit blindly */
-+              if (0x0 != R_SBREG(sbh, &sb->sbtmerrlog)) {
-+                      SB_ERROR(("SDIO target abort, clean it"));
-+                      W_SBREG(sbh, &sb->sbtmstatehigh, 0);
-+              }
-+              rc = FALSE;
-+      }
-+
-+      return (rc);
-+}
 +
 +/* do buffered registers update */
 +void
-+sb_commit(void *sbh)
++sb_commit(sb_t *sbh)
 +{
 +      sb_info_t *si;
-+      sbpciregs_t *pciregs;
 +      uint origidx;
 +      uint intr_val = 0;
 +
@@ -6052,12 +3738,22 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      ASSERT(GOODIDX(origidx));
 +
 +      INTR_OFF(si, intr_val);
-+      /* switch over to pci core */
-+      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);
++      /* 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);
@@ -6066,7 +3762,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* reset and re-enable a core */
 +void
-+sb_core_reset(void *sbh, uint32 bits)
++sb_core_reset(sb_t *sbh, uint32 bits)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -6086,69 +3782,135 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +       */
 +
 +      /* set reset while enabling the clock and forcing them on throughout the core */
-+      W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits));
-+      dummy = R_SBREG(sbh, &sb->sbtmstatelow);
-+
-+      if (sb_coreid(sbh) == SB_ILINE100) {
-+              bcm_mdelay(50);
-+      } else {
-+              OSL_DELAY(1);
-+      }
++      W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits));
++      dummy = R_SBREG(si, &sb->sbtmstatelow);
++      OSL_DELAY(1);
 +
-+      if (R_SBREG(sbh, &sb->sbtmstatehigh) & SBTMH_SERR) {
-+              W_SBREG(sbh, &sb->sbtmstatehigh, 0);
++      if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_SERR) {
++              W_SBREG(si, &sb->sbtmstatehigh, 0);
 +      }
-+      if ((dummy = R_SBREG(sbh, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
-+              AND_SBREG(sbh, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
++      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(sbh, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | bits));
-+      dummy = R_SBREG(sbh, &sb->sbtmstatelow);
++      W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | bits));
++      dummy = R_SBREG(si, &sb->sbtmstatelow);
 +      OSL_DELAY(1);
 +
 +      /* leave clock enabled */
-+      W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_CLK | bits));
-+      dummy = R_SBREG(sbh, &sb->sbtmstatelow);
++      W_SBREG(si, &sb->sbtmstatelow, (SBTML_CLK | bits));
++      dummy = R_SBREG(si, &sb->sbtmstatelow);
 +      OSL_DELAY(1);
 +}
 +
 +void
-+sb_core_tofixup(void *sbh)
++sb_core_tofixup(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
 +
 +      si = SB_INFO(sbh);
 +
-+      if (si->pcirev >= 5)
++      if ( (BUSTYPE(si->sb.bustype) != PCI_BUS) || (PCI(si) && (si->sb.buscorerev >= 5)) )
 +              return;
 +
 +      ASSERT(GOODREGS(si->curmap));
 +      sb = REGS2SB(si->curmap);
 +
-+      if (si->bus == SB_BUS) {
-+              SET_SBREG(sbh, &sb->sbimconfiglow,
++      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(sbh, &sb->sbimconfiglow,
++                      SET_SBREG(si, &sb->sbimconfiglow,
 +                                SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
 +                                (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
 +              } else {
-+                      SET_SBREG(sbh, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0);
++                      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
++ *
++ * 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 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(void *sbh, uint32 bits)
++sb_core_disable(sb_t *sbh, uint32 bits)
 +{
 +      sb_info_t *si;
 +      volatile uint32 dummy;
++      uint32 rej;
 +      sbconfig_t *sb;
 +
 +      si = SB_INFO(sbh);
@@ -6156,83 +3918,72 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      ASSERT(GOODREGS(si->curmap));
 +      sb = REGS2SB(si->curmap);
 +
-+      /* must return if core is already in reset */
-+      if (R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_RESET)
++      /* if core is already in reset, just return */
++      if (R_SBREG(si, &sb->sbtmstatelow) & SBTML_RESET)
 +              return;
 +
-+      /* put into reset and return if clocks are not enabled */
-+      if ((R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_CLK) == 0)
-+              goto disable;
++      /* 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);
 +
-+      /* set the reject bit */
-+      W_SBREG(sbh, &sb->sbtmstatelow, (SBTML_CLK | SBTML_REJ));
++      /* if clocks are not enabled, put into reset and return */
++      if ((R_SBREG(si, &sb->sbtmstatelow) & SBTML_CLK) == 0)
++              goto disable;
 +
-+      /* spin until reject is set */
-+      while ((R_SBREG(sbh, &sb->sbtmstatelow) & SBTML_REJ) == 0)
-+              OSL_DELAY(1);
++      /* 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);
 +
-+      /* spin until sbtmstatehigh.busy is clear */
-+      while (R_SBREG(sbh, &sb->sbtmstatehigh) & SBTMH_BUSY)
++      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(sbh, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | SBTML_REJ | SBTML_RESET));
-+      dummy = R_SBREG(sbh, &sb->sbtmstatelow);
++      W_SBREG(si, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | rej | SBTML_RESET));
++      dummy = R_SBREG(si, &sb->sbtmstatelow);
 +      OSL_DELAY(10);
 +
-+ disable:
++      /* 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(sbh, &sb->sbtmstatelow, (bits | SBTML_REJ | SBTML_RESET));
++      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(void *sbh, uint ticks)
++sb_watchdog(sb_t *sbh, uint ticks)
 +{
 +      sb_info_t *si = SB_INFO(sbh);
 +
 +      /* instant NMI */
 +      switch (si->gpioid) {
 +      case SB_CC:
-+              sb_corereg(sbh, si->gpioidx, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
++              sb_corereg(si, 0, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
 +              break;
 +      case SB_EXTIF:
-+              sb_corereg(sbh, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks);
++              sb_corereg(si, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks);
 +              break;
 +      }
 +}
 +
-+/* initialize the pcmcia core */
-+void
-+sb_pcmcia_init(void *sbh)
-+{
-+      sb_info_t *si;
-+      uint8 cor;
-+
-+      si = SB_INFO(sbh);
-+
-+      /* enable d11 mac interrupts */
-+      if (si->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
-+ * and get appropriate dma offset value.
 + * coremask is the bitvec of cores by index to be enabled.
 + */
 +void
-+sb_pci_setup(void *sbh, uint32 *dmaoffset, uint coremask)
++sb_pci_setup(sb_t *sbh, uint coremask)
 +{
 +      sb_info_t *si;
 +      sbconfig_t *sb;
@@ -6243,14 +3994,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +      si = SB_INFO(sbh);
 +
-+      if (dmaoffset)
-+              *dmaoffset = 0;
-+
 +      /* if not pci bus, we're done */
-+      if (si->bus != PCI_BUS)
++      if (BUSTYPE(si->sb.bustype) != PCI_BUS)
 +              return;
 +
-+      ASSERT(si->pciidx);
++      ASSERT(PCI(si));
++      ASSERT(si->sb.buscoreidx != BADIDX);
 +
 +      /* get current core index */
 +      idx = si->curidx;
@@ -6258,41 +4007,39 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      /* we interrupt on this backplane flag number */
 +      ASSERT(GOODREGS(si->curmap));
 +      sb = REGS2SB(si->curmap);
-+      sbflag = R_SBREG(sbh, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
++      sbflag = R_SBREG(si, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
 +
 +      /* switch over to pci core */
-+      pciregs = (sbpciregs_t*) sb_setcoreidx(sbh, si->pciidx);
++      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 (si->pcirev < 6) {
-+              /* set sbintvec bit for our flag number */
-+              OR_SBREG(sbh, &sb->sbintvec, (1 << sbflag));
-+      } else {
++      if ((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));
 +      }
 +
-+      /* enable prefetch and bursts for sonics-to-pci translation 2 */
-+      OR_REG(&pciregs->sbtopci2, (SBTOPCI_PREF|SBTOPCI_BURST));
-+
-+      if (si->pcirev < 5) {
-+              SET_SBREG(sbh, &sb->sbimconfiglow, SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
-+                      (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
-+              sb_commit(sbh);
++      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);
++              }
 +      }
 +
 +      /* switch back to previous core */
 +      sb_setcoreidx(sbh, idx);
-+
-+      /* use large sb pci dma window */
-+      if (dmaoffset)
-+              *dmaoffset = SB_PCI_DMA;
 +}
 +
 +uint32
@@ -6345,7 +4092,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* return the core-type instantiation # of the current core */
 +uint
-+sb_coreunit(void *sbh)
++sb_coreunit(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      uint idx;
@@ -6392,7 +4139,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      n1 = n & CN_N1_MASK;
 +      n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
 +
-+      if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE4)) {
++      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) {
@@ -6400,12 +4155,17 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              n2 += CC_T2_BIAS;
 +              ASSERT((n1 >= 2) && (n1 <= 7));
 +              ASSERT((n2 >= 5) && (n2 <= 23));
-+      } else if (pll_type == PLL_TYPE3) {
++      } else if (pll_type == PLL_TYPE5) {
 +              return (100000000);
 +      } else
-+              ASSERT((pll_type >= PLL_TYPE1) && (pll_type <= PLL_TYPE4));
-+
-+      clock = CC_CLOCK_BASE * n1 * n2;
++              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;
@@ -6415,9 +4175,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
 +      mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
 +
-+      if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE4)) {
++      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)
++              if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
 +                      m2 += CC_F5_BIAS;
 +              else
 +                      m2 = factor6(m2);
@@ -6454,7 +4217,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* returns the current speed the SB is running at */
 +uint32
-+sb_clock(void *sbh)
++sb_clock(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      extifregs_t *eir;
@@ -6477,14 +4240,35 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      } 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);
-+              m = R_REG(&cc->clockcontrol_sb);
++              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;
 +      }
 +
-+      /* calculate rate */
-+      rate = sb_clock_rate(pll_type, n, m);
++      // 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);
@@ -6496,7 +4280,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* change logical "focus" to the gpio core for optimized access */
 +void*
-+sb_gpiosetcore(void *sbh)
++sb_gpiosetcore(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +
@@ -6507,7 +4291,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +/* mask&set gpiocontrol bits */
 +uint32
-+sb_gpiocontrol(void *sbh, uint32 mask, uint32 val)
++sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
 +{
 +      sb_info_t *si;
 +      uint regoff;
@@ -6515,6 +4299,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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);
@@ -6528,12 +4321,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              return (0);
 +      }
 +
-+      return (sb_corereg(sbh, si->gpioidx, regoff, mask, val));
++      return (sb_corereg(si, si->gpioidx, regoff, mask, val));
 +}
 +
 +/* mask&set gpio output enable bits */
 +uint32
-+sb_gpioouten(void *sbh, uint32 mask, uint32 val)
++sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
 +{
 +      sb_info_t *si;
 +      uint regoff;
@@ -6541,6 +4334,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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);
@@ -6555,12 +4357,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              break;
 +      }
 +
-+      return (sb_corereg(sbh, si->gpioidx, regoff, mask, val));
++      return (sb_corereg(si, si->gpioidx, regoff, mask, val));
 +}
 +
 +/* mask&set gpio output bits */
 +uint32
-+sb_gpioout(void *sbh, uint32 mask, uint32 val)
++sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
 +{
 +      sb_info_t *si;
 +      uint regoff;
@@ -6568,6 +4370,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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);
@@ -6582,12 +4393,78 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              break;
 +      }
 +
-+      return (sb_corereg(sbh, si->gpioidx, regoff, mask, val));
++      return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* reserve one gpio */
++uint32
++sb_gpioreserve(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
++{
++      sb_info_t *si;
++
++      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;
++      }
++
++      /* already reserved */
++      if (sb_gpioreservation & gpio_bitmask)
++              return -1;
++      /* set reservation */
++      sb_gpioreservation |= gpio_bitmask;
++
++      return sb_gpioreservation;
++}
++
++/* release one gpio */
++/* 
++ * 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)
++{
++      sb_info_t *si;
++
++      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;
++      }
++      
++      /* already released */
++      if (!(sb_gpioreservation & gpio_bitmask))
++              return -1;
++
++      /* clear reservation */
++      sb_gpioreservation &= ~gpio_bitmask;
++
++      return sb_gpioreservation;
 +}
 +
 +/* return the current gpioin register value */
 +uint32
-+sb_gpioin(void *sbh)
++sb_gpioin(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      uint regoff;
@@ -6609,12 +4486,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              break;
 +      }
 +
-+      return (sb_corereg(sbh, si->gpioidx, regoff, 0, 0));
++      return (sb_corereg(si, si->gpioidx, regoff, 0, 0));
 +}
 +
 +/* mask&set gpio interrupt polarity bits */
 +uint32
-+sb_gpiointpolarity(void *sbh, uint32 mask, uint32 val)
++sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
 +{
 +      sb_info_t *si;
 +      uint regoff;
@@ -6622,6 +4499,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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, gpiointpolarity);
@@ -6637,12 +4523,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              break;
 +      }
 +
-+      return (sb_corereg(sbh, si->gpioidx, regoff, mask, val));
++      return (sb_corereg(si, si->gpioidx, regoff, mask, val));
 +}
 +
 +/* mask&set gpio interrupt mask bits */
 +uint32
-+sb_gpiointmask(void *sbh, uint32 mask, uint32 val)
++sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
 +{
 +      sb_info_t *si;
 +      uint regoff;
@@ -6650,6 +4536,15 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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, gpiointmask);
@@ -6665,71 +4560,180 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +              break;
 +      }
 +
-+      return (sb_corereg(sbh, si->gpioidx, regoff, mask, val));
++      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));
++}
++
++/* mask&set gpio timer val */
++uint32 
++sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 gpiotimerval)
++{
++      sb_info_t *si;
++      si = SB_INFO(sbh);
++
++      if (si->sb.ccrev < 16)
++              return -1;
++
++      return(sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
 +}
 +
 +
-+/*
-+ * Return the slowclock min or max frequency.
-+ * Three sources of SLOW CLOCK:
-+ *    1. On Chip LPO         -     32khz or 160khz
-+ *    2. On Chip Xtal OSC    -     20mhz/4*(divider+1) 
-+ *    3. External PCI clock  -     66mhz/4*(divider+1)
-+ */
++/* return the slow clock source - LPO, XTAL, or PCI */
 +static uint
-+slowfreq(void *sbh, bool max)
++sb_slowclk_src(sb_info_t *si)
++{
++      chipcregs_t *cc;
++
++
++      ASSERT(sb_coreid(&si->sb) == SB_CC);
++
++      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);
++}
++
++/* return the ILP (slowclock) min or max frequency */
++static uint
++sb_slowclk_freq(sb_info_t *si, bool max)
 +{
-+      sb_info_t *si;
 +      chipcregs_t *cc;
-+      uint32 v;
++      uint32 slowclk;
 +      uint div;
 +
++
++      ASSERT(sb_coreid(&si->sb) == SB_CC);
++
++      cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
++
++      /* shouldn't be here unless we've established the chip has dynamic clk control */
++      ASSERT(R_REG(&cc->capabilities) & CAP_PWR_CTL);
++
++      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);
++}
++
++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;
++
++      pll_delay = PLL_DELAY;
++
++      /* 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;
++
++      /* Starting with 4318 it is ILP that is used for the delays */
++      slowmaxfreq = sb_slowclk_freq(si, (si->sb.ccrev >= 10) ? FALSE : TRUE);
++
++      pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
++      fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
++
++      cc = (chipcregs_t *)chipcregs;
++      W_REG(&cc->pll_on_delay, pll_on_delay);
++      W_REG(&cc->fref_sel_delay, fref_sel_delay);
++}
++
++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);
 +
-+      ASSERT(sb_coreid(sbh) == SB_CC);
++      /* chipcommon cores prior to rev6 don't support slowclkcontrol */
++      if (si->sb.ccrev < 6)
++              return 1;
 +
-+      cc = (chipcregs_t*) sb_setcoreidx(sbh, si->curidx);
++      /* chipcommon cores rev10 are a whole new ball game */
++      if (si->sb.ccrev >= 10)
++              return 1;
 +
-+      /* shouldn't be here unless we've established the chip has dynamic power control */
-+      ASSERT(R_REG(&cc->capabilities) & CAP_PWR_CTL);
++      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;
++      }
 +
-+      if (si->ccrev < 6) {
-+              v = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32));
++      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);
 +
-+              if (v & PCI_CFG_GPIO_SCS)
-+                      return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64));
-+              else
-+                      return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32));
-+      } else {
-+              v = R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK;
-+              div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHF) + 1);
-+              if (v == SCC_SS_LPO)
-+                      return (max? LPOMAXFREQ : LPOMINFREQ);
-+              else if (v == SCC_SS_XTAL)
-+                      return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div));
-+              else if (v == SCC_SS_PCI)
-+                      return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div));
-+              else
-+                      ASSERT(0);
-+      }
-+      return (0);
++done:
++      sb_setcoreidx(sbh, origidx);
++      INTR_RESTORE(si, intr_val);
++      return err;
 +}
 +
 +/* initialize power control delay registers */
-+void
-+sb_pwrctl_init(void *sbh)
++void sb_clkctl_init(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      uint origidx;
 +      chipcregs_t *cc;
-+      uint slowmaxfreq;
-+      uint pll_on_delay, fref_sel_delay;
 +
 +      si = SB_INFO(sbh);
 +
-+      if (si->bus == SB_BUS)
-+              return;
-+
 +      origidx = si->curidx;
 +
 +      if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
@@ -6738,24 +4742,22 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
 +              goto done;
 +
-+      slowmaxfreq = slowfreq(sbh, TRUE);
-+      pll_on_delay = ((slowmaxfreq * PLL_DELAY) + 999999) / 1000000;
-+      fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
-+
-+      W_REG(&cc->pll_on_delay, pll_on_delay);
-+      W_REG(&cc->fref_sel_delay, fref_sel_delay);
-+
-+      /* 4317pc does not work with SlowClock less than 5Mhz */
-+      if (si->bus == PCMCIA_BUS)
-+              SET_REG(&cc->slow_clk_ctl, SCC_CD_MASK, (0 << SCC_CD_SHF));
++      /* set all Instaclk chip ILP to 1 MHz */
++      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);
 +
 +done:
 +      sb_setcoreidx(sbh, origidx);
 +}
-+
++void sb_pwrctl_init(sb_t *sbh)
++{
++sb_clkctl_init(sbh);
++}
 +/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
 +uint16
-+sb_pwrctl_fast_pwrup_delay(void *sbh)
++sb_clkctl_fast_pwrup_delay(sb_t *sbh)
 +{
 +      sb_info_t *si;
 +      uint origidx;
@@ -6768,9 +4770,6 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      fpdelay = 0;
 +      origidx = si->curidx;
 +
-+      if (si->bus == SB_BUS)
-+              goto done;
-+
 +      INTR_OFF(si, intr_val);
 +
 +      if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
@@ -6779,7 +4778,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
 +              goto done;
 +
-+      slowminfreq = slowfreq(sbh, FALSE);
++      slowminfreq = sb_slowclk_freq(si, FALSE);
 +      fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + (slowminfreq - 1)) / slowminfreq;
 +
 +done:
@@ -6787,73 +4786,81 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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_pwrctl_xtal(void *sbh, uint what, bool on)
++sb_clkctl_xtal(sb_t *sbh, uint what, bool on)
 +{
 +      sb_info_t *si;
 +      uint32 in, out, outen;
 +
 +      si = SB_INFO(sbh);
 +
++      switch (BUSTYPE(si->sb.bustype)) {
++              case PCI_BUS:
 +
-+      if (si->bus == PCMCIA_BUS) {
-+              return (0);
-+      }
-+
-+      if (si->bus != PCI_BUS) 
-+              return (-1);
-+
-+      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));
-+
-+      /*
-+       * 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);
++                      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));
 +
-+      if (what & XTAL)
-+              outen |= PCI_CFG_GPIO_XTAL;
-+      if (what & PLL)
-+              outen |= PCI_CFG_GPIO_PLL;
++                      /*
++                       * 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 (on) {
-+              /* turn primary xtal on */
-+              if (what & XTAL) {
-+                      out |= PCI_CFG_GPIO_XTAL;
++                      if (what & XTAL)
++                              outen |= 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(200);
-+              }
++                              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 {
-+              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);
++                              /* 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 {
++                              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);
++                      }
++
++              default:
++                      return (-1);
 +      }
 +
 +      return (0);
 +}
 +
-+/* set dynamic power control mode (forceslow, forcefast, dynamic) */
++int sb_pwrctl_xtal(sb_t *sbh, uint what, bool on)
++{
++return sb_clkctl_xtal(sbh,what,on);
++}
++
++/* set dynamic clk control mode (forceslow, forcefast, dynamic) */
 +/*   returns true if ignore pll off is set and false if it is not */
 +bool
-+sb_pwrctl_clk(void *sbh, uint mode)
++sb_clkctl_clk(sb_t *sbh, uint mode)
 +{
 +      sb_info_t *si;
 +      uint origidx;
@@ -6864,8 +4871,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +      si = SB_INFO(sbh);
 +
-+      /* chipcommon cores prior to rev6 don't support slowclkcontrol */
-+      if (si->ccrev < 6)
++      /* chipcommon cores prior to rev6 don't support dynamic clock control */
++      if (si->sb.ccrev < 6)
++              return (FALSE);
++
++      /* chipcommon cores rev10 are a whole new ball game */
++      if (si->sb.ccrev >= 10)
 +              return (FALSE);
 +
 +      INTR_OFF(si, intr_val);
@@ -6881,20 +4892,12 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      switch (mode) {
 +      case CLK_FAST:  /* force fast (pll) clock */
 +              /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
-+              sb_pwrctl_xtal(sbh, XTAL, ON);
++              sb_clkctl_xtal(&si->sb, XTAL, ON);
 +
 +              SET_REG(&cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
 +              break;
 +
-+      case CLK_SLOW:  /* force slow clock */
-+              if ((si->bus == SDIO_BUS) || (si->bus == PCMCIA_BUS))
-+                      return (-1);
-+
-+              if (si->ccrev >= 6)
-+                      OR_REG(&cc->slow_clk_ctl, SCC_FS);
-+              break;
-+
-+      case CLK_DYNAMIC:       /* enable dynamic power control */
++      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)
@@ -6903,10 +4906,13 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +
 +              /* for dynamic control, we have to release our xtal_pu "force on" */
 +              if (scc & SCC_XC)
-+                      sb_pwrctl_xtal(sbh, XTAL, OFF);
++                      sb_clkctl_xtal(&si->sb, XTAL, OFF);
 +              break;
++
++      default:
++              ASSERT(0);
 +      }
-+      
++
 +      /* Is the h/w forcing the use of the fast clk */
 +      forcefastclk = (bool)((R_REG(&cc->slow_clk_ctl) & SCC_IP) == SCC_IP);
 +
@@ -6916,9 +4922,13 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      return (forcefastclk);
 +}
 +
++bool sb_pwrctl_clk(sb_t *sbh, uint mode)
++{
++return sb_clkctl_clk(sbh, mode);
++}
 +/* register driver interrupt disabling and restoring callback functions */
 +void
-+sb_register_intr_callback(void *sbh, void *intrsoff_fn, void *intrsrestore_fn, void *intr_arg)
++sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg)
 +{
 +      sb_info_t *si;
 +
@@ -6926,6 +4936,7 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +      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.)
 +       */
@@ -6933,115 +4944,645 @@ diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.15-rc
 +}
 +
 +
-diff -Nur linux-2.6.15-rc5/arch/mips/bcm947xx/include/bcm4710.h linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/include/bcm4710.h
---- linux-2.6.15-rc5/arch/mips/bcm947xx/include/bcm4710.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-rc5-openwrt/arch/mips/bcm947xx/include/bcm4710.h      2005-12-13 14:59:52.000000000 +0100
-@@ -0,0 +1,90 @@
++void
++sb_corepciid(sb_t *sbh, uint16 *pcivendor, uint16 *pcidevice, 
++      uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif)
++{
++      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);
++
++      chip = BCMINIT(sb_chip)(sbh);
++      chippkg = BCMINIT(sb_chippkg)(sbh);
++
++      progif = 0;
++      
++      /* 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:
++              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;
++}
++
++#if 0
++/* Build device path. Support SB, PCI, and JTAG for now. */
++int
++sb_devpath(sb_t *sbh, char *path, int size)
++{
++      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),
++                      PCI_SLOT(((struct pci_dev *)(SB_INFO(sbh))->osh)->pdev)->devfn);
++              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;
++}
++#endif
++
++/* Fix chip's configuration. The current core may be changed upon return */
++static int
++sb_pci_fixcfg(sb_info_t *si)
++{
++      uint origidx, pciidx;
++      sbpciregs_t *pciregs;
++      uint16 val16, *reg16;
++      char name[SB_DEVPATH_BUFSZ+16], *value;
++      char devpath[SB_DEVPATH_BUFSZ];
++
++      ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS);
++
++      /* Fix PCI(e) SROM shadow area */
++      /* save the current index */
++      origidx = sb_coreidx(&si->sb);
++
++      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);
++      }
++
++      /* restore the original index */
++      sb_setcoreidx(&si->sb, origidx);
++
++#if 0
++      /* 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;
++              }
++      }
++#endif
++
++      return 0;
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/broadcom/sflash.c linux.dev/arch/mips/bcm947xx/broadcom/sflash.c
+--- linux.old/arch/mips/bcm947xx/broadcom/sflash.c     1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/broadcom/sflash.c     2005-12-15 16:59:20.045933750 +0100
+@@ -0,0 +1,418 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * 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 <osl.h>
++#include <typedefs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <mipsinc.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sflash.h>
++
++/* Private global state */
++static struct sflash sflash;
++
++/* Issue a serial flash command */
++static INLINE void
++sflash_cmd(chipcregs_t *cc, uint opcode)
++{
++      W_REG(&cc->flashcontrol, SFLASH_START | opcode);
++      while (R_REG(&cc->flashcontrol) & SFLASH_BUSY);
++}
++
++/* Initialize serial flash access */
++struct sflash *
++sflash_init(chipcregs_t *cc)
++{
++      uint32 id, id2;
++
++      bzero(&sflash, sizeof(sflash));
++
++      sflash.type = R_REG(&cc->capabilities) & CAP_FLASH_MASK;
++
++      switch (sflash.type) {
++      case SFLASH_ST:
++              /* Probe for ST chips */
++              sflash_cmd(cc, SFLASH_ST_DP);
++              sflash_cmd(cc, SFLASH_ST_RES);
++              id = R_REG(&cc->flashdata);
++              switch (id) {
++              case 0x11:
++                      /* ST M25P20 2 Mbit Serial Flash */
++                      sflash.blocksize = 64 * 1024;
++                      sflash.numblocks = 4;
++                      break;
++              case 0x12:
++                      /* ST M25P40 4 Mbit Serial Flash */
++                      sflash.blocksize = 64 * 1024;
++                      sflash.numblocks = 8;
++                      break;
++              case 0x13:
++                      /* ST M25P80 8 Mbit Serial Flash */
++                      sflash.blocksize = 64 * 1024;
++                      sflash.numblocks = 16;
++                      break;
++              case 0x14:
++                      /* ST M25P16 16 Mbit Serial Flash */
++                      sflash.blocksize = 64 * 1024;
++                      sflash.numblocks = 32;
++                      break;
++              case 0x15:
++                      /* ST M25P32 32 Mbit Serial Flash */
++                      sflash.blocksize = 64 * 1024;
++                      sflash.numblocks = 64;
++                      break;
++              case 0xbf:
++                      W_REG(&cc->flashaddress, 1);
++                      sflash_cmd(cc, SFLASH_ST_RES);
++                      id2 = R_REG(&cc->flashdata);
++                      if (id2 == 0x44) {
++                              /* SST M25VF80 4 Mbit Serial Flash */
++                              sflash.blocksize = 64 * 1024;
++                              sflash.numblocks = 8;
++                      }
++                      break;
++              }
++              break;
++
++      case SFLASH_AT:
++              /* Probe for Atmel chips */
++              sflash_cmd(cc, SFLASH_AT_STATUS);
++              id = R_REG(&cc->flashdata) & 0x3c;
++              switch (id) {
++              case 0xc:
++                      /* Atmel AT45DB011 1Mbit Serial Flash */
++                      sflash.blocksize = 256;
++                      sflash.numblocks = 512;
++                      break;
++              case 0x14:
++                      /* Atmel AT45DB021 2Mbit Serial Flash */
++                      sflash.blocksize = 256;
++                      sflash.numblocks = 1024;
++                      break;
++              case 0x1c:
++                      /* Atmel AT45DB041 4Mbit Serial Flash */
++                      sflash.blocksize = 256;
++                      sflash.numblocks = 2048;
++                      break;
++              case 0x24:
++                      /* Atmel AT45DB081 8Mbit Serial Flash */
++                      sflash.blocksize = 256;
++                      sflash.numblocks = 4096;
++                      break;
++              case 0x2c:
++                      /* Atmel AT45DB161 16Mbit Serial Flash */
++                      sflash.blocksize = 512;
++                      sflash.numblocks = 4096;
++                      break;
++              case 0x34:
++                      /* Atmel AT45DB321 32Mbit Serial Flash */
++                      sflash.blocksize = 512;
++                      sflash.numblocks = 8192;
++                      break;
++              case 0x3c:
++                      /* Atmel AT45DB642 64Mbit Serial Flash */
++                      sflash.blocksize = 1024;
++                      sflash.numblocks = 8192;
++                      break;
++              }
++              break;
++      }
++
++      sflash.size = sflash.blocksize * sflash.numblocks;
++      return sflash.size ? &sflash : NULL;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int
++sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
++{
++      int cnt;
++      uint32 *from, *to;
++
++      if (!len)
++              return 0;
++
++      if ((offset + len) > sflash.size)
++              return -22;
++
++      if ((len >= 4) && (offset & 3))
++              cnt = 4 - (offset & 3);
++      else if ((len >= 4) && ((uint32)buf & 3))
++              cnt = 4 - ((uint32)buf & 3);
++      else
++              cnt = len;
++
++      from = (uint32 *)KSEG1ADDR(SB_FLASH2 + offset);
++      to = (uint32 *)buf;
++
++      if (cnt < 4) {
++              bcopy(from, to, cnt);
++              return cnt;
++      }
++
++      while (cnt >= 4) {
++              *to++ = *from++;
++              cnt -= 4;
++      }
++
++      return (len - cnt);
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int
++sflash_poll(chipcregs_t *cc, uint offset)
++{
++      if (offset >= sflash.size)
++              return -22;
++
++      switch (sflash.type) {
++      case SFLASH_ST:
++              /* Check for ST Write In Progress bit */
++              sflash_cmd(cc, SFLASH_ST_RDSR);
++              return R_REG(&cc->flashdata) & SFLASH_ST_WIP;
++      case SFLASH_AT:
++              /* Check for Atmel Ready bit */
++              sflash_cmd(cc, SFLASH_AT_STATUS);
++              return !(R_REG(&cc->flashdata) & SFLASH_AT_READY);
++      }
++
++      return 0;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int
++sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++      struct sflash *sfl;
++      int ret = 0;
++      bool is4712b0;
++      uint32 page, byte, mask;
++
++      if (!len)
++              return 0;
++
++      if ((offset + len) > sflash.size)
++              return -22;
++
++      sfl = &sflash;
++      switch (sfl->type) {
++      case SFLASH_ST:
++              mask = R_REG(&cc->chipid);
++              is4712b0 = (((mask & CID_ID_MASK) == BCM4712_DEVICE_ID) &&
++                          ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT)));
++              /* Enable writes */
++              sflash_cmd(cc, SFLASH_ST_WREN);
++              if (is4712b0) {
++                      mask = 1 << 14;
++                      W_REG(&cc->flashaddress, offset);
++                      W_REG(&cc->flashdata, *buf++);
++                      /* Set chip select */
++                      OR_REG(&cc->gpioout, mask);
++                      /* Issue a page program with the first byte */
++                      sflash_cmd(cc, SFLASH_ST_PP);
++                      ret = 1;
++                      offset++;
++                      len--;
++                      while (len > 0) {
++                              if ((offset & 255) == 0) {
++                                      /* Page boundary, drop cs and return */
++                                      AND_REG(&cc->gpioout, ~mask);
++                                      if (!sflash_poll(cc, offset)) {
++                                              /* Flash rejected command */
++                                              return -11;
++                                      }
++                                      return ret;
++                              } else {
++                                      /* Write single byte */
++                                      sflash_cmd(cc, *buf++);
++                              }
++                              ret++;
++                              offset++;
++                              len--;
++                      }
++                      /* All done, drop cs if needed */
++                      if ((offset & 255) != 1) {
++                              /* Drop cs */
++                              AND_REG(&cc->gpioout, ~mask);
++                              if (!sflash_poll(cc, offset)) {
++                                      /* Flash rejected command */
++                                      return -12;
++                              }
++                      }
++              } else {
++                      ret = 1;
++                      W_REG(&cc->flashaddress, offset);
++                      W_REG(&cc->flashdata, *buf);
++                      /* Page program */
++                      sflash_cmd(cc, SFLASH_ST_PP);
++              }
++              break;
++      case SFLASH_AT:
++              mask = sfl->blocksize - 1;
++              page = (offset & ~mask) << 1;
++              byte = offset & mask;
++              /* Read main memory page into buffer 1 */
++              if (byte || len < sfl->blocksize) {
++                      W_REG(&cc->flashaddress, page);
++                      sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
++                      /* 250 us for AT45DB321B */
++                      SPINWAIT(sflash_poll(cc, offset), 1000);
++                      ASSERT(!sflash_poll(cc, offset));
++              }
++              /* Write into buffer 1 */
++              for (ret = 0; ret < len && byte < sfl->blocksize; ret++) {
++                      W_REG(&cc->flashaddress, byte++);
++                      W_REG(&cc->flashdata, *buf++);
++                      sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
++              }
++              /* Write buffer 1 into main memory page */
++              W_REG(&cc->flashaddress, page);
++              sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
++              break;
++      }
++
++      return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int
++sflash_erase(chipcregs_t *cc, uint offset)
++{
++      struct sflash *sfl;
++
++      if (offset >= sflash.size)
++              return -22;
++
++      sfl = &sflash;
++      switch (sfl->type) {
++      c