Browse Source

ssb: update ssb to version from linux-next-20110311

SVN-Revision: 26127
Hauke Mehrtens 15 years ago
parent
commit
a08bd03fad
24 changed files with 4573 additions and 441 deletions
  1. 1 1
      target/linux/brcm47xx/patches-2.6.34/220-bcm5354.patch
  2. 0 45
      target/linux/brcm47xx/patches-2.6.34/950-sbb-sysfs-files.patch
  3. 2 2
      target/linux/brcm47xx/patches-2.6.34/951-brcm4716-defines.patch
  4. 1 1
      target/linux/brcm47xx/patches-2.6.34/977-ssb_export_fallback_sprom.patch
  5. 0 51
      target/linux/brcm47xx/patches-2.6.36/031-sb-fix-nvram_get-on-bcm47xx-platform.patch
  6. 1 1
      target/linux/brcm47xx/patches-2.6.36/220-bcm5354.patch
  7. 0 62
      target/linux/brcm47xx/patches-2.6.36/950-sbb-sysfs-files.patch
  8. 2 2
      target/linux/brcm47xx/patches-2.6.36/951-brcm4716-defines.patch
  9. 1 1
      target/linux/brcm47xx/patches-2.6.36/977-ssb_export_fallback_sprom.patch
  10. 1 1
      target/linux/brcm47xx/patches-2.6.37/220-bcm5354.patch
  11. 0 62
      target/linux/brcm47xx/patches-2.6.37/950-sbb-sysfs-files.patch
  12. 2 2
      target/linux/brcm47xx/patches-2.6.37/951-brcm4716-defines.patch
  13. 1 1
      target/linux/brcm47xx/patches-2.6.37/977-ssb_export_fallback_sprom.patch
  14. 850 39
      target/linux/generic/patches-2.6.30/941-ssb_update.patch
  15. 0 29
      target/linux/generic/patches-2.6.30/942-ssb_add_dma_dev.patch
  16. 1180 21
      target/linux/generic/patches-2.6.31/941-ssb_update.patch
  17. 0 29
      target/linux/generic/patches-2.6.31/942-ssb_add_dma_dev.patch
  18. 552 13
      target/linux/generic/patches-2.6.32/975-ssb_update.patch
  19. 0 52
      target/linux/generic/patches-2.6.32/976-ssb_add_dma_dev.patch
  20. 451 12
      target/linux/generic/patches-2.6.34/975-ssb_update.patch
  21. 480 14
      target/linux/generic/patches-2.6.35/975-ssb_update.patch
  22. 467 0
      target/linux/generic/patches-2.6.36/941-ssb_update.patch
  23. 445 0
      target/linux/generic/patches-2.6.37/941-ssb_update.patch
  24. 136 0
      target/linux/generic/patches-2.6.38/941-ssb_update.patch

+ 1 - 1
target/linux/brcm47xx/patches-2.6.34/220-bcm5354.patch

