diff options
Diffstat (limited to 'target/linux/brcm47xx-2.6/patches-2.6.22')
11 files changed, 3068 insertions, 0 deletions
diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/100-board_support.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/100-board_support.patch new file mode 100644 index 000000000..b67b8d5e5 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/100-board_support.patch @@ -0,0 +1,211 @@ +Index: linux-2.6.22-rc4/arch/mips/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/Kconfig 2007-06-10 21:32:36.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/Kconfig 2007-06-10 21:33:12.000000000 +0100 +@@ -4,6 +4,10 @@ + # Horrible source of confusion. Die, die, die ... + select EMBEDDED + ++config CFE ++ bool ++ # Common Firmware Environment ++ + mainmenu "Linux/MIPS Kernel Configuration" + + menu "Machine selection" +@@ -126,6 +130,23 @@ + Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and + Olivetti M700-10 workstations. + ++config BCM947XX ++ bool "Support for BCM947xx based boards" ++ select DMA_NONCOHERENT ++ select HW_HAS_PCI ++ select IRQ_CPU ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SSB ++ select SSB_SERIAL ++ select SSB_DRIVER_PCICORE ++ select SSB_PCICORE_HOSTMODE ++ select CFE ++ select GENERIC_GPIO ++ help ++ Support for BCM947xx based boards ++ + config LASAT + bool "LASAT Networks platforms" + select DMA_NONCOHERENT +Index: linux-2.6.22-rc4/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/kernel/cpu-probe.c 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/kernel/cpu-probe.c 2007-06-10 21:33:12.000000000 +0100 +@@ -711,6 +711,28 @@ + } + + ++static inline void cpu_probe_broadcom(struct cpuinfo_mips *c) ++{ ++ decode_config1(c); ++ switch (c->processor_id & 0xff00) { ++ case PRID_IMP_BCM3302: ++ c->cputype = CPU_BCM3302; ++ c->isa_level = MIPS_CPU_ISA_M32R1; ++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | ++ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER; ++ break; ++ case PRID_IMP_BCM4710: ++ c->cputype = CPU_BCM4710; ++ c->isa_level = MIPS_CPU_ISA_M32R1; ++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | ++ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER; ++ break; ++ default: ++ c->cputype = CPU_UNKNOWN; ++ break; ++ } ++} ++ + __init void cpu_probe(void) + { + struct cpuinfo_mips *c = ¤t_cpu_data; +@@ -733,6 +755,9 @@ + case PRID_COMP_SIBYTE: + cpu_probe_sibyte(c); + break; ++ case PRID_COMP_BROADCOM: ++ cpu_probe_broadcom(c); ++ break; + case PRID_COMP_SANDCRAFT: + cpu_probe_sandcraft(c); + break; +Index: linux-2.6.22-rc4/arch/mips/kernel/proc.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/kernel/proc.c 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/kernel/proc.c 2007-06-10 21:33:12.000000000 +0100 +@@ -83,6 +83,8 @@ + [CPU_VR4181] = "NEC VR4181", + [CPU_VR4181A] = "NEC VR4181A", + [CPU_SR71000] = "Sandcraft SR71000", ++ [CPU_BCM3302] = "Broadcom BCM3302", ++ [CPU_BCM4710] = "Broadcom BCM4710", + [CPU_PR4450] = "Philips PR4450", + }; + +Index: linux-2.6.22-rc4/arch/mips/Makefile +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/Makefile 2007-06-10 21:32:56.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/Makefile 2007-06-10 21:33:12.000000000 +0100 +@@ -560,6 +560,18 @@ + load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000 + + # ++# Broadcom BCM47XX boards ++# ++core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/ ++cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include -Iinclude/asm-mips/mach-bcm947xx ++load-$(CONFIG_BCM947XX) := 0xffffffff80001000 ++ ++# ++# Common Firmware Environment ++# ++core-$(CONFIG_CFE) += arch/mips/cfe/ ++ ++# + # SNI RM + # + core-$(CONFIG_SNI_RM) += arch/mips/sni/ +Index: linux-2.6.22-rc4/arch/mips/mm/tlbex.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/mm/tlbex.c 2007-06-10 21:32:35.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/mm/tlbex.c 2007-06-10 21:33:12.000000000 +0100 +@@ -892,6 +892,8 @@ + case CPU_4KSC: + case CPU_20KC: + case CPU_25KF: ++ case CPU_BCM3302: ++ case CPU_BCM4710: + tlbw(p); + break; + +Index: linux-2.6.22-rc4/drivers/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/Kconfig 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/Kconfig 2007-06-10 21:33:12.000000000 +0100 +@@ -56,6 +56,8 @@ + + source "drivers/hwmon/Kconfig" + ++source "drivers/ssb/Kconfig" ++ + source "drivers/mfd/Kconfig" + + source "drivers/media/Kconfig" +Index: linux-2.6.22-rc4/drivers/Makefile +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/Makefile 2007-06-10 21:32:14.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/Makefile 2007-06-10 21:33:12.000000000 +0100 +@@ -81,3 +81,4 @@ + obj-$(CONFIG_DMA_ENGINE) += dma/ + obj-$(CONFIG_HID) += hid/ + obj-$(CONFIG_PPC_PS3) += ps3/ ++obj-$(CONFIG_SSB) += ssb/ +Index: linux-2.6.22-rc4/include/asm-mips/bootinfo.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/asm-mips/bootinfo.h 2007-06-10 21:32:14.000000000 +0100 ++++ linux-2.6.22-rc4/include/asm-mips/bootinfo.h 2007-06-10 21:33:12.000000000 +0100 +@@ -213,6 +213,12 @@ + #define MACH_GROUP_NEC_EMMA2RH 25 /* NEC EMMA2RH (was 23) */ + #define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */ + ++/* ++ * Valid machtype for group Broadcom ++ */ ++#define MACH_GROUP_BRCM 23 /* Broadcom */ ++#define MACH_BCM47XX 1 /* Broadcom BCM47xx */ ++ + #define CL_SIZE COMMAND_LINE_SIZE + + const char *get_system_type(void); +Index: linux-2.6.22-rc4/include/asm-mips/cpu.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/asm-mips/cpu.h 2007-06-10 21:32:14.000000000 +0100 ++++ linux-2.6.22-rc4/include/asm-mips/cpu.h 2007-06-10 21:33:12.000000000 +0100 +@@ -104,6 +104,13 @@ + #define PRID_IMP_SR71000 0x0400 + + /* ++ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM ++ */ ++ ++#define PRID_IMP_BCM4710 0x4000 ++#define PRID_IMP_BCM3302 0x9000 ++ ++/* + * Definitions for 7:0 on legacy processors + */ + +@@ -200,7 +207,9 @@ + #define CPU_SB1A 62 + #define CPU_74K 63 + #define CPU_R14000 64 +-#define CPU_LAST 64 ++#define CPU_BCM3302 65 ++#define CPU_BCM4710 66 ++#define CPU_LAST 66 + + /* + * ISA Level encodings +Index: linux-2.6.22-rc4/include/linux/pci_ids.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/pci_ids.h 2007-06-10 21:32:14.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/pci_ids.h 2007-06-10 21:33:12.000000000 +0100 +@@ -1991,6 +1991,7 @@ + #define PCI_DEVICE_ID_TIGON3_5906M 0x1713 + #define PCI_DEVICE_ID_BCM4401 0x4401 + #define PCI_DEVICE_ID_BCM4401B0 0x4402 ++#define PCI_DEVICE_ID_BCM4713 0x4713 + + #define PCI_VENDOR_ID_TOPIC 0x151f + #define PCI_DEVICE_ID_TOPIC_TP560 0x0000 diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/110-flash_map.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/110-flash_map.patch new file mode 100644 index 000000000..74fe01a25 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/110-flash_map.patch @@ -0,0 +1,29 @@ +Index: linux-2.6.22-rc4/drivers/mtd/maps/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/mtd/maps/Kconfig 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/mtd/maps/Kconfig 2007-06-10 21:33:14.000000000 +0100 +@@ -358,6 +358,12 @@ + Mapping for the Flaga digital module. If you don't have one, ignore + this setting. + ++config MTD_BCM47XX ++ tristate "BCM47xx flash device" ++ depends on MIPS && MTD_CFI && BCM947XX ++ help ++ Support for the flash chips on the BCM947xx board. ++ + config MTD_WALNUT + tristate "Flash device mapped on IBM 405GP Walnut" + depends on MTD_JEDECPROBE && WALNUT +Index: linux-2.6.22-rc4/drivers/mtd/maps/Makefile +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/mtd/maps/Makefile 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/mtd/maps/Makefile 2007-06-10 21:33:14.000000000 +0100 +@@ -33,6 +33,7 @@ + obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o + obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o + obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o ++obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o + obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o + obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o + obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/120-b44_ssb_support.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/120-b44_ssb_support.patch new file mode 100644 index 000000000..fcda25363 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/120-b44_ssb_support.patch @@ -0,0 +1,1547 @@ +Index: linux-2.6.22-rc4/drivers/net/b44.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/net/b44.c 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/net/b44.c 2007-06-10 21:33:15.000000000 +0100 +@@ -1,7 +1,9 @@ +-/* b44.c: Broadcom 4400 device driver. ++/* b44.c: Broadcom 4400/47xx device driver. + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) +- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) ++ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi) ++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) ++ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org) + * Copyright (C) 2006 Broadcom Corporation. + * + * Distribute under GPL. +@@ -20,11 +22,13 @@ + #include <linux/delay.h> + #include <linux/init.h> + #include <linux/dma-mapping.h> ++#include <linux/ssb/ssb.h> + + #include <asm/uaccess.h> + #include <asm/io.h> + #include <asm/irq.h> + ++ + #include "b44.h" + + #define DRV_MODULE_NAME "b44" +@@ -86,8 +90,8 @@ + static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller"); +-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver"); ++MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller"); ++MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver"); + MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_MODULE_VERSION); + +@@ -95,18 +99,11 @@ + module_param(b44_debug, int, 0); + MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value"); + +-static struct pci_device_id b44_pci_tbl[] = { +- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +- { } /* terminate list with empty entry */ ++static struct ssb_device_id b44_ssb_tbl[] = { ++ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV), ++ SSB_DEVTABLE_END + }; + +-MODULE_DEVICE_TABLE(pci, b44_pci_tbl); +- + static void b44_halt(struct b44 *); + static void b44_init_rings(struct b44 *); + +@@ -118,6 +115,7 @@ + + static int dma_desc_align_mask; + static int dma_desc_sync_size; ++static int instance; + + static const char b44_gstrings[][ETH_GSTRING_LEN] = { + #define _B44(x...) # x, +@@ -125,35 +123,24 @@ + #undef _B44 + }; + +-static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev, +- dma_addr_t dma_base, +- unsigned long offset, +- enum dma_data_direction dir) +-{ +- dma_sync_single_range_for_device(&pdev->dev, dma_base, +- offset & dma_desc_align_mask, +- dma_desc_sync_size, dir); +-} +- +-static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev, +- dma_addr_t dma_base, +- unsigned long offset, +- enum dma_data_direction dir) +-{ +- dma_sync_single_range_for_cpu(&pdev->dev, dma_base, +- offset & dma_desc_align_mask, +- dma_desc_sync_size, dir); +-} +- +-static inline unsigned long br32(const struct b44 *bp, unsigned long reg) +-{ +- return readl(bp->regs + reg); +-} +- +-static inline void bw32(const struct b44 *bp, +- unsigned long reg, unsigned long val) +-{ +- writel(val, bp->regs + reg); ++static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev, ++ dma_addr_t dma_base, ++ unsigned long offset, ++ enum dma_data_direction dir) ++{ ++ dma_sync_single_range_for_device(&sdev->dev, dma_base, ++ offset & dma_desc_align_mask, ++ dma_desc_sync_size, dir); ++} ++ ++static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev, ++ dma_addr_t dma_base, ++ unsigned long offset, ++ enum dma_data_direction dir) ++{ ++ dma_sync_single_range_for_cpu(&sdev->dev, dma_base, ++ offset & dma_desc_align_mask, ++ dma_desc_sync_size, dir); + } + + static int b44_wait_bit(struct b44 *bp, unsigned long reg, +@@ -181,117 +168,29 @@ + return 0; + } + +-/* Sonics SiliconBackplane support routines. ROFL, you should see all the +- * buzz words used on this company's website :-) +- * +- * All of these routines must be invoked with bp->lock held and +- * interrupts disabled. +- */ +- +-#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */ +-#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */ +- +-static u32 ssb_get_core_rev(struct b44 *bp) +-{ +- return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK); +-} +- +-static u32 ssb_pci_setup(struct b44 *bp, u32 cores) +-{ +- u32 bar_orig, pci_rev, val; +- +- pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig); +- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR); +- pci_rev = ssb_get_core_rev(bp); +- +- val = br32(bp, B44_SBINTVEC); +- val |= cores; +- bw32(bp, B44_SBINTVEC, val); +- +- val = br32(bp, SSB_PCI_TRANS_2); +- val |= SSB_PCI_PREF | SSB_PCI_BURST; +- bw32(bp, SSB_PCI_TRANS_2, val); +- +- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig); +- +- return pci_rev; +-} +- +-static void ssb_core_disable(struct b44 *bp) +-{ +- if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET) +- return; +- +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK)); +- b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0); +- b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1); +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK | +- SBTMSLOW_REJECT | SBTMSLOW_RESET)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +-} +- +-static void ssb_core_reset(struct b44 *bp) ++static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index) + { + u32 val; + +- ssb_core_disable(bp); +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +- +- /* Clear SERR if set, this is a hw bug workaround. */ +- if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR) +- bw32(bp, B44_SBTMSHIGH, 0); +- +- val = br32(bp, B44_SBIMSTATE); +- if (val & (SBIMSTATE_IBE | SBIMSTATE_TO)) +- bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO)); +- +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); ++ bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ | ++ (index << CAM_CTRL_INDEX_SHIFT))); + +- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK)); +- br32(bp, B44_SBTMSLOW); +- udelay(1); +-} ++ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); + +-static int ssb_core_unit(struct b44 *bp) +-{ +-#if 0 +- u32 val = br32(bp, B44_SBADMATCH0); +- u32 base; ++ val = br32(bp, B44_CAM_DATA_LO); + +- type = val & SBADMATCH0_TYPE_MASK; +- switch (type) { +- case 0: +- base = val & SBADMATCH0_BS0_MASK; +- break; ++ data[2] = (val >> 24) & 0xFF; ++ data[3] = (val >> 16) & 0xFF; ++ data[4] = (val >> 8) & 0xFF; ++ data[5] = (val >> 0) & 0xFF; + +- case 1: +- base = val & SBADMATCH0_BS1_MASK; +- break; ++ val = br32(bp, B44_CAM_DATA_HI); + +- case 2: +- default: +- base = val & SBADMATCH0_BS2_MASK; +- break; +- }; +-#endif +- return 0; +-} +- +-static int ssb_is_core_up(struct b44 *bp) +-{ +- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) +- == SBTMSLOW_CLOCK); ++ data[0] = (val >> 8) & 0xFF; ++ data[1] = (val >> 0) & 0xFF; + } + +-static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) ++static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) + { + u32 val; + +@@ -327,14 +226,14 @@ + bw32(bp, B44_IMASK, bp->imask); + } + +-static int b44_readphy(struct b44 *bp, int reg, u32 *val) ++static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val) + { + int err; + + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | + (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) | +- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | ++ (phy_addr << MDIO_DATA_PMD_SHIFT) | + (reg << MDIO_DATA_RA_SHIFT) | + (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT))); + err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); +@@ -343,18 +242,34 @@ + return err; + } + +-static int b44_writephy(struct b44 *bp, int reg, u32 val) ++static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val) + { + bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII); + bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | + (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) | +- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) | ++ (phy_addr << MDIO_DATA_PMD_SHIFT) | + (reg << MDIO_DATA_RA_SHIFT) | + (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) | + (val & MDIO_DATA_DATA))); + return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0); + } + ++static inline int b44_readphy(struct b44 *bp, int reg, u32 *val) ++{ ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; ++ ++ return __b44_readphy(bp, bp->phy_addr, reg, val); ++} ++ ++static inline int b44_writephy(struct b44 *bp, int reg, u32 val) ++{ ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; ++ ++ return __b44_writephy(bp, bp->phy_addr, reg, val); ++} ++ + /* miilib interface */ + /* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional + * due to code existing before miilib use was added to this driver. +@@ -383,6 +298,8 @@ + u32 val; + int err; + ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; + err = b44_writephy(bp, MII_BMCR, BMCR_RESET); + if (err) + return err; +@@ -441,11 +358,27 @@ + __b44_set_flow_ctrl(bp, pause_enab); + } + ++ ++extern char *nvram_get(char *name); //FIXME: move elsewhere + static int b44_setup_phy(struct b44 *bp) + { + u32 val; + int err; + ++ /* ++ * workaround for bad hardware design in Linksys WAP54G v1.0 ++ * see https://dev.openwrt.org/ticket/146 ++ * check and reset bit "isolate" ++ */ ++ if ((atoi(nvram_get("boardnum")) == 2) && ++ (__b44_readphy(bp, 0, MII_BMCR, &val) == 0) && ++ (val & BMCR_ISOLATE) && ++ (__b44_writephy(bp, 0, MII_BMCR, val & ~BMCR_ISOLATE) != 0)) { ++ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n"); ++ } ++ ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) ++ return 0; + if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0) + goto out; + if ((err = b44_writephy(bp, B44_MII_ALEDCTRL, +@@ -541,6 +474,19 @@ + { + u32 bmsr, aux; + ++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) { ++ bp->flags |= B44_FLAG_100_BASE_T; ++ bp->flags |= B44_FLAG_FULL_DUPLEX; ++ if (!netif_carrier_ok(bp->dev)) { ++ u32 val = br32(bp, B44_TX_CTRL); ++ val |= TX_CTRL_DUPLEX; ++ bw32(bp, B44_TX_CTRL, val); ++ netif_carrier_on(bp->dev); ++ b44_link_report(bp); ++ } ++ return; ++ } ++ + if (!b44_readphy(bp, MII_BMSR, &bmsr) && + !b44_readphy(bp, B44_MII_AUXCTRL, &aux) && + (bmsr != 0xffff)) { +@@ -617,10 +563,10 @@ + + BUG_ON(skb == NULL); + +- pci_unmap_single(bp->pdev, ++ dma_unmap_single(&bp->sdev->dev, + pci_unmap_addr(rp, mapping), + skb->len, +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + rp->skb = NULL; + dev_kfree_skb_irq(skb); + } +@@ -656,10 +602,10 @@ + skb = dev_alloc_skb(RX_PKT_BUF_SZ); + if (skb == NULL) + return -ENOMEM; +- +- mapping = pci_map_single(bp->pdev, skb->data, ++ ++ mapping = dma_map_single(&bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + + /* Hardware bug work-around, the chip is unable to do PCI DMA + to/from anything above 1GB :-( */ +@@ -667,18 +613,18 @@ + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + /* Sigh... */ + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); ++ dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA); + if (skb == NULL) + return -ENOMEM; +- mapping = pci_map_single(bp->pdev, skb->data, ++ mapping = dma_map_single(&bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + if (dma_mapping_error(mapping) || + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE); ++ dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return -ENOMEM; + } +@@ -707,9 +653,9 @@ + dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, +- dest_idx * sizeof(dp), +- DMA_BIDIRECTIONAL); ++ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, ++ dest_idx * sizeof(dp), ++ DMA_BIDIRECTIONAL); + + return RX_PKT_BUF_SZ; + } +@@ -736,9 +682,9 @@ + pci_unmap_addr(src_map, mapping)); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma, +- src_idx * sizeof(src_desc), +- DMA_BIDIRECTIONAL); ++ b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma, ++ src_idx * sizeof(src_desc), ++ DMA_BIDIRECTIONAL); + + ctrl = src_desc->ctrl; + if (dest_idx == (B44_RX_RING_SIZE - 1)) +@@ -752,13 +698,13 @@ + src_map->skb = NULL; + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma, +- dest_idx * sizeof(dest_desc), +- DMA_BIDIRECTIONAL); ++ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, ++ dest_idx * sizeof(dest_desc), ++ DMA_BIDIRECTIONAL); + +- pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr), ++ dma_sync_single_for_device(&bp->sdev->dev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + } + + static int b44_rx(struct b44 *bp, int budget) +@@ -778,9 +724,9 @@ + struct rx_header *rh; + u16 len; + +- pci_dma_sync_single_for_cpu(bp->pdev, map, ++ dma_sync_single_for_cpu(&bp->sdev->dev, map, + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + rh = (struct rx_header *) skb->data; + len = le16_to_cpu(rh->len); + if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) || +@@ -812,11 +758,11 @@ + skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); + if (skb_size < 0) + goto drop_it; +- pci_unmap_single(bp->pdev, map, +- skb_size, PCI_DMA_FROMDEVICE); ++ dma_unmap_single(&bp->sdev->dev, map, ++ skb_size, DMA_FROM_DEVICE); + /* Leave out rx_header */ +- skb_put(skb, len+bp->rx_offset); +- skb_pull(skb,bp->rx_offset); ++ skb_put(skb, len+bp->rx_offset); ++ skb_pull(skb,bp->rx_offset); + } else { + struct sk_buff *copy_skb; + +@@ -985,23 +931,23 @@ + goto err_out; + } + +- mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); ++ mapping = dma_map_single(&bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + /* Chip can't handle DMA to/from >1GB, use bounce buffer */ + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE); ++ dma_unmap_single(&bp->sdev->dev, mapping, len, DMA_TO_DEVICE); + + bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ, + GFP_ATOMIC|GFP_DMA); + if (!bounce_skb) + goto err_out; + +- mapping = pci_map_single(bp->pdev, bounce_skb->data, +- len, PCI_DMA_TODEVICE); ++ mapping = dma_map_single(&bp->sdev->dev, bounce_skb->data, ++ len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- pci_unmap_single(bp->pdev, mapping, +- len, PCI_DMA_TODEVICE); ++ dma_unmap_single(&bp->sdev->dev, mapping, ++ len, DMA_TO_DEVICE); + dev_kfree_skb_any(bounce_skb); + goto err_out; + } +@@ -1025,9 +971,9 @@ + bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset); + + if (bp->flags & B44_FLAG_TX_RING_HACK) +- b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma, +- entry * sizeof(bp->tx_ring[0]), +- DMA_TO_DEVICE); ++ b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma, ++ entry * sizeof(bp->tx_ring[0]), ++ DMA_TO_DEVICE); + + entry = NEXT_TX(entry); + +@@ -1100,10 +1046,10 @@ + + if (rp->skb == NULL) + continue; +- pci_unmap_single(bp->pdev, ++ dma_unmap_single(&bp->sdev->dev, + pci_unmap_addr(rp, mapping), + RX_PKT_BUF_SZ, +- PCI_DMA_FROMDEVICE); ++ DMA_FROM_DEVICE); + dev_kfree_skb_any(rp->skb); + rp->skb = NULL; + } +@@ -1114,10 +1060,10 @@ + + if (rp->skb == NULL) + continue; +- pci_unmap_single(bp->pdev, ++ dma_unmap_single(&bp->sdev->dev, + pci_unmap_addr(rp, mapping), + rp->skb->len, +- PCI_DMA_TODEVICE); ++ DMA_TO_DEVICE); + dev_kfree_skb_any(rp->skb); + rp->skb = NULL; + } +@@ -1139,14 +1085,14 @@ + memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma, +- DMA_TABLE_BYTES, +- PCI_DMA_BIDIRECTIONAL); ++ dma_sync_single_for_device(&bp->sdev->dev, bp->rx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_BIDIRECTIONAL); + + if (bp->flags & B44_FLAG_TX_RING_HACK) +- dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma, +- DMA_TABLE_BYTES, +- PCI_DMA_TODEVICE); ++ dma_sync_single_for_device(&bp->sdev->dev, bp->tx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_TO_DEVICE); + + for (i = 0; i < bp->rx_pending; i++) { + if (b44_alloc_rx_skb(bp, -1, i) < 0) +@@ -1166,24 +1112,24 @@ + bp->tx_buffers = NULL; + if (bp->rx_ring) { + if (bp->flags & B44_FLAG_RX_RING_HACK) { +- dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma, +- DMA_TABLE_BYTES, +- DMA_BIDIRECTIONAL); ++ dma_unmap_single(&bp->sdev->dev, bp->rx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else +- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, ++ dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma); + bp->rx_ring = NULL; + bp->flags &= ~B44_FLAG_RX_RING_HACK; + } + if (bp->tx_ring) { + if (bp->flags & B44_FLAG_TX_RING_HACK) { +- dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma, +- DMA_TABLE_BYTES, +- DMA_TO_DEVICE); ++ dma_unmap_single(&bp->sdev->dev, bp->tx_ring_dma, ++ DMA_TABLE_BYTES, ++ DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else +- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES, ++ dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma); + bp->tx_ring = NULL; + bp->flags &= ~B44_FLAG_TX_RING_HACK; +@@ -1209,7 +1155,7 @@ + goto out_err; + + size = DMA_TABLE_BYTES; +- bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma); ++ bp->rx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); + if (!bp->rx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive +@@ -1221,9 +1167,9 @@ + if (!rx_ring) + goto out_err; + +- rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring, +- DMA_TABLE_BYTES, +- DMA_BIDIRECTIONAL); ++ rx_ring_dma = dma_map_single(&bp->sdev->dev, rx_ring, ++ DMA_TABLE_BYTES, ++ DMA_BIDIRECTIONAL); + + if (dma_mapping_error(rx_ring_dma) || + rx_ring_dma + size > DMA_30BIT_MASK) { +@@ -1236,9 +1182,9 @@ + bp->flags |= B44_FLAG_RX_RING_HACK; + } + +- bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma); ++ bp->tx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); + if (!bp->tx_ring) { +- /* Allocation may have failed due to pci_alloc_consistent ++ /* Allocation may have failed due to dma_alloc_coherent + insisting on use of GFP_DMA, which is more restrictive + than necessary... */ + struct dma_desc *tx_ring; +@@ -1248,9 +1194,9 @@ + if (!tx_ring) + goto out_err; + +- tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring, +- DMA_TABLE_BYTES, +- DMA_TO_DEVICE); ++ tx_ring_dma = dma_map_single(&bp->sdev->dev, tx_ring, ++ DMA_TABLE_BYTES, ++ DMA_TO_DEVICE); + + if (dma_mapping_error(tx_ring_dma) || + tx_ring_dma + size > DMA_30BIT_MASK) { +@@ -1285,7 +1231,9 @@ + /* bp->lock is held. */ + static void b44_chip_reset(struct b44 *bp) + { +- if (ssb_is_core_up(bp)) { ++ struct ssb_device *sdev = bp->sdev; ++ ++ if (ssb_device_is_enabled(bp->sdev)) { + bw32(bp, B44_RCV_LAZY, 0); + bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE); + b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1); +@@ -1297,19 +1245,23 @@ + } + bw32(bp, B44_DMARX_CTRL, 0); + bp->rx_prod = bp->rx_cons = 0; +- } else { +- ssb_pci_setup(bp, (bp->core_unit == 0 ? +- SBINTVEC_ENET0 : +- SBINTVEC_ENET1)); + } + +- ssb_core_reset(bp); +- ++ ssb_device_enable(bp->sdev, 0); + b44_clear_stats(bp); + +- /* Make PHY accessible. */ +- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | ++ switch (sdev->bus->bustype) { ++ case SSB_BUSTYPE_SSB: ++ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | ++ (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO) ++ & MDIO_CTRL_MAXF_MASK))); ++ break; ++ case SSB_BUSTYPE_PCI: ++ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | + (0x0d & MDIO_CTRL_MAXF_MASK))); ++ break; ++ } ++ + br32(bp, B44_MDIO_CTRL); + + if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) { +@@ -1352,6 +1304,7 @@ + { + struct b44 *bp = netdev_priv(dev); + struct sockaddr *addr = p; ++ u32 val; + + if (netif_running(dev)) + return -EBUSY; +@@ -1362,7 +1315,11 @@ + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + spin_lock_irq(&bp->lock); +- __b44_set_mac_addr(bp); ++ ++ val = br32(bp, B44_RXCONFIG); ++ if (!(val & RXCONFIG_CAM_ABSENT)) ++ __b44_set_mac_addr(bp); ++ + spin_unlock_irq(&bp->lock); + + return 0; +@@ -1448,18 +1405,6 @@ + return err; + } + +-#if 0 +-/*static*/ void b44_dump_state(struct b44 *bp) +-{ +- u32 val32, val32_2, val32_3, val32_4, val32_5; +- u16 val16; +- +- pci_read_config_word(bp->pdev, PCI_STATUS, &val16); +- printk("DEBUG: PCI status [%04x] \n", val16); +- +-} +-#endif +- + #ifdef CONFIG_NET_POLL_CONTROLLER + /* + * Polling receive - used by netconsole and other diagnostic tools +@@ -1574,7 +1519,6 @@ + static void b44_setup_wol(struct b44 *bp) + { + u32 val; +- u16 pmval; + + bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); + +@@ -1598,13 +1542,6 @@ + } else { + b44_setup_pseudo_magicp(bp); + } +- +- val = br32(bp, B44_SBTMSLOW); +- bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); +- +- pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval); +- pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE); +- + } + + static int b44_close(struct net_device *dev) +@@ -1704,7 +1641,7 @@ + + val = br32(bp, B44_RXCONFIG); + val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); +- if (dev->flags & IFF_PROMISC) { ++ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) { + val |= RXCONFIG_PROMISC; + bw32(bp, B44_RXCONFIG, val); + } else { +@@ -1751,12 +1688,8 @@ + + static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) + { +- struct b44 *bp = netdev_priv(dev); +- struct pci_dev *pci_dev = bp->pdev; +- + strcpy (info->driver, DRV_MODULE_NAME); + strcpy (info->version, DRV_MODULE_VERSION); +- strcpy (info->bus_info, pci_name(pci_dev)); + } + + static int b44_nway_reset(struct net_device *dev) +@@ -2040,6 +1973,245 @@ + .get_perm_addr = ethtool_op_get_perm_addr, + }; + ++static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr) ++{ ++ struct b44 *bp = dev->priv; ++ u32 ethcmd; ++ ++ if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) ++ return -EFAULT; ++ ++ switch (ethcmd) { ++ case ETHTOOL_GDRVINFO: { ++ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; ++ strcpy (info.driver, DRV_MODULE_NAME); ++ strcpy (info.version, DRV_MODULE_VERSION); ++ memset(&info.fw_version, 0, sizeof(info.fw_version)); ++ info.eedump_len = 0; ++ info.regdump_len = 0; ++ if (copy_to_user (useraddr, &info, sizeof (info))) ++ return -EFAULT; ++ return 0; ++ } ++ ++ case ETHTOOL_GSET: { ++ struct ethtool_cmd cmd = { ETHTOOL_GSET }; ++ ++ if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) ++ return -EAGAIN; ++ cmd.supported = (SUPPORTED_Autoneg); ++ cmd.supported |= (SUPPORTED_100baseT_Half | ++ SUPPORTED_100baseT_Full | ++ SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_MII); ++ ++ cmd.advertising = 0; ++ if (bp->flags & B44_FLAG_ADV_10HALF) ++ cmd.advertising |= ADVERTISE_10HALF; ++ if (bp->flags & B44_FLAG_ADV_10FULL) ++ cmd.advertising |= ADVERTISE_10FULL; ++ if (bp->flags & B44_FLAG_ADV_100HALF) ++ cmd.advertising |= ADVERTISE_100HALF; ++ if (bp->flags & B44_FLAG_ADV_100FULL) ++ cmd.advertising |= ADVERTISE_100FULL; ++ cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; ++ cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ? ++ SPEED_100 : SPEED_10; ++ cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ? ++ DUPLEX_FULL : DUPLEX_HALF; ++ cmd.port = 0; ++ cmd.phy_address = bp->phy_addr; ++ cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ? ++ XCVR_INTERNAL : XCVR_EXTERNAL; ++ cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? ++ AUTONEG_DISABLE : AUTONEG_ENABLE; ++ cmd.maxtxpkt = 0; ++ cmd.maxrxpkt = 0; ++ if (copy_to_user(useraddr, &cmd, sizeof(cmd))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SSET: { ++ struct ethtool_cmd cmd; ++ ++ if (!(bp->flags & B44_FLAG_INIT_COMPLETE)) ++ return -EAGAIN; ++ ++ if (copy_from_user(&cmd, useraddr, sizeof(cmd))) ++ return -EFAULT; ++ ++ /* We do not support gigabit. */ ++ if (cmd.autoneg == AUTONEG_ENABLE) { ++ if (cmd.advertising & ++ (ADVERTISED_1000baseT_Half | ++ ADVERTISED_1000baseT_Full)) ++ return -EINVAL; ++ } else if ((cmd.speed != SPEED_100 && ++ cmd.speed != SPEED_10) || ++ (cmd.duplex != DUPLEX_HALF && ++ cmd.duplex != DUPLEX_FULL)) { ++ return -EINVAL; ++ } ++ ++ spin_lock_irq(&bp->lock); ++ ++ if (cmd.autoneg == AUTONEG_ENABLE) { ++ bp->flags &= ~B44_FLAG_FORCE_LINK; ++ bp->flags &= ~(B44_FLAG_ADV_10HALF | ++ B44_FLAG_ADV_10FULL | ++ B44_FLAG_ADV_100HALF | ++ B44_FLAG_ADV_100FULL); ++ if (cmd.advertising & ADVERTISE_10HALF) ++ bp->flags |= B44_FLAG_ADV_10HALF; ++ if (cmd.advertising & ADVERTISE_10FULL) ++ bp->flags |= B44_FLAG_ADV_10FULL; ++ if (cmd.advertising & ADVERTISE_100HALF) ++ bp->flags |= B44_FLAG_ADV_100HALF; ++ if (cmd.advertising & ADVERTISE_100FULL) ++ bp->flags |= B44_FLAG_ADV_100FULL; ++ } else { ++ bp->flags |= B44_FLAG_FORCE_LINK; ++ if (cmd.speed == SPEED_100) ++ bp->flags |= B44_FLAG_100_BASE_T; ++ if (cmd.duplex == DUPLEX_FULL) ++ bp->flags |= B44_FLAG_FULL_DUPLEX; ++ } ++ ++ b44_setup_phy(bp); ++ ++ spin_unlock_irq(&bp->lock); ++ ++ return 0; ++ } ++ ++ case ETHTOOL_GMSGLVL: { ++ struct ethtool_value edata = { ETHTOOL_GMSGLVL }; ++ edata.data = bp->msg_enable; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SMSGLVL: { ++ struct ethtool_value edata; ++ if (copy_from_user(&edata, useraddr, sizeof(edata))) ++ return -EFAULT; ++ bp->msg_enable = edata.data; ++ return 0; ++ } ++ case ETHTOOL_NWAY_RST: { ++ u32 bmcr; ++ int r; ++ ++ spin_lock_irq(&bp->lock); ++ b44_readphy(bp, MII_BMCR, &bmcr); ++ b44_readphy(bp, MII_BMCR, &bmcr); ++ r = -EINVAL; ++ if (bmcr & BMCR_ANENABLE) { ++ b44_writephy(bp, MII_BMCR, ++ bmcr | BMCR_ANRESTART); ++ r = 0; ++ } ++ spin_unlock_irq(&bp->lock); ++ ++ return r; ++ } ++ case ETHTOOL_GLINK: { ++ struct ethtool_value edata = { ETHTOOL_GLINK }; ++ edata.data = netif_carrier_ok(bp->dev) ? 1 : 0; ++ if (copy_to_user(useraddr, &edata, sizeof(edata))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_GRINGPARAM: { ++ struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM }; ++ ++ ering.rx_max_pending = B44_RX_RING_SIZE - 1; ++ ering.rx_pending = bp->rx_pending; ++ ++ /* XXX ethtool lacks a tx_max_pending, oops... */ ++ ++ if (copy_to_user(useraddr, &ering, sizeof(ering))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SRINGPARAM: { ++ struct ethtool_ringparam ering; ++ ++ if (copy_from_user(&ering, useraddr, sizeof(ering))) ++ return -EFAULT; ++ ++ if ((ering.rx_pending > B44_RX_RING_SIZE - 1) || ++ (ering.rx_mini_pending != 0) || ++ (ering.rx_jumbo_pending != 0) || ++ (ering.tx_pending > B44_TX_RING_SIZE - 1)) ++ return -EINVAL; ++ ++ spin_lock_irq(&bp->lock); ++ ++ bp->rx_pending = ering.rx_pending; ++ bp->tx_pending = ering.tx_pending; ++ ++ b44_halt(bp); ++ b44_init_rings(bp); ++ b44_init_hw(bp, 1); ++ netif_wake_queue(bp->dev); ++ spin_unlock_irq(&bp->lock); ++ ++ b44_enable_ints(bp); ++ ++ return 0; ++ } ++ case ETHTOOL_GPAUSEPARAM: { ++ struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM }; ++ ++ epause.autoneg = ++ (bp->flags & B44_FLAG_PAUSE_AUTO) != 0; ++ epause.rx_pause = ++ (bp->flags & B44_FLAG_RX_PAUSE) != 0; ++ epause.tx_pause = ++ (bp->flags & B44_FLAG_TX_PAUSE) != 0; ++ if (copy_to_user(useraddr, &epause, sizeof(epause))) ++ return -EFAULT; ++ return 0; ++ } ++ case ETHTOOL_SPAUSEPARAM: { ++ struct ethtool_pauseparam epause; ++ ++ if (copy_from_user(&epause, useraddr, sizeof(epause))) ++ return -EFAULT; ++ ++ spin_lock_irq(&bp->lock); ++ if (epause.autoneg) ++ bp->flags |= B44_FLAG_PAUSE_AUTO; ++ else ++ bp->flags &= ~B44_FLAG_PAUSE_AUTO; ++ if (epause.rx_pause) ++ bp->flags |= B44_FLAG_RX_PAUSE; ++ else ++ bp->flags &= ~B44_FLAG_RX_PAUSE; ++ if (epause.tx_pause) ++ bp->flags |= B44_FLAG_TX_PAUSE; ++ else ++ bp->flags &= ~B44_FLAG_TX_PAUSE; ++ if (bp->flags & B44_FLAG_PAUSE_AUTO) { ++ b44_halt(bp); ++ b44_init_rings(bp); ++ b44_init_hw(bp, 1); ++ } else { ++ __b44_set_flow_ctrl(bp, bp->flags); ++ } ++ spin_unlock_irq(&bp->lock); ++ ++ b44_enable_ints(bp); ++ ++ return 0; ++ } ++ }; ++ ++ return -EOPNOTSUPP; ++} ++ + static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { + struct mii_ioctl_data *data = if_mii(ifr); +@@ -2049,40 +2221,64 @@ + if (!netif_running(dev)) + goto out; + +- spin_lock_irq(&bp->lock); +- err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL); +- spin_unlock_irq(&bp->lock); +-out: +- return err; +-} ++ switch (cmd) { ++ case SIOCETHTOOL: ++ return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data); + +-/* Read 128-bytes of EEPROM. */ +-static int b44_read_eeprom(struct b44 *bp, u8 *data) +-{ +- long i; +- __le16 *ptr = (__le16 *) data; ++ case SIOCGMIIPHY: ++ data->phy_id = bp->phy_addr; + +- for (i = 0; i < 128; i += 2) +- ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); ++ /* fallthru */ ++ case SIOCGMIIREG: { ++ u32 mii_regval; ++ spin_lock_irq(&bp->lock); ++ err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval); ++ spin_unlock_irq(&bp->lock); + +- return 0; ++ data->val_out = mii_regval; ++ ++ return err; ++ } ++ ++ case SIOCSMIIREG: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ spin_lock_irq(&bp->lock); ++ err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); ++ spin_unlock_irq(&bp->lock); ++ ++ return err; ++ ++ default: ++ break; ++ }; ++ return -EOPNOTSUPP; ++ ++out: ++ return err; + } + + static int __devinit b44_get_invariants(struct b44 *bp) + { +- u8 eeprom[128]; +- int err; ++ struct ssb_device *sdev = bp->sdev; ++ int err = 0; ++ u8 *addr; + +- err = b44_read_eeprom(bp, &eeprom[0]); +- if (err) +- goto out; ++ bp->dma_offset = ssb_dma_translation(sdev); ++ ++ switch (instance) { ++ case 1: ++ addr = sdev->bus->sprom.r1.et0mac; ++ bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr; ++ break; ++ default: ++ addr = sdev->bus->sprom.r1.et1mac; ++ bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr; ++ break; ++ } + +- bp->dev->dev_addr[0] = eeprom[79]; +- bp->dev->dev_addr[1] = eeprom[78]; +- bp->dev->dev_addr[2] = eeprom[81]; +- bp->dev->dev_addr[3] = eeprom[80]; +- bp->dev->dev_addr[4] = eeprom[83]; +- bp->dev->dev_addr[5] = eeprom[82]; ++ memcpy(bp->dev->dev_addr, addr, 6); + + if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ + printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n"); +@@ -2091,108 +2287,52 @@ + + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); + +- bp->phy_addr = eeprom[90] & 0x1f; +- + /* With this, plus the rx_header prepended to the data by the + * hardware, we'll land the ethernet header on a 2-byte boundary. + */ + bp->rx_offset = 30; +- + bp->imask = IMASK_DEF; +- +- bp->core_unit = ssb_core_unit(bp); +- bp->dma_offset = SB_PCI_DMA; +- + /* XXX - really required? + bp->flags |= B44_FLAG_BUGGY_TXPTR; +- */ +- +- if (ssb_get_core_rev(bp) >= 7) +- bp->flags |= B44_FLAG_B0_ANDLATER; ++ */ + +-out: + return err; + } + +-static int __devinit b44_init_one(struct pci_dev *pdev, +- const struct pci_device_id *ent) ++static int __devinit b44_init_one(struct ssb_device *sdev, ++ const struct ssb_device_id *ent) + { + static int b44_version_printed = 0; +- unsigned long b44reg_base, b44reg_len; + struct net_device *dev; + struct b44 *bp; + int err, i; + ++ instance++; ++ + if (b44_version_printed++ == 0) + printk(KERN_INFO "%s", version); + +- err = pci_enable_device(pdev); +- if (err) { +- dev_err(&pdev->dev, "Cannot enable PCI device, " +- "aborting.\n"); +- return err; +- } +- +- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { +- dev_err(&pdev->dev, +- "Cannot find proper PCI device " +- "base address, aborting.\n"); +- err = -ENODEV; +- goto err_out_disable_pdev; +- } +- +- err = pci_request_regions(pdev, DRV_MODULE_NAME); +- if (err) { +- dev_err(&pdev->dev, +- "Cannot obtain PCI resources, aborting.\n"); +- goto err_out_disable_pdev; +- } +- +- pci_set_master(pdev); +- +- err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK); +- if (err) { +- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); +- goto err_out_free_res; +- } +- +- err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK); +- if (err) { +- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n"); +- goto err_out_free_res; +- } +- +- b44reg_base = pci_resource_start(pdev, 0); +- b44reg_len = pci_resource_len(pdev, 0); +- + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) { +- dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n"); ++ dev_err(&sdev->dev, "Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; +- goto err_out_free_res; ++ goto out; + } + + SET_MODULE_OWNER(dev); +- SET_NETDEV_DEV(dev,&pdev->dev); ++ SET_NETDEV_DEV(dev,&sdev->dev); + + /* No interesting netdevice features in this card... */ + dev->features |= 0; + + bp = netdev_priv(dev); +- bp->pdev = pdev; ++ bp->sdev = sdev; + bp->dev = dev; + + bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE); + + spin_lock_init(&bp->lock); + +- bp->regs = ioremap(b44reg_base, b44reg_len); +- if (bp->regs == 0UL) { +- dev_err(&pdev->dev, "Cannot map device registers, aborting.\n"); +- err = -ENOMEM; +- goto err_out_free_dev; +- } +- + bp->rx_pending = B44_DEF_RX_RING_PENDING; + bp->tx_pending = B44_DEF_TX_RING_PENDING; + +@@ -2211,16 +2351,16 @@ + dev->poll_controller = b44_poll_controller; + #endif + dev->change_mtu = b44_change_mtu; +- dev->irq = pdev->irq; ++ dev->irq = sdev->irq; + SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); + + netif_carrier_off(dev); + + err = b44_get_invariants(bp); + if (err) { +- dev_err(&pdev->dev, ++ dev_err(&sdev->dev, + "Problem fetching invariants of chip, aborting.\n"); +- goto err_out_iounmap; ++ goto err_out_free_dev; + } + + bp->mii_if.dev = dev; +@@ -2239,61 +2379,52 @@ + + err = register_netdev(dev); + if (err) { +- dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); +- goto err_out_iounmap; ++ dev_err(&sdev->dev, "Cannot register net device, aborting.\n"); ++ goto out; + } + +- pci_set_drvdata(pdev, dev); +- +- pci_save_state(bp->pdev); ++ ssb_set_drvdata(sdev, dev); + + /* Chip reset provides power to the b44 MAC & PCI cores, which + * is necessary for MAC register access. + */ + b44_chip_reset(bp); + +- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); ++ printk(KERN_INFO "%s: Broadcom 10/100BaseT Ethernet ", dev->name); + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? '\n' : ':'); + +- return 0; ++ /* Initialize phy */ ++ spin_lock_irq(&bp->lock); ++ b44_chip_reset(bp); ++ spin_unlock_irq(&bp->lock); + +-err_out_iounmap: +- iounmap(bp->regs); ++ return 0; + + err_out_free_dev: + free_netdev(dev); + +-err_out_free_res: +- pci_release_regions(pdev); +- +-err_out_disable_pdev: +- pci_disable_device(pdev); +- pci_set_drvdata(pdev, NULL); ++out: + return err; + } + +-static void __devexit b44_remove_one(struct pci_dev *pdev) ++static void __devexit b44_remove_one(struct ssb_device *pdev) + { +- struct net_device *dev = pci_get_drvdata(pdev); +- struct b44 *bp = netdev_priv(dev); ++ struct net_device *dev = ssb_get_drvdata(pdev); + + unregister_netdev(dev); +- iounmap(bp->regs); + free_netdev(dev); +- pci_release_regions(pdev); +- pci_disable_device(pdev); +- pci_set_drvdata(pdev, NULL); ++ ssb_set_drvdata(pdev, NULL); + } + +-static int b44_suspend(struct pci_dev *pdev, pm_message_t state) ++static int b44_suspend(struct ssb_device *pdev, pm_message_t state) + { +- struct net_device *dev = pci_get_drvdata(pdev); ++ struct net_device *dev = ssb_get_drvdata(pdev); + struct b44 *bp = netdev_priv(dev); + + if (!netif_running(dev)) +- return 0; ++ return 0; + + del_timer_sync(&bp->timer); + +@@ -2311,26 +2442,16 @@ + b44_init_hw(bp, B44_PARTIAL_RESET); + b44_setup_wol(bp); + } +- pci_disable_device(pdev); ++ + return 0; + } + +-static int b44_resume(struct pci_dev *pdev) ++static int b44_resume(struct ssb_device *pdev) + { +- struct net_device *dev = pci_get_drvdata(pdev); ++ struct net_device *dev = ssb_get_drvdata(pdev); + struct b44 *bp = netdev_priv(dev); + int rc = 0; + +- pci_restore_state(pdev); +- rc = pci_enable_device(pdev); +- if (rc) { +- printk(KERN_ERR PFX "%s: pci_enable_device failed\n", +- dev->name); +- return rc; +- } +- +- pci_set_master(pdev); +- + if (!netif_running(dev)) + return 0; + +@@ -2356,29 +2477,31 @@ + return 0; + } + +-static struct pci_driver b44_driver = { ++static struct ssb_driver b44_driver = { + .name = DRV_MODULE_NAME, +- .id_table = b44_pci_tbl, ++ .id_table = b44_ssb_tbl, + .probe = b44_init_one, + .remove = __devexit_p(b44_remove_one), +- .suspend = b44_suspend, +- .resume = b44_resume, ++ .suspend = b44_suspend, ++ .resume = b44_resume, + }; + + static int __init b44_init(void) + { + unsigned int dma_desc_align_size = dma_get_cache_alignment(); + ++ instance = 0; ++ + /* Setup paramaters for syncing RX/TX DMA descriptors */ + dma_desc_align_mask = ~(dma_desc_align_size - 1); + dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc)); + +- return pci_register_driver(&b44_driver); ++ return ssb_driver_register(&b44_driver); + } + + static void __exit b44_cleanup(void) + { +- pci_unregister_driver(&b44_driver); ++ ssb_driver_unregister(&b44_driver); + } + + module_init(b44_init); +Index: linux-2.6.22-rc4/drivers/net/b44.h +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/net/b44.h 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/net/b44.h 2007-06-10 21:33:15.000000000 +0100 +@@ -129,6 +129,7 @@ + #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */ + #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */ + #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */ ++#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */ + #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */ + #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */ + #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */ +@@ -227,75 +228,9 @@ + #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */ + #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */ + +-/* Silicon backplane register definitions */ +-#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */ +-#define SBIMSTATE_PC 0x0000000f /* Pipe Count */ +-#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */ +-#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */ +-#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */ +-#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */ +-#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */ +-#define SBIMSTATE_IBE 0x00020000 /* In Band Error */ +-#define SBIMSTATE_TO 0x00040000 /* Timeout */ +-#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */ +-#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */ +-#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */ +-#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */ +-#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */ +-#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */ +-#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */ +-#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ +-#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */ +-#define SBTMSLOW_RESET 0x00000001 /* Reset */ +-#define SBTMSLOW_REJECT 0x00000002 /* Reject */ +-#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */ +-#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ +-#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */ +-#define SBTMSLOW_BE 0x80000000 /* BIST Enable */ +-#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */ +-#define SBTMSHIGH_SERR 0x00000001 /* S-error */ +-#define SBTMSHIGH_INT 0x00000002 /* Interrupt */ +-#define SBTMSHIGH_BUSY 0x00000004 /* Busy */ +-#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */ +-#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */ +-#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */ +-#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */ +-#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */ +-#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */ +-#define SBIDHIGH_CC_SHIFT 4 +-#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */ +-#define SBIDHIGH_VC_SHIFT 16 +- +-/* SSB PCI config space registers. */ +-#define SSB_PMCSR 0x44 +-#define SSB_PE 0x100 +-#define SSB_BAR0_WIN 0x80 +-#define SSB_BAR1_WIN 0x84 +-#define SSB_SPROM_CONTROL 0x88 +-#define SSB_BAR1_CONTROL 0x8c +- +-/* SSB core and host control registers. */ +-#define SSB_CONTROL 0x0000UL +-#define SSB_ARBCONTROL 0x0010UL +-#define SSB_ISTAT 0x0020UL +-#define SSB_IMASK 0x0024UL +-#define SSB_MBOX 0x0028UL +-#define SSB_BCAST_ADDR 0x0050UL +-#define SSB_BCAST_DATA 0x0054UL +-#define SSB_PCI_TRANS_0 0x0100UL +-#define SSB_PCI_TRANS_1 0x0104UL +-#define SSB_PCI_TRANS_2 0x0108UL +-#define SSB_SPROM 0x0800UL +- +-#define SSB_PCI_MEM 0x00000000 +-#define SSB_PCI_IO 0x00000001 +-#define SSB_PCI_CFG0 0x00000002 +-#define SSB_PCI_CFG1 0x00000003 +-#define SSB_PCI_PREF 0x00000004 +-#define SSB_PCI_BURST 0x00000008 +-#define SSB_PCI_MASK0 0xfc000000 +-#define SSB_PCI_MASK1 0xfc000000 +-#define SSB_PCI_MASK2 0xc0000000 ++#define br32(bp, REG) ssb_read32((bp)->sdev, (REG)) ++#define bw32(bp, REG, VAL) ssb_write32((bp)->sdev, (REG), (VAL)) ++#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0) + + /* 4400 PHY registers */ + #define B44_MII_AUXCTRL 24 /* Auxiliary Control */ +@@ -346,10 +281,12 @@ + + struct ring_info { + struct sk_buff *skb; +- DECLARE_PCI_UNMAP_ADDR(mapping); ++ dma_addr_t mapping; + }; + + #define B44_MCAST_TABLE_SIZE 32 ++#define B44_PHY_ADDR_NO_PHY 30 ++#define B44_MDC_RATIO 5000000 + + #define B44_STAT_REG_DECLARE \ + _B44(tx_good_octets) \ +@@ -425,9 +362,10 @@ + + u32 dma_offset; + u32 flags; +-#define B44_FLAG_B0_ANDLATER 0x00000001 ++#define B44_FLAG_INIT_COMPLETE 0x00000001 + #define B44_FLAG_BUGGY_TXPTR 0x00000002 + #define B44_FLAG_REORDER_BUG 0x00000004 ++#define B44_FLAG_B0_ANDLATER 0x00000008 + #define B44_FLAG_PAUSE_AUTO 0x00008000 + #define B44_FLAG_FULL_DUPLEX 0x00010000 + #define B44_FLAG_100_BASE_T 0x00020000 +@@ -452,8 +390,7 @@ + struct net_device_stats stats; + struct b44_hw_stats hw_stats; + +- void __iomem *regs; +- struct pci_dev *pdev; ++ struct ssb_device *sdev; + struct net_device *dev; + + dma_addr_t rx_ring_dma, tx_ring_dma; +Index: linux-2.6.22-rc4/drivers/net/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/net/Kconfig 2007-06-10 21:32:48.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/net/Kconfig 2007-06-10 21:33:15.000000000 +0100 +@@ -1511,7 +1511,7 @@ + + config B44 + tristate "Broadcom 4400 ethernet support" +- depends on NET_PCI && PCI ++ depends on SSB && EXPERIMENTAL + select MII + help + If you have a network (Ethernet) controller of this type, say Y and diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/130-remove_scache.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/130-remove_scache.patch new file mode 100644 index 000000000..ed821843b --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/130-remove_scache.patch @@ -0,0 +1,95 @@ +Index: linux-2.6.22-rc4/arch/mips/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/Kconfig 2007-06-10 21:33:12.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/Kconfig 2007-06-10 21:33:17.000000000 +0100 +@@ -202,7 +202,6 @@ + select I8259 + select MIPS_BOARDS_GEN + select MIPS_BONITO64 +- select MIPS_CPU_SCACHE + select PCI_GT64XXX_PCI0 + select MIPS_MSC + select SWAP_IO_SPACE +@@ -1345,13 +1344,6 @@ + bool + select BOARD_SCACHE + +-# +-# Support for a MIPS32 / MIPS64 style S-caches +-# +-config MIPS_CPU_SCACHE +- bool +- select BOARD_SCACHE +- + config R5000_CPU_SCACHE + bool + select BOARD_SCACHE +Index: linux-2.6.22-rc4/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/kernel/cpu-probe.c 2007-06-10 21:33:12.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/kernel/cpu-probe.c 2007-06-10 21:33:17.000000000 +0100 +@@ -619,6 +619,8 @@ + break; + case PRID_IMP_25KF: + c->cputype = CPU_25KF; ++ /* Probe for L2 cache */ ++ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + break; + case PRID_IMP_34K: + c->cputype = CPU_34K; +Index: linux-2.6.22-rc4/arch/mips/mm/c-r4k.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/mm/c-r4k.c 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/mm/c-r4k.c 2007-06-10 21:33:17.000000000 +0100 +@@ -1038,7 +1038,6 @@ + + extern int r5k_sc_init(void); + extern int rm7k_sc_init(void); +-extern int mips_sc_init(void); + + static void __init setup_scache(void) + { +@@ -1086,29 +1085,17 @@ + return; + + default: +- if (c->isa_level == MIPS_CPU_ISA_M32R1 || +- c->isa_level == MIPS_CPU_ISA_M32R2 || +- c->isa_level == MIPS_CPU_ISA_M64R1 || +- c->isa_level == MIPS_CPU_ISA_M64R2) { +-#ifdef CONFIG_MIPS_CPU_SCACHE +- if (mips_sc_init ()) { +- scache_size = c->scache.ways * c->scache.sets * c->scache.linesz; +- printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n", +- scache_size >> 10, +- way_string[c->scache.ways], c->scache.linesz); +- } +-#else +- if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) +- panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); +-#endif +- return; +- } + sc_present = 0; + } + + if (!sc_present) + return; + ++ if ((c->isa_level == MIPS_CPU_ISA_M32R1 || ++ c->isa_level == MIPS_CPU_ISA_M64R1) && ++ !(c->scache.flags & MIPS_CACHE_NOT_PRESENT)) ++ panic("Dunno how to handle MIPS32 / MIPS64 second level cache"); ++ + /* compute a couple of other cache variables */ + c->scache.waysize = scache_size / c->scache.ways; + +Index: linux-2.6.22-rc4/arch/mips/mm/Makefile +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/mm/Makefile 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/mm/Makefile 2007-06-10 21:33:17.000000000 +0100 +@@ -30,4 +30,3 @@ + obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o + obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o + obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o +-obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/140-export_uevent_handler.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/140-export_uevent_handler.patch new file mode 100644 index 000000000..f6a41f32a --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/140-export_uevent_handler.patch @@ -0,0 +1,12 @@ +Index: linux-2.6.22-rc4/lib/kobject_uevent.c +=================================================================== +--- linux-2.6.22-rc4.orig/lib/kobject_uevent.c 2007-06-10 21:32:13.000000000 +0100 ++++ linux-2.6.22-rc4/lib/kobject_uevent.c 2007-06-10 21:33:18.000000000 +0100 +@@ -29,6 +29,7 @@ + u64 uevent_seqnum; + char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug"; + static DEFINE_SPINLOCK(sequence_lock); ++EXPORT_SYMBOL(uevent_helper); + #if defined(CONFIG_NET) + static struct sock *uevent_sock; + #endif diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/150-cpu_fixes.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/150-cpu_fixes.patch new file mode 100644 index 000000000..ef297a4c0 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/150-cpu_fixes.patch @@ -0,0 +1,343 @@ +Index: linux-2.6.22-rc4/arch/mips/kernel/genex.S +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/kernel/genex.S 2007-06-10 21:32:12.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/kernel/genex.S 2007-06-10 21:33:19.000000000 +0100 +@@ -51,6 +51,10 @@ + NESTED(except_vec3_generic, 0, sp) + .set push + .set noat ++#ifdef CONFIG_BCM947XX ++ nop ++ nop ++#endif + #if R5432_CP0_INTERRUPT_WAR + mfc0 k0, CP0_INDEX + #endif +Index: linux-2.6.22-rc4/arch/mips/mm/c-r4k.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/mm/c-r4k.c 2007-06-10 21:33:17.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/mm/c-r4k.c 2007-06-10 21:33:19.000000000 +0100 +@@ -29,6 +29,9 @@ + #include <asm/cacheflush.h> /* for run_uncached() */ + + ++/* For enabling BCM4710 cache workarounds */ ++int bcm4710 = 0; ++ + /* + * Special Variant of smp_call_function for use by cache functions: + * +@@ -93,6 +96,9 @@ + { + unsigned long dc_lsize = cpu_dcache_line_size(); + ++ if (bcm4710) ++ r4k_blast_dcache_page = blast_dcache_page; ++ else + if (dc_lsize == 0) + r4k_blast_dcache_page = (void *)cache_noop; + else if (dc_lsize == 16) +@@ -107,6 +113,9 @@ + { + unsigned long dc_lsize = cpu_dcache_line_size(); + ++ if (bcm4710) ++ r4k_blast_dcache_page_indexed = blast_dcache_page_indexed; ++ else + if (dc_lsize == 0) + r4k_blast_dcache_page_indexed = (void *)cache_noop; + else if (dc_lsize == 16) +@@ -121,6 +130,9 @@ + { + unsigned long dc_lsize = cpu_dcache_line_size(); + ++ if (bcm4710) ++ r4k_blast_dcache = blast_dcache; ++ else + if (dc_lsize == 0) + r4k_blast_dcache = (void *)cache_noop; + else if (dc_lsize == 16) +@@ -538,6 +550,9 @@ + r4k_blast_icache(); + else + protected_blast_icache_range(start, end); ++ ++ if (bcm4710) ++ r4k_flush_cache_all(); + } + + static void r4k_flush_icache_range(unsigned long start, unsigned long end) +@@ -618,6 +633,8 @@ + unsigned long addr = (unsigned long) arg; + + R4600_HIT_CACHEOP_WAR_IMPL; ++ BCM4710_PROTECTED_FILL_TLB(addr); ++ BCM4710_PROTECTED_FILL_TLB(addr + 4); + if (dc_lsize) + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + if (!cpu_icache_snoops_remote_store && scache_size) +@@ -1173,6 +1190,15 @@ + + /* Default cache error handler for R4000 and R5000 family */ + set_uncached_handler (0x100, &except_vec2_generic, 0x80); ++ ++ /* Check if special workarounds are required */ ++#ifdef CONFIG_BCM947XX ++ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) { ++ printk("Enabling BCM4710A0 cache workarounds.\n"); ++ bcm4710 = 1; ++ } else ++#endif ++ bcm4710 = 0; + + probe_pcache(); + setup_scache(); +Index: linux-2.6.22-rc4/arch/mips/mm/tlbex.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/mm/tlbex.c 2007-06-10 21:33:12.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/mm/tlbex.c 2007-06-10 21:33:19.000000000 +0100 +@@ -1229,6 +1229,10 @@ + #endif + } + ++#ifdef CONFIG_BCM947XX ++extern int bcm4710; ++#endif ++ + static void __init build_r4000_tlb_refill_handler(void) + { + u32 *p = tlb_handler; +@@ -1243,6 +1247,12 @@ + memset(relocs, 0, sizeof(relocs)); + memset(final_handler, 0, sizeof(final_handler)); + ++#ifdef CONFIG_BCM947XX ++ if (bcm4710) { ++ i_nop(&p); ++ } ++#endif ++ + /* + * create the plain linear handler + */ +Index: linux-2.6.22-rc4/include/asm-mips/r4kcache.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/asm-mips/r4kcache.h 2007-06-10 21:32:12.000000000 +0100 ++++ linux-2.6.22-rc4/include/asm-mips/r4kcache.h 2007-06-10 21:33:19.000000000 +0100 +@@ -17,6 +17,20 @@ + #include <asm/cpu-features.h> + #include <asm/mipsmtregs.h> + ++#ifdef CONFIG_BCM947XX ++#include <asm/paccess.h> ++#include <linux/ssb/ssb.h> ++#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE))) ++ ++#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr)) ++#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); }) ++#else ++#define BCM4710_DUMMY_RREG() ++ ++#define BCM4710_FILL_TLB(addr) ++#define BCM4710_PROTECTED_FILL_TLB(addr) ++#endif ++ + /* + * This macro return a properly sign-extended address suitable as base address + * for indexed cache operations. Two issues here: +@@ -150,6 +164,7 @@ + static inline void flush_dcache_line_indexed(unsigned long addr) + { + __dflush_prologue ++ BCM4710_DUMMY_RREG(); + cache_op(Index_Writeback_Inv_D, addr); + __dflush_epilogue + } +@@ -169,6 +184,7 @@ + static inline void flush_dcache_line(unsigned long addr) + { + __dflush_prologue ++ BCM4710_DUMMY_RREG(); + cache_op(Hit_Writeback_Inv_D, addr); + __dflush_epilogue + } +@@ -176,6 +192,7 @@ + static inline void invalidate_dcache_line(unsigned long addr) + { + __dflush_prologue ++ BCM4710_DUMMY_RREG(); + cache_op(Hit_Invalidate_D, addr); + __dflush_epilogue + } +@@ -208,6 +225,7 @@ + */ + static inline void protected_flush_icache_line(unsigned long addr) + { ++ BCM4710_DUMMY_RREG(); + protected_cache_op(Hit_Invalidate_I, addr); + } + +@@ -219,6 +237,7 @@ + */ + static inline void protected_writeback_dcache_line(unsigned long addr) + { ++ BCM4710_DUMMY_RREG(); + protected_cache_op(Hit_Writeback_Inv_D, addr); + } + +@@ -339,8 +358,52 @@ + : "r" (base), \ + "i" (op)); + ++static inline void blast_dcache(void) ++{ ++ unsigned long start = KSEG0; ++ unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways; ++ unsigned long end = (start + dcache_size); ++ ++ do { ++ BCM4710_DUMMY_RREG(); ++ cache_op(Index_Writeback_Inv_D, start); ++ start += current_cpu_data.dcache.linesz; ++ } while(start < end); ++} ++ ++static inline void blast_dcache_page(unsigned long page) ++{ ++ unsigned long start = page; ++ unsigned long end = start + PAGE_SIZE; ++ ++ BCM4710_FILL_TLB(start); ++ do { ++ BCM4710_DUMMY_RREG(); ++ cache_op(Hit_Writeback_Inv_D, start); ++ start += current_cpu_data.dcache.linesz; ++ } while(start < end); ++} ++ ++static inline void blast_dcache_page_indexed(unsigned long page) ++{ ++ unsigned long start = page; ++ unsigned long end = start + PAGE_SIZE; ++ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; ++ unsigned long ws_end = current_cpu_data.dcache.ways << ++ current_cpu_data.dcache.waybit; ++ unsigned long ws, addr; ++ for (ws = 0; ws < ws_end; ws += ws_inc) { ++ start = page + ws; ++ for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) { ++ BCM4710_DUMMY_RREG(); ++ cache_op(Index_Writeback_Inv_D, addr); ++ } ++ } ++} ++ ++ + /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */ +-#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \ ++#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \ + static inline void blast_##pfx##cache##lsize(void) \ + { \ + unsigned long start = INDEX_BASE; \ +@@ -352,6 +415,7 @@ + \ + __##pfx##flush_prologue \ + \ ++ war \ + for (ws = 0; ws < ws_end; ws += ws_inc) \ + for (addr = start; addr < end; addr += lsize * 32) \ + cache##lsize##_unroll32(addr|ws,indexop); \ +@@ -366,6 +430,7 @@ + \ + __##pfx##flush_prologue \ + \ ++ war \ + do { \ + cache##lsize##_unroll32(start,hitop); \ + start += lsize * 32; \ +@@ -384,6 +449,8 @@ + current_cpu_data.desc.waybit; \ + unsigned long ws, addr; \ + \ ++ war \ ++ \ + __##pfx##flush_prologue \ + \ + for (ws = 0; ws < ws_end; ws += ws_inc) \ +@@ -393,28 +460,30 @@ + __##pfx##flush_epilogue \ + } + +-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16) +-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16) +-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32) +-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32) +-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64) +-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128) ++__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, ) ++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, ) ++__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, ) ++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, BCM4710_FILL_TLB(start);) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, ) ++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, ) ++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, ) + + /* build blast_xxx_range, protected_blast_xxx_range */ +-#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \ ++#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war, war2) \ + static inline void prot##blast_##pfx##cache##_range(unsigned long start, \ + unsigned long end) \ + { \ + unsigned long lsize = cpu_##desc##_line_size(); \ + unsigned long addr = start & ~(lsize - 1); \ + unsigned long aend = (end - 1) & ~(lsize - 1); \ ++ war \ + \ + __##pfx##flush_prologue \ + \ + while (1) { \ ++ war2 \ + prot##cache_op(hitop, addr); \ + if (addr == aend) \ + break; \ +@@ -424,13 +493,13 @@ + __##pfx##flush_epilogue \ + } + +-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_) +-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_) +-__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_) +-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, ) +-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, ) ++__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);, BCM4710_DUMMY_RREG();) ++__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_,, ) ++__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_,, ) ++__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D,, BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);, BCM4710_DUMMY_RREG();) ++__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD,,, ) + /* blast_inv_dcache_range */ +-__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, ) +-__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, ) ++__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D,,,BCM4710_DUMMY_RREG();) ++__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, ) + + #endif /* _ASM_R4KCACHE_H */ +Index: linux-2.6.22-rc4/include/asm-mips/stackframe.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/asm-mips/stackframe.h 2007-06-10 21:32:12.000000000 +0100 ++++ linux-2.6.22-rc4/include/asm-mips/stackframe.h 2007-06-10 21:33:19.000000000 +0100 +@@ -352,6 +352,10 @@ + .macro RESTORE_SP_AND_RET + LONG_L sp, PT_R29(sp) + .set mips3 ++#ifdef CONFIG_BCM947XX ++ nop ++ nop ++#endif + eret + .set mips0 + .endm diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/160-kmap_coherent.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/160-kmap_coherent.patch new file mode 100644 index 000000000..67068081d --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/160-kmap_coherent.patch @@ -0,0 +1,63 @@ +Index: linux-2.6.22-rc4/arch/mips/mm/init.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/mm/init.c 2007-06-10 21:32:12.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/mm/init.c 2007-06-10 21:33:21.000000000 +0100 +@@ -207,7 +207,7 @@ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); +- if (cpu_has_dc_aliases) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(); +@@ -230,7 +230,7 @@ + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) + { +- if (cpu_has_dc_aliases) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(); +@@ -246,7 +246,7 @@ + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) + { +- if (cpu_has_dc_aliases) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) { + void *vfrom = + kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); +Index: linux-2.6.22-rc4/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.22-rc4/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h 2007-06-10 21:33:21.000000000 +0100 +@@ -0,0 +1,13 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) ++ */ ++#ifndef __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H ++#define __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H ++ ++#define cpu_use_kmap_coherent 0 ++ ++#endif /* __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H */ +Index: linux-2.6.22-rc4/include/asm-mips/cpu-features.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/asm-mips/cpu-features.h 2007-06-10 21:32:12.000000000 +0100 ++++ linux-2.6.22-rc4/include/asm-mips/cpu-features.h 2007-06-10 21:33:21.000000000 +0100 +@@ -101,6 +101,9 @@ + #ifndef cpu_has_pindexed_dcache + #define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX) + #endif ++#ifndef cpu_use_kmap_coherent ++#define cpu_use_kmap_coherent 1 ++#endif + + /* + * I-Cache snoops remote store. This only matters on SMP. Some multiprocessors diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/170-cpu_wait.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/170-cpu_wait.patch new file mode 100644 index 000000000..92bf0a37e --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/170-cpu_wait.patch @@ -0,0 +1,13 @@ +Index: linux-2.6.22-rc4/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.22-rc4.orig/arch/mips/kernel/cpu-probe.c 2007-06-10 21:33:17.000000000 +0100 ++++ linux-2.6.22-rc4/arch/mips/kernel/cpu-probe.c 2007-06-10 21:33:22.000000000 +0100 +@@ -143,6 +143,8 @@ + case CPU_34K: + case CPU_74K: + case CPU_PR4450: ++ case CPU_BCM3302: ++ case CPU_BCM4710: + cpu_wait = r4k_wait; + break; + case CPU_TX49XX: diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/200-b44_ssb_fixup.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/200-b44_ssb_fixup.patch new file mode 100644 index 000000000..816d7e18b --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/200-b44_ssb_fixup.patch @@ -0,0 +1,256 @@ +Index: linux-2.6.22-rc4/drivers/net/b44.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/net/b44.c 2007-06-10 21:33:15.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/net/b44.c 2007-06-10 21:33:23.000000000 +0100 +@@ -128,7 +128,7 @@ + unsigned long offset, + enum dma_data_direction dir) + { +- dma_sync_single_range_for_device(&sdev->dev, dma_base, ++ dma_sync_single_range_for_device(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); + } +@@ -138,7 +138,7 @@ + unsigned long offset, + enum dma_data_direction dir) + { +- dma_sync_single_range_for_cpu(&sdev->dev, dma_base, ++ dma_sync_single_range_for_cpu(sdev->dev, dma_base, + offset & dma_desc_align_mask, + dma_desc_sync_size, dir); + } +@@ -563,7 +563,7 @@ + + BUG_ON(skb == NULL); + +- dma_unmap_single(&bp->sdev->dev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + skb->len, + DMA_TO_DEVICE); +@@ -603,7 +603,7 @@ + if (skb == NULL) + return -ENOMEM; + +- mapping = dma_map_single(&bp->sdev->dev, skb->data, ++ mapping = dma_map_single(bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + +@@ -613,18 +613,18 @@ + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + /* Sigh... */ + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA); + if (skb == NULL) + return -ENOMEM; +- mapping = dma_map_single(&bp->sdev->dev, skb->data, ++ mapping = dma_map_single(bp->sdev->dev, skb->data, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + if (dma_mapping_error(mapping) || + mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + return -ENOMEM; + } +@@ -702,7 +702,7 @@ + dest_idx * sizeof(dest_desc), + DMA_BIDIRECTIONAL); + +- dma_sync_single_for_device(&bp->sdev->dev, le32_to_cpu(src_desc->addr), ++ dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + } +@@ -724,7 +724,7 @@ + struct rx_header *rh; + u16 len; + +- dma_sync_single_for_cpu(&bp->sdev->dev, map, ++ dma_sync_single_for_cpu(bp->sdev->dev, map, + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); + rh = (struct rx_header *) skb->data; +@@ -758,7 +758,7 @@ + skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod); + if (skb_size < 0) + goto drop_it; +- dma_unmap_single(&bp->sdev->dev, map, ++ dma_unmap_single(bp->sdev->dev, map, + skb_size, DMA_FROM_DEVICE); + /* Leave out rx_header */ + skb_put(skb, len+bp->rx_offset); +@@ -931,22 +931,22 @@ + goto err_out; + } + +- mapping = dma_map_single(&bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); ++ mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + /* Chip can't handle DMA to/from >1GB, use bounce buffer */ + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, len, DMA_TO_DEVICE); ++ dma_unmap_single(bp->sdev->dev, mapping, len, DMA_TO_DEVICE); + + bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ, + GFP_ATOMIC|GFP_DMA); + if (!bounce_skb) + goto err_out; + +- mapping = dma_map_single(&bp->sdev->dev, bounce_skb->data, ++ mapping = dma_map_single(bp->sdev->dev, bounce_skb->data, + len, DMA_TO_DEVICE); + if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) { + if (!dma_mapping_error(mapping)) +- dma_unmap_single(&bp->sdev->dev, mapping, ++ dma_unmap_single(bp->sdev->dev, mapping, + len, DMA_TO_DEVICE); + dev_kfree_skb_any(bounce_skb); + goto err_out; +@@ -1046,7 +1046,7 @@ + + if (rp->skb == NULL) + continue; +- dma_unmap_single(&bp->sdev->dev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + RX_PKT_BUF_SZ, + DMA_FROM_DEVICE); +@@ -1060,7 +1060,7 @@ + + if (rp->skb == NULL) + continue; +- dma_unmap_single(&bp->sdev->dev, ++ dma_unmap_single(bp->sdev->dev, + pci_unmap_addr(rp, mapping), + rp->skb->len, + DMA_TO_DEVICE); +@@ -1085,12 +1085,12 @@ + memset(bp->tx_ring, 0, B44_TX_RING_BYTES); + + if (bp->flags & B44_FLAG_RX_RING_HACK) +- dma_sync_single_for_device(&bp->sdev->dev, bp->rx_ring_dma, ++ dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + + if (bp->flags & B44_FLAG_TX_RING_HACK) +- dma_sync_single_for_device(&bp->sdev->dev, bp->tx_ring_dma, ++ dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + +@@ -1112,24 +1112,24 @@ + bp->tx_buffers = NULL; + if (bp->rx_ring) { + if (bp->flags & B44_FLAG_RX_RING_HACK) { +- dma_unmap_single(&bp->sdev->dev, bp->rx_ring_dma, ++ dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + kfree(bp->rx_ring); + } else +- dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES, ++ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + bp->rx_ring, bp->rx_ring_dma); + bp->rx_ring = NULL; + bp->flags &= ~B44_FLAG_RX_RING_HACK; + } + if (bp->tx_ring) { + if (bp->flags & B44_FLAG_TX_RING_HACK) { +- dma_unmap_single(&bp->sdev->dev, bp->tx_ring_dma, ++ dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + kfree(bp->tx_ring); + } else +- dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES, ++ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES, + bp->tx_ring, bp->tx_ring_dma); + bp->tx_ring = NULL; + bp->flags &= ~B44_FLAG_TX_RING_HACK; +@@ -1155,7 +1155,7 @@ + goto out_err; + + size = DMA_TABLE_BYTES; +- bp->rx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); ++ bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC); + if (!bp->rx_ring) { + /* Allocation may have failed due to pci_alloc_consistent + insisting on use of GFP_DMA, which is more restrictive +@@ -1167,7 +1167,7 @@ + if (!rx_ring) + goto out_err; + +- rx_ring_dma = dma_map_single(&bp->sdev->dev, rx_ring, ++ rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring, + DMA_TABLE_BYTES, + DMA_BIDIRECTIONAL); + +@@ -1182,7 +1182,7 @@ + bp->flags |= B44_FLAG_RX_RING_HACK; + } + +- bp->tx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); ++ bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC); + if (!bp->tx_ring) { + /* Allocation may have failed due to dma_alloc_coherent + insisting on use of GFP_DMA, which is more restrictive +@@ -1194,7 +1194,7 @@ + if (!tx_ring) + goto out_err; + +- tx_ring_dma = dma_map_single(&bp->sdev->dev, tx_ring, ++ tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring, + DMA_TABLE_BYTES, + DMA_TO_DEVICE); + +@@ -2314,13 +2314,13 @@ + + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) { +- dev_err(&sdev->dev, "Etherdev alloc failed, aborting.\n"); ++ dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; + goto out; + } + + SET_MODULE_OWNER(dev); +- SET_NETDEV_DEV(dev,&sdev->dev); ++ SET_NETDEV_DEV(dev,sdev->dev); + + /* No interesting netdevice features in this card... */ + dev->features |= 0; +@@ -2358,7 +2358,7 @@ + + err = b44_get_invariants(bp); + if (err) { +- dev_err(&sdev->dev, ++ dev_err(sdev->dev, + "Problem fetching invariants of chip, aborting.\n"); + goto err_out_free_dev; + } +@@ -2379,7 +2379,7 @@ + + err = register_netdev(dev); + if (err) { +- dev_err(&sdev->dev, "Cannot register net device, aborting.\n"); ++ dev_err(sdev->dev, "Cannot register net device, aborting.\n"); + goto out; + } + +@@ -2458,7 +2458,6 @@ + rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); + if (rc) { + printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name); +- pci_disable_device(pdev); + return rc; + } + diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/205-ssb_integrate.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/205-ssb_integrate.patch new file mode 100644 index 000000000..67882454d --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/205-ssb_integrate.patch @@ -0,0 +1,78 @@ +Index: linux-2.6.22-rc4/drivers/usb/host/Kconfig +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/usb/host/Kconfig 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/usb/host/Kconfig 2007-06-10 21:33:24.000000000 +0100 +@@ -142,6 +142,19 @@ + Enables support for PCI-bus plug-in USB controller cards. + If unsure, say Y. + ++config USB_OHCI_HCD_SSB ++ bool "OHCI support for the Broadcom SSB OHCI core (embedded systems only)" ++ depends on USB_OHCI_HCD && ((USB_OHCI_HCD=m && SSB) || (USB_OHCI_HCD=y && SSB=y)) && EXPERIMENTAL ++ default n ++ ---help--- ++ Support for the Sonics Silicon Backplane (SSB) attached ++ Broadcom USB OHCI core. ++ ++ This device is only present in some embedded devices with ++ Broadcom based SSB bus. ++ ++ If unsure, say N. ++ + config USB_OHCI_BIG_ENDIAN_DESC + bool + depends on USB_OHCI_HCD +Index: linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/usb/host/ohci-hcd.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/usb/host/ohci-hcd.c 2007-06-10 21:33:24.000000000 +0100 +@@ -920,11 +920,17 @@ + #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver + #endif + ++#ifdef CONFIG_USB_OHCI_HCD_SSB ++#include "ohci-ssb.c" ++#define SSB_OHCI_DRIVER ssb_ohci_driver ++#endif ++ + #if !defined(PCI_DRIVER) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) && \ +- !defined(PS3_SYSTEM_BUS_DRIVER) ++ !defined(PS3_SYSTEM_BUS_DRIVER) && \ ++ !defined(SSB_OHCI_DRIVER) + #error "missing bus glue for ohci-hcd" + #endif + +@@ -972,10 +978,20 @@ + goto error_pci; + #endif + ++#ifdef SSB_OHCI_DRIVER ++ retval = ssb_driver_register(&SSB_OHCI_DRIVER); ++ if (retval) ++ goto error_ssb; ++#endif ++ + return retval; + + /* Error path */ ++#ifdef SSB_OHCI_DRIVER ++ error_ssb: ++#endif + #ifdef PCI_DRIVER ++ pci_unregister_driver(&PCI_DRIVER); + error_pci: + #endif + #ifdef SA1111_DRIVER +@@ -1001,6 +1017,9 @@ + + static void __exit ohci_hcd_mod_exit(void) + { ++#ifdef SSB_OHCI_DRIVER ++ ssb_driver_unregister(&SSB_OHCI_DRIVER); ++#endif + #ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); + #endif diff --git a/target/linux/brcm47xx-2.6/patches-2.6.22/210-ssb_merge.patch b/target/linux/brcm47xx-2.6/patches-2.6.22/210-ssb_merge.patch new file mode 100644 index 000000000..21986b342 --- /dev/null +++ b/target/linux/brcm47xx-2.6/patches-2.6.22/210-ssb_merge.patch @@ -0,0 +1,421 @@ +Index: linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_chipcommon.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_chipcommon.c 2007-06-10 21:33:25.000000000 +0100 +@@ -264,6 +264,31 @@ + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); + } + ++/* TODO: These two functions are a clear candidate for merging, but one gets ++ * the processor clock, and the other gets the bus clock. ++ */ ++void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, ++ u32 *plltype, u32 *n, u32 *m) ++{ ++ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N); ++ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT); ++ switch (*plltype) { ++ case SSB_PLLTYPE_2: ++ case SSB_PLLTYPE_4: ++ case SSB_PLLTYPE_6: ++ case SSB_PLLTYPE_7: ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS); ++ break; ++ case SSB_PLLTYPE_3: ++ /* 5350 uses m2 to control mips */ ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2); ++ break; ++ default: ++ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB); ++ break; ++ } ++} ++ + void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m) + { +@@ -400,3 +425,13 @@ + return nr_ports; + } + #endif /* CONFIG_SSB_SERIAL */ ++ ++/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */ ++int ++ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks) ++{ ++ /* instant NMI */ ++ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks); ++ return 0; ++} ++EXPORT_SYMBOL(ssb_chipco_watchdog); +Index: linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_mipscore.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_mipscore.c 2007-06-10 21:33:25.000000000 +0100 +@@ -4,6 +4,7 @@ + * + * Copyright 2005, Broadcom Corporation + * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> ++ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org> + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +@@ -31,6 +32,16 @@ + ssb_write32(mcore->dev, offset, value); + } + ++static inline u32 extif_read32(struct ssb_extif *extif, u16 offset) ++{ ++ return ssb_read32(extif->dev, offset); ++} ++ ++static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value) ++{ ++ ssb_write32(extif->dev, offset, value); ++} ++ + static const u32 ipsflag_irq_mask[] = { + 0, + SSB_IPSFLAG_IRQ1, +@@ -118,9 +129,9 @@ + } + + /* XXX: leave here or move into separate extif driver? */ +-static int ssb_extif_serial_init(struct ssb_device *dev, struct ssb_serial_ports *ports) ++static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports) + { +- ++ return 0; + } + + +@@ -174,23 +185,76 @@ + { + struct ssb_bus *bus = mcore->dev->bus; + ++ mcore->flash_buswidth = 2; + if (bus->chipco.dev) { + mcore->flash_window = 0x1c000000; +- mcore->flash_window_size = 0x800000; ++ mcore->flash_window_size = 0x02000000; ++ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG) ++ & SSB_CHIPCO_CFG_DS16) == 0) ++ mcore->flash_buswidth = 1; + } else { + mcore->flash_window = 0x1fc00000; +- mcore->flash_window_size = 0x400000; ++ mcore->flash_window_size = 0x00400000; + } + } + ++static void ssb_extif_timing_init(struct ssb_extif *extif, u32 ns) ++{ ++ u32 tmp; ++ ++ /* Initialize extif so we can get to the LEDs and external UART */ ++ extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN); ++ ++ /* Set timing for the flash */ ++ tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= ceildiv(40, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= ceildiv(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++ ++ /* Set programmable interface timing for external uart */ ++ tmp = ceildiv(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= ceildiv(20, ns) << SSB_PROG_WCNT_2_SHIFT; ++ tmp |= ceildiv(100, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= ceildiv(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++} + +-static void ssb_cpu_clock(struct ssb_mipscore *mcore) ++static inline void ssb_extif_get_clockcontrol(struct ssb_extif *extif, ++ u32 *pll_type, u32 *n, u32 *m) + { ++ *pll_type = SSB_PLLTYPE_1; ++ *n = extif_read32(extif, SSB_EXTIF_CLOCK_N); ++ *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB); + } + +-void ssb_mipscore_init(struct ssb_mipscore *mcore) ++u32 ssb_cpu_clock(struct ssb_mipscore *mcore) + { + struct ssb_bus *bus = mcore->dev->bus; ++ u32 pll_type, n, m, rate = 0; ++ ++ if (bus->extif.dev) { ++ ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m); ++ } else if (bus->chipco.dev) { ++ ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m); ++ } else ++ return 0; ++ ++ if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) { ++ rate = 200000000; ++ } else { ++ rate = ssb_calc_clock_rate(pll_type, n, m); ++ } ++ ++ if (pll_type == SSB_PLLTYPE_6) { ++ rate *= 2; ++ } ++ ++ return rate; ++} ++ ++void ssb_mipscore_init(struct ssb_mipscore *mcore) ++{ ++ struct ssb_bus *bus; + struct ssb_device *dev; + unsigned long hz, ns; + unsigned int irq, i; +@@ -198,6 +262,8 @@ + if (!mcore->dev) + return; /* We don't have a MIPS core */ + ++ bus = mcore->dev->bus; ++ + ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n"); + + hz = ssb_clockspeed(bus); +@@ -205,28 +271,9 @@ + hz = 100000000; + ns = 1000000000 / hz; + +-//TODO +-#if 0 +- if (have EXTIF) { +- /* Initialize extif so we can get to the LEDs and external UART */ +- W_REG(&eir->prog_config, CF_EN); +- +- /* Set timing for the flash */ +- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ +- tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */ +- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ +- W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */ +- +- /* Set programmable interface timing for external uart */ +- tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */ +- tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */ +- tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */ +- tmp = tmp | CEIL(120, ns); /* W0 = 120nS */ +- W_REG(&eir->prog_waitcount, tmp); +- } +- else... chipcommon +-#endif +- if (bus->chipco.dev) ++ if (bus->extif.dev) ++ ssb_extif_timing_init(&bus->extif, ns); ++ else if (bus->chipco.dev) + ssb_chipco_timing_init(&bus->chipco, ns); + + /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */ +@@ -256,3 +303,5 @@ + ssb_mips_serial_init(mcore); + ssb_mips_flash_detect(mcore); + } ++ ++EXPORT_SYMBOL(ssb_mips_irq); +Index: linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c +=================================================================== +--- linux-2.6.22-rc4.orig/drivers/ssb/driver_pcicore.c 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/drivers/ssb/driver_pcicore.c 2007-06-10 21:33:25.000000000 +0100 +@@ -93,6 +93,9 @@ + + /* Enable PCI bridge BAR1 prefetch and burst */ + pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); ++ ++ /* Make sure our latency is high enough to handle the devices behind us */ ++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8); + } + DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); + +@@ -110,7 +113,7 @@ + + if (unlikely(pc->cardbusmode && dev > 1)) + goto out; +- if (bus == 0) { ++ if (bus == 0) {//FIXME busnumber ok? + /* Type 0 transaction */ + if (unlikely(dev >= SSB_PCI_SLOT_MAX)) + goto out; +@@ -224,7 +227,7 @@ + val = *((const u32 *)buf); + break; + } +- writel(*((const u32 *)buf), mmio); ++ writel(val, mmio); + + err = 0; + unmap: +@@ -307,6 +310,8 @@ + udelay(150); + val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */ + pcicore_write32(pc, SSB_PCICORE_CTL, val); ++ val = SSB_PCICORE_ARBCTL_INTERN; ++ pcicore_write32(pc, SSB_PCICORE_ARBCTL, val); + udelay(1); + + //TODO cardbus mode +@@ -336,6 +341,7 @@ + * The following needs change, if we want to port hostmode + * to non-MIPS platform. */ + set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000)); ++ mdelay(300); + register_pci_controller(&ssb_pcicore_controller); + } + +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 21:33:25.000000000 +0100 +@@ -364,6 +364,8 @@ + extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); + extern void ssb_chipco_resume(struct ssb_chipcommon *cc); + ++extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, ++ u32 *plltype, u32 *n, u32 *m); + extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc, + u32 *plltype, u32 *n, u32 *m); + extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc, +@@ -378,6 +380,46 @@ + extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, + enum ssb_clkmode mode); + ++/* GPIO functions */ ++static inline u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, ++ u32 mask) ++{ ++ return ssb_read32(cc->dev, SSB_CHIPCO_GPIOIN) & mask; ++} ++ ++static inline u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUT, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOOUTEN, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOCTL, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOIRQ, mask, value); ++} ++ ++static inline u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(cc->dev, SSB_CHIPCO_GPIOPOL, mask, value); ++} ++/* TODO: GPIO reservation */ ++ ++extern int ssb_chipco_watchdog(struct ssb_chipcommon *cc, uint ticks); ++ + #ifdef CONFIG_SSB_SERIAL + extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc, + struct ssb_serial_port *ports); +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_extif.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_extif.h 2007-06-10 21:33:25.000000000 +0100 +@@ -158,6 +158,36 @@ + /* watchdog */ + #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + ++/* GPIO functions */ ++static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, ++ u32 mask) ++{ ++ return ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN) & mask; ++} ++ ++static inline u32 ssb_extif_gpio_out(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUT(0), mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_outen(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_OUTEN(0), mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTPOL, mask, value); ++} ++ ++static inline u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, ++ u32 mask, u32 value) ++{ ++ return ssb_write32_masked(extif->dev, SSB_EXTIF_GPIO_INTMASK, mask, value); ++} + + #endif /* __KERNEL__ */ + #endif /* LINUX_SSB_EXTIFCORE_H_ */ +Index: linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb_driver_mips.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb_driver_mips.h 2007-06-10 21:33:25.000000000 +0100 +@@ -22,11 +22,13 @@ + int nr_serial_ports; + struct ssb_serial_port serial_ports[4]; + ++ int flash_buswidth; + u32 flash_window; + u32 flash_window_size; + }; + + extern void ssb_mipscore_init(struct ssb_mipscore *mcore); ++extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore); + + extern unsigned int ssb_mips_irq(struct ssb_device *dev); + +Index: linux-2.6.22-rc4/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.22-rc4.orig/include/linux/ssb/ssb.h 2007-06-10 21:32:11.000000000 +0100 ++++ linux-2.6.22-rc4/include/linux/ssb/ssb.h 2007-06-10 21:33:25.000000000 +0100 +@@ -263,6 +263,12 @@ + #define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */ + #define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */ + ++static inline u16 ssb_read16(struct ssb_device *dev, u16 offset); ++static inline u32 ssb_read32(struct ssb_device *dev, u16 offset); ++static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value); ++static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value); ++static inline u32 ssb_write32_masked(struct ssb_device *dev, u16 offset, u32 mask, u32 value); ++ + #include <linux/ssb/ssb_driver_chipcommon.h> + #include <linux/ssb/ssb_driver_mips.h> + #include <linux/ssb/ssb_driver_extif.h> +@@ -369,6 +375,16 @@ + dev->ops->write32(dev, offset, value); + } + ++static inline u32 ssb_write32_masked(struct ssb_device *dev, ++ u16 offset, ++ u32 mask, ++ u32 value) ++{ ++ value &= mask; ++ value |= ssb_read32(dev, offset) & ~mask; ++ ssb_write32(dev, offset, value); ++ return value; ++} + + /* Translation (routing) bits that need to be ORed to DMA + * addresses before they are given to a device. */ |