diff options
author | Felix Fietkau <nbd@openwrt.org> | 2007-10-13 02:04:37 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2007-10-13 02:04:37 +0000 |
commit | 30777ac989c985ce56f339edcd819e01ffd6a776 (patch) | |
tree | 715f5f4c6da43215b86f71fc30cd2456c29fb4da /target/linux/brcm47xx/patches-2.6.23 | |
parent | a5164cf41b12edc652bc26e115e798e3cf2ec8c2 (diff) | |
download | master-31e0f0ae-30777ac989c985ce56f339edcd819e01ffd6a776.tar.gz master-31e0f0ae-30777ac989c985ce56f339edcd819e01ffd6a776.tar.bz2 master-31e0f0ae-30777ac989c985ce56f339edcd819e01ffd6a776.zip |
add patches for 2.6.23 on brcm47xx (not enabled yet)
SVN-Revision: 9279
Diffstat (limited to 'target/linux/brcm47xx/patches-2.6.23')
10 files changed, 3389 insertions, 0 deletions
diff --git a/target/linux/brcm47xx/patches-2.6.23/100-board_support.patch b/target/linux/brcm47xx/patches-2.6.23/100-board_support.patch new file mode 100644 index 0000000000..5b11e58058 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/100-board_support.patch @@ -0,0 +1,212 @@ +Index: linux-2.6.23/arch/mips/Kconfig +=================================================================== +--- linux-2.6.23.orig/arch/mips/Kconfig 2007-10-13 02:23:06.662507926 +0200 ++++ linux-2.6.23/arch/mips/Kconfig 2007-10-13 02:23:41.484492317 +0200 +@@ -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" +@@ -44,6 +48,23 @@ + note that a kernel built with this option selected will not be + able to run on normal units. + ++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 MIPS_COBALT + bool "Cobalt Server" + select DMA_NONCOHERENT +Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:06.666508151 +0200 ++++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:11.210767122 +0200 +@@ -793,6 +793,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; +@@ -815,6 +837,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.23/arch/mips/kernel/proc.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/proc.c 2007-10-13 02:23:06.678508839 +0200 ++++ linux-2.6.23/arch/mips/kernel/proc.c 2007-10-13 02:23:11.210767122 +0200 +@@ -82,6 +82,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", + [CPU_LOONGSON2] = "ICT Loongson-2", + }; +Index: linux-2.6.23/arch/mips/Makefile +=================================================================== +--- linux-2.6.23.orig/arch/mips/Makefile 2007-10-13 02:23:06.682509066 +0200 ++++ linux-2.6.23/arch/mips/Makefile 2007-10-13 02:23:11.210767122 +0200 +@@ -533,6 +533,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.23/arch/mips/mm/tlbex.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/tlbex.c 2007-10-13 02:23:06.694509748 +0200 ++++ linux-2.6.23/arch/mips/mm/tlbex.c 2007-10-13 02:26:00.272401391 +0200 +@@ -895,6 +895,8 @@ + case CPU_AU1550: + case CPU_AU1200: + case CPU_PR4450: ++ case CPU_BCM3302: ++ case CPU_BCM4710: + i_nop(p); + tlbw(p); + break; +Index: linux-2.6.23/drivers/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/Kconfig 2007-10-13 02:23:06.702510206 +0200 ++++ linux-2.6.23/drivers/Kconfig 2007-10-13 02:23:11.214767346 +0200 +@@ -58,6 +58,8 @@ + + source "drivers/hwmon/Kconfig" + ++source "drivers/ssb/Kconfig" ++ + source "drivers/mfd/Kconfig" + + source "drivers/media/Kconfig" +Index: linux-2.6.23/drivers/Makefile +=================================================================== +--- linux-2.6.23.orig/drivers/Makefile 2007-10-13 02:23:06.710510659 +0200 ++++ linux-2.6.23/drivers/Makefile 2007-10-13 02:27:08.120267817 +0200 +@@ -88,3 +88,4 @@ + obj-$(CONFIG_HID) += hid/ + obj-$(CONFIG_PPC_PS3) += ps3/ + obj-$(CONFIG_OF) += of/ ++obj-$(CONFIG_SSB) += ssb/ +Index: linux-2.6.23/include/asm-mips/bootinfo.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/bootinfo.h 2007-10-13 02:23:06.718511119 +0200 ++++ linux-2.6.23/include/asm-mips/bootinfo.h 2007-10-13 02:23:11.214767346 +0200 +@@ -208,6 +208,12 @@ + #define MACH_GROUP_WINDRIVER 28 /* Windriver boards */ + #define MACH_WRPPMC 1 + ++/* ++ * 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.23/include/asm-mips/cpu.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/cpu.h 2007-10-13 02:23:06.726511570 +0200 ++++ linux-2.6.23/include/asm-mips/cpu.h 2007-10-13 02:27:43.994312161 +0200 +@@ -106,6 +106,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 + */ + +@@ -217,8 +224,10 @@ + #define CPU_R14000 64 + #define CPU_LOONGSON1 65 + #define CPU_LOONGSON2 66 ++#define CPU_BCM3302 67 ++#define CPU_BCM4710 68 + +-#define CPU_LAST 66 ++#define CPU_LAST 68 + + /* + * ISA Level encodings +Index: linux-2.6.23/include/linux/pci_ids.h +=================================================================== +--- linux-2.6.23.orig/include/linux/pci_ids.h 2007-10-13 02:23:06.734512028 +0200 ++++ linux-2.6.23/include/linux/pci_ids.h 2007-10-13 02:23:11.218767569 +0200 +@@ -1972,6 +1972,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/patches-2.6.23/110-flash_map.patch b/target/linux/brcm47xx/patches-2.6.23/110-flash_map.patch new file mode 100644 index 0000000000..7dc05b6c6a --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/110-flash_map.patch @@ -0,0 +1,29 @@ +Index: linux-2.6.23/drivers/mtd/maps/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/mtd/maps/Kconfig 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/drivers/mtd/maps/Kconfig 2007-10-13 02:28:13.644001805 +0200 +@@ -352,6 +352,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.23/drivers/mtd/maps/Makefile +=================================================================== +--- linux-2.6.23.orig/drivers/mtd/maps/Makefile 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/drivers/mtd/maps/Makefile 2007-10-13 02:27:56.727037761 +0200 +@@ -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/patches-2.6.23/120-b44_ssb_support.patch b/target/linux/brcm47xx/patches-2.6.23/120-b44_ssb_support.patch new file mode 100644 index 0000000000..e8114c6bbe --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/120-b44_ssb_support.patch @@ -0,0 +1,1535 @@ +Index: linux-2.6.23/drivers/net/b44.c +=================================================================== +--- linux-2.6.23.orig/drivers/net/b44.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/drivers/net/b44.c 2007-10-13 02:46:38.946989430 +0200 +@@ -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. +@@ -21,11 +23,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" +@@ -87,8 +91,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); + +@@ -96,18 +100,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 *); + +@@ -119,6 +116,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, +@@ -126,35 +124,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, +@@ -182,117 +169,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; ++ data[0] = (val >> 8) & 0xFF; ++ data[1] = (val >> 0) & 0xFF; + } + +-static int ssb_is_core_up(struct b44 *bp) +-{ +- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK)) +- == SBTMSLOW_CLOCK); +-} +- +-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; + +@@ -328,14 +227,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); +@@ -344,18 +243,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. +@@ -384,6 +299,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; +@@ -442,11 +359,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, +@@ -542,6 +475,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); + } +@@ -657,9 +603,9 @@ + 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 = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|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; + } +@@ -705,9 +651,9 @@ + dp->addr = cpu_to_le32((u32) mapping + RX_PKT_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; + } +@@ -734,9 +680,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)) +@@ -750,13 +696,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) +@@ -776,9 +722,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 - RX_PKT_OFFSET)) || +@@ -810,8 +756,8 @@ + 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 + RX_PKT_OFFSET); + skb_pull(skb, RX_PKT_OFFSET); +@@ -982,24 +928,24 @@ + 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) { + struct sk_buff *bounce_skb; + + /* 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(len, 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; + } +@@ -1022,9 +968,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); + +@@ -1097,10 +1043,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; + } +@@ -1111,10 +1057,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; + } +@@ -1136,14 +1082,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) +@@ -1163,24 +1109,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; +@@ -1206,7 +1152,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 +@@ -1218,9 +1164,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) { +@@ -1233,9 +1179,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; +@@ -1245,9 +1191,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) { +@@ -1282,7 +1228,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); +@@ -1294,19 +1242,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)) { +@@ -1349,6 +1301,7 @@ + { + struct b44 *bp = netdev_priv(dev); + struct sockaddr *addr = p; ++ u32 val; + + if (netif_running(dev)) + return -EBUSY; +@@ -1359,7 +1312,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; +@@ -1445,18 +1402,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 +@@ -1570,7 +1515,6 @@ + static void b44_setup_wol(struct b44 *bp) + { + u32 val; +- u16 pmval; + + bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); + +@@ -1594,13 +1538,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) +@@ -1700,7 +1637,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 { +@@ -1747,12 +1684,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) +@@ -2035,6 +1968,245 @@ + .get_ethtool_stats = b44_get_ethtool_stats, + }; + ++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); +@@ -2044,40 +2216,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); + +- 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]; ++ 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; ++ } ++ ++ 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"); +@@ -2086,26 +2282,20 @@ + + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); + +- bp->phy_addr = eeprom[90] & 0x1f; +- + 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) ++ if (bp->sdev->dev->id.revision >= 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; +@@ -2113,76 +2303,32 @@ + 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"); + 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; + +@@ -2201,16 +2347,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; +@@ -2229,61 +2375,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); + +@@ -2301,26 +2438,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; + +@@ -2346,29 +2473,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.23/drivers/net/b44.h +=================================================================== +--- linux-2.6.23.orig/drivers/net/b44.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/drivers/net/b44.h 2007-10-13 02:28:25.848697310 +0200 +@@ -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 +@@ -450,8 +388,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.23/drivers/net/Kconfig +=================================================================== +--- linux-2.6.23.orig/drivers/net/Kconfig 2007-10-13 02:19:47.919182188 +0200 ++++ linux-2.6.23/drivers/net/Kconfig 2007-10-13 02:28:25.860697993 +0200 +@@ -1577,7 +1577,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/patches-2.6.23/130-remove_scache.patch b/target/linux/brcm47xx/patches-2.6.23/130-remove_scache.patch new file mode 100644 index 0000000000..eea4e26026 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/130-remove_scache.patch @@ -0,0 +1,97 @@ +Index: linux-2.6.23/arch/mips/Kconfig +=================================================================== +--- linux-2.6.23.orig/arch/mips/Kconfig 2007-10-13 02:23:41.484492317 +0200 ++++ linux-2.6.23/arch/mips/Kconfig 2007-10-13 02:47:02.784347843 +0200 +@@ -192,7 +192,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 +@@ -1281,13 +1280,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.23/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:11.210767122 +0200 ++++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:47:02.788348072 +0200 +@@ -701,6 +701,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.23/arch/mips/mm/c-r4k.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/c-r4k.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/mm/c-r4k.c 2007-10-13 02:47:02.792348301 +0200 +@@ -1086,7 +1086,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) + { +@@ -1140,29 +1139,17 @@ + #endif + + 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.23/arch/mips/mm/Makefile +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/Makefile 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/mm/Makefile 2007-10-13 02:47:23.393522295 +0200 +@@ -31,6 +31,5 @@ + 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 + + EXTRA_CFLAGS += -Werror diff --git a/target/linux/brcm47xx/patches-2.6.23/150-cpu_fixes.patch b/target/linux/brcm47xx/patches-2.6.23/150-cpu_fixes.patch new file mode 100644 index 0000000000..fe759dc62b --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/150-cpu_fixes.patch @@ -0,0 +1,643 @@ +Index: linux-2.6.23/arch/mips/kernel/genex.S +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/genex.S 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/kernel/genex.S 2007-10-13 02:47:32.546043867 +0200 +@@ -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.23/arch/mips/mm/c-r4k.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/c-r4k.c 2007-10-13 02:47:02.792348301 +0200 ++++ linux-2.6.23/arch/mips/mm/c-r4k.c 2007-10-13 02:55:35.877587360 +0200 +@@ -30,6 +30,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: + * +@@ -86,14 +89,21 @@ + + static inline void r4k_blast_dcache_page_dc32(unsigned long addr) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); + R4600_HIT_CACHEOP_WAR_IMPL; + blast_dcache32_page(addr); ++ local_irq_restore(flags); + } + + static void __init r4k_blast_dcache_page_setup(void) + { + 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) +@@ -108,6 +118,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) +@@ -122,6 +135,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) +@@ -203,8 +219,12 @@ + + static void (* r4k_blast_icache_page)(unsigned long addr); + ++static void r4k_flush_cache_all(void); + static void __init r4k_blast_icache_page_setup(void) + { ++#ifdef CONFIG_BCM947XX ++ r4k_blast_icache_page = (void *)r4k_flush_cache_all; ++#else + unsigned long ic_lsize = cpu_icache_line_size(); + + if (ic_lsize == 0) +@@ -215,6 +235,7 @@ + r4k_blast_icache_page = blast_icache32_page; + else if (ic_lsize == 64) + r4k_blast_icache_page = blast_icache64_page; ++#endif + } + + +@@ -222,6 +243,9 @@ + + static void __init r4k_blast_icache_page_indexed_setup(void) + { ++#ifdef CONFIG_BCM947XX ++ r4k_blast_icache_page_indexed = (void *)r4k_flush_cache_all; ++#else + unsigned long ic_lsize = cpu_icache_line_size(); + + if (ic_lsize == 0) +@@ -240,6 +264,7 @@ + blast_icache32_page_indexed; + } else if (ic_lsize == 64) + r4k_blast_icache_page_indexed = blast_icache64_page_indexed; ++#endif + } + + static void (* r4k_blast_icache)(void); +@@ -323,12 +348,17 @@ + */ + static inline void local_r4k_flush_cache_all(void * args) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); + r4k_blast_dcache(); ++ r4k_blast_icache(); ++ local_irq_restore(flags); + } + + static void r4k_flush_cache_all(void) + { +- if (!cpu_has_dc_aliases) ++ if (!cpu_has_dc_aliases && cpu_use_kmap_coherent) + return; + + r4k_on_each_cpu(local_r4k_flush_cache_all, NULL, 1, 1); +@@ -336,6 +366,9 @@ + + static inline void local_r4k___flush_cache_all(void * args) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); + #if defined(CONFIG_CPU_LOONGSON2) + r4k_blast_scache(); + return; +@@ -353,6 +386,7 @@ + case CPU_R14000: + r4k_blast_scache(); + } ++ local_irq_restore(flags); + } + + static void r4k___flush_cache_all(void) +@@ -363,17 +397,21 @@ + static inline void local_r4k_flush_cache_range(void * args) + { + struct vm_area_struct *vma = args; ++ unsigned long flags; + + if (!(cpu_context(smp_processor_id(), vma->vm_mm))) + return; + ++ local_irq_save(flags); + r4k_blast_dcache(); ++ r4k_blast_icache(); ++ local_irq_restore(flags); + } + + static void r4k_flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) + { +- if (!cpu_has_dc_aliases) ++ if (!cpu_has_dc_aliases && cpu_use_kmap_coherent) + return; + + r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1, 1); +@@ -382,6 +420,7 @@ + static inline void local_r4k_flush_cache_mm(void * args) + { + struct mm_struct *mm = args; ++ unsigned long flags; + + if (!cpu_context(smp_processor_id(), mm)) + return; +@@ -400,12 +439,15 @@ + return; + } + ++ local_irq_save(flags); + r4k_blast_dcache(); ++ r4k_blast_icache(); ++ local_irq_restore(flags); + } + + static void r4k_flush_cache_mm(struct mm_struct *mm) + { +- if (!cpu_has_dc_aliases) ++ if (!cpu_has_dc_aliases && cpu_use_kmap_coherent) + return; + + r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1, 1); +@@ -425,6 +467,7 @@ + unsigned long paddr = fcp_args->pfn << PAGE_SHIFT; + int exec = vma->vm_flags & VM_EXEC; + struct mm_struct *mm = vma->vm_mm; ++ unsigned long flags; + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; +@@ -456,8 +499,9 @@ + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ ++ local_irq_save(flags); + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { +- if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { ++ if (!cpu_use_kmap_coherent || cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { + r4k_blast_dcache_page(addr); + if (exec && !cpu_icache_snoops_remote_store) + r4k_blast_scache_page(addr); +@@ -465,14 +509,14 @@ + if (exec) + r4k_blast_icache_page(addr); + +- return; ++ goto done; + } + + /* + * Do indexed flush, too much work to get the (possible) TLB refills + * to work correctly. + */ +- if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { ++ if (!cpu_use_kmap_coherent || cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { + r4k_blast_dcache_page_indexed(cpu_has_pindexed_dcache ? + paddr : addr); + if (exec && !cpu_icache_snoops_remote_store) { +@@ -488,6 +532,8 @@ + } else + r4k_blast_icache_page_indexed(addr); + } ++done: ++ local_irq_restore(flags); + } + + static void r4k_flush_cache_page(struct vm_area_struct *vma, +@@ -504,7 +550,11 @@ + + static inline void local_r4k_flush_data_cache_page(void * addr) + { ++ unsigned long flags; ++ ++ local_irq_save(flags); + r4k_blast_dcache_page((unsigned long) addr); ++ local_irq_restore(flags); + } + + static void r4k_flush_data_cache_page(unsigned long addr) +@@ -547,6 +597,9 @@ + + static void r4k_flush_icache_range(unsigned long start, unsigned long end) + { ++#ifdef CONFIG_BCM947XX ++ r4k_flush_cache_all(); ++#else + struct flush_icache_range_args args; + + args.start = start; +@@ -554,12 +607,15 @@ + + r4k_on_each_cpu(local_r4k_flush_icache_range, &args, 1, 1); + instruction_hazard(); ++#endif + } + + #ifdef CONFIG_DMA_NONCOHERENT + + static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) + { ++ unsigned long flags; ++ + /* Catch bad driver code */ + BUG_ON(size == 0); + +@@ -576,18 +632,21 @@ + * subset property so we have to flush the primary caches + * explicitly + */ ++ local_irq_save(flags); + if (size >= dcache_size) { + r4k_blast_dcache(); + } else { + R4600_HIT_CACHEOP_WAR_IMPL; + blast_dcache_range(addr, addr + size); + } +- + bc_wback_inv(addr, size); ++ local_irq_restore(flags); + } + + static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) + { ++ unsigned long flags; ++ + /* Catch bad driver code */ + BUG_ON(size == 0); + +@@ -599,6 +658,7 @@ + return; + } + ++ local_irq_save(flags); + if (size >= dcache_size) { + r4k_blast_dcache(); + } else { +@@ -607,6 +667,7 @@ + } + + bc_inv(addr, size); ++ local_irq_restore(flags); + } + #endif /* CONFIG_DMA_NONCOHERENT */ + +@@ -621,8 +682,12 @@ + unsigned long dc_lsize = cpu_dcache_line_size(); + unsigned long sc_lsize = cpu_scache_line_size(); + unsigned long addr = (unsigned long) arg; ++ unsigned long flags; + ++ local_irq_save(flags); + 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) +@@ -649,6 +714,7 @@ + } + if (MIPS_CACHE_SYNC_WAR) + __asm__ __volatile__ ("sync"); ++ local_irq_restore(flags); + } + + static void r4k_flush_cache_sigtramp(unsigned long addr) +@@ -1198,6 +1264,17 @@ + * silly idea of putting something else there ... + */ + switch (current_cpu_data.cputype) { ++ case CPU_BCM3302: ++ { ++ u32 cm; ++ cm = read_c0_diag(); ++ /* Enable icache */ ++ cm |= (1 << 31); ++ /* Enable dcache */ ++ cm |= (1 << 30); ++ write_c0_diag(cm); ++ } ++ break; + case CPU_R4000PC: + case CPU_R4000SC: + case CPU_R4000MC: +@@ -1228,6 +1305,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(); + +@@ -1273,5 +1359,13 @@ + build_clear_page(); + build_copy_page(); + local_r4k___flush_cache_all(NULL); ++#ifdef CONFIG_BCM947XX ++ { ++ static void (*_coherency_setup)(void); ++ _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup); ++ _coherency_setup(); ++ } ++#else + coherency_setup(); ++#endif + } +Index: linux-2.6.23/arch/mips/mm/tlbex.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/tlbex.c 2007-10-13 02:26:00.272401391 +0200 ++++ linux-2.6.23/arch/mips/mm/tlbex.c 2007-10-13 02:47:32.550044103 +0200 +@@ -1247,6 +1247,10 @@ + #endif + } + ++#ifdef CONFIG_BCM947XX ++extern int bcm4710; ++#endif ++ + static void __init build_r4000_tlb_refill_handler(void) + { + u32 *p = tlb_handler; +@@ -1261,6 +1265,10 @@ + memset(relocs, 0, sizeof(relocs)); + memset(final_handler, 0, sizeof(final_handler)); + ++#ifdef CONFIG_BCM947XX ++ i_nop(&p); ++#endif ++ + /* + * create the plain linear handler + */ +@@ -1756,6 +1764,9 @@ + memset(labels, 0, sizeof(labels)); + memset(relocs, 0, sizeof(relocs)); + ++#ifdef CONFIG_BCM947XX ++ i_nop(&p); ++#endif + if (bcm1250_m3_war()) { + i_MFC0(&p, K0, C0_BADVADDR); + i_MFC0(&p, K1, C0_ENTRYHI); +Index: linux-2.6.23/include/asm-mips/r4kcache.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/r4kcache.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/include/asm-mips/r4kcache.h 2007-10-13 02:47:32.554044332 +0200 +@@ -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.23/include/asm-mips/stackframe.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/stackframe.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/include/asm-mips/stackframe.h 2007-10-13 02:47:32.554044332 +0200 +@@ -350,6 +350,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/patches-2.6.23/160-kmap_coherent.patch b/target/linux/brcm47xx/patches-2.6.23/160-kmap_coherent.patch new file mode 100644 index 0000000000..8a3bd0ec74 --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/160-kmap_coherent.patch @@ -0,0 +1,63 @@ +Index: linux-2.6.23/arch/mips/mm/init.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/mm/init.c 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/arch/mips/mm/init.c 2007-10-13 02:57:18.483434538 +0200 +@@ -211,7 +211,7 @@ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); +- if (cpu_has_dc_aliases && !Page_dcache_dirty(from)) { ++ if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(); +@@ -234,7 +234,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(); +@@ -250,7 +250,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.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h 2007-10-13 02:56:22.020216880 +0200 +@@ -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.23/include/asm-mips/cpu-features.h +=================================================================== +--- linux-2.6.23.orig/include/asm-mips/cpu-features.h 2007-10-09 22:31:38.000000000 +0200 ++++ linux-2.6.23/include/asm-mips/cpu-features.h 2007-10-13 02:56:22.028217337 +0200 +@@ -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/patches-2.6.23/170-cpu_wait.patch b/target/linux/brcm47xx/patches-2.6.23/170-cpu_wait.patch new file mode 100644 index 0000000000..62b3b12b8f --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/170-cpu_wait.patch @@ -0,0 +1,12 @@ +Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c +=================================================================== +--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:47:02.788348072 +0200 ++++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:57:46.293019312 +0200 +@@ -159,6 +159,7 @@ + case CPU_5KC: + case CPU_25KF: + case CPU_PR4450: ++ case CPU_BCM3302: + cpu_wait = r4k_wait; + break; + diff --git a/target/linux/brcm47xx/patches-2.6.23/200-b44_ssb_fixup.patch b/target/linux/brcm47xx/patches-2.6.23/200-b44_ssb_fixup.patch new file mode 100644 index 0000000000..e0456c6d8a --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/200-b44_ssb_fixup.patch @@ -0,0 +1,274 @@ +Index: linux-2.6.23/drivers/net/b44.c +=================================================================== +--- linux-2.6.23.orig/drivers/net/b44.c 2007-10-13 02:46:38.946989430 +0200 ++++ linux-2.6.23/drivers/net/b44.c 2007-10-13 03:15:34.889915180 +0200 +@@ -129,7 +129,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); + } +@@ -139,7 +139,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 = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|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; + } +@@ -700,7 +700,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); + } +@@ -722,7 +722,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; +@@ -756,7 +756,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 + RX_PKT_OFFSET); +@@ -928,23 +928,23 @@ + 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) { + struct sk_buff *bounce_skb; + + /* 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(len, 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; +@@ -1043,7 +1043,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); +@@ -1057,7 +1057,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); +@@ -1082,12 +1082,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); + +@@ -1109,24 +1109,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; +@@ -1152,7 +1152,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 +@@ -1164,7 +1164,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); + +@@ -1179,7 +1179,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 +@@ -1191,7 +1191,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); + +@@ -2288,7 +2288,7 @@ + bp->flags |= B44_FLAG_BUGGY_TXPTR; + */ + +- if (bp->sdev->dev->id.revision >= 7) ++ if (bp->sdev->id.revision >= 7) + bp->flags |= B44_FLAG_B0_ANDLATER; + + return err; +@@ -2298,7 +2298,6 @@ + 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; +@@ -2310,13 +2309,13 @@ + + 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 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; +@@ -2354,7 +2353,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; + } +@@ -2375,7 +2374,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; + } + +@@ -2454,7 +2453,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/patches-2.6.23/210-ssb_fixes.patch b/target/linux/brcm47xx/patches-2.6.23/210-ssb_fixes.patch new file mode 100644 index 0000000000..273d8bb34f --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/210-ssb_fixes.patch @@ -0,0 +1,372 @@ +Index: linux-2.6.22-rc5/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.22-rc5.orig/drivers/ssb/driver_chipcommon.c 2007-06-21 23:04:38.000000000 +0100 ++++ linux-2.6.22-rc5/drivers/ssb/driver_chipcommon.c 2007-06-24 20:07:15.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-rc5/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.22-rc5.orig/drivers/ssb/driver_mipscore.c 2007-06-10 16:44:31.000000000 +0100 ++++ linux-2.6.22-rc5/drivers/ssb/driver_mipscore.c 2007-06-24 20:48:52.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 = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= DIV_ROUND_UP(120, ns); ++ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); ++ ++ /* Set programmable interface timing for external uart */ ++ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; ++ tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; ++ tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; ++ tmp |= DIV_ROUND_UP(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-rc5/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-10 16:44:47.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb_driver_chipcommon.h 2007-06-24 20:07:15.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-rc5/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb_driver_extif.h 2007-06-10 16:44:47.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb_driver_extif.h 2007-06-24 20:07:15.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-rc5/include/linux/ssb/ssb_driver_mips.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb_driver_mips.h 2007-06-10 16:44:47.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb_driver_mips.h 2007-06-24 20:07:15.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-rc5/include/linux/ssb/ssb.h +=================================================================== +--- linux-2.6.22-rc5.orig/include/linux/ssb/ssb.h 2007-06-24 19:49:56.000000000 +0100 ++++ linux-2.6.22-rc5/include/linux/ssb/ssb.h 2007-06-24 20:07:15.000000000 +0100 +@@ -270,6 +270,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> +@@ -388,6 +394,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. */ diff --git a/target/linux/brcm47xx/patches-2.6.23/240-extif_fixes.patch b/target/linux/brcm47xx/patches-2.6.23/240-extif_fixes.patch new file mode 100644 index 0000000000..48df245b5c --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.23/240-extif_fixes.patch @@ -0,0 +1,152 @@ +Index: linux-2.6.23/drivers/ssb/driver_mipscore.c +=================================================================== +--- linux-2.6.23.orig/drivers/ssb/driver_mipscore.c 2007-10-13 03:01:19.829188047 +0200 ++++ linux-2.6.23/drivers/ssb/driver_mipscore.c 2007-10-13 03:01:21.777299062 +0200 +@@ -128,10 +128,46 @@ + ssb_write32(mdev, SSB_IPSFLAG, irqflag); + } + +-/* XXX: leave here or move into separate extif driver? */ ++static inline bool serial_exists(u8 *regs) ++{ ++ u8 save_mcr, status1 = 0; ++ ++ if (regs) { ++ save_mcr = regs[UART_MCR]; ++ regs[UART_MCR] = (UART_MCR_LOOP | 0x0a); ++ // Fixme UART_MSR_DSR appears in status1 ++ status1 = regs[UART_MSR] & 0xd0; ++ regs[UART_MCR] = save_mcr; ++ } ++ return (status1 == (UART_MSR_DCD | UART_MSR_CTS)); ++} ++ + static int ssb_extif_serial_init(struct ssb_extif *dev, struct ssb_serial_port *ports) + { +- return 0; ++ u32 i, nr_ports = 0; ++ ++ /* Disable GPIO interrupt initially */ ++ extif_write32(dev, SSB_EXTIF_GPIO_INTPOL, 0); ++ extif_write32(dev, SSB_EXTIF_GPIO_INTMASK, 0); ++ ++ for (i = 0; i < 2; i++) { ++ void __iomem *uart_regs; ++ ++ uart_regs = ioremap_nocache(SSB_EUART, 16); ++ uart_regs += (i * 8); ++ ++ if (serial_exists(uart_regs) && ports) { ++ extif_write32(dev, SSB_EXTIF_GPIO_INTMASK, 2); ++ ++ nr_ports++; ++ ports[i].regs = uart_regs; ++ ports[i].irq = 2; ++ ports[i].baud_base = 13500000; ++ ports[i].reg_shift = 0; ++ } ++ iounmap(uart_regs); ++ } ++ return nr_ports; + } + + +@@ -139,40 +175,6 @@ + { + struct ssb_bus *bus = mcore->dev->bus; + +- //TODO if (EXTIF available +-#if 0 +- extifregs_t *eir = (extifregs_t *) regs; +- sbconfig_t *sb; +- +- /* Determine external UART register base */ +- sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF); +- base = EXTIF_CFGIF_BASE(sb_base(R_REG(&sb->sbadmatch1))); +- +- /* Determine IRQ */ +- irq = sb_irq(sbh); +- +- /* Disable GPIO interrupt initially */ +- W_REG(&eir->gpiointpolarity, 0); +- W_REG(&eir->gpiointmask, 0); +- +- /* Search for external UARTs */ +- n = 2; +- for (i = 0; i < 2; i++) { +- regs = (void *) REG_MAP(base + (i * 8), 8); +- if (BCMINIT(serial_exists)(regs)) { +- /* Set GPIO 1 to be the external UART IRQ */ +- W_REG(&eir->gpiointmask, 2); +- if (add) +- add(regs, irq, 13500000, 0); +- } +- } +- +- /* Add internal UART if enabled */ +- if (R_REG(&eir->corecontrol) & CC_UE) +- if (add) +- add((void *) &eir->uartdata, irq, sb_clock(sbh), 2); +- +-#endif + if (bus->extif.dev) + mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports); + else if (bus->chipco.dev) +@@ -219,7 +221,7 @@ + extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp); + } + +-static inline void ssb_extif_get_clockcontrol(struct ssb_extif *extif, ++void ssb_extif_get_clockcontrol(struct ssb_extif *extif, + u32 *pll_type, u32 *n, u32 *m) + { + *pll_type = SSB_PLLTYPE_1; +Index: linux-2.6.23/drivers/ssb/main.c +=================================================================== +--- linux-2.6.23.orig/drivers/ssb/main.c 2007-10-11 19:38:13.198446000 +0200 ++++ linux-2.6.23/drivers/ssb/main.c 2007-10-13 03:01:21.785299518 +0200 +@@ -774,12 +774,12 @@ + u32 plltype; + u32 clkctl_n, clkctl_m; + +- //TODO if EXTIF: PLLTYPE == 1, read n from clockcontrol_n, m from clockcontrol_sb +- +- if (bus->chipco.dev) { ++ if (bus->extif.dev) ++ ssb_extif_get_clockcontrol(&bus->extif, &plltype, &clkctl_n, &clkctl_m); ++ else if (bus->chipco.dev) + ssb_chipco_get_clockcontrol(&bus->chipco, &plltype, + &clkctl_n, &clkctl_m); +- } else ++ else + return 0; + + if (bus->chip_id == 0x5365) { +Index: linux-2.6.23/include/linux/ssb/ssb_driver_extif.h +=================================================================== +--- linux-2.6.23.orig/include/linux/ssb/ssb_driver_extif.h 2007-10-13 03:01:19.841188731 +0200 ++++ linux-2.6.23/include/linux/ssb/ssb_driver_extif.h 2007-10-13 03:01:21.789299747 +0200 +@@ -158,6 +158,8 @@ + /* watchdog */ + #define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */ + ++extern void ssb_extif_get_clockcontrol(struct ssb_extif *, u32 *, u32 *, u32 *); ++ + /* GPIO functions */ + static inline u32 ssb_extif_gpio_in(struct ssb_extif *extif, + u32 mask) +Index: linux-2.6.23/include/linux/ssb/ssb_regs.h +=================================================================== +--- linux-2.6.23.orig/include/linux/ssb/ssb_regs.h 2007-10-11 19:38:13.206447000 +0200 ++++ linux-2.6.23/include/linux/ssb/ssb_regs.h 2007-10-13 03:01:21.793299976 +0200 +@@ -24,8 +24,8 @@ + #define SSB_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ + #define SSB_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */ + #define SSB_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */ +-#define SSB_EUART (SB_EXTIF_BASE + 0x00800000) +-#define SSB_LED (SB_EXTIF_BASE + 0x00900000) ++#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000) ++#define SSB_LED (SSB_EXTIF_BASE + 0x00900000) + + + /* Enumeration space constants */ |