@@ -31,7 +31,7 @@
  	}
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -1075,6 +1075,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+@@ -1105,6 +1105,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
  
  	if (bus->chip_id == 0x5365) {
  		rate = 100000000;

+ 0 - 45
target/linux/brcm47xx/patches-2.6.34/950-sbb-sysfs-files.patch

@@ -1,45 +0,0 @@
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -385,6 +385,34 @@ static int ssb_device_uevent(struct devi
- 			     ssb_dev->id.revision);
- }
- 
-+#define ssb_config_attr(attrib, field, format_string)					\
-+static ssize_t													\
-+attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
-+{																\
-+	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field);		\
-+}
-+
-+ssb_config_attr(core_num, core_index, "%u\n")
-+ssb_config_attr(coreid, id.coreid, "0x%04x\n")
-+ssb_config_attr(vendor, id.vendor, "0x%04x\n")
-+ssb_config_attr(revision, id.revision, "%u\n")
-+ssb_config_attr(irq, irq, "%u\n")
-+static ssize_t
-+name_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+	return sprintf(buf, "%s\n", ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
-+}
-+
-+static struct device_attribute ssb_device_attrs[] = {
-+	__ATTR_RO(name),
-+	__ATTR_RO(core_num),
-+	__ATTR_RO(coreid),
-+	__ATTR_RO(vendor),
-+	__ATTR_RO(revision),
-+	__ATTR_RO(irq),
-+	__ATTR_NULL,
-+};
-+
- static struct bus_type ssb_bustype = {
- 	.name		= "ssb",
- 	.match		= ssb_bus_match,
-@@ -394,6 +422,7 @@ static struct bus_type ssb_bustype = {
- 	.suspend	= ssb_device_suspend,
- 	.resume		= ssb_device_resume,
- 	.uevent		= ssb_device_uevent,
-+	.dev_attrs	= ssb_device_attrs,
- };
- 
- static void ssb_buses_lock(void)

+ 2 - 2
target/linux/brcm47xx/patches-2.6.34/951-brcm4716-defines.patch

@@ -25,7 +25,7 @@
  		ssb_printk(KERN_ERR PFX
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -151,9 +151,16 @@ struct ssb_bus_ops {
+@@ -155,9 +155,16 @@ struct ssb_bus_ops {
  #define SSB_DEV_MINI_MACPHY	0x823
  #define SSB_DEV_ARM_1176	0x824
  #define SSB_DEV_ARM_7TDMI	0x825
@@ -60,7 +60,7 @@
  
  /* Enumeration space constants */
  #define SSB_CORE_SIZE		0x1000	/* Size of a core MMIO area */
-@@ -453,5 +455,41 @@ enum {
+@@ -499,5 +501,41 @@ enum {
  #define SSB_ADM_BASE2			0xFFFF0000	/* Type2 base address for the core */
  #define SSB_ADM_BASE2_SHIFT		16
  

+ 1 - 1
target/linux/brcm47xx/patches-2.6.34/977-ssb_export_fallback_sprom.patch

@@ -10,7 +10,7 @@
  bool ssb_is_sprom_available(struct ssb_bus *bus)
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -408,6 +408,7 @@ extern bool ssb_is_sprom_available(struc
+@@ -412,6 +412,7 @@ extern bool ssb_is_sprom_available(struc
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);

+ 0 - 51
target/linux/brcm47xx/patches-2.6.36/031-sb-fix-nvram_get-on-bcm47xx-platform.patch

@@ -1,51 +0,0 @@
-From 99dfec6e793651963ede3c2721b9ff3c81e3aeac Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <[email protected]>
-Date: Sat, 27 Nov 2010 14:04:36 +0100
-Subject: [PATCH 6/6] sb: fix nvram_get on bcm47xx platform
-
-The nvram_get function was never in the mainline kernel, it only
-existed in an external OpenWrt patch. Use nvram_getenv function, which
-is in mainline and use an include instead of an extra function
-declaration.
-et0macaddr contains the mac address in text from like
-00:11:22:33:44:55. We have to parse it before adding it into macaddr.
-
-nvram_parse_macaddr will be merged into asm/mach-bcm47xx/nvram.h though
-the MIPS git tree and will be available soon. It will not build now
-without nvram_parse_macaddr, but it haven't done before.
-
-Signed-off-by: Hauke Mehrtens <[email protected]>
----
- include/linux/ssb/ssb_driver_gige.h |   17 +++++++++++------
- 1 files changed, 11 insertions(+), 6 deletions(-)
-
---- a/include/linux/ssb/ssb_driver_gige.h
-+++ b/include/linux/ssb/ssb_driver_gige.h
-@@ -96,16 +96,21 @@ static inline bool ssb_gige_must_flush_p
- 	return 0;
- }
- 
--extern char * nvram_get(const char *name);
-+#ifdef CONFIG_BCM47XX
-+#include <asm/mach-bcm47xx/nvram.h>
- /* Get the device MAC address */
- static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
- {
--#ifdef CONFIG_BCM47XX
--	char *res = nvram_get("et0macaddr");
--	if (res)
--		memcpy(macaddr, res, 6);
--#endif
-+	char buf[20];
-+	if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0)
-+		return;
-+	nvram_parse_macaddr(buf, macaddr);
- }
-+#else
-+static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
-+{
-+}
-+#endif
- 
- extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
- 					  struct pci_dev *pdev);

+ 1 - 1
target/linux/brcm47xx/patches-2.6.36/220-bcm5354.patch

@@ -31,7 +31,7 @@
  	}
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -1074,6 +1074,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+@@ -1104,6 +1104,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
  
  	if (bus->chip_id == 0x5365) {
  		rate = 100000000;

+ 0 - 62
target/linux/brcm47xx/patches-2.6.36/950-sbb-sysfs-files.patch

@@ -1,62 +0,0 @@
-From 3cfa0a9d4b4cc30ec735c5c9535ff493bae24d08 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <[email protected]>
-Date: Sat, 27 Nov 2010 18:14:23 +0100
-Subject: [PATCH] ssb: Add sysfs attributes to ssb devices
-
-Make it possible to read out the attributes, till now only show on
-dmesg, through sysfs.
-
-This patch was some time in OpenWrt.
-
-Signed-off-by: Bernhard Loos <[email protected]>
-Signed-off-by: Hauke Mehrtens <[email protected]>
----
- drivers/ssb/main.c |   30 ++++++++++++++++++++++++++++++
- 1 files changed, 30 insertions(+), 0 deletions(-)
-
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -384,6 +384,35 @@ static int ssb_device_uevent(struct devi
- 			     ssb_dev->id.revision);
- }
- 
-+#define ssb_config_attr(attrib, field, format_string) \
-+static ssize_t \
-+attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
-+{ \
-+	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
-+}
-+
-+ssb_config_attr(core_num, core_index, "%u\n")
-+ssb_config_attr(coreid, id.coreid, "0x%04x\n")
-+ssb_config_attr(vendor, id.vendor, "0x%04x\n")
-+ssb_config_attr(revision, id.revision, "%u\n")
-+ssb_config_attr(irq, irq, "%u\n")
-+static ssize_t
-+name_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+	return sprintf(buf, "%s\n",
-+		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
-+}
-+
-+static struct device_attribute ssb_device_attrs[] = {
-+	__ATTR_RO(name),
-+	__ATTR_RO(core_num),
-+	__ATTR_RO(coreid),
-+	__ATTR_RO(vendor),
-+	__ATTR_RO(revision),
-+	__ATTR_RO(irq),
-+	__ATTR_NULL,
-+};
-+
- static struct bus_type ssb_bustype = {
- 	.name		= "ssb",
- 	.match		= ssb_bus_match,
-@@ -393,6 +422,7 @@ static struct bus_type ssb_bustype = {
- 	.suspend	= ssb_device_suspend,
- 	.resume		= ssb_device_resume,
- 	.uevent		= ssb_device_uevent,
-+	.dev_attrs	= ssb_device_attrs,
- };
- 
- static void ssb_buses_lock(void)

+ 2 - 2
target/linux/brcm47xx/patches-2.6.36/951-brcm4716-defines.patch

@@ -25,7 +25,7 @@
  		ssb_printk(KERN_ERR PFX
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -151,9 +151,16 @@ struct ssb_bus_ops {
+@@ -155,9 +155,16 @@ struct ssb_bus_ops {
  #define SSB_DEV_MINI_MACPHY	0x823
  #define SSB_DEV_ARM_1176	0x824
  #define SSB_DEV_ARM_7TDMI	0x825
@@ -60,7 +60,7 @@
  
  /* Enumeration space constants */
  #define SSB_CORE_SIZE		0x1000	/* Size of a core MMIO area */
-@@ -453,5 +455,41 @@ enum {
+@@ -499,5 +501,41 @@ enum {
  #define SSB_ADM_BASE2			0xFFFF0000	/* Type2 base address for the core */
  #define SSB_ADM_BASE2_SHIFT		16
  

+ 1 - 1
target/linux/brcm47xx/patches-2.6.36/977-ssb_export_fallback_sprom.patch

@@ -10,7 +10,7 @@
  bool ssb_is_sprom_available(struct ssb_bus *bus)
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -401,6 +401,7 @@ extern bool ssb_is_sprom_available(struc
+@@ -412,6 +412,7 @@ extern bool ssb_is_sprom_available(struc
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);

+ 1 - 1
target/linux/brcm47xx/patches-2.6.37/220-bcm5354.patch

@@ -31,7 +31,7 @@
  	}
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -1073,6 +1073,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+@@ -1103,6 +1103,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
  
  	if (bus->chip_id == 0x5365) {
  		rate = 100000000;

+ 0 - 62
target/linux/brcm47xx/patches-2.6.37/950-sbb-sysfs-files.patch

@@ -1,62 +0,0 @@
-From 3cfa0a9d4b4cc30ec735c5c9535ff493bae24d08 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <[email protected]>
-Date: Sat, 27 Nov 2010 18:14:23 +0100
-Subject: [PATCH] ssb: Add sysfs attributes to ssb devices
-
-Make it possible to read out the attributes, till now only show on
-dmesg, through sysfs.
-
-This patch was some time in OpenWrt.
-
-Signed-off-by: Bernhard Loos <[email protected]>
-Signed-off-by: Hauke Mehrtens <[email protected]>
----
- drivers/ssb/main.c |   30 ++++++++++++++++++++++++++++++
- 1 files changed, 30 insertions(+), 0 deletions(-)
-
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -383,6 +383,35 @@ static int ssb_device_uevent(struct devi
- 			     ssb_dev->id.revision);
- }
- 
-+#define ssb_config_attr(attrib, field, format_string) \
-+static ssize_t \
-+attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
-+{ \
-+	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
-+}
-+
-+ssb_config_attr(core_num, core_index, "%u\n")
-+ssb_config_attr(coreid, id.coreid, "0x%04x\n")
-+ssb_config_attr(vendor, id.vendor, "0x%04x\n")
-+ssb_config_attr(revision, id.revision, "%u\n")
-+ssb_config_attr(irq, irq, "%u\n")
-+static ssize_t
-+name_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+	return sprintf(buf, "%s\n",
-+		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
-+}
-+
-+static struct device_attribute ssb_device_attrs[] = {
-+	__ATTR_RO(name),
-+	__ATTR_RO(core_num),
-+	__ATTR_RO(coreid),
-+	__ATTR_RO(vendor),
-+	__ATTR_RO(revision),
-+	__ATTR_RO(irq),
-+	__ATTR_NULL,
-+};
-+
- static struct bus_type ssb_bustype = {
- 	.name		= "ssb",
- 	.match		= ssb_bus_match,
-@@ -392,6 +421,7 @@ static struct bus_type ssb_bustype = {
- 	.suspend	= ssb_device_suspend,
- 	.resume		= ssb_device_resume,
- 	.uevent		= ssb_device_uevent,
-+	.dev_attrs	= ssb_device_attrs,
- };
- 
- static void ssb_buses_lock(void)

+ 2 - 2
target/linux/brcm47xx/patches-2.6.37/951-brcm4716-defines.patch

@@ -25,7 +25,7 @@
  		ssb_printk(KERN_ERR PFX
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -151,9 +151,16 @@ struct ssb_bus_ops {
+@@ -155,9 +155,16 @@ struct ssb_bus_ops {
  #define SSB_DEV_MINI_MACPHY	0x823
  #define SSB_DEV_ARM_1176	0x824
  #define SSB_DEV_ARM_7TDMI	0x825
@@ -60,7 +60,7 @@
  
  /* Enumeration space constants */
  #define SSB_CORE_SIZE		0x1000	/* Size of a core MMIO area */
-@@ -454,5 +456,41 @@ enum {
+@@ -499,5 +501,41 @@ enum {
  #define SSB_ADM_BASE2			0xFFFF0000	/* Type2 base address for the core */
  #define SSB_ADM_BASE2_SHIFT		16
  

+ 1 - 1
target/linux/brcm47xx/patches-2.6.37/977-ssb_export_fallback_sprom.patch

@@ -10,7 +10,7 @@
  bool ssb_is_sprom_available(struct ssb_bus *bus)
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -408,6 +408,7 @@ extern bool ssb_is_sprom_available(struc
+@@ -412,6 +412,7 @@ extern bool ssb_is_sprom_available(struc
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);

File diff suppressed because it is too large
+ 850 - 39
target/linux/generic/patches-2.6.30/941-ssb_update.patch


+ 0 - 29
target/linux/generic/patches-2.6.30/942-ssb_add_dma_dev.patch

@@ -1,29 +0,0 @@
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -465,6 +465,7 @@ static int ssb_devices_register(struct s
- #ifdef CONFIG_SSB_PCIHOST
- 			sdev->irq = bus->host_pci->irq;
- 			dev->parent = &bus->host_pci->dev;
-+			sdev->dma_dev = dev->parent;
- #endif
- 			break;
- 		case SSB_BUSTYPE_PCMCIA:
-@@ -475,6 +476,7 @@ static int ssb_devices_register(struct s
- 			break;
- 		case SSB_BUSTYPE_SSB:
- 			dev->dma_mask = &dev->coherent_dma_mask;
-+			sdev->dma_dev = dev;
- 			break;
- 		default:
- 			break;
---- a/include/linux/ssb/ssb.h
-+++ b/include/linux/ssb/ssb.h
-@@ -167,7 +167,7 @@ struct ssb_device {
- 	 * is an optimization. */
- 	const struct ssb_bus_ops *ops;
- 
--	struct device *dev;
-+	struct device *dev, *dma_dev;
- 
- 	struct ssb_bus *bus;
- 	struct ssb_device_id id;

File diff suppressed because it is too large
+ 1180 - 21
target/linux/generic/patches-2.6.31/941-ssb_update.patch


+ 0 - 29
target/linux/generic/patches-2.6.31/942-ssb_add_dma_dev.patch

@@ -1,29 +0,0 @@
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -461,6 +461,7 @@
- #ifdef CONFIG_SSB_PCIHOST
- 			sdev->irq = bus->host_pci->irq;
- 			dev->parent = &bus->host_pci->dev;
-+			sdev->dma_dev = dev->parent;
- #endif
- 			break;
- 		case SSB_BUSTYPE_PCMCIA:
-@@ -473,6 +474,7 @@
- 			break;
- 		case SSB_BUSTYPE_SSB:
- 			dev->dma_mask = &dev->coherent_dma_mask;
-+			sdev->dma_dev = dev;
- 			break;
- 		}
- 
---- a/include/linux/ssb/ssb.h
-+++ b/include/linux/ssb/ssb.h
-@@ -167,7 +167,7 @@
- 	 * is an optimization. */
- 	const struct ssb_bus_ops *ops;
- 
--	struct device *dev;
-+	struct device *dev, *dma_dev;
- 
- 	struct ssb_bus *bus;
- 	struct ssb_device_id id;

+ 552 - 13
target/linux/generic/patches-2.6.32/975-ssb_update.patch

@@ -1,6 +1,44 @@
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
-@@ -373,6 +373,7 @@ u32 ssb_chipco_gpio_control(struct ssb_c
+@@ -209,6 +209,24 @@ static void chipco_powercontrol_init(str
+ 	}
+ }
+ 
++/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */
++static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
++{
++	struct ssb_bus *bus = cc->dev->bus;
++
++	switch (bus->chip_id) {
++	case 0x4312:
++	case 0x4322:
++	case 0x4328:
++		return 7000;
++	case 0x4325:
++		/* TODO: */
++	default:
++		return 15000;
++	}
++}
++
++/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */
+ static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+ {
+ 	struct ssb_bus *bus = cc->dev->bus;
+@@ -218,6 +236,12 @@ static void calc_fast_powerup_delay(stru
+ 
+ 	if (bus->bustype != SSB_BUSTYPE_PCI)
+ 		return;
++
++	if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
++		cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc);
++		return;
++	}
++
+ 	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ 		return;
+ 
+@@ -373,6 +397,7 @@ u32 ssb_chipco_gpio_control(struct ssb_c
  {
  	return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
  }
@@ -31,6 +69,39 @@
  		/* We keep the default settings:
  		 * min_msk = 0xCBB
  		 * max_msk = 0x7FFFF
+@@ -495,9 +502,9 @@ static void ssb_pmu_resources_init(struc
+ 		chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
+ }
+ 
++/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
+ void ssb_pmu_init(struct ssb_chipcommon *cc)
+ {
+-	struct ssb_bus *bus = cc->dev->bus;
+ 	u32 pmucap;
+ 
+ 	if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
+@@ -509,15 +516,12 @@ void ssb_pmu_init(struct ssb_chipcommon
+ 	ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
+ 		    cc->pmu.rev, pmucap);
+ 
+-	if (cc->pmu.rev >= 1) {
+-		if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
+-			chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
+-				      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
+-		} else {
+-			chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
+-				     SSB_CHIPCO_PMU_CTL_NOILPONW);
+-		}
+-	}
++	if (cc->pmu.rev == 1)
++		chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
++			      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
++	else
++		chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
++			     SSB_CHIPCO_PMU_CTL_NOILPONW);
+ 	ssb_pmu_pll_init(cc);
+ 	ssb_pmu_resources_init(cc);
+ }
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
 @@ -12,6 +12,7 @@
@@ -214,13 +285,13 @@
 -		if (!dev->dev ||
 -		    !dev->dev->driver ||
 -		    !device_is_registered(dev->dev))
+-			continue;
+-		drv = drv_to_ssb_drv(dev->dev->driver);
+-		if (!drv)
 +		sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
 +		if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
 +			ssb_device_put(sdev);
  			continue;
--		drv = drv_to_ssb_drv(dev->dev->driver);
--		if (!drv)
--			continue;
 -		err = drv->suspend(dev, state);
 -		if (err) {
 -			ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
@@ -302,7 +373,59 @@
  }
  #endif /* CONFIG_SSB_SPROM */
  
-@@ -490,8 +495,7 @@ static int ssb_devices_register(struct s
+@@ -380,6 +385,35 @@ static int ssb_device_uevent(struct devi
+ 			     ssb_dev->id.revision);
+ }
+ 
++#define ssb_config_attr(attrib, field, format_string) \
++static ssize_t \
++attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
++{ \
++	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
++}
++
++ssb_config_attr(core_num, core_index, "%u\n")
++ssb_config_attr(coreid, id.coreid, "0x%04x\n")
++ssb_config_attr(vendor, id.vendor, "0x%04x\n")
++ssb_config_attr(revision, id.revision, "%u\n")
++ssb_config_attr(irq, irq, "%u\n")
++static ssize_t
++name_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n",
++		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
++}
++
++static struct device_attribute ssb_device_attrs[] = {
++	__ATTR_RO(name),
++	__ATTR_RO(core_num),
++	__ATTR_RO(coreid),
++	__ATTR_RO(vendor),
++	__ATTR_RO(revision),
++	__ATTR_RO(irq),
++	__ATTR_NULL,
++};
++
+ static struct bus_type ssb_bustype = {
+ 	.name		= "ssb",
+ 	.match		= ssb_bus_match,
+@@ -389,6 +423,7 @@ static struct bus_type ssb_bustype = {
+ 	.suspend	= ssb_device_suspend,
+ 	.resume		= ssb_device_resume,
+ 	.uevent		= ssb_device_uevent,
++	.dev_attrs	= ssb_device_attrs,
+ };
+ 
+ static void ssb_buses_lock(void)
+@@ -481,6 +516,7 @@ static int ssb_devices_register(struct s
+ #ifdef CONFIG_SSB_PCIHOST
+ 			sdev->irq = bus->host_pci->irq;
+ 			dev->parent = &bus->host_pci->dev;
++			sdev->dma_dev = dev->parent;
+ #endif
+ 			break;
+ 		case SSB_BUSTYPE_PCMCIA:
+@@ -490,13 +526,13 @@ static int ssb_devices_register(struct s
  #endif
  			break;
  		case SSB_BUSTYPE_SDIO:
@@ -312,7 +435,13 @@
  			dev->parent = &bus->host_sdio->dev;
  #endif
  			break;
-@@ -830,6 +834,9 @@ int ssb_bus_pcibus_register(struct ssb_b
+ 		case SSB_BUSTYPE_SSB:
+ 			dev->dma_mask = &dev->coherent_dma_mask;
++			sdev->dma_dev = dev;
+ 			break;
+ 		}
+ 
+@@ -830,6 +866,9 @@ int ssb_bus_pcibus_register(struct ssb_b
  	if (!err) {
  		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
  			   "PCI device %s\n", dev_name(&host_pci->dev));
@@ -322,6 +451,270 @@
  	}
  
  	return err;
+@@ -1155,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+ 
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+  * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+-			int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++			 int timeout, int set)
+ {
+ 	int i;
+ 	u32 val;
+@@ -1166,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
+ 	for (i = 0; i < timeout; i++) {
+ 		val = ssb_read32(dev, reg);
+ 		if (set) {
+-			if (val & bitmask)
++			if ((val & bitmask) == bitmask)
+ 				return 0;
+ 		} else {
+ 			if (!(val & bitmask))
+@@ -1183,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
+ 
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+-	u32 reject;
++	u32 reject, val;
+ 
+ 	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ 		return;
+ 
+ 	reject = ssb_tmslow_reject_bitmask(dev);
+-	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+-	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+-	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+-	ssb_write32(dev, SSB_TMSLOW,
+-		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+-		    reject | SSB_TMSLOW_RESET |
+-		    core_specific_flags);
+-	ssb_flush_tmslow(dev);
++
++	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val |= SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++				      0);
++		}
++
++		ssb_write32(dev, SSB_TMSLOW,
++			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++			reject | SSB_TMSLOW_RESET |
++			core_specific_flags);
++		ssb_flush_tmslow(dev);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val &= ~SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++		}
++	}
+ 
+ 	ssb_write32(dev, SSB_TMSLOW,
+ 		    reject | SSB_TMSLOW_RESET |
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -17,6 +17,7 @@
+ 
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
++#include <linux/slab.h>
+ #include <linux/pci.h>
+ #include <linux/delay.h>
+ 
+@@ -167,7 +168,7 @@ err_pci:
+ }
+ 
+ /* Get the word-offset for a SSB_SPROM_XXX define. */
+-#define SPOFF(offset)	(((offset) - SSB_SPROM_BASE1) / sizeof(u16))
++#define SPOFF(offset)	((offset) / sizeof(u16))
+ /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
+ #define SPEX16(_outvar, _offset, _mask, _shift)	\
+ 	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+@@ -405,6 +406,46 @@ static void sprom_extract_r123(struct ss
+ 	out->antenna_gain.ghz5.a3 = gain;
+ }
+ 
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
++
++	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
++	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
++	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
++	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
++
++	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
++	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
++	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
++	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
++
++	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
++	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
++	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
++	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
++}
++
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+@@ -427,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ 		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ 	} else {
+ 		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ 	}
+ 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -470,6 +515,8 @@ static void sprom_extract_r45(struct ssb
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 4 stuff needed */
+ }
+ 
+@@ -560,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 8 stuff needed */
+ }
+ 
+@@ -572,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+ 	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
+ 	memset(out->et1mac, 0xFF, 6);
++
+ 	if ((bus->chip_id & 0xFF00) == 0x4400) {
+ 		/* Workaround: The BCM44XX chip has a stupid revision
+ 		 * number stored in the SPROM.
+ 		 * Always extract r1. */
+ 		out->revision = 1;
++		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++	}
++
++	switch (out->revision) {
++	case 1:
++	case 2:
++	case 3:
+ 		sprom_extract_r123(out, in);
+-	} else if (bus->chip_id == 0x4321) {
+-		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+-		out->revision = 4;
++		break;
++	case 4:
++	case 5:
+ 		sprom_extract_r45(out, in);
+-	} else {
+-		switch (out->revision) {
+-		case 1:
+-		case 2:
+-		case 3:
+-			sprom_extract_r123(out, in);
+-			break;
+-		case 4:
+-		case 5:
+-			sprom_extract_r45(out, in);
+-			break;
+-		case 8:
+-			sprom_extract_r8(out, in);
+-			break;
+-		default:
+-			ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-				   "  revision %d detected. Will extract"
+-				   " v1\n", out->revision);
+-			out->revision = 1;
+-			sprom_extract_r123(out, in);
+-		}
++		break;
++	case 8:
++		sprom_extract_r8(out, in);
++		break;
++	default:
++		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
++			   " revision %d detected. Will extract"
++			   " v1\n", out->revision);
++		out->revision = 1;
++		sprom_extract_r123(out, in);
+ 	}
+ 
+ 	if (out->boardflags_lo == 0xFFFF)
+@@ -617,7 +663,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 			     struct ssb_sprom *sprom)
+ {
+ 	const struct ssb_sprom *fallback;
+-	int err = -ENOMEM;
++	int err;
+ 	u16 *buf;
+ 
+ 	if (!ssb_is_sprom_available(bus)) {
+@@ -644,7 +690,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ 	if (!buf)
+-		goto out;
++		return -ENOMEM;
+ 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ 	sprom_do_read(bus, buf);
+ 	err = sprom_check_crc(buf, bus->sprom_size);
+@@ -654,7 +700,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ 			      GFP_KERNEL);
+ 		if (!buf)
+-			goto out;
++			return -ENOMEM;
+ 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ 		sprom_do_read(bus, buf);
+ 		err = sprom_check_crc(buf, bus->sprom_size);
+@@ -676,7 +722,6 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ out_free:
+ 	kfree(buf);
+-out:
+ 	return err;
+ }
+ 
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
 @@ -12,6 +12,7 @@
@@ -332,6 +725,27 @@
  #include <linux/ssb/ssb.h>
  
  
+@@ -58,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_
+ 	struct ssb_bus *ssb;
+ 	int err = -ENOMEM;
+ 	const char *name;
++	u32 val;
+ 
+ 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ 	if (!ssb)
+@@ -73,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_
+ 		goto err_pci_disable;
+ 	pci_set_master(dev);
+ 
++	/* Disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state */
++	pci_read_config_dword(dev, 0x40, &val);
++	if ((val & 0x0000ff00) != 0)
++		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
++
+ 	err = ssb_bus_pcibus_register(ssb, dev);
+ 	if (err)
+ 		goto err_pci_release_regions;
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
 @@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(co
@@ -576,7 +990,7 @@
 -		GOTO_ERROR_ON(res != 0, "VEN next tpl data");
 -	}
 +	res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
-+				ssb_pcmcia_do_get_invariants, sprom);
++				ssb_pcmcia_do_get_invariants, iv);
 +	if ((res == 0) || (res == -ENOSPC))
 +		return 0;
  
@@ -600,6 +1014,23 @@
  			    "Core %d found: %s "
  			    "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
  			    i, ssb_core_name(dev->id.coreid),
+@@ -422,6 +422,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 			bus->pcicore.dev = dev;
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ 			break;
++		case SSB_DEV_ETHERNET:
++			if (bus->bustype == SSB_BUSTYPE_PCI) {
++				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
++				    (bus->host_pci->device & 0xFF00) == 0x4300) {
++					/* This is a dangling ethernet core on a
++					 * wireless device. Ignore it. */
++					continue;
++				}
++			}
++			break;
+ 		default:
+ 			break;
+ 		}
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
 @@ -14,6 +14,7 @@
@@ -682,7 +1113,27 @@
  #endif /* LINUX_SSB_PRIVATE_H_ */
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -269,7 +269,8 @@ struct ssb_bus {
+@@ -55,6 +55,10 @@ struct ssb_sprom {
+ 	u8 tri5gl;		/* 5.2GHz TX isolation */
+ 	u8 tri5g;		/* 5.3GHz TX isolation */
+ 	u8 tri5gh;		/* 5.8GHz TX isolation */
++	u8 txpid2g[4];		/* 2GHz TX power index */
++	u8 txpid5gl[4];		/* 4.9 - 5.1GHz TX power index */
++	u8 txpid5g[4];		/* 5.1 - 5.5GHz TX power index */
++	u8 txpid5gh[4];		/* 5.5 - ...GHz TX power index */
+ 	u8 rxpo2g;		/* 2GHz RX power offset */
+ 	u8 rxpo5g;		/* 5GHz RX power offset */
+ 	u8 rssisav2g;		/* 2GHz RSSI params */
+@@ -167,7 +171,7 @@ struct ssb_device {
+ 	 * is an optimization. */
+ 	const struct ssb_bus_ops *ops;
+ 
+-	struct device *dev;
++	struct device *dev, *dma_dev;
+ 
+ 	struct ssb_bus *bus;
+ 	struct ssb_device_id id;
+@@ -269,7 +273,8 @@ struct ssb_bus {
  
  	const struct ssb_bus_ops *ops;
  
@@ -692,7 +1143,7 @@
  	struct ssb_device *mapped_device;
  	union {
  		/* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */
-@@ -281,14 +282,17 @@ struct ssb_bus {
+@@ -281,14 +286,17 @@ struct ssb_bus {
  	 * On PCMCIA-host busses this is used to protect the whole MMIO access. */
  	spinlock_t bar_lock;
  
@@ -719,7 +1170,51 @@
  	unsigned int quirks;
 --- a/include/linux/ssb/ssb_regs.h
 +++ b/include/linux/ssb/ssb_regs.h
-@@ -198,63 +198,63 @@
+@@ -85,6 +85,8 @@
+ #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+ #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+ #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
++#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
++#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
+ #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+ #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+ #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+@@ -172,25 +174,25 @@
+ #define SSB_SPROMSIZE_BYTES_R4		(SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
+ #define SSB_SPROM_BASE1			0x1000
+ #define SSB_SPROM_BASE31		0x0800
+-#define SSB_SPROM_REVISION		0x107E
++#define SSB_SPROM_REVISION		0x007E
+ #define  SSB_SPROM_REVISION_REV		0x00FF	/* SPROM Revision number */
+ #define  SSB_SPROM_REVISION_CRC		0xFF00	/* SPROM CRC8 value */
+ #define  SSB_SPROM_REVISION_CRC_SHIFT	8
+ 
+ /* SPROM Revision 1 */
+-#define SSB_SPROM1_SPID			0x1004	/* Subsystem Product ID for PCI */
+-#define SSB_SPROM1_SVID			0x1006	/* Subsystem Vendor ID for PCI */
+-#define SSB_SPROM1_PID			0x1008	/* Product ID for PCI */
+-#define SSB_SPROM1_IL0MAC		0x1048	/* 6 bytes MAC address for 802.11b/g */
+-#define SSB_SPROM1_ET0MAC		0x104E	/* 6 bytes MAC address for Ethernet */
+-#define SSB_SPROM1_ET1MAC		0x1054	/* 6 bytes MAC address for 802.11a */
+-#define SSB_SPROM1_ETHPHY		0x105A	/* Ethernet PHY settings */
++#define SSB_SPROM1_SPID			0x0004	/* Subsystem Product ID for PCI */
++#define SSB_SPROM1_SVID			0x0006	/* Subsystem Vendor ID for PCI */
++#define SSB_SPROM1_PID			0x0008	/* Product ID for PCI */
++#define SSB_SPROM1_IL0MAC		0x0048	/* 6 bytes MAC address for 802.11b/g */
++#define SSB_SPROM1_ET0MAC		0x004E	/* 6 bytes MAC address for Ethernet */
++#define SSB_SPROM1_ET1MAC		0x0054	/* 6 bytes MAC address for 802.11a */
++#define SSB_SPROM1_ETHPHY		0x005A	/* Ethernet PHY settings */
+ #define  SSB_SPROM1_ETHPHY_ET0A		0x001F	/* MII Address for enet0 */
+ #define  SSB_SPROM1_ETHPHY_ET1A		0x03E0	/* MII Address for enet1 */
+ #define  SSB_SPROM1_ETHPHY_ET1A_SHIFT	5
+ #define  SSB_SPROM1_ETHPHY_ET0M		(1<<14)	/* MDIO for enet0 */
+ #define  SSB_SPROM1_ETHPHY_ET1M		(1<<15)	/* MDIO for enet1 */
+-#define SSB_SPROM1_BINF			0x105C	/* Board info */
++#define SSB_SPROM1_BINF			0x005C	/* Board info */
+ #define  SSB_SPROM1_BINF_BREV		0x00FF	/* Board Revision */
+ #define  SSB_SPROM1_BINF_CCODE		0x0F00	/* Country Code */
+ #define  SSB_SPROM1_BINF_CCODE_SHIFT	8
+@@ -198,63 +200,63 @@
  #define  SSB_SPROM1_BINF_ANTBG_SHIFT	12
  #define  SSB_SPROM1_BINF_ANTA		0xC000	/* Available A-PHY antennas */
  #define  SSB_SPROM1_BINF_ANTA_SHIFT	14
@@ -811,7 +1306,7 @@
  #define  SSB_SPROM3_CCKPO_1M		0x000F	/* 1M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M		0x00F0	/* 2M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M_SHIFT	4
-@@ -265,100 +265,100 @@
+@@ -265,100 +267,144 @@
  #define  SSB_SPROM3_OFDMGPO		0x107A	/* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
  
  /* SPROM Revision 4 */
@@ -819,6 +1314,8 @@
 -#define SSB_SPROM4_ETHPHY		0x105A	/* Ethernet PHY settings ?? */
 +#define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
 +#define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
++#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
 +#define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
 +#define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
 +#define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
@@ -861,6 +1358,46 @@
  #define  SSB_SPROM4_AGAIN3_SHIFT	8
 -#define SSB_SPROM4_BFLHI		0x1046  /* Board Flags Hi */
 -#define SSB_SPROM4_MAXP_BG		0x1080  /* Max Power BG in path 1 */
++#define SSB_SPROM4_TXPID2G01		0x0062 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G0		0x00FF
++#define  SSB_SPROM4_TXPID2G0_SHIFT	0
++#define  SSB_SPROM4_TXPID2G1		0xFF00
++#define  SSB_SPROM4_TXPID2G1_SHIFT	8
++#define SSB_SPROM4_TXPID2G23		0x0064 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G2		0x00FF
++#define  SSB_SPROM4_TXPID2G2_SHIFT	0
++#define  SSB_SPROM4_TXPID2G3		0xFF00
++#define  SSB_SPROM4_TXPID2G3_SHIFT	8
++#define SSB_SPROM4_TXPID5G01		0x0066 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G0		0x00FF
++#define  SSB_SPROM4_TXPID5G0_SHIFT	0
++#define  SSB_SPROM4_TXPID5G1		0xFF00
++#define  SSB_SPROM4_TXPID5G1_SHIFT	8
++#define SSB_SPROM4_TXPID5G23		0x0068 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G2		0x00FF
++#define  SSB_SPROM4_TXPID5G2_SHIFT	0
++#define  SSB_SPROM4_TXPID5G3		0xFF00
++#define  SSB_SPROM4_TXPID5G3_SHIFT	8
++#define SSB_SPROM4_TXPID5GL01		0x006A 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL0		0x00FF
++#define  SSB_SPROM4_TXPID5GL0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL1		0xFF00
++#define  SSB_SPROM4_TXPID5GL1_SHIFT	8
++#define SSB_SPROM4_TXPID5GL23		0x006C 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL2		0x00FF
++#define  SSB_SPROM4_TXPID5GL2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL3		0xFF00
++#define  SSB_SPROM4_TXPID5GL3_SHIFT	8
++#define SSB_SPROM4_TXPID5GH01		0x006E 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH0		0x00FF
++#define  SSB_SPROM4_TXPID5GH0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH1		0xFF00
++#define  SSB_SPROM4_TXPID5GH1_SHIFT	8
++#define SSB_SPROM4_TXPID5GH23		0x0070 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH2		0x00FF
++#define  SSB_SPROM4_TXPID5GH2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH3		0xFF00
++#define  SSB_SPROM4_TXPID5GH3_SHIFT	8
 +#define SSB_SPROM4_MAXP_BG		0x0080  /* Max Power BG in path 1 */
  #define  SSB_SPROM4_MAXP_BG_MASK	0x00FF  /* Mask for Max Power BG */
  #define  SSB_SPROM4_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
@@ -900,6 +1437,8 @@
 +#define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
 +#define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
 +#define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
++#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
 +#define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
 +#define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
  #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */
@@ -969,7 +1508,7 @@
  #define  SSB_SPROM8_RSSISMF2G		0x000F
  #define  SSB_SPROM8_RSSISMC2G		0x00F0
  #define  SSB_SPROM8_RSSISMC2G_SHIFT	4
-@@ -366,7 +366,7 @@
+@@ -366,7 +412,7 @@
  #define  SSB_SPROM8_RSSISAV2G_SHIFT	8
  #define  SSB_SPROM8_BXA2G		0x1800
  #define  SSB_SPROM8_BXA2G_SHIFT		11
@@ -978,7 +1517,7 @@
  #define  SSB_SPROM8_RSSISMF5G		0x000F
  #define  SSB_SPROM8_RSSISMC5G		0x00F0
  #define  SSB_SPROM8_RSSISMC5G_SHIFT	4
-@@ -374,47 +374,47 @@
+@@ -374,47 +420,47 @@
  #define  SSB_SPROM8_RSSISAV5G_SHIFT	8
  #define  SSB_SPROM8_BXA5G		0x1800
  #define  SSB_SPROM8_BXA5G_SHIFT		11

+ 0 - 52
target/linux/generic/patches-2.6.32/976-ssb_add_dma_dev.patch

@@ -1,52 +0,0 @@
-From: FUJITA Tomonori <[email protected]>
-
-Add dma_dev, a pointer to struct device, to struct ssb_device.  We pass it
-to the generic DMA API with SSB_BUSTYPE_PCI and SSB_BUSTYPE_SSB. 
-ssb_devices_register() sets up it properly.
-
-This is preparation for replacing the ssb bus specific DMA API (ssb_dma_*)
-with the generic DMA API.
-
-Signed-off-by: FUJITA Tomonori <[email protected]>
-Acked-by: Michael Buesch <[email protected]>
-Cc: Gary Zambrano <[email protected]>
-Cc: Stefano Brivio <[email protected]>
-Cc: Larry Finger <[email protected]>
-Cc: John W. Linville <[email protected]>
-Acked-by: David S. Miller <[email protected]>
-Signed-off-by: Andrew Morton <[email protected]>
----
-
- drivers/ssb/main.c      |    2 ++
- include/linux/ssb/ssb.h |    2 +-
- 2 files changed, 3 insertions(+), 1 deletion(-)
-
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -486,6 +486,7 @@ static int ssb_devices_register(struct s
- #ifdef CONFIG_SSB_PCIHOST
- 			sdev->irq = bus->host_pci->irq;
- 			dev->parent = &bus->host_pci->dev;
-+			sdev->dma_dev = dev->parent;
- #endif
- 			break;
- 		case SSB_BUSTYPE_PCMCIA:
-@@ -501,6 +502,7 @@ static int ssb_devices_register(struct s
- 			break;
- 		case SSB_BUSTYPE_SSB:
- 			dev->dma_mask = &dev->coherent_dma_mask;
-+			sdev->dma_dev = dev;
- 			break;
- 		}
- 
---- a/include/linux/ssb/ssb.h
-+++ b/include/linux/ssb/ssb.h
-@@ -167,7 +167,7 @@ struct ssb_device {
- 	 * is an optimization. */
- 	const struct ssb_bus_ops *ops;
- 
--	struct device *dev;
-+	struct device *dev, *dma_dev;
- 
- 	struct ssb_bus *bus;
- 	struct ssb_device_id id;

+ 451 - 12
target/linux/generic/patches-2.6.34/975-ssb_update.patch

@@ -324,6 +324,16 @@
  	dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
  
  	err = b44_pci_init();
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -24,6 +24,7 @@ static const struct pci_device_id b43_pc
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
++	{ PCI_DEVICE(PCI_VENDOR_ID_BCM_GVC,  0x4318) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
 @@ -209,6 +209,24 @@ static void chipco_powercontrol_init(str
@@ -409,7 +419,51 @@
  }
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -486,6 +486,7 @@ static int ssb_devices_register(struct s
+@@ -385,6 +385,35 @@ static int ssb_device_uevent(struct devi
+ 			     ssb_dev->id.revision);
+ }
+ 
++#define ssb_config_attr(attrib, field, format_string) \
++static ssize_t \
++attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
++{ \
++	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
++}
++
++ssb_config_attr(core_num, core_index, "%u\n")
++ssb_config_attr(coreid, id.coreid, "0x%04x\n")
++ssb_config_attr(vendor, id.vendor, "0x%04x\n")
++ssb_config_attr(revision, id.revision, "%u\n")
++ssb_config_attr(irq, irq, "%u\n")
++static ssize_t
++name_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n",
++		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
++}
++
++static struct device_attribute ssb_device_attrs[] = {
++	__ATTR_RO(name),
++	__ATTR_RO(core_num),
++	__ATTR_RO(coreid),
++	__ATTR_RO(vendor),
++	__ATTR_RO(revision),
++	__ATTR_RO(irq),
++	__ATTR_NULL,
++};
++
+ static struct bus_type ssb_bustype = {
+ 	.name		= "ssb",
+ 	.match		= ssb_bus_match,
+@@ -394,6 +423,7 @@ static struct bus_type ssb_bustype = {
+ 	.suspend	= ssb_device_suspend,
+ 	.resume		= ssb_device_resume,
+ 	.uevent		= ssb_device_uevent,
++	.dev_attrs	= ssb_device_attrs,
+ };
+ 
+ static void ssb_buses_lock(void)
+@@ -486,6 +516,7 @@ static int ssb_devices_register(struct s
  #ifdef CONFIG_SSB_PCIHOST
  			sdev->irq = bus->host_pci->irq;
  			dev->parent = &bus->host_pci->dev;
@@ -417,7 +471,7 @@
  #endif
  			break;
  		case SSB_BUSTYPE_PCMCIA:
-@@ -501,6 +502,7 @@ static int ssb_devices_register(struct s
+@@ -501,6 +532,7 @@ static int ssb_devices_register(struct s
  			break;
  		case SSB_BUSTYPE_SSB:
  			dev->dma_mask = &dev->coherent_dma_mask;
@@ -425,7 +479,7 @@
  			break;
  		}
  
-@@ -834,6 +836,9 @@ int ssb_bus_pcibus_register(struct ssb_b
+@@ -834,6 +866,9 @@ int ssb_bus_pcibus_register(struct ssb_b
  	if (!err) {
  		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
  			   "PCI device %s\n", dev_name(&host_pci->dev));
@@ -435,7 +489,78 @@
  	}
  
  	return err;
-@@ -1223,80 +1228,6 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1159,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+ 
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+  * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+-			int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++			 int timeout, int set)
+ {
+ 	int i;
+ 	u32 val;
+@@ -1170,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
+ 	for (i = 0; i < timeout; i++) {
+ 		val = ssb_read32(dev, reg);
+ 		if (set) {
+-			if (val & bitmask)
++			if ((val & bitmask) == bitmask)
+ 				return 0;
+ 		} else {
+ 			if (!(val & bitmask))
+@@ -1187,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
+ 
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+-	u32 reject;
++	u32 reject, val;
+ 
+ 	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ 		return;
+ 
+ 	reject = ssb_tmslow_reject_bitmask(dev);
+-	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+-	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+-	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+-	ssb_write32(dev, SSB_TMSLOW,
+-		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+-		    reject | SSB_TMSLOW_RESET |
+-		    core_specific_flags);
+-	ssb_flush_tmslow(dev);
++
++	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val |= SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++				      0);
++		}
++
++		ssb_write32(dev, SSB_TMSLOW,
++			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++			reject | SSB_TMSLOW_RESET |
++			core_specific_flags);
++		ssb_flush_tmslow(dev);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val &= ~SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++		}
++	}
+ 
+ 	ssb_write32(dev, SSB_TMSLOW,
+ 		    reject | SSB_TMSLOW_RESET |
+@@ -1223,80 +1276,6 @@ u32 ssb_dma_translation(struct ssb_devic
  }
  EXPORT_SYMBOL(ssb_dma_translation);
  
@@ -527,9 +652,270 @@
  /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
  #define SPEX16(_outvar, _offset, _mask, _shift)	\
  	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
+ 	out->antenna_gain.ghz5.a3 = gain;
+ }
+ 
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
++
++	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
++	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
++	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
++	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
++
++	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
++	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
++	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
++	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
++
++	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
++	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
++	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
++	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
++}
++
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+@@ -428,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ 		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ 	} else {
+ 		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ 	}
+ 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -471,6 +515,8 @@ static void sprom_extract_r45(struct ssb
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 4 stuff needed */
+ }
+ 
+@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 8 stuff needed */
+ }
+ 
+@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+ 	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
+ 	memset(out->et1mac, 0xFF, 6);
++
+ 	if ((bus->chip_id & 0xFF00) == 0x4400) {
+ 		/* Workaround: The BCM44XX chip has a stupid revision
+ 		 * number stored in the SPROM.
+ 		 * Always extract r1. */
+ 		out->revision = 1;
++		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++	}
++
++	switch (out->revision) {
++	case 1:
++	case 2:
++	case 3:
+ 		sprom_extract_r123(out, in);
+-	} else if (bus->chip_id == 0x4321) {
+-		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+-		out->revision = 4;
++		break;
++	case 4:
++	case 5:
+ 		sprom_extract_r45(out, in);
+-	} else {
+-		switch (out->revision) {
+-		case 1:
+-		case 2:
+-		case 3:
+-			sprom_extract_r123(out, in);
+-			break;
+-		case 4:
+-		case 5:
+-			sprom_extract_r45(out, in);
+-			break;
+-		case 8:
+-			sprom_extract_r8(out, in);
+-			break;
+-		default:
+-			ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-				   "  revision %d detected. Will extract"
+-				   " v1\n", out->revision);
+-			out->revision = 1;
+-			sprom_extract_r123(out, in);
+-		}
++		break;
++	case 8:
++		sprom_extract_r8(out, in);
++		break;
++	default:
++		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
++			   " revision %d detected. Will extract"
++			   " v1\n", out->revision);
++		out->revision = 1;
++		sprom_extract_r123(out, in);
+ 	}
+ 
+ 	if (out->boardflags_lo == 0xFFFF)
+@@ -618,7 +663,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 			     struct ssb_sprom *sprom)
+ {
+ 	const struct ssb_sprom *fallback;
+-	int err = -ENOMEM;
++	int err;
+ 	u16 *buf;
+ 
+ 	if (!ssb_is_sprom_available(bus)) {
+@@ -645,7 +690,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ 	if (!buf)
+-		goto out;
++		return -ENOMEM;
+ 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ 	sprom_do_read(bus, buf);
+ 	err = sprom_check_crc(buf, bus->sprom_size);
+@@ -655,7 +700,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ 			      GFP_KERNEL);
+ 		if (!buf)
+-			goto out;
++			return -ENOMEM;
+ 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ 		sprom_do_read(bus, buf);
+ 		err = sprom_check_crc(buf, bus->sprom_size);
+@@ -677,7 +722,6 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ out_free:
+ 	kfree(buf);
+-out:
+ 	return err;
+ }
+ 
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -59,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_
+ 	struct ssb_bus *ssb;
+ 	int err = -ENOMEM;
+ 	const char *name;
++	u32 val;
+ 
+ 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ 	if (!ssb)
+@@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_
+ 		goto err_pci_disable;
+ 	pci_set_master(dev);
+ 
++	/* Disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state */
++	pci_read_config_dword(dev, 0x40, &val);
++	if ((val & 0x0000ff00) != 0)
++		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
++
+ 	err = ssb_bus_pcibus_register(ssb, dev);
+ 	if (err)
+ 		goto err_pci_release_regions;
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -745,7 +745,7 @@ int ssb_pcmcia_get_invariants(struct ssb
+ 
+ 	/* Fetch the vendor specific tuples. */
+ 	res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
+-				ssb_pcmcia_do_get_invariants, sprom);
++				ssb_pcmcia_do_get_invariants, iv);
+ 	if ((res == 0) || (res == -ENOSPC))
+ 		return 0;
+ 
+--- a/drivers/ssb/scan.c
++++ b/drivers/ssb/scan.c
+@@ -407,10 +407,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 				/* Ignore PCI cores on PCI-E cards.
+ 				 * Ignore PCI-E cores on PCI cards. */
+ 				if (dev->id.coreid == SSB_DEV_PCI) {
+-					if (bus->host_pci->is_pcie)
++					if (pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				} else {
+-					if (!bus->host_pci->is_pcie)
++					if (!pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				}
+ 			}
+@@ -422,6 +422,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 			bus->pcicore.dev = dev;
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ 			break;
++		case SSB_DEV_ETHERNET:
++			if (bus->bustype == SSB_BUSTYPE_PCI) {
++				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
++				    (bus->host_pci->device & 0xFF00) == 0x4300) {
++					/* This is a dangling ethernet core on a
++					 * wireless device. Ignore it. */
++					continue;
++				}
++			}
++			break;
+ 		default:
+ 			break;
+ 		}
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -2038,6 +2038,7 @@
+ #define PCI_DEVICE_ID_AFAVLAB_P030	0x2182
+ #define PCI_SUBDEVICE_ID_AFAVLAB_P061		0x2150
+ 
++#define PCI_VENDOR_ID_BCM_GVC          0x14a4
+ #define PCI_VENDOR_ID_BROADCOM		0x14e4
+ #define PCI_DEVICE_ID_TIGON3_5752	0x1600
+ #define PCI_DEVICE_ID_TIGON3_5752M	0x1601
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -167,7 +167,7 @@ struct ssb_device {
+@@ -55,6 +55,10 @@ struct ssb_sprom {
+ 	u8 tri5gl;		/* 5.2GHz TX isolation */
+ 	u8 tri5g;		/* 5.3GHz TX isolation */
+ 	u8 tri5gh;		/* 5.8GHz TX isolation */
++	u8 txpid2g[4];		/* 2GHz TX power index */
++	u8 txpid5gl[4];		/* 4.9 - 5.1GHz TX power index */
++	u8 txpid5g[4];		/* 5.1 - 5.5GHz TX power index */
++	u8 txpid5gh[4];		/* 5.5 - ...GHz TX power index */
+ 	u8 rxpo2g;		/* 2GHz RX power offset */
+ 	u8 rxpo5g;		/* 5GHz RX power offset */
+ 	u8 rssisav2g;		/* 2GHz RSSI params */
+@@ -167,7 +171,7 @@ struct ssb_device {
  	 * is an optimization. */
  	const struct ssb_bus_ops *ops;
  
@@ -538,7 +924,7 @@
  
  	struct ssb_bus *bus;
  	struct ssb_device_id id;
-@@ -470,14 +470,6 @@ extern u32 ssb_dma_translation(struct ss
+@@ -470,14 +474,6 @@ extern u32 ssb_dma_translation(struct ss
  #define SSB_DMA_TRANSLATION_MASK	0xC0000000
  #define SSB_DMA_TRANSLATION_SHIFT	30
  
@@ -553,7 +939,7 @@
  static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
  {
  #ifdef CONFIG_SSB_DEBUG
-@@ -486,155 +478,6 @@ static inline void __cold __ssb_dma_not_
+@@ -486,155 +482,6 @@ static inline void __cold __ssb_dma_not_
  #endif /* DEBUG */
  }
  
@@ -711,7 +1097,16 @@
  extern int ssb_pcihost_register(struct pci_driver *driver);
 --- a/include/linux/ssb/ssb_regs.h
 +++ b/include/linux/ssb/ssb_regs.h
-@@ -172,25 +172,25 @@
+@@ -85,6 +85,8 @@
+ #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+ #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+ #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
++#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
++#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
+ #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+ #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+ #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+@@ -172,25 +174,25 @@
  #define SSB_SPROMSIZE_BYTES_R4		(SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
  #define SSB_SPROM_BASE1			0x1000
  #define SSB_SPROM_BASE31		0x0800
@@ -746,7 +1141,7 @@
  #define  SSB_SPROM1_BINF_BREV		0x00FF	/* Board Revision */
  #define  SSB_SPROM1_BINF_CCODE		0x0F00	/* Country Code */
  #define  SSB_SPROM1_BINF_CCODE_SHIFT	8
-@@ -198,63 +198,63 @@
+@@ -198,63 +200,63 @@
  #define  SSB_SPROM1_BINF_ANTBG_SHIFT	12
  #define  SSB_SPROM1_BINF_ANTA		0xC000	/* Available A-PHY antennas */
  #define  SSB_SPROM1_BINF_ANTA_SHIFT	14
@@ -838,7 +1233,7 @@
  #define  SSB_SPROM3_CCKPO_1M		0x000F	/* 1M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M		0x00F0	/* 2M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M_SHIFT	4
-@@ -265,100 +265,100 @@
+@@ -265,100 +267,144 @@
  #define  SSB_SPROM3_OFDMGPO		0x107A	/* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
  
  /* SPROM Revision 4 */
@@ -846,6 +1241,8 @@
 -#define SSB_SPROM4_ETHPHY		0x105A	/* Ethernet PHY settings ?? */
 +#define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
 +#define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
++#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
 +#define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
 +#define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
 +#define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
@@ -888,6 +1285,46 @@
  #define  SSB_SPROM4_AGAIN3_SHIFT	8
 -#define SSB_SPROM4_BFLHI		0x1046  /* Board Flags Hi */
 -#define SSB_SPROM4_MAXP_BG		0x1080  /* Max Power BG in path 1 */
++#define SSB_SPROM4_TXPID2G01		0x0062 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G0		0x00FF
++#define  SSB_SPROM4_TXPID2G0_SHIFT	0
++#define  SSB_SPROM4_TXPID2G1		0xFF00
++#define  SSB_SPROM4_TXPID2G1_SHIFT	8
++#define SSB_SPROM4_TXPID2G23		0x0064 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G2		0x00FF
++#define  SSB_SPROM4_TXPID2G2_SHIFT	0
++#define  SSB_SPROM4_TXPID2G3		0xFF00
++#define  SSB_SPROM4_TXPID2G3_SHIFT	8
++#define SSB_SPROM4_TXPID5G01		0x0066 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G0		0x00FF
++#define  SSB_SPROM4_TXPID5G0_SHIFT	0
++#define  SSB_SPROM4_TXPID5G1		0xFF00
++#define  SSB_SPROM4_TXPID5G1_SHIFT	8
++#define SSB_SPROM4_TXPID5G23		0x0068 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G2		0x00FF
++#define  SSB_SPROM4_TXPID5G2_SHIFT	0
++#define  SSB_SPROM4_TXPID5G3		0xFF00
++#define  SSB_SPROM4_TXPID5G3_SHIFT	8
++#define SSB_SPROM4_TXPID5GL01		0x006A 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL0		0x00FF
++#define  SSB_SPROM4_TXPID5GL0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL1		0xFF00
++#define  SSB_SPROM4_TXPID5GL1_SHIFT	8
++#define SSB_SPROM4_TXPID5GL23		0x006C 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL2		0x00FF
++#define  SSB_SPROM4_TXPID5GL2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL3		0xFF00
++#define  SSB_SPROM4_TXPID5GL3_SHIFT	8
++#define SSB_SPROM4_TXPID5GH01		0x006E 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH0		0x00FF
++#define  SSB_SPROM4_TXPID5GH0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH1		0xFF00
++#define  SSB_SPROM4_TXPID5GH1_SHIFT	8
++#define SSB_SPROM4_TXPID5GH23		0x0070 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH2		0x00FF
++#define  SSB_SPROM4_TXPID5GH2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH3		0xFF00
++#define  SSB_SPROM4_TXPID5GH3_SHIFT	8
 +#define SSB_SPROM4_MAXP_BG		0x0080  /* Max Power BG in path 1 */
  #define  SSB_SPROM4_MAXP_BG_MASK	0x00FF  /* Mask for Max Power BG */
  #define  SSB_SPROM4_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
@@ -927,6 +1364,8 @@
 +#define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
 +#define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
 +#define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
++#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
 +#define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
 +#define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
  #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */
@@ -996,7 +1435,7 @@
  #define  SSB_SPROM8_RSSISMF2G		0x000F
  #define  SSB_SPROM8_RSSISMC2G		0x00F0
  #define  SSB_SPROM8_RSSISMC2G_SHIFT	4
-@@ -366,7 +366,7 @@
+@@ -366,7 +412,7 @@
  #define  SSB_SPROM8_RSSISAV2G_SHIFT	8
  #define  SSB_SPROM8_BXA2G		0x1800
  #define  SSB_SPROM8_BXA2G_SHIFT		11
@@ -1005,7 +1444,7 @@
  #define  SSB_SPROM8_RSSISMF5G		0x000F
  #define  SSB_SPROM8_RSSISMC5G		0x00F0
  #define  SSB_SPROM8_RSSISMC5G_SHIFT	4
-@@ -374,47 +374,47 @@
+@@ -374,47 +420,47 @@
  #define  SSB_SPROM8_RSSISAV5G_SHIFT	8
  #define  SSB_SPROM8_BXA5G		0x1800
  #define  SSB_SPROM8_BXA5G_SHIFT		11

+ 480 - 14
target/linux/generic/patches-2.6.35/975-ssb_update.patch

@@ -1,11 +1,3 @@
----
- drivers/net/b44.c                   |  146 +++++++++++++++------------------
- drivers/ssb/driver_chipcommon.c     |   24 +++++
- drivers/ssb/driver_chipcommon_pmu.c |   17 +--
- drivers/ssb/main.c                  |   76 -----------------
- include/linux/ssb/ssb.h             |  159 ------------------------------------
- 5 files changed, 104 insertions(+), 318 deletions(-)
-
 --- a/drivers/net/b44.c
 +++ b/drivers/net/b44.c
 @@ -135,7 +135,6 @@ static void b44_init_rings(struct b44 *)
@@ -400,7 +392,51 @@
  }
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -486,6 +486,7 @@ static int ssb_devices_register(struct s
+@@ -385,6 +385,35 @@ static int ssb_device_uevent(struct devi
+ 			     ssb_dev->id.revision);
+ }
+ 
++#define ssb_config_attr(attrib, field, format_string) \
++static ssize_t \
++attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
++{ \
++	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
++}
++
++ssb_config_attr(core_num, core_index, "%u\n")
++ssb_config_attr(coreid, id.coreid, "0x%04x\n")
++ssb_config_attr(vendor, id.vendor, "0x%04x\n")
++ssb_config_attr(revision, id.revision, "%u\n")
++ssb_config_attr(irq, irq, "%u\n")
++static ssize_t
++name_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n",
++		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
++}
++
++static struct device_attribute ssb_device_attrs[] = {
++	__ATTR_RO(name),
++	__ATTR_RO(core_num),
++	__ATTR_RO(coreid),
++	__ATTR_RO(vendor),
++	__ATTR_RO(revision),
++	__ATTR_RO(irq),
++	__ATTR_NULL,
++};
++
+ static struct bus_type ssb_bustype = {
+ 	.name		= "ssb",
+ 	.match		= ssb_bus_match,
+@@ -394,6 +423,7 @@ static struct bus_type ssb_bustype = {
+ 	.suspend	= ssb_device_suspend,
+ 	.resume		= ssb_device_resume,
+ 	.uevent		= ssb_device_uevent,
++	.dev_attrs	= ssb_device_attrs,
+ };
+ 
+ static void ssb_buses_lock(void)
+@@ -486,6 +516,7 @@ static int ssb_devices_register(struct s
  #ifdef CONFIG_SSB_PCIHOST
  			sdev->irq = bus->host_pci->irq;
  			dev->parent = &bus->host_pci->dev;
@@ -408,7 +444,7 @@
  #endif
  			break;
  		case SSB_BUSTYPE_PCMCIA:
-@@ -501,6 +502,7 @@ static int ssb_devices_register(struct s
+@@ -501,6 +532,7 @@ static int ssb_devices_register(struct s
  			break;
  		case SSB_BUSTYPE_SSB:
  			dev->dma_mask = &dev->coherent_dma_mask;
@@ -416,7 +452,78 @@
  			break;
  		}
  
-@@ -1226,80 +1228,6 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1162,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+ 
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+  * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+-			int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++			 int timeout, int set)
+ {
+ 	int i;
+ 	u32 val;
+@@ -1173,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
+ 	for (i = 0; i < timeout; i++) {
+ 		val = ssb_read32(dev, reg);
+ 		if (set) {
+-			if (val & bitmask)
++			if ((val & bitmask) == bitmask)
+ 				return 0;
+ 		} else {
+ 			if (!(val & bitmask))
+@@ -1190,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
+ 
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+-	u32 reject;
++	u32 reject, val;
+ 
+ 	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ 		return;
+ 
+ 	reject = ssb_tmslow_reject_bitmask(dev);
+-	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+-	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+-	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+-	ssb_write32(dev, SSB_TMSLOW,
+-		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+-		    reject | SSB_TMSLOW_RESET |
+-		    core_specific_flags);
+-	ssb_flush_tmslow(dev);
++
++	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val |= SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++				      0);
++		}
++
++		ssb_write32(dev, SSB_TMSLOW,
++			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++			reject | SSB_TMSLOW_RESET |
++			core_specific_flags);
++		ssb_flush_tmslow(dev);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val &= ~SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++		}
++	}
+ 
+ 	ssb_write32(dev, SSB_TMSLOW,
+ 		    reject | SSB_TMSLOW_RESET |
+@@ -1226,80 +1276,6 @@ u32 ssb_dma_translation(struct ssb_devic
  }
  EXPORT_SYMBOL(ssb_dma_translation);
  
@@ -497,9 +604,262 @@
  int ssb_bus_may_powerdown(struct ssb_bus *bus)
  {
  	struct ssb_chipcommon *cc;
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
+ 	out->antenna_gain.ghz5.a3 = gain;
+ }
+ 
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
++
++	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
++	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
++	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
++	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
++
++	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
++	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
++	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
++	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
++
++	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
++	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
++	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
++	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
++}
++
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+@@ -428,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ 		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ 	} else {
+ 		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ 	}
+ 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -471,6 +515,8 @@ static void sprom_extract_r45(struct ssb
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 4 stuff needed */
+ }
+ 
+@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 8 stuff needed */
+ }
+ 
+@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+ 	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
+ 	memset(out->et1mac, 0xFF, 6);
++
+ 	if ((bus->chip_id & 0xFF00) == 0x4400) {
+ 		/* Workaround: The BCM44XX chip has a stupid revision
+ 		 * number stored in the SPROM.
+ 		 * Always extract r1. */
+ 		out->revision = 1;
++		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++	}
++
++	switch (out->revision) {
++	case 1:
++	case 2:
++	case 3:
+ 		sprom_extract_r123(out, in);
+-	} else if (bus->chip_id == 0x4321) {
+-		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+-		out->revision = 4;
++		break;
++	case 4:
++	case 5:
+ 		sprom_extract_r45(out, in);
+-	} else {
+-		switch (out->revision) {
+-		case 1:
+-		case 2:
+-		case 3:
+-			sprom_extract_r123(out, in);
+-			break;
+-		case 4:
+-		case 5:
+-			sprom_extract_r45(out, in);
+-			break;
+-		case 8:
+-			sprom_extract_r8(out, in);
+-			break;
+-		default:
+-			ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-				   "  revision %d detected. Will extract"
+-				   " v1\n", out->revision);
+-			out->revision = 1;
+-			sprom_extract_r123(out, in);
+-		}
++		break;
++	case 8:
++		sprom_extract_r8(out, in);
++		break;
++	default:
++		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
++			   " revision %d detected. Will extract"
++			   " v1\n", out->revision);
++		out->revision = 1;
++		sprom_extract_r123(out, in);
+ 	}
+ 
+ 	if (out->boardflags_lo == 0xFFFF)
+@@ -618,7 +663,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 			     struct ssb_sprom *sprom)
+ {
+ 	const struct ssb_sprom *fallback;
+-	int err = -ENOMEM;
++	int err;
+ 	u16 *buf;
+ 
+ 	if (!ssb_is_sprom_available(bus)) {
+@@ -645,7 +690,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ 	if (!buf)
+-		goto out;
++		return -ENOMEM;
+ 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ 	sprom_do_read(bus, buf);
+ 	err = sprom_check_crc(buf, bus->sprom_size);
+@@ -655,7 +700,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ 			      GFP_KERNEL);
+ 		if (!buf)
+-			goto out;
++			return -ENOMEM;
+ 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ 		sprom_do_read(bus, buf);
+ 		err = sprom_check_crc(buf, bus->sprom_size);
+@@ -677,7 +722,6 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ out_free:
+ 	kfree(buf);
+-out:
+ 	return err;
+ }
+ 
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -59,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_
+ 	struct ssb_bus *ssb;
+ 	int err = -ENOMEM;
+ 	const char *name;
++	u32 val;
+ 
+ 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ 	if (!ssb)
+@@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_
+ 		goto err_pci_disable;
+ 	pci_set_master(dev);
+ 
++	/* Disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state */
++	pci_read_config_dword(dev, 0x40, &val);
++	if ((val & 0x0000ff00) != 0)
++		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
++
+ 	err = ssb_bus_pcibus_register(ssb, dev);
+ 	if (err)
+ 		goto err_pci_release_regions;
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -745,7 +745,7 @@ int ssb_pcmcia_get_invariants(struct ssb
+ 
+ 	/* Fetch the vendor specific tuples. */
+ 	res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
+-				ssb_pcmcia_do_get_invariants, sprom);
++				ssb_pcmcia_do_get_invariants, iv);
+ 	if ((res == 0) || (res == -ENOSPC))
+ 		return 0;
+ 
+--- a/drivers/ssb/scan.c
++++ b/drivers/ssb/scan.c
+@@ -407,10 +407,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 				/* Ignore PCI cores on PCI-E cards.
+ 				 * Ignore PCI-E cores on PCI cards. */
+ 				if (dev->id.coreid == SSB_DEV_PCI) {
+-					if (bus->host_pci->is_pcie)
++					if (pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				} else {
+-					if (!bus->host_pci->is_pcie)
++					if (!pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				}
+ 			}
+@@ -422,6 +422,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 			bus->pcicore.dev = dev;
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ 			break;
++		case SSB_DEV_ETHERNET:
++			if (bus->bustype == SSB_BUSTYPE_PCI) {
++				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
++				    (bus->host_pci->device & 0xFF00) == 0x4300) {
++					/* This is a dangling ethernet core on a
++					 * wireless device. Ignore it. */
++					continue;
++				}
++			}
++			break;
+ 		default:
+ 			break;
+ 		}
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -167,7 +167,7 @@ struct ssb_device {
+@@ -55,6 +55,10 @@ struct ssb_sprom {
+ 	u8 tri5gl;		/* 5.2GHz TX isolation */
+ 	u8 tri5g;		/* 5.3GHz TX isolation */
+ 	u8 tri5gh;		/* 5.8GHz TX isolation */
++	u8 txpid2g[4];		/* 2GHz TX power index */
++	u8 txpid5gl[4];		/* 4.9 - 5.1GHz TX power index */
++	u8 txpid5g[4];		/* 5.1 - 5.5GHz TX power index */
++	u8 txpid5gh[4];		/* 5.5 - ...GHz TX power index */
+ 	u8 rxpo2g;		/* 2GHz RX power offset */
+ 	u8 rxpo5g;		/* 5GHz RX power offset */
+ 	u8 rssisav2g;		/* 2GHz RSSI params */
+@@ -167,7 +171,7 @@ struct ssb_device {
  	 * is an optimization. */
  	const struct ssb_bus_ops *ops;
  
@@ -508,7 +868,7 @@
  
  	struct ssb_bus *bus;
  	struct ssb_device_id id;
-@@ -470,14 +470,6 @@ extern u32 ssb_dma_translation(struct ss
+@@ -470,14 +474,6 @@ extern u32 ssb_dma_translation(struct ss
  #define SSB_DMA_TRANSLATION_MASK	0xC0000000
  #define SSB_DMA_TRANSLATION_SHIFT	30
  
@@ -523,7 +883,7 @@
  static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
  {
  #ifdef CONFIG_SSB_DEBUG
-@@ -486,155 +478,6 @@ static inline void __cold __ssb_dma_not_
+@@ -486,155 +482,6 @@ static inline void __cold __ssb_dma_not_
  #endif /* DEBUG */
  }
  
@@ -679,3 +1039,109 @@
  #ifdef CONFIG_SSB_PCIHOST
  /* PCI-host wrapper driver */
  extern int ssb_pcihost_register(struct pci_driver *driver);
+--- a/include/linux/ssb/ssb_driver_gige.h
++++ b/include/linux/ssb/ssb_driver_gige.h
+@@ -96,16 +96,21 @@ static inline bool ssb_gige_must_flush_p
+ 	return 0;
+ }
+ 
+-extern char * nvram_get(const char *name);
++#ifdef CONFIG_BCM47XX
++#include <asm/mach-bcm47xx/nvram.h>
+ /* Get the device MAC address */
+ static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
+ {
+-#ifdef CONFIG_BCM47XX
+-	char *res = nvram_get("et0macaddr");
+-	if (res)
+-		memcpy(macaddr, res, 6);
+-#endif
++	char buf[20];
++	if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0)
++		return;
++	nvram_parse_macaddr(buf, macaddr);
+ }
++#else
++static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
++{
++}
++#endif
+ 
+ extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
+ 					  struct pci_dev *pdev);
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -85,6 +85,8 @@
+ #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+ #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+ #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
++#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
++#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
+ #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+ #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+ #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+@@ -267,6 +269,8 @@
+ /* SPROM Revision 4 */
+ #define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
++#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
+ #define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
+ #define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
+@@ -298,6 +302,46 @@
+ #define  SSB_SPROM4_AGAIN2_SHIFT	0
+ #define  SSB_SPROM4_AGAIN3		0xFF00	/* Antenna 3 */
+ #define  SSB_SPROM4_AGAIN3_SHIFT	8
++#define SSB_SPROM4_TXPID2G01		0x0062 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G0		0x00FF
++#define  SSB_SPROM4_TXPID2G0_SHIFT	0
++#define  SSB_SPROM4_TXPID2G1		0xFF00
++#define  SSB_SPROM4_TXPID2G1_SHIFT	8
++#define SSB_SPROM4_TXPID2G23		0x0064 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G2		0x00FF
++#define  SSB_SPROM4_TXPID2G2_SHIFT	0
++#define  SSB_SPROM4_TXPID2G3		0xFF00
++#define  SSB_SPROM4_TXPID2G3_SHIFT	8
++#define SSB_SPROM4_TXPID5G01		0x0066 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G0		0x00FF
++#define  SSB_SPROM4_TXPID5G0_SHIFT	0
++#define  SSB_SPROM4_TXPID5G1		0xFF00
++#define  SSB_SPROM4_TXPID5G1_SHIFT	8
++#define SSB_SPROM4_TXPID5G23		0x0068 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G2		0x00FF
++#define  SSB_SPROM4_TXPID5G2_SHIFT	0
++#define  SSB_SPROM4_TXPID5G3		0xFF00
++#define  SSB_SPROM4_TXPID5G3_SHIFT	8
++#define SSB_SPROM4_TXPID5GL01		0x006A 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL0		0x00FF
++#define  SSB_SPROM4_TXPID5GL0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL1		0xFF00
++#define  SSB_SPROM4_TXPID5GL1_SHIFT	8
++#define SSB_SPROM4_TXPID5GL23		0x006C 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL2		0x00FF
++#define  SSB_SPROM4_TXPID5GL2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL3		0xFF00
++#define  SSB_SPROM4_TXPID5GL3_SHIFT	8
++#define SSB_SPROM4_TXPID5GH01		0x006E 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH0		0x00FF
++#define  SSB_SPROM4_TXPID5GH0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH1		0xFF00
++#define  SSB_SPROM4_TXPID5GH1_SHIFT	8
++#define SSB_SPROM4_TXPID5GH23		0x0070 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH2		0x00FF
++#define  SSB_SPROM4_TXPID5GH2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH3		0xFF00
++#define  SSB_SPROM4_TXPID5GH3_SHIFT	8
+ #define SSB_SPROM4_MAXP_BG		0x0080  /* Max Power BG in path 1 */
+ #define  SSB_SPROM4_MAXP_BG_MASK	0x00FF  /* Mask for Max Power BG */
+ #define  SSB_SPROM4_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
+@@ -317,6 +361,8 @@
+ #define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
+ #define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
++#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
+ #define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
+ #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */

+ 467 - 0
target/linux/generic/patches-2.6.36/941-ssb_update.patch

@@ -0,0 +1,467 @@
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -384,6 +384,35 @@ static int ssb_device_uevent(struct devi
+ 			     ssb_dev->id.revision);
+ }
+ 
++#define ssb_config_attr(attrib, field, format_string) \
++static ssize_t \
++attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
++{ \
++	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
++}
++
++ssb_config_attr(core_num, core_index, "%u\n")
++ssb_config_attr(coreid, id.coreid, "0x%04x\n")
++ssb_config_attr(vendor, id.vendor, "0x%04x\n")
++ssb_config_attr(revision, id.revision, "%u\n")
++ssb_config_attr(irq, irq, "%u\n")
++static ssize_t
++name_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n",
++		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
++}
++
++static struct device_attribute ssb_device_attrs[] = {
++	__ATTR_RO(name),
++	__ATTR_RO(core_num),
++	__ATTR_RO(coreid),
++	__ATTR_RO(vendor),
++	__ATTR_RO(revision),
++	__ATTR_RO(irq),
++	__ATTR_NULL,
++};
++
+ static struct bus_type ssb_bustype = {
+ 	.name		= "ssb",
+ 	.match		= ssb_bus_match,
+@@ -393,6 +422,7 @@ static struct bus_type ssb_bustype = {
+ 	.suspend	= ssb_device_suspend,
+ 	.resume		= ssb_device_resume,
+ 	.uevent		= ssb_device_uevent,
++	.dev_attrs	= ssb_device_attrs,
+ };
+ 
+ static void ssb_buses_lock(void)
+@@ -1163,10 +1193,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+ 
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+  * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+-			int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++			 int timeout, int set)
+ {
+ 	int i;
+ 	u32 val;
+@@ -1174,7 +1204,7 @@ static int ssb_wait_bit(struct ssb_devic
+ 	for (i = 0; i < timeout; i++) {
+ 		val = ssb_read32(dev, reg);
+ 		if (set) {
+-			if (val & bitmask)
++			if ((val & bitmask) == bitmask)
+ 				return 0;
+ 		} else {
+ 			if (!(val & bitmask))
+@@ -1191,20 +1221,38 @@ static int ssb_wait_bit(struct ssb_devic
+ 
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+-	u32 reject;
++	u32 reject, val;
+ 
+ 	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ 		return;
+ 
+ 	reject = ssb_tmslow_reject_bitmask(dev);
+-	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+-	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+-	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+-	ssb_write32(dev, SSB_TMSLOW,
+-		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+-		    reject | SSB_TMSLOW_RESET |
+-		    core_specific_flags);
+-	ssb_flush_tmslow(dev);
++
++	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val |= SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++				      0);
++		}
++
++		ssb_write32(dev, SSB_TMSLOW,
++			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++			reject | SSB_TMSLOW_RESET |
++			core_specific_flags);
++		ssb_flush_tmslow(dev);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val &= ~SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++		}
++	}
+ 
+ 	ssb_write32(dev, SSB_TMSLOW,
+ 		    reject | SSB_TMSLOW_RESET |
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
+ 	out->antenna_gain.ghz5.a3 = gain;
+ }
+ 
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
++
++	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
++	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
++	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
++	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
++
++	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
++	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
++	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
++	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
++
++	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
++	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
++	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
++	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
++}
++
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+@@ -428,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ 		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ 	} else {
+ 		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ 	}
+ 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -471,6 +515,8 @@ static void sprom_extract_r45(struct ssb
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 4 stuff needed */
+ }
+ 
+@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 8 stuff needed */
+ }
+ 
+@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+ 	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
+ 	memset(out->et1mac, 0xFF, 6);
++
+ 	if ((bus->chip_id & 0xFF00) == 0x4400) {
+ 		/* Workaround: The BCM44XX chip has a stupid revision
+ 		 * number stored in the SPROM.
+ 		 * Always extract r1. */
+ 		out->revision = 1;
++		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++	}
++
++	switch (out->revision) {
++	case 1:
++	case 2:
++	case 3:
+ 		sprom_extract_r123(out, in);
+-	} else if (bus->chip_id == 0x4321) {
+-		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+-		out->revision = 4;
++		break;
++	case 4:
++	case 5:
+ 		sprom_extract_r45(out, in);
+-	} else {
+-		switch (out->revision) {
+-		case 1:
+-		case 2:
+-		case 3:
+-			sprom_extract_r123(out, in);
+-			break;
+-		case 4:
+-		case 5:
+-			sprom_extract_r45(out, in);
+-			break;
+-		case 8:
+-			sprom_extract_r8(out, in);
+-			break;
+-		default:
+-			ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-				   "  revision %d detected. Will extract"
+-				   " v1\n", out->revision);
+-			out->revision = 1;
+-			sprom_extract_r123(out, in);
+-		}
++		break;
++	case 8:
++		sprom_extract_r8(out, in);
++		break;
++	default:
++		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
++			   " revision %d detected. Will extract"
++			   " v1\n", out->revision);
++		out->revision = 1;
++		sprom_extract_r123(out, in);
+ 	}
+ 
+ 	if (out->boardflags_lo == 0xFFFF)
+@@ -618,7 +663,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 			     struct ssb_sprom *sprom)
+ {
+ 	const struct ssb_sprom *fallback;
+-	int err = -ENOMEM;
++	int err;
+ 	u16 *buf;
+ 
+ 	if (!ssb_is_sprom_available(bus)) {
+@@ -645,7 +690,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ 	if (!buf)
+-		goto out;
++		return -ENOMEM;
+ 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ 	sprom_do_read(bus, buf);
+ 	err = sprom_check_crc(buf, bus->sprom_size);
+@@ -655,7 +700,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ 			      GFP_KERNEL);
+ 		if (!buf)
+-			goto out;
++			return -ENOMEM;
+ 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ 		sprom_do_read(bus, buf);
+ 		err = sprom_check_crc(buf, bus->sprom_size);
+@@ -677,7 +722,6 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ out_free:
+ 	kfree(buf);
+-out:
+ 	return err;
+ }
+ 
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -59,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_
+ 	struct ssb_bus *ssb;
+ 	int err = -ENOMEM;
+ 	const char *name;
++	u32 val;
+ 
+ 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ 	if (!ssb)
+@@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_
+ 		goto err_pci_disable;
+ 	pci_set_master(dev);
+ 
++	/* Disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state */
++	pci_read_config_dword(dev, 0x40, &val);
++	if ((val & 0x0000ff00) != 0)
++		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
++
+ 	err = ssb_bus_pcibus_register(ssb, dev);
+ 	if (err)
+ 		goto err_pci_release_regions;
+--- a/drivers/ssb/scan.c
++++ b/drivers/ssb/scan.c
+@@ -406,10 +406,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 				/* Ignore PCI cores on PCI-E cards.
+ 				 * Ignore PCI-E cores on PCI cards. */
+ 				if (dev->id.coreid == SSB_DEV_PCI) {
+-					if (bus->host_pci->is_pcie)
++					if (pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				} else {
+-					if (!bus->host_pci->is_pcie)
++					if (!pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				}
+ 			}
+@@ -421,6 +421,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 			bus->pcicore.dev = dev;
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ 			break;
++		case SSB_DEV_ETHERNET:
++			if (bus->bustype == SSB_BUSTYPE_PCI) {
++				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
++				    (bus->host_pci->device & 0xFF00) == 0x4300) {
++					/* This is a dangling ethernet core on a
++					 * wireless device. Ignore it. */
++					continue;
++				}
++			}
++			break;
+ 		default:
+ 			break;
+ 		}
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -55,6 +55,10 @@ struct ssb_sprom {
+ 	u8 tri5gl;		/* 5.2GHz TX isolation */
+ 	u8 tri5g;		/* 5.3GHz TX isolation */
+ 	u8 tri5gh;		/* 5.8GHz TX isolation */
++	u8 txpid2g[4];		/* 2GHz TX power index */
++	u8 txpid5gl[4];		/* 4.9 - 5.1GHz TX power index */
++	u8 txpid5g[4];		/* 5.1 - 5.5GHz TX power index */
++	u8 txpid5gh[4];		/* 5.5 - ...GHz TX power index */
+ 	u8 rxpo2g;		/* 2GHz RX power offset */
+ 	u8 rxpo5g;		/* 5GHz RX power offset */
+ 	u8 rssisav2g;		/* 2GHz RSSI params */
+--- a/include/linux/ssb/ssb_driver_gige.h
++++ b/include/linux/ssb/ssb_driver_gige.h
+@@ -96,16 +96,21 @@ static inline bool ssb_gige_must_flush_p
+ 	return 0;
+ }
+ 
+-extern char * nvram_get(const char *name);
++#ifdef CONFIG_BCM47XX
++#include <asm/mach-bcm47xx/nvram.h>
+ /* Get the device MAC address */
+ static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
+ {
+-#ifdef CONFIG_BCM47XX
+-	char *res = nvram_get("et0macaddr");
+-	if (res)
+-		memcpy(macaddr, res, 6);
+-#endif
++	char buf[20];
++	if (nvram_getenv("et0macaddr", buf, sizeof(buf)) < 0)
++		return;
++	nvram_parse_macaddr(buf, macaddr);
+ }
++#else
++static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr)
++{
++}
++#endif
+ 
+ extern int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
+ 					  struct pci_dev *pdev);
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -85,6 +85,8 @@
+ #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+ #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+ #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
++#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
++#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
+ #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+ #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+ #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+@@ -267,6 +269,8 @@
+ /* SPROM Revision 4 */
+ #define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
++#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
+ #define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
+ #define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
+@@ -298,6 +302,46 @@
+ #define  SSB_SPROM4_AGAIN2_SHIFT	0
+ #define  SSB_SPROM4_AGAIN3		0xFF00	/* Antenna 3 */
+ #define  SSB_SPROM4_AGAIN3_SHIFT	8
++#define SSB_SPROM4_TXPID2G01		0x0062 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G0		0x00FF
++#define  SSB_SPROM4_TXPID2G0_SHIFT	0
++#define  SSB_SPROM4_TXPID2G1		0xFF00
++#define  SSB_SPROM4_TXPID2G1_SHIFT	8
++#define SSB_SPROM4_TXPID2G23		0x0064 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G2		0x00FF
++#define  SSB_SPROM4_TXPID2G2_SHIFT	0
++#define  SSB_SPROM4_TXPID2G3		0xFF00
++#define  SSB_SPROM4_TXPID2G3_SHIFT	8
++#define SSB_SPROM4_TXPID5G01		0x0066 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G0		0x00FF
++#define  SSB_SPROM4_TXPID5G0_SHIFT	0
++#define  SSB_SPROM4_TXPID5G1		0xFF00
++#define  SSB_SPROM4_TXPID5G1_SHIFT	8
++#define SSB_SPROM4_TXPID5G23		0x0068 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G2		0x00FF
++#define  SSB_SPROM4_TXPID5G2_SHIFT	0
++#define  SSB_SPROM4_TXPID5G3		0xFF00
++#define  SSB_SPROM4_TXPID5G3_SHIFT	8
++#define SSB_SPROM4_TXPID5GL01		0x006A 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL0		0x00FF
++#define  SSB_SPROM4_TXPID5GL0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL1		0xFF00
++#define  SSB_SPROM4_TXPID5GL1_SHIFT	8
++#define SSB_SPROM4_TXPID5GL23		0x006C 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL2		0x00FF
++#define  SSB_SPROM4_TXPID5GL2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL3		0xFF00
++#define  SSB_SPROM4_TXPID5GL3_SHIFT	8
++#define SSB_SPROM4_TXPID5GH01		0x006E 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH0		0x00FF
++#define  SSB_SPROM4_TXPID5GH0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH1		0xFF00
++#define  SSB_SPROM4_TXPID5GH1_SHIFT	8
++#define SSB_SPROM4_TXPID5GH23		0x0070 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH2		0x00FF
++#define  SSB_SPROM4_TXPID5GH2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH3		0xFF00
++#define  SSB_SPROM4_TXPID5GH3_SHIFT	8
+ #define SSB_SPROM4_MAXP_BG		0x0080  /* Max Power BG in path 1 */
+ #define  SSB_SPROM4_MAXP_BG_MASK	0x00FF  /* Mask for Max Power BG */
+ #define  SSB_SPROM4_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
+@@ -317,6 +361,8 @@
+ #define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
+ #define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
++#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
+ #define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
+ #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */

+ 445 - 0
target/linux/generic/patches-2.6.37/941-ssb_update.patch

@@ -0,0 +1,445 @@
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -383,6 +383,35 @@ static int ssb_device_uevent(struct devi
+ 			     ssb_dev->id.revision);
+ }
+ 
++#define ssb_config_attr(attrib, field, format_string) \
++static ssize_t \
++attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
++{ \
++	return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
++}
++
++ssb_config_attr(core_num, core_index, "%u\n")
++ssb_config_attr(coreid, id.coreid, "0x%04x\n")
++ssb_config_attr(vendor, id.vendor, "0x%04x\n")
++ssb_config_attr(revision, id.revision, "%u\n")
++ssb_config_attr(irq, irq, "%u\n")
++static ssize_t
++name_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	return sprintf(buf, "%s\n",
++		       ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
++}
++
++static struct device_attribute ssb_device_attrs[] = {
++	__ATTR_RO(name),
++	__ATTR_RO(core_num),
++	__ATTR_RO(coreid),
++	__ATTR_RO(vendor),
++	__ATTR_RO(revision),
++	__ATTR_RO(irq),
++	__ATTR_NULL,
++};
++
+ static struct bus_type ssb_bustype = {
+ 	.name		= "ssb",
+ 	.match		= ssb_bus_match,
+@@ -392,6 +421,7 @@ static struct bus_type ssb_bustype = {
+ 	.suspend	= ssb_device_suspend,
+ 	.resume		= ssb_device_resume,
+ 	.uevent		= ssb_device_uevent,
++	.dev_attrs	= ssb_device_attrs,
+ };
+ 
+ static void ssb_buses_lock(void)
+@@ -1162,10 +1192,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+ 
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+  * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+-			int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++			 int timeout, int set)
+ {
+ 	int i;
+ 	u32 val;
+@@ -1173,7 +1203,7 @@ static int ssb_wait_bit(struct ssb_devic
+ 	for (i = 0; i < timeout; i++) {
+ 		val = ssb_read32(dev, reg);
+ 		if (set) {
+-			if (val & bitmask)
++			if ((val & bitmask) == bitmask)
+ 				return 0;
+ 		} else {
+ 			if (!(val & bitmask))
+@@ -1190,20 +1220,38 @@ static int ssb_wait_bit(struct ssb_devic
+ 
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+-	u32 reject;
++	u32 reject, val;
+ 
+ 	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ 		return;
+ 
+ 	reject = ssb_tmslow_reject_bitmask(dev);
+-	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+-	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+-	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+-	ssb_write32(dev, SSB_TMSLOW,
+-		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+-		    reject | SSB_TMSLOW_RESET |
+-		    core_specific_flags);
+-	ssb_flush_tmslow(dev);
++
++	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val |= SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++				      0);
++		}
++
++		ssb_write32(dev, SSB_TMSLOW,
++			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++			reject | SSB_TMSLOW_RESET |
++			core_specific_flags);
++		ssb_flush_tmslow(dev);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val &= ~SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++		}
++	}
+ 
+ 	ssb_write32(dev, SSB_TMSLOW,
+ 		    reject | SSB_TMSLOW_RESET |
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
+ 	out->antenna_gain.ghz5.a3 = gain;
+ }
+ 
++/* Revs 4 5 and 8 have partially shared layout */
++static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
++{
++	SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
++	SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
++	     SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
++	SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
++	SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
++	     SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
++
++	SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
++	SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
++	     SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
++	SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
++	SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
++	     SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
++
++	SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
++	SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
++	     SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
++	SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
++	SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
++	     SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
++
++	SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
++	SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
++	     SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
++	SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
++	SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
++	     SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
++}
++
+ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
+ {
+ 	int i;
+@@ -428,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ 		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ 	} else {
+ 		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ 	}
+ 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -471,6 +515,8 @@ static void sprom_extract_r45(struct ssb
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 4 stuff needed */
+ }
+ 
+@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+ 	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+ 	       sizeof(out->antenna_gain.ghz5));
+ 
++	sprom_extract_r458(out, in);
++
+ 	/* TODO - get remaining rev 8 stuff needed */
+ }
+ 
+@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+ 	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ 	memset(out->et0mac, 0xFF, 6);		/* preset et0 and et1 mac */
+ 	memset(out->et1mac, 0xFF, 6);
++
+ 	if ((bus->chip_id & 0xFF00) == 0x4400) {
+ 		/* Workaround: The BCM44XX chip has a stupid revision
+ 		 * number stored in the SPROM.
+ 		 * Always extract r1. */
+ 		out->revision = 1;
++		ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
++	}
++
++	switch (out->revision) {
++	case 1:
++	case 2:
++	case 3:
+ 		sprom_extract_r123(out, in);
+-	} else if (bus->chip_id == 0x4321) {
+-		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+-		out->revision = 4;
++		break;
++	case 4:
++	case 5:
+ 		sprom_extract_r45(out, in);
+-	} else {
+-		switch (out->revision) {
+-		case 1:
+-		case 2:
+-		case 3:
+-			sprom_extract_r123(out, in);
+-			break;
+-		case 4:
+-		case 5:
+-			sprom_extract_r45(out, in);
+-			break;
+-		case 8:
+-			sprom_extract_r8(out, in);
+-			break;
+-		default:
+-			ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-				   "  revision %d detected. Will extract"
+-				   " v1\n", out->revision);
+-			out->revision = 1;
+-			sprom_extract_r123(out, in);
+-		}
++		break;
++	case 8:
++		sprom_extract_r8(out, in);
++		break;
++	default:
++		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
++			   " revision %d detected. Will extract"
++			   " v1\n", out->revision);
++		out->revision = 1;
++		sprom_extract_r123(out, in);
+ 	}
+ 
+ 	if (out->boardflags_lo == 0xFFFF)
+@@ -618,7 +663,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 			     struct ssb_sprom *sprom)
+ {
+ 	const struct ssb_sprom *fallback;
+-	int err = -ENOMEM;
++	int err;
+ 	u16 *buf;
+ 
+ 	if (!ssb_is_sprom_available(bus)) {
+@@ -645,7 +690,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ 	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
+ 	if (!buf)
+-		goto out;
++		return -ENOMEM;
+ 	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
+ 	sprom_do_read(bus, buf);
+ 	err = sprom_check_crc(buf, bus->sprom_size);
+@@ -655,7 +700,7 @@ static int ssb_pci_sprom_get(struct ssb_
+ 		buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ 			      GFP_KERNEL);
+ 		if (!buf)
+-			goto out;
++			return -ENOMEM;
+ 		bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ 		sprom_do_read(bus, buf);
+ 		err = sprom_check_crc(buf, bus->sprom_size);
+@@ -677,7 +722,6 @@ static int ssb_pci_sprom_get(struct ssb_
+ 
+ out_free:
+ 	kfree(buf);
+-out:
+ 	return err;
+ }
+ 
+--- a/drivers/ssb/pcihost_wrapper.c
++++ b/drivers/ssb/pcihost_wrapper.c
+@@ -59,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_
+ 	struct ssb_bus *ssb;
+ 	int err = -ENOMEM;
+ 	const char *name;
++	u32 val;
+ 
+ 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ 	if (!ssb)
+@@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_
+ 		goto err_pci_disable;
+ 	pci_set_master(dev);
+ 
++	/* Disable the RETRY_TIMEOUT register (0x41) to keep
++	 * PCI Tx retries from interfering with C3 CPU state */
++	pci_read_config_dword(dev, 0x40, &val);
++	if ((val & 0x0000ff00) != 0)
++		pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
++
+ 	err = ssb_bus_pcibus_register(ssb, dev);
+ 	if (err)
+ 		goto err_pci_release_regions;
+--- a/drivers/ssb/scan.c
++++ b/drivers/ssb/scan.c
+@@ -405,10 +405,10 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 				/* Ignore PCI cores on PCI-E cards.
+ 				 * Ignore PCI-E cores on PCI cards. */
+ 				if (dev->id.coreid == SSB_DEV_PCI) {
+-					if (bus->host_pci->is_pcie)
++					if (pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				} else {
+-					if (!bus->host_pci->is_pcie)
++					if (!pci_is_pcie(bus->host_pci))
+ 						continue;
+ 				}
+ 			}
+@@ -420,6 +420,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
+ 			bus->pcicore.dev = dev;
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+ 			break;
++		case SSB_DEV_ETHERNET:
++			if (bus->bustype == SSB_BUSTYPE_PCI) {
++				if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
++				    (bus->host_pci->device & 0xFF00) == 0x4300) {
++					/* This is a dangling ethernet core on a
++					 * wireless device. Ignore it. */
++					continue;
++				}
++			}
++			break;
+ 		default:
+ 			break;
+ 		}
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -55,6 +55,10 @@ struct ssb_sprom {
+ 	u8 tri5gl;		/* 5.2GHz TX isolation */
+ 	u8 tri5g;		/* 5.3GHz TX isolation */
+ 	u8 tri5gh;		/* 5.8GHz TX isolation */
++	u8 txpid2g[4];		/* 2GHz TX power index */
++	u8 txpid5gl[4];		/* 4.9 - 5.1GHz TX power index */
++	u8 txpid5g[4];		/* 5.1 - 5.5GHz TX power index */
++	u8 txpid5gh[4];		/* 5.5 - ...GHz TX power index */
+ 	u8 rxpo2g;		/* 2GHz RX power offset */
+ 	u8 rxpo5g;		/* 5GHz RX power offset */
+ 	u8 rssisav2g;		/* 2GHz RSSI params */
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -85,6 +85,8 @@
+ #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+ #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+ #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
++#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
++#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
+ #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+ #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+ #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+@@ -97,7 +99,6 @@
+ #define  SSB_TMSLOW_RESET	0x00000001 /* Reset */
+ #define  SSB_TMSLOW_REJECT_22	0x00000002 /* Reject (Backplane rev 2.2) */
+ #define  SSB_TMSLOW_REJECT_23	0x00000004 /* Reject (Backplane rev 2.3) */
+-#define  SSB_TMSLOW_PHYCLK	0x00000010 /* MAC PHY Clock Control Enable */
+ #define  SSB_TMSLOW_CLOCK	0x00010000 /* Clock Enable */
+ #define  SSB_TMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
+ #define  SSB_TMSLOW_PE		0x40000000 /* Power Management Enable */
+@@ -268,6 +269,8 @@
+ /* SPROM Revision 4 */
+ #define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
++#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
+ #define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
+ #define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
+@@ -299,6 +302,46 @@
+ #define  SSB_SPROM4_AGAIN2_SHIFT	0
+ #define  SSB_SPROM4_AGAIN3		0xFF00	/* Antenna 3 */
+ #define  SSB_SPROM4_AGAIN3_SHIFT	8
++#define SSB_SPROM4_TXPID2G01		0x0062 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G0		0x00FF
++#define  SSB_SPROM4_TXPID2G0_SHIFT	0
++#define  SSB_SPROM4_TXPID2G1		0xFF00
++#define  SSB_SPROM4_TXPID2G1_SHIFT	8
++#define SSB_SPROM4_TXPID2G23		0x0064 	/* TX Power Index 2GHz */
++#define  SSB_SPROM4_TXPID2G2		0x00FF
++#define  SSB_SPROM4_TXPID2G2_SHIFT	0
++#define  SSB_SPROM4_TXPID2G3		0xFF00
++#define  SSB_SPROM4_TXPID2G3_SHIFT	8
++#define SSB_SPROM4_TXPID5G01		0x0066 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G0		0x00FF
++#define  SSB_SPROM4_TXPID5G0_SHIFT	0
++#define  SSB_SPROM4_TXPID5G1		0xFF00
++#define  SSB_SPROM4_TXPID5G1_SHIFT	8
++#define SSB_SPROM4_TXPID5G23		0x0068 	/* TX Power Index 5GHz middle subband */
++#define  SSB_SPROM4_TXPID5G2		0x00FF
++#define  SSB_SPROM4_TXPID5G2_SHIFT	0
++#define  SSB_SPROM4_TXPID5G3		0xFF00
++#define  SSB_SPROM4_TXPID5G3_SHIFT	8
++#define SSB_SPROM4_TXPID5GL01		0x006A 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL0		0x00FF
++#define  SSB_SPROM4_TXPID5GL0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL1		0xFF00
++#define  SSB_SPROM4_TXPID5GL1_SHIFT	8
++#define SSB_SPROM4_TXPID5GL23		0x006C 	/* TX Power Index 5GHz low subband */
++#define  SSB_SPROM4_TXPID5GL2		0x00FF
++#define  SSB_SPROM4_TXPID5GL2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GL3		0xFF00
++#define  SSB_SPROM4_TXPID5GL3_SHIFT	8
++#define SSB_SPROM4_TXPID5GH01		0x006E 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH0		0x00FF
++#define  SSB_SPROM4_TXPID5GH0_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH1		0xFF00
++#define  SSB_SPROM4_TXPID5GH1_SHIFT	8
++#define SSB_SPROM4_TXPID5GH23		0x0070 	/* TX Power Index 5GHz high subband */
++#define  SSB_SPROM4_TXPID5GH2		0x00FF
++#define  SSB_SPROM4_TXPID5GH2_SHIFT	0
++#define  SSB_SPROM4_TXPID5GH3		0xFF00
++#define  SSB_SPROM4_TXPID5GH3_SHIFT	8
+ #define SSB_SPROM4_MAXP_BG		0x0080  /* Max Power BG in path 1 */
+ #define  SSB_SPROM4_MAXP_BG_MASK	0x00FF  /* Mask for Max Power BG */
+ #define  SSB_SPROM4_ITSSI_BG		0xFF00	/* Mask for path 1 itssi_bg */
+@@ -318,6 +361,8 @@
+ #define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
+ #define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
++#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
+ #define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
+ #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */

+ 136 - 0
target/linux/generic/patches-2.6.38/941-ssb_update.patch

@@ -0,0 +1,136 @@
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -1192,10 +1192,10 @@ void ssb_device_enable(struct ssb_device
+ }
+ EXPORT_SYMBOL(ssb_device_enable);
+ 
+-/* Wait for a bit in a register to get set or unset.
++/* Wait for bitmask in a register to get set or cleared.
+  * timeout is in units of ten-microseconds */
+-static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+-			int timeout, int set)
++static int ssb_wait_bits(struct ssb_device *dev, u16 reg, u32 bitmask,
++			 int timeout, int set)
+ {
+ 	int i;
+ 	u32 val;
+@@ -1203,7 +1203,7 @@ static int ssb_wait_bit(struct ssb_devic
+ 	for (i = 0; i < timeout; i++) {
+ 		val = ssb_read32(dev, reg);
+ 		if (set) {
+-			if (val & bitmask)
++			if ((val & bitmask) == bitmask)
+ 				return 0;
+ 		} else {
+ 			if (!(val & bitmask))
+@@ -1220,20 +1220,38 @@ static int ssb_wait_bit(struct ssb_devic
+ 
+ void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+ {
+-	u32 reject;
++	u32 reject, val;
+ 
+ 	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ 		return;
+ 
+ 	reject = ssb_tmslow_reject_bitmask(dev);
+-	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+-	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+-	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+-	ssb_write32(dev, SSB_TMSLOW,
+-		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+-		    reject | SSB_TMSLOW_RESET |
+-		    core_specific_flags);
+-	ssb_flush_tmslow(dev);
++
++	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_CLOCK) {
++		ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
++		ssb_wait_bits(dev, SSB_TMSLOW, reject, 1000, 1);
++		ssb_wait_bits(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val |= SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++			ssb_wait_bits(dev, SSB_IMSTATE, SSB_IMSTATE_BUSY, 1000,
++				      0);
++		}
++
++		ssb_write32(dev, SSB_TMSLOW,
++			SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
++			reject | SSB_TMSLOW_RESET |
++			core_specific_flags);
++		ssb_flush_tmslow(dev);
++
++		if (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_INITIATOR) {
++			val = ssb_read32(dev, SSB_IMSTATE);
++			val &= ~SSB_IMSTATE_REJECT;
++			ssb_write32(dev, SSB_IMSTATE, val);
++		}
++	}
+ 
+ 	ssb_write32(dev, SSB_TMSLOW,
+ 		    reject | SSB_TMSLOW_RESET |
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -468,10 +468,14 @@ static void sprom_extract_r45(struct ssb
+ 		SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
+ 	} else {
+ 		SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ 		SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
+ 		SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
++		SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
++		SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0);
+ 	}
+ 	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+ 	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+@@ -641,7 +645,7 @@ static int sprom_extract(struct ssb_bus
+ 		break;
+ 	default:
+ 		ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
+-			   "  revision %d detected. Will extract"
++			   " revision %d detected. Will extract"
+ 			   " v1\n", out->revision);
+ 		out->revision = 1;
+ 		sprom_extract_r123(out, in);
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -85,6 +85,8 @@
+ #define  SSB_IMSTATE_AP_RSV	0x00000030 /* Reserved */
+ #define  SSB_IMSTATE_IBE	0x00020000 /* In Band Error */
+ #define  SSB_IMSTATE_TO		0x00040000 /* Timeout */
++#define  SSB_IMSTATE_BUSY	0x01800000 /* Busy (Backplane rev >= 2.3 only) */
++#define  SSB_IMSTATE_REJECT	0x02000000 /* Reject (Backplane rev >= 2.3 only) */
+ #define SSB_INTVEC		0x0F94     /* SB Interrupt Mask */
+ #define  SSB_INTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+ #define  SSB_INTVEC_ENET0	0x00000002 /* Enable interrupts for enet 0 */
+@@ -97,7 +99,6 @@
+ #define  SSB_TMSLOW_RESET	0x00000001 /* Reset */
+ #define  SSB_TMSLOW_REJECT_22	0x00000002 /* Reject (Backplane rev 2.2) */
+ #define  SSB_TMSLOW_REJECT_23	0x00000004 /* Reject (Backplane rev 2.3) */
+-#define  SSB_TMSLOW_PHYCLK	0x00000010 /* MAC PHY Clock Control Enable */
+ #define  SSB_TMSLOW_CLOCK	0x00010000 /* Clock Enable */
+ #define  SSB_TMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
+ #define  SSB_TMSLOW_PE		0x40000000 /* Power Management Enable */
+@@ -268,6 +269,8 @@
+ /* SPROM Revision 4 */
+ #define SSB_SPROM4_BFLLO		0x0044	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM4_BFLHI		0x0046  /* Board Flags Hi */
++#define SSB_SPROM4_BFL2LO		0x0048	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM4_BFL2HI		0x004A	/* Board flags 2 Hi */
+ #define SSB_SPROM4_IL0MAC		0x004C	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM4_CCODE		0x0052	/* Country Code (2 bytes) */
+ #define SSB_SPROM4_GPIOA		0x0056	/* Gen. Purpose IO # 0 and 1 */
+@@ -358,6 +361,8 @@
+ #define SSB_SPROM5_CCODE		0x0044	/* Country Code (2 bytes) */
+ #define SSB_SPROM5_BFLLO		0x004A	/* Boardflags (low 16 bits) */
+ #define SSB_SPROM5_BFLHI		0x004C  /* Board Flags Hi */
++#define SSB_SPROM5_BFL2LO		0x004E	/* Board flags 2 (low 16 bits) */
++#define SSB_SPROM5_BFL2HI		0x0050	/* Board flags 2 Hi */
+ #define SSB_SPROM5_IL0MAC		0x0052	/* 6 byte MAC address for a/b/g/n */
+ #define SSB_SPROM5_GPIOA		0x0076	/* Gen. Purpose IO # 0 and 1 */
+ #define  SSB_SPROM5_GPIOA_P0		0x00FF	/* Pin 0 */

Some files were not shown because too many files changed in this diff