source: clfs-embedded/patches/linux-2.6.19.2-bcm947xx-2.patch@ 05ce0d3

Last change on this file since 05ce0d3 was be76242, checked in by Jim Gifford <clfs@…>, 18 years ago

Updated to Linux 2.6.19.2
Fixes for uClibc
Changed > to &gt;
Updated all Linux Patches
Updated Linux Headers
Updated to Busybox 1.4.1
Added E2FSProgs since it was removed from Busybox
Fixed Typos

  • Property mode set to 100644
File size: 122.7 KB
RevLine 
[a6b0b88]1From da20def23769f672480f6d7bc472d1fa54e1bafa Mon Sep 17 00:00:00 2001
2From: Maarten Lankhorst <mlankhorst:cross-lfs.org>
3Date: Tue, 9 Jan 2007 22:42:47 +0000
4Subject: [PATCH] Add bcm947xx support
5
6---
7 arch/mips/Kconfig | 20 +
8 arch/mips/Makefile | 12 +
9 arch/mips/bcm947xx/Makefile | 8 +
10 arch/mips/bcm947xx/cfe_env.c | 232 ++++++
11 arch/mips/bcm947xx/include/nvram.h | 37 +
12 arch/mips/bcm947xx/irq.c | 63 ++
13 arch/mips/bcm947xx/nvram.c | 131 +++
14 arch/mips/bcm947xx/pci.c | 227 +++++
15 arch/mips/bcm947xx/prom.c | 59 ++
16 arch/mips/bcm947xx/setup.c | 163 ++++
17 arch/mips/bcm947xx/time.c | 62 ++
18 arch/mips/cfe/Makefile | 5 +
19 arch/mips/cfe/cfe.c | 533 ++++++++++++
20 arch/mips/cfe/cfe_private.h | 176 ++++
21 arch/mips/kernel/cpu-probe.c | 25 +
22 arch/mips/kernel/head.S | 3 +
23 arch/mips/kernel/proc.c | 2 +
24 arch/mips/mm/tlbex.c | 2 +
25 drivers/mtd/chips/cfi_cmdset_0002.c | 3 -
26 drivers/mtd/maps/Kconfig | 6 +
27 drivers/mtd/maps/Makefile | 1 +
28 drivers/mtd/maps/bcm47xx-flash.c | 477 +++++++++++
29 drivers/net/Kconfig | 2 +-
30 drivers/net/b44.c | 873 +++++++++++---------
31 drivers/net/b44.h | 83 +--
32 include/asm-mips/bootinfo.h | 6 +
33 include/asm-mips/cfe.h | 189 +++++
34 include/asm-mips/cpu.h | 11 +-
35 include/asm-mips/mach-bcm947xx/kernel-entry-init.h | 26 +
36 include/linux/pci_ids.h | 1 +
37 30 files changed, 2988 insertions(+), 450 deletions(-)
38
39diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
40index 1443024..d845a8f 100644
41--- a/arch/mips/Kconfig
42+++ b/arch/mips/Kconfig
43@@ -4,6 +4,10 @@ config MIPS
44 # Horrible source of confusion. Die, die, die ...
45 select EMBEDDED
46
47+config CFE
48+ bool
49+ # Common Firmware Environment
50+
51 mainmenu "Linux/MIPS Kernel Configuration"
52
53 menu "Machine selection"
54@@ -222,6 +226,22 @@ config MACH_JAZZ
55 Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and
56 Olivetti M700-10 workstations.
57
58+config BCM947XX
59+ bool "Support for BCM947xx based boards"
60+ select DMA_NONCOHERENT
61+ select HW_HAS_PCI
62+ select IRQ_CPU
63+ select SYS_HAS_CPU_MIPS32_R1
64+ select SYS_SUPPORTS_32BIT_KERNEL
65+ select SYS_SUPPORTS_LITTLE_ENDIAN
66+ select MIPS_CPU_SCACHE
67+ select SSB
68+ select SSB_DRIVER_MIPS
69+ select SSB_DRIVER_EXTIF
70+ select CFE
71+ help
72+ Support for BCM947xx based boards
73+
74 config LASAT
75 bool "LASAT Networks platforms"
76 select DMA_NONCOHERENT
77diff --git a/arch/mips/Makefile b/arch/mips/Makefile
78index d580d46..03429c5 100644
79--- a/arch/mips/Makefile
80+++ b/arch/mips/Makefile
81@@ -571,6 +571,18 @@ libs-$(CONFIG_SIBYTE_BIGSUR) += arch/mip
82 load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
83
84 #
85+# Broadcom BCM47XX boards
86+#
87+core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/
88+cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include -Iinclude/asm-mips/mach-bcm947xx
89+load-$(CONFIG_BCM947XX) := 0xffffffff80001000
90+
91+#
92+# Common Firmware Environment
93+#
94+core-$(CONFIG_CFE) += arch/mips/cfe/
95+
96+#
97 # SNI RM200 PCI
98 #
99 core-$(CONFIG_SNI_RM200_PCI) += arch/mips/sni/
100diff --git a/arch/mips/bcm947xx/Makefile b/arch/mips/bcm947xx/Makefile
101new file mode 100644
102index 0000000..b02e840
103--- /dev/null
104+++ b/arch/mips/bcm947xx/Makefile
105@@ -0,0 +1,8 @@
106+#
107+# Makefile for the BCM47xx specific kernel interface routines
108+# under Linux.
109+#
110+
111+obj-y := irq.o prom.o setup.o time.o
112+obj-y += nvram.o cfe_env.o
113+#obj-y += pci.o
114diff --git a/arch/mips/bcm947xx/cfe_env.c b/arch/mips/bcm947xx/cfe_env.c
115new file mode 100644
116index 0000000..6ef464f
117--- /dev/null
118+++ b/arch/mips/bcm947xx/cfe_env.c
119@@ -0,0 +1,232 @@
120+/*
121+ * CFE environment varialble access
122+ *
123+ * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
124+ *
125+ * This program is free software; you can redistribute it and/or modify it
126+ * under the terms of the GNU General Public License as published by the
127+ * Free Software Foundation; either version 2 of the License, or (at your
128+ * option) any later version.
129+ *
130+ * Copyright 2001-2003, Broadcom Corporation
131+ *
132+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
133+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
134+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
135+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
136+ */
137+
138+#include <linux/init.h>
139+#include <linux/module.h>
140+#include <linux/kernel.h>
141+#include <linux/string.h>
142+#include <asm/io.h>
143+#include <asm/uaccess.h>
144+
145+#define NVRAM_SIZE (0x1ff0)
146+static char _nvdata[NVRAM_SIZE] __initdata;
147+static char _valuestr[256] __initdata;
148+
149+/*
150+ * TLV types. These codes are used in the "type-length-value"
151+ * encoding of the items stored in the NVRAM device (flash or EEPROM)
152+ *
153+ * The layout of the flash/nvram is as follows:
154+ *
155+ * <type> <length> <data ...> <type> <length> <data ...> <type_end>
156+ *
157+ * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
158+ * The "length" field marks the length of the data section, not
159+ * including the type and length fields.
160+ *
161+ * Environment variables are stored as follows:
162+ *
163+ * <type_env> <length> <flags> <name> = <value>
164+ *
165+ * If bit 0 (low bit) is set, the length is an 8-bit value.
166+ * If bit 0 (low bit) is clear, the length is a 16-bit value
167+ *
168+ * Bit 7 set indicates "user" TLVs. In this case, bit 0 still
169+ * indicates the size of the length field.
170+ *
171+ * Flags are from the constants below:
172+ *
173+ */
174+#define ENV_LENGTH_16BITS 0x00 /* for low bit */
175+#define ENV_LENGTH_8BITS 0x01
176+
177+#define ENV_TYPE_USER 0x80
178+
179+#define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
180+#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
181+
182+/*
183+ * The actual TLV types we support
184+ */
185+
186+#define ENV_TLV_TYPE_END 0x00
187+#define ENV_TLV_TYPE_ENV ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
188+
189+/*
190+ * Environment variable flags
191+ */
192+
193+#define ENV_FLG_NORMAL 0x00 /* normal read/write */
194+#define ENV_FLG_BUILTIN 0x01 /* builtin - not stored in flash */
195+#define ENV_FLG_READONLY 0x02 /* read-only - cannot be changed */
196+
197+#define ENV_FLG_MASK 0xFF /* mask of attributes we keep */
198+#define ENV_FLG_ADMIN 0x100 /* lets us internally override permissions */
199+
200+
201+/* *********************************************************************
202+ * _nvram_read(buffer,offset,length)
203+ *
204+ * Read data from the NVRAM device
205+ *
206+ * Input parameters:
207+ * buffer - destination buffer
208+ * offset - offset of data to read
209+ * length - number of bytes to read
210+ *
211+ * Return value:
212+ * number of bytes read, or <0 if error occured
213+ ********************************************************************* */
214+static int
215+_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
216+{
217+ int i;
218+ if (offset > NVRAM_SIZE)
219+ return -1;
220+
221+ for ( i = 0; i < length; i++) {
222+ buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
223+ }
224+ return length;
225+}
226+
227+
228+static char*
229+_strnchr(const char *dest,int c,size_t cnt)
230+{
231+ while (*dest && (cnt > 0)) {
232+ if (*dest == c) return (char *) dest;
233+ dest++;
234+ cnt--;
235+ }
236+ return NULL;
237+}
238+
239+
240+
241+/*
242+ * Core support API: Externally visible.
243+ */
244+
245+/*
246+ * Get the value of an NVRAM variable
247+ * @param name name of variable to get
248+ * @return value of variable or NULL if undefined
249+ */
250+
251+char*
252+cfe_env_get(unsigned char *nv_buf, char* name)
253+{
254+ int size;
255+ unsigned char *buffer;
256+ unsigned char *ptr;
257+ unsigned char *envval;
258+ unsigned int reclen;
259+ unsigned int rectype;
260+ int offset;
261+ int flg;
262+
263+ size = NVRAM_SIZE;
264+ buffer = &_nvdata[0];
265+
266+ ptr = buffer;
267+ offset = 0;
268+
269+ /* Read the record type and length */
270+ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
271+ goto error;
272+ }
273+
274+ while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) {
275+
276+ /* Adjust pointer for TLV type */
277+ rectype = *(ptr);
278+ offset++;
279+ size--;
280+
281+ /*
282+ * Read the length. It can be either 1 or 2 bytes
283+ * depending on the code
284+ */
285+ if (rectype & ENV_LENGTH_8BITS) {
286+ /* Read the record type and length - 8 bits */
287+ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
288+ goto error;
289+ }
290+ reclen = *(ptr);
291+ size--;
292+ offset++;
293+ }
294+ else {
295+ /* Read the record type and length - 16 bits, MSB first */
296+ if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
297+ goto error;
298+ }
299+ reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
300+ size -= 2;
301+ offset += 2;
302+ }
303+
304+ if (reclen > size)
305+ break; /* should not happen, bad NVRAM */
306+
307+ switch (rectype) {
308+ case ENV_TLV_TYPE_ENV:
309+ /* Read the TLV data */
310+ if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
311+ goto error;
312+ flg = *ptr++;
313+ envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
314+ if (envval) {
315+ *envval++ = '\0';
316+ memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
317+ _valuestr[(reclen-1)-(envval-ptr)] = '\0';
318+#if 0
319+ printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
320+#endif
321+ if(!strcmp(ptr, name)){
322+ return _valuestr;
323+ }
324+ if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
325+ return _valuestr;
326+ }
327+ break;
328+
329+ default:
330+ /* Unknown TLV type, skip it. */
331+ break;
332+ }
333+
334+ /*
335+ * Advance to next TLV
336+ */
337+
338+ size -= (int)reclen;
339+ offset += reclen;
340+
341+ /* Read the next record type */
342+ ptr = buffer;
343+ if (_nvram_read(nv_buf, ptr,offset,1) != 1)
344+ goto error;
345+ }
346+
347+error:
348+ return NULL;
349+
350+}
351+
352diff --git a/arch/mips/bcm947xx/include/nvram.h b/arch/mips/bcm947xx/include/nvram.h
353new file mode 100644
354index 0000000..6bb18e8
355--- /dev/null
356+++ b/arch/mips/bcm947xx/include/nvram.h
357@@ -0,0 +1,37 @@
358+/*
359+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
360+ *
361+ * This program is free software; you can redistribute it and/or modify it
362+ * under the terms of the GNU General Public License as published by the
363+ * Free Software Foundation; either version 2 of the License, or (at your
364+ * option) any later version.
365+ */
366+
367+#ifndef __NVRAM_H
368+#define __NVRAM_H
369+
370+struct nvram_header {
371+ u32 magic;
372+ u32 len;
373+ u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
374+ u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
375+ u32 config_ncdl; /* ncdl values for memc */
376+};
377+
378+struct nvram_tuple {
379+ char *name;
380+ char *value;
381+ struct nvram_tuple *next;
382+};
383+
384+#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */
385+#define NVRAM_VERSION 1
386+#define NVRAM_HEADER_SIZE 20
387+#define NVRAM_SPACE 0x8000
388+
389+#define NVRAM_MAX_VALUE_LEN 255
390+#define NVRAM_MAX_PARAM_LEN 64
391+
392+char *nvram_get(const char *name);
393+
394+#endif
395diff --git a/arch/mips/bcm947xx/irq.c b/arch/mips/bcm947xx/irq.c
396new file mode 100644
397index 0000000..8727a4f
398--- /dev/null
399+++ b/arch/mips/bcm947xx/irq.c
400@@ -0,0 +1,63 @@
401+/*
402+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
403+ *
404+ * This program is free software; you can redistribute it and/or modify it
405+ * under the terms of the GNU General Public License as published by the
406+ * Free Software Foundation; either version 2 of the License, or (at your
407+ * option) any later version.
408+ *
409+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
410+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
411+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
412+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
413+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
414+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
415+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
416+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
417+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
418+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
419+ *
420+ * You should have received a copy of the GNU General Public License along
421+ * with this program; if not, write to the Free Software Foundation, Inc.,
422+ * 675 Mass Ave, Cambridge, MA 02139, USA.
423+ */
424+
425+#include <linux/errno.h>
426+#include <linux/init.h>
427+#include <linux/interrupt.h>
428+#include <linux/irq.h>
429+#include <linux/module.h>
430+#include <linux/smp.h>
431+#include <linux/types.h>
432+
433+#include <asm/cpu.h>
434+#include <asm/io.h>
435+#include <asm/irq.h>
436+#include <asm/irq_cpu.h>
437+
438+void plat_irq_dispatch(void)
439+{
440+ u32 cause;
441+
442+ cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
443+
444+ clear_c0_status(cause);
445+
446+ if (cause & CAUSEF_IP7)
447+ do_IRQ(7);
448+ if (cause & CAUSEF_IP2)
449+ do_IRQ(2);
450+ if (cause & CAUSEF_IP3)
451+ do_IRQ(3);
452+ if (cause & CAUSEF_IP4)
453+ do_IRQ(4);
454+ if (cause & CAUSEF_IP5)
455+ do_IRQ(5);
456+ if (cause & CAUSEF_IP6)
457+ do_IRQ(6);
458+}
459+
460+void __init arch_init_irq(void)
461+{
462+ mips_cpu_irq_init(0);
463+}
464diff --git a/arch/mips/bcm947xx/nvram.c b/arch/mips/bcm947xx/nvram.c
465new file mode 100644
466index 0000000..d147adb
467--- /dev/null
468+++ b/arch/mips/bcm947xx/nvram.c
469@@ -0,0 +1,131 @@
470+/*
471+ * BCM947xx nvram variable access
472+ *
473+ * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
474+ *
475+ * This program is free software; you can redistribute it and/or modify it
476+ * under the terms of the GNU General Public License as published by the
477+ * Free Software Foundation; either version 2 of the License, or (at your
478+ * option) any later version.
479+ *
480+ *
481+ * Copyright 2005, Broadcom Corporation
482+ *
483+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
484+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
485+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
486+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
487+ *
488+ */
489+
490+#include <linux/init.h>
491+#include <linux/module.h>
492+#include <linux/ssb.h>
493+#include <linux/kernel.h>
494+#include <linux/string.h>
495+#include <linux/interrupt.h>
496+#include <linux/spinlock.h>
497+#include <linux/slab.h>
498+#include <asm/byteorder.h>
499+#include <asm/bootinfo.h>
500+#include <asm/addrspace.h>
501+#include <asm/io.h>
502+#include <asm/uaccess.h>
503+
504+#include <nvram.h>
505+
506+#define MB * 1048576
507+extern struct ssb_bus ssb;
508+
509+static char nvram_buf[NVRAM_SPACE];
510+static int cfe_env;
511+extern char *cfe_env_get(char *nv_buf, const char *name);
512+
513+/* Probe for NVRAM header */
514+static void __init early_nvram_init(void)
515+{
516+ struct ssb_mipscore *mcore = &ssb.mipscore;
517+ struct nvram_header *header;
518+ int i;
519+ u32 base, lim, off;
520+ u32 *src, *dst;
521+
522+ base = mcore->flash_window;
523+ lim = mcore->flash_window_size;
524+ cfe_env = 0;
525+
526+
527+ /* XXX: hack for supporting the CFE environment stuff on WGT634U */
528+ if (lim >= 8 MB) {
529+ src = (u32 *) KSEG1ADDR(base + 8 MB - 0x2000);
530+ dst = (u32 *) nvram_buf;
531+
532+ if ((*src & 0xff00ff) == 0x000001) {
533+ printk("early_nvram_init: WGT634U NVRAM found.\n");
534+
535+ for (i = 0; i < 0x1ff0; i++) {
536+ if (*src == 0xFFFFFFFF)
537+ break;
538+ *dst++ = *src++;
539+ }
540+ cfe_env = 1;
541+ return;
542+ }
543+ }
544+
545+ off = 0x20000;
546+ while (off <= lim) {
547+ /* Windowed flash access */
548+ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
549+ if (header->magic == NVRAM_HEADER)
550+ goto found;
551+ off <<= 1;
552+ }
553+
554+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
555+ header = (struct nvram_header *) KSEG1ADDR(base + 4096);
556+ if (header->magic == NVRAM_HEADER)
557+ goto found;
558+
559+ header = (struct nvram_header *) KSEG1ADDR(base + 1024);
560+ if (header->magic == NVRAM_HEADER)
561+ goto found;
562+
563+ return;
564+
565+found:
566+ src = (u32 *) header;
567+ dst = (u32 *) nvram_buf;
568+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
569+ *dst++ = *src++;
570+ for (; i < header->len && i < NVRAM_SPACE; i += 4)
571+ *dst++ = le32_to_cpu(*src++);
572+}
573+
574+char *nvram_get(const char *name)
575+{
576+ char *var, *value, *end, *eq;
577+
578+ if (!name)
579+ return NULL;
580+
581+ if (!nvram_buf[0])
582+ early_nvram_init();
583+
584+ if (cfe_env)
585+ return cfe_env_get(nvram_buf, name);
586+
587+ /* Look for name=value and return value */
588+ var = &nvram_buf[sizeof(struct nvram_header)];
589+ end = nvram_buf + sizeof(nvram_buf) - 2;
590+ end[0] = end[1] = '\0';
591+ for (; *var; var = value + strlen(value) + 1) {
592+ if (!(eq = strchr(var, '=')))
593+ break;
594+ value = eq + 1;
595+ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
596+ return value;
597+ }
598+
599+ return NULL;
600+}
601diff --git a/arch/mips/bcm947xx/pci.c b/arch/mips/bcm947xx/pci.c
602new file mode 100644
603index 0000000..bdc3d96
604--- /dev/null
605+++ b/arch/mips/bcm947xx/pci.c
606@@ -0,0 +1,227 @@
607+#include <linux/kernel.h>
608+#include <linux/init.h>
609+#include <linux/pci.h>
610+#include <linux/types.h>
611+
612+#include <asm/cpu.h>
613+#include <asm/io.h>
614+
615+#include <typedefs.h>
616+#include <osl.h>
617+#include <sbutils.h>
618+#include <sbmips.h>
619+#include <sbconfig.h>
620+#include <sbpci.h>
621+#include <bcmdevs.h>
622+#include <pcicfg.h>
623+
624+extern sb_t *sbh;
625+extern spinlock_t sbh_lock;
626+
627+
628+static int
629+sb_pci_read_config(struct pci_bus *bus, unsigned int devfn,
630+ int reg, int size, u32 *val)
631+{
632+ int ret;
633+ unsigned long flags;
634+
635+ spin_lock_irqsave(&sbh_lock, flags);
636+ ret = sbpci_read_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, val, size);
637+ spin_unlock_irqrestore(&sbh_lock, flags);
638+
639+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
640+}
641+
642+static int
643+sb_pci_write_config(struct pci_bus *bus, unsigned int devfn,
644+ int reg, int size, u32 val)
645+{
646+ int ret;
647+ unsigned long flags;
648+
649+ spin_lock_irqsave(&sbh_lock, flags);
650+ ret = sbpci_write_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, &val, size);
651+ spin_unlock_irqrestore(&sbh_lock, flags);
652+
653+ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
654+}
655+
656+
657+static struct pci_ops sb_pci_ops = {
658+ .read = sb_pci_read_config,
659+ .write = sb_pci_write_config,
660+};
661+
662+static struct resource sb_pci_mem_resource = {
663+ .name = "SB PCI Memory resources",
664+ .start = SB_ENUM_BASE,
665+ .end = SB_ENUM_LIM - 1,
666+ .flags = IORESOURCE_MEM,
667+};
668+
669+static struct resource sb_pci_io_resource = {
670+ .name = "SB PCI I/O resources",
671+ .start = 0x000,
672+ .end = 0x0FF,
673+ .flags = IORESOURCE_IO,
674+};
675+
676+static struct pci_controller bcm47xx_sb_pci_controller = {
677+ .pci_ops = &sb_pci_ops,
678+ .mem_resource = &sb_pci_mem_resource,
679+ .io_resource = &sb_pci_io_resource,
680+};
681+
682+static struct resource ext_pci_mem_resource = {
683+ .name = "Ext PCI Memory resources",
684+ .start = 0x40000000,
685+ .end = 0x7fffffff,
686+ .flags = IORESOURCE_MEM,
687+};
688+
689+static struct resource ext_pci_io_resource = {
690+ .name = "Ext PCI I/O resources",
691+ .start = 0x100,
692+ .end = 0x7FF,
693+ .flags = IORESOURCE_IO,
694+};
695+
696+static struct pci_controller bcm47xx_ext_pci_controller = {
697+ .pci_ops = &sb_pci_ops,
698+ .io_resource = &ext_pci_io_resource,
699+ .mem_resource = &ext_pci_mem_resource,
700+ .mem_offset = 0x24000000,
701+};
702+
703+void bcm47xx_pci_init(void)
704+{
705+ unsigned long flags;
706+
707+ spin_lock_irqsave(&sbh_lock, flags);
708+ sbpci_init(sbh);
709+ spin_unlock_irqrestore(&sbh_lock, flags);
710+
711+ set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000));
712+
713+ register_pci_controller(&bcm47xx_sb_pci_controller);
714+ register_pci_controller(&bcm47xx_ext_pci_controller);
715+}
716+
717+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
718+{
719+ unsigned long flags;
720+ u8 irq;
721+ uint idx;
722+
723+ /* external: use the irq of the pci core */
724+ if (dev->bus->number >= 1) {
725+ spin_lock_irqsave(&sbh_lock, flags);
726+ idx = sb_coreidx(sbh);
727+ sb_setcore(sbh, SB_PCI, 0);
728+ irq = sb_irq(sbh);
729+ sb_setcoreidx(sbh, idx);
730+ spin_unlock_irqrestore(&sbh_lock, flags);
731+
732+ return irq + 2;
733+ }
734+
735+ /* internal */
736+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
737+ return irq + 2;
738+}
739+
740+u32 pci_iobase = 0x100;
741+u32 pci_membase = SB_PCI_DMA;
742+
743+static void bcm47xx_fixup_device(struct pci_dev *d)
744+{
745+ struct resource *res;
746+ int pos, size;
747+ u32 *base;
748+
749+ if (d->bus->number == 0)
750+ return;
751+
752+ printk("PCI: Fixing up device %s\n", pci_name(d));
753+
754+ /* Fix up resource bases */
755+ for (pos = 0; pos < 6; pos++) {
756+ res = &d->resource[pos];
757+ base = ((res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase);
758+ if (res->end) {
759+ size = res->end - res->start + 1;
760+ if (*base & (size - 1))
761+ *base = (*base + size) & ~(size - 1);
762+ res->start = *base;
763+ res->end = res->start + size - 1;
764+ *base += size;
765+ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
766+ }
767+ /* Fix up PCI bridge BAR0 only */
768+ if (d->bus->number == 1 && PCI_SLOT(d->devfn) == 0)
769+ break;
770+ }
771+ /* Fix up interrupt lines */
772+ if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))
773+ d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq;
774+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
775+}
776+
777+
778+static void bcm47xx_fixup_bridge(struct pci_dev *dev)
779+{
780+ if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0)
781+ return;
782+
783+ printk("PCI: fixing up bridge\n");
784+
785+ /* Enable PCI bridge bus mastering and memory space */
786+ pci_set_master(dev);
787+ pcibios_enable_device(dev, ~0);
788+
789+ /* Enable PCI bridge BAR1 prefetch and burst */
790+ pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
791+}
792+
793+/* Do platform specific device initialization at pci_enable_device() time */
794+int pcibios_plat_dev_init(struct pci_dev *dev)
795+{
796+ uint coreidx;
797+ unsigned long flags;
798+
799+ bcm47xx_fixup_device(dev);
800+
801+ /* These cores come out of reset enabled */
802+ if ((dev->bus->number != 0) ||
803+ (dev->device == SB_MIPS) ||
804+ (dev->device == SB_MIPS33) ||
805+ (dev->device == SB_EXTIF) ||
806+ (dev->device == SB_CC))
807+ return 0;
808+
809+ /* Do a core reset */
810+ spin_lock_irqsave(&sbh_lock, flags);
811+ coreidx = sb_coreidx(sbh);
812+ if (sb_setcoreidx(sbh, PCI_SLOT(dev->devfn)) && (sb_coreid(sbh) == SB_USB)) {
813+ /*
814+ * The USB core requires a special bit to be set during core
815+ * reset to enable host (OHCI) mode. Resetting the SB core in
816+ * pcibios_enable_device() is a hack for compatibility with
817+ * vanilla usb-ohci so that it does not have to know about
818+ * SB. A driver that wants to use the USB core in device mode
819+ * should know about SB and should reset the bit back to 0
820+ * after calling pcibios_enable_device().
821+ */
822+ sb_core_disable(sbh, sb_coreflags(sbh, 0, 0));
823+ sb_core_reset(sbh, 1 << 29);
824+ } else {
825+ sb_core_reset(sbh, 0);
826+ }
827+ sb_setcoreidx(sbh, coreidx);
828+ spin_unlock_irqrestore(&sbh_lock, flags);
829+
830+ return 0;
831+}
832+
833+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcm47xx_fixup_bridge);
834diff --git a/arch/mips/bcm947xx/prom.c b/arch/mips/bcm947xx/prom.c
835new file mode 100644
836index 0000000..7a6981d
837--- /dev/null
838+++ b/arch/mips/bcm947xx/prom.c
839@@ -0,0 +1,59 @@
840+/*
841+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
842+ *
843+ * This program is free software; you can redistribute it and/or modify it
844+ * under the terms of the GNU General Public License as published by the
845+ * Free Software Foundation; either version 2 of the License, or (at your
846+ * option) any later version.
847+ *
848+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
849+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
850+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
851+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
852+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
853+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
854+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
855+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
856+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
857+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
858+ *
859+ * You should have received a copy of the GNU General Public License along
860+ * with this program; if not, write to the Free Software Foundation, Inc.,
861+ * 675 Mass Ave, Cambridge, MA 02139, USA.
862+ */
863+
864+#include <linux/init.h>
865+#include <linux/mm.h>
866+#include <linux/sched.h>
867+#include <linux/bootmem.h>
868+
869+#include <asm/addrspace.h>
870+#include <asm/bootinfo.h>
871+#include <asm/pmon.h>
872+
873+const char *get_system_type(void)
874+{
875+ return "Broadcom BCM47xx";
876+}
877+
878+void __init prom_init(void)
879+{
880+ unsigned long mem;
881+
882+ mips_machgroup = MACH_GROUP_BRCM;
883+ mips_machtype = MACH_BCM47XX;
884+
885+ /* Figure out memory size by finding aliases */
886+ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
887+ if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
888+ *(unsigned long *)(prom_init))
889+ break;
890+ }
891+
892+ add_memory_region(0, mem, BOOT_MEM_RAM);
893+}
894+
895+unsigned long __init prom_free_prom_memory(void)
896+{
897+ return 0;
898+}
899diff --git a/arch/mips/bcm947xx/setup.c b/arch/mips/bcm947xx/setup.c
900new file mode 100644
901index 0000000..5ebbd02
902--- /dev/null
903+++ b/arch/mips/bcm947xx/setup.c
904@@ -0,0 +1,163 @@
905+/*
906+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
907+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
908+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
909+ * Copyright (C) 2006 Michael Buesch
910+ *
911+ * This program is free software; you can redistribute it and/or modify it
912+ * under the terms of the GNU General Public License as published by the
913+ * Free Software Foundation; either version 2 of the License, or (at your
914+ * option) any later version.
915+ *
916+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
917+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
918+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
919+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
920+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
921+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
922+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
923+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
924+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
925+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
926+ *
927+ * You should have received a copy of the GNU General Public License along
928+ * with this program; if not, write to the Free Software Foundation, Inc.,
929+ * 675 Mass Ave, Cambridge, MA 02139, USA.
930+ */
931+
932+#include <linux/init.h>
933+#include <linux/types.h>
934+#include <linux/tty.h>
935+#include <linux/serial.h>
936+#include <linux/serial_core.h>
937+#include <linux/serial_reg.h>
938+#include <asm/bootinfo.h>
939+#include <asm/time.h>
940+#include <asm/reboot.h>
941+#include <asm/cfe.h>
942+#include <linux/pm.h>
943+#include <linux/ssb.h>
944+
945+#include <nvram.h>
946+
947+extern void bcm47xx_pci_init(void);
948+extern void bcm47xx_time_init(void);
949+
950+struct ssb_bus ssb;
951+
952+static void bcm47xx_machine_restart(char *command)
953+{
954+ printk(KERN_ALERT "Please stand by while rebooting the system...\n");
955+ local_irq_disable();
956+ /* CFE has a reboot callback, but that does not work.
957+ * Oopses with: Reserved instruction in kernel code.
958+ */
959+
960+ /* Set the watchdog timer to reset immediately */
961+//TODO sb_watchdog(sbh, 1);
962+ while (1)
963+ cpu_relax();
964+}
965+
966+static void bcm47xx_machine_halt(void)
967+{
968+ /* Disable interrupts and watchdog and spin forever */
969+ local_irq_disable();
970+//TODO sb_watchdog(sbh, 0);
971+ while (1)
972+ cpu_relax();
973+}
974+
975+static void e_aton(char *str, char *dest)
976+{
977+ int i = 0;
978+
979+ if (str == NULL) {
980+ memset(dest, 0, 6);
981+ return;
982+ }
983+
984+ for (;;) {
985+ dest[i++] = (char) simple_strtoul(str, NULL, 16);
986+ str += 2;
987+ if (!*str++ || i == 6)
988+ break;
989+ }
990+}
991+
992+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
993+{
994+ // TODO
995+}
996+
997+static void bcm47xx_fill_sprom_nvram(struct ssb_sprom *sprom)
998+{
999+ char *s;
1000+
1001+ memset(sprom, 0, sizeof(struct ssb_sprom));
1002+
1003+ sprom->revision = 3;
1004+ if ((s = nvram_get("et0macaddr")))
1005+ e_aton(s, sprom->r1.et0mac);
1006+ if ((s = nvram_get("et1macaddr")))
1007+ e_aton(s, sprom->r1.et1mac);
1008+ if ((s = nvram_get("il0macaddr")))
1009+ e_aton(s, sprom->r1.il0mac);
1010+ if ((s = nvram_get("et0phyaddr")))
1011+ sprom->r1.et0phyaddr = simple_strtoul(s, NULL, 10);
1012+ if ((s = nvram_get("et1phyaddr")))
1013+ sprom->r1.et1phyaddr = simple_strtoul(s, NULL, 10);
1014+}
1015+
1016+void __init plat_mem_setup(void)
1017+{
1018+ int i, err;
1019+ char *s;
1020+ struct ssb_mipscore *mcore;
1021+
1022+ err = ssb_bus_ssbbus_register(&ssb, SSB_ENUM_BASE, bcm47xx_fill_sprom);
1023+ if (err) {
1024+ const char *msg = "Failed to initialize SSB bus (err %d)\n";
1025+ cfe_printk(msg, err); /* Make sure the message gets out of the box. */
1026+ panic(msg, err);
1027+ }
1028+ mcore = &ssb.mipscore;
1029+
1030+ /* FIXME: the nvram init depends on the ssb being fully initializes,
1031+ * can't use the fill_sprom callback yet! */
1032+ bcm47xx_fill_sprom_nvram(&ssb.sprom);
1033+
1034+ s = nvram_get("kernel_args");
1035+ if (s && !strncmp(s, "console=ttyS1", 13) && (mcore->nr_serial_ports >= 2)) {
1036+ struct ssb_serial_port port;
1037+
1038+ /* swap serial ports */
1039+ memcpy(&port, &mcore->serial_ports[0], sizeof(port));
1040+ memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
1041+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
1042+ }
1043+
1044+ for (i = 0; i < mcore->nr_serial_ports; i++) {
1045+ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
1046+ struct uart_port s;
1047+
1048+ memset(&s, 0, sizeof(s));
1049+ s.line = i;
1050+ s.membase = port->regs;
1051+ s.irq = port->irq + 2;//FIXME?
1052+ s.uartclk = port->baud_base;
1053+ s.flags = ASYNC_BOOT_AUTOCONF;
1054+ s.iotype = SERIAL_IO_MEM;
1055+ s.regshift = port->reg_shift;
1056+
1057+ early_serial_setup(&s);
1058+ }
1059+ cfe_printk("Serial init done.\n");
1060+
1061+ _machine_restart = bcm47xx_machine_restart;
1062+ _machine_halt = bcm47xx_machine_halt;
1063+ pm_power_off = bcm47xx_machine_halt;
1064+
1065+ board_time_init = bcm47xx_time_init;//FIXME move into ssb
1066+}
1067+
1068diff --git a/arch/mips/bcm947xx/time.c b/arch/mips/bcm947xx/time.c
1069new file mode 100644
1070index 0000000..0adf6af
1071--- /dev/null
1072+++ b/arch/mips/bcm947xx/time.c
1073@@ -0,0 +1,62 @@
1074+/*
1075+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
1076+ *
1077+ * This program is free software; you can redistribute it and/or modify it
1078+ * under the terms of the GNU General Public License as published by the
1079+ * Free Software Foundation; either version 2 of the License, or (at your
1080+ * option) any later version.
1081+ *
1082+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1083+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1084+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
1085+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1086+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1087+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1088+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1089+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1090+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1091+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1092+ *
1093+ * You should have received a copy of the GNU General Public License along
1094+ * with this program; if not, write to the Free Software Foundation, Inc.,
1095+ * 675 Mass Ave, Cambridge, MA 02139, USA.
1096+ */
1097+
1098+#include <linux/init.h>
1099+#include <linux/kernel.h>
1100+#include <linux/sched.h>
1101+#include <linux/serial_reg.h>
1102+#include <linux/interrupt.h>
1103+#include <linux/ssb.h>
1104+#include <asm/addrspace.h>
1105+#include <asm/io.h>
1106+#include <asm/time.h>
1107+
1108+extern struct ssb_bus ssb;
1109+
1110+void __init
1111+bcm47xx_time_init(void)
1112+{
1113+ unsigned long hz;
1114+
1115+ /*
1116+ * Use deterministic values for initial counter interrupt
1117+ * so that calibrate delay avoids encountering a counter wrap.
1118+ */
1119+ write_c0_count(0);
1120+ write_c0_compare(0xffff);
1121+
1122+ hz = ssb_clockspeed(&ssb);
1123+ if (!hz)
1124+ hz = 100000000;
1125+
1126+ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
1127+ mips_hpt_frequency = hz;
1128+}
1129+
1130+void __init
1131+plat_timer_setup(struct irqaction *irq)
1132+{
1133+ /* Enable the timer interrupt */
1134+ setup_irq(7, irq);
1135+}
1136diff --git a/arch/mips/cfe/Makefile b/arch/mips/cfe/Makefile
1137new file mode 100644
1138index 0000000..d9f046a
1139--- /dev/null
1140+++ b/arch/mips/cfe/Makefile
1141@@ -0,0 +1,5 @@
1142+#
1143+# Makefile for the Broadcom Common Firmware Environment support
1144+#
1145+
1146+obj-y += cfe.o
1147diff --git a/arch/mips/cfe/cfe.c b/arch/mips/cfe/cfe.c
1148new file mode 100644
1149index 0000000..6d16111
1150--- /dev/null
1151+++ b/arch/mips/cfe/cfe.c
1152@@ -0,0 +1,533 @@
1153+/*
1154+ * Broadcom Common Firmware Environment (CFE) support
1155+ *
1156+ * Copyright 2000, 2001, 2002
1157+ * Broadcom Corporation. All rights reserved.
1158+ *
1159+ * Copyright (C) 2006 Michael Buesch
1160+ *
1161+ * Original Authors: Mitch Lichtenberg, Chris Demetriou
1162+ *
1163+ * This software is furnished under license and may be used and copied only
1164+ * in accordance with the following terms and conditions. Subject to these
1165+ * conditions, you may download, copy, install, use, modify and distribute
1166+ * modified or unmodified copies of this software in source and/or binary
1167+ * form. No title or ownership is transferred hereby.
1168+ *
1169+ * 1) Any source code used, modified or distributed must reproduce and
1170+ * retain this copyright notice and list of conditions as they appear in
1171+ * the source file.
1172+ *
1173+ * 2) No right is granted to use any trade name, trademark, or logo of
1174+ * Broadcom Corporation. The "Broadcom Corporation" name may not be
1175+ * used to endorse or promote products derived from this software
1176+ * without the prior written permission of Broadcom Corporation.
1177+ *
1178+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
1179+ * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
1180+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
1181+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
1182+ * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
1183+ * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1184+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1185+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
1186+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1187+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
1188+ * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1189+ */
1190+
1191+#include <linux/init.h>
1192+#include <linux/string.h>
1193+#include <linux/errno.h>
1194+#include <linux/spinlock.h>
1195+#include <asm/cfe.h>
1196+
1197+#include "cfe_private.h"
1198+
1199+
1200+static cfe_uint_t cfe_handle;
1201+static int (*cfe_trampoline)(long handle, long iocb);
1202+
1203+
1204+#include <linux/kernel.h>
1205+
1206+void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
1207+ unsigned long fwarg2, unsigned long fwarg3)
1208+{
1209+ if (fwarg3 == 0x80300000) {
1210+ /* WRT54G workaround */
1211+ fwarg3 = CFE_EPTSEAL;
1212+ fwarg2 = 0xBFC00500;
1213+ }
1214+ if (fwarg3 != CFE_EPTSEAL) {
1215+ /* We are not booted from CFE */
1216+ return;
1217+ }
1218+ if (fwarg1 == 0) {
1219+ /* We are on the boot CPU */
1220+ cfe_handle = (cfe_uint_t)fwarg0;
1221+ cfe_trampoline = CFE_TO_PTR(fwarg2);
1222+ }
1223+}
1224+
1225+int cfe_vprintk(const char *fmt, va_list args)
1226+{
1227+ static char buffer[1024];
1228+ static DEFINE_SPINLOCK(lock);
1229+ static const char pfx[] = "CFE-console: ";
1230+ static const size_t pfx_len = sizeof(pfx) - 1;
1231+ unsigned long flags;
1232+ int len, cnt, pos;
1233+ int handle;
1234+ int res;
1235+
1236+ if (!cfe_present())
1237+ return -ENODEV;
1238+
1239+ spin_lock_irqsave(&lock, flags);
1240+ handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
1241+ if (CFE_ISERR(handle)) {
1242+ len = -EIO;
1243+ goto out;
1244+ }
1245+ strcpy(buffer, pfx);
1246+ len = vscnprintf(buffer + pfx_len,
1247+ sizeof(buffer) - pfx_len - 2,
1248+ fmt, args);
1249+ len += pfx_len;
1250+ /* The CFE console requires CR-LF line-ends.
1251+ * Add a CR, if we only terminate lines with a LF.
1252+ * This does only fix CR-LF at the end of the string.
1253+ * So for multiple lines, use multiple cfe_vprintk calls.
1254+ */
1255+ if (len > 1 &&
1256+ buffer[len - 1] == '\n' && buffer[len - 2] != '\r') {
1257+ buffer[len - 1] = '\r';
1258+ buffer[len] = '\n';
1259+ len += 1;
1260+ }
1261+ cnt = len;
1262+ pos = 0;
1263+ while (cnt > 0) {
1264+ res = cfe_write(handle, buffer + pos, len - pos);
1265+ if (CFE_ISERR(res)) {
1266+ len = -EIO;
1267+ goto out;
1268+ }
1269+ cnt -= res;
1270+ pos += res;
1271+ }
1272+out:
1273+ spin_unlock_irqrestore(&lock, flags);
1274+
1275+ return len;
1276+}
1277+
1278+int cfe_printk(const char *fmt, ...)
1279+{
1280+ va_list args;
1281+ int res;
1282+
1283+ va_start(args, fmt);
1284+ res = cfe_vprintk(fmt, args);
1285+ va_end(args);
1286+
1287+ return res;
1288+}
1289+
1290+static int cfe_iocb_dispatch(struct cfe_iocb *iocb)
1291+{
1292+ if (!cfe_present())
1293+ return CFE_ERR_UNSUPPORTED;
1294+ return cfe_trampoline((long)cfe_handle, (long)iocb);
1295+}
1296+
1297+int cfe_present(void)
1298+{
1299+ return (cfe_trampoline != NULL);
1300+}
1301+
1302+int cfe_close(int handle)
1303+{
1304+ struct cfe_iocb iocb;
1305+ int err;
1306+
1307+ memset(&iocb, 0, sizeof(iocb));
1308+ iocb.fcode = CFE_CMD_DEV_CLOSE;
1309+ iocb.handle = handle;
1310+
1311+ err = cfe_iocb_dispatch(&iocb);
1312+
1313+ return (CFE_ISERR(err)) ? err : iocb.status;
1314+}
1315+
1316+int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1)
1317+{
1318+ struct cfe_iocb iocb;
1319+ int err;
1320+
1321+ memset(&iocb, 0, sizeof(iocb));
1322+ iocb.fcode = CFE_CMD_FW_CPUCTL;
1323+ iocb.psize = sizeof(struct cfe_iocb_cpuctl);
1324+ iocb.cpuctl.number = cpu;
1325+ iocb.cpuctl.command = CFE_CPU_CMD_START;
1326+ iocb.cpuctl.gp = gp;
1327+ iocb.cpuctl.sp = sp;
1328+ iocb.cpuctl.a1 = a1;
1329+ iocb.cpuctl.start_addr = (long)fn;
1330+
1331+ err = cfe_iocb_dispatch(&iocb);
1332+
1333+ return (CFE_ISERR(err)) ? err : iocb.status;
1334+}
1335+
1336+int cfe_cpu_stop(int cpu)
1337+{
1338+ struct cfe_iocb iocb;
1339+ int err;
1340+
1341+ memset(&iocb, 0, sizeof(iocb));
1342+ iocb.fcode = CFE_CMD_FW_CPUCTL;
1343+ iocb.psize = sizeof(struct cfe_iocb_cpuctl);
1344+ iocb.cpuctl.number = cpu;
1345+ iocb.cpuctl.command = CFE_CPU_CMD_STOP;
1346+
1347+ err = cfe_iocb_dispatch(&iocb);
1348+
1349+ return (CFE_ISERR(err)) ? err : iocb.status;
1350+}
1351+
1352+int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
1353+{
1354+ struct cfe_iocb iocb;
1355+ int err;
1356+
1357+ memset(&iocb, 0, sizeof(iocb));
1358+ iocb.fcode = CFE_CMD_ENV_ENUM;
1359+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
1360+ iocb.envbuf.index = idx;
1361+ iocb.envbuf.name = PTR_TO_CFE(name);
1362+ iocb.envbuf.name_len = namelen;
1363+ iocb.envbuf.val = PTR_TO_CFE(val);
1364+ iocb.envbuf.val_len = vallen;
1365+
1366+ err = cfe_iocb_dispatch(&iocb);
1367+
1368+ return (CFE_ISERR(err)) ? err : iocb.status;
1369+}
1370+
1371+int cfe_enumdev(int idx, char *name, int namelen)
1372+{
1373+ struct cfe_iocb iocb;
1374+ int err;
1375+
1376+ memset(&iocb, 0, sizeof(iocb));
1377+
1378+ iocb.fcode = CFE_CMD_DEV_ENUM;
1379+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
1380+ iocb.envbuf.index = idx;
1381+ iocb.envbuf.name = PTR_TO_CFE(name);
1382+ iocb.envbuf.name_len = namelen;
1383+
1384+ err = cfe_iocb_dispatch(&iocb);
1385+
1386+ return (CFE_ISERR(err)) ? err : iocb.status;
1387+}
1388+
1389+int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
1390+ u64 *type)
1391+{
1392+ struct cfe_iocb iocb;
1393+ int err;
1394+
1395+ memset(&iocb, 0, sizeof(iocb));
1396+
1397+ iocb.fcode = CFE_CMD_FW_MEMENUM;
1398+ iocb.flags = flags;
1399+ iocb.psize = sizeof(struct cfe_iocb_meminfo);
1400+ iocb.meminfo.index = idx;
1401+
1402+ err = cfe_iocb_dispatch(&iocb);
1403+ if (CFE_ISERR(err))
1404+ return err;
1405+ if (!CFE_ISERR(iocb.status)) {
1406+ *start = iocb.meminfo.addr;
1407+ *length = iocb.meminfo.size;
1408+ *type = iocb.meminfo.type;
1409+ }
1410+
1411+ return iocb.status;
1412+}
1413+
1414+int cfe_exit(int warm, int status)
1415+{
1416+ struct cfe_iocb iocb;
1417+ int err;
1418+
1419+printk("CFE REBOOT\n");
1420+ memset(&iocb, 0, sizeof(iocb));
1421+ iocb.fcode = CFE_CMD_FW_RESTART;
1422+ if (warm)
1423+ iocb.flags = CFE_FLG_WARMSTART;
1424+ iocb.psize = sizeof(struct cfe_iocb_exitstat);
1425+ iocb.exitstat.status = status;
1426+
1427+printk("CALL\n");
1428+ err = cfe_iocb_dispatch(&iocb);
1429+printk("DONE\n");
1430+
1431+ return (CFE_ISERR(err)) ? err : iocb.status;
1432+}
1433+
1434+int cfe_flushcache(int flags)
1435+{
1436+ struct cfe_iocb iocb;
1437+ int err;
1438+
1439+ memset(&iocb, 0, sizeof(iocb));
1440+ iocb.fcode = CFE_CMD_FW_FLUSHCACHE;
1441+ iocb.flags = flags;
1442+
1443+ err = cfe_iocb_dispatch(&iocb);
1444+
1445+ return (CFE_ISERR(err)) ? err : iocb.status;
1446+}
1447+
1448+int cfe_getdevinfo(char *name)
1449+{
1450+ struct cfe_iocb iocb;
1451+ int err;
1452+
1453+ memset(&iocb, 0, sizeof(iocb));
1454+ iocb.fcode = CFE_CMD_DEV_GETINFO;
1455+ iocb.psize = sizeof(struct cfe_iocb_buf);
1456+ iocb.buffer.ptr = PTR_TO_CFE(name);
1457+ iocb.buffer.length = strlen(name);
1458+
1459+ err = cfe_iocb_dispatch(&iocb);
1460+ if (CFE_ISERR(err))
1461+ return err;
1462+ if (CFE_ISERR(iocb.status))
1463+ return iocb.status;
1464+
1465+ return iocb.buffer.devflags;
1466+}
1467+
1468+int cfe_getenv(char *name, char *dest, int destlen)
1469+{
1470+ struct cfe_iocb iocb;
1471+ int err;
1472+
1473+ dest[0] = '\0';
1474+ memset(&iocb, 0, sizeof(iocb));
1475+ iocb.fcode = CFE_CMD_ENV_GET;
1476+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
1477+ iocb.envbuf.name = PTR_TO_CFE(name);
1478+ iocb.envbuf.name_len = strlen(name);
1479+ iocb.envbuf.val = PTR_TO_CFE(dest);
1480+ iocb.envbuf.val_len = destlen;
1481+
1482+ err = cfe_iocb_dispatch(&iocb);
1483+
1484+ return (CFE_ISERR(err)) ? err : iocb.status;
1485+}
1486+
1487+int cfe_getfwinfo(struct cfe_fwinfo *info)
1488+{
1489+ struct cfe_iocb iocb;
1490+ int err;
1491+
1492+ memset(&iocb, 0, sizeof(iocb));
1493+ iocb.fcode = CFE_CMD_FW_GETINFO;
1494+ iocb.psize = sizeof(struct cfe_iocb_fwinfo);
1495+
1496+ err = cfe_iocb_dispatch(&iocb);
1497+ if (CFE_ISERR(err))
1498+ return err;
1499+ if (CFE_ISERR(iocb.status))
1500+ return err;
1501+
1502+ info->version = iocb.fwinfo.version;
1503+ info->totalmem = iocb.fwinfo.totalmem;
1504+ info->flags = iocb.fwinfo.flags;
1505+ info->boardid = iocb.fwinfo.boardid;
1506+ info->bootarea_va = iocb.fwinfo.bootarea_va;
1507+ info->bootarea_pa = iocb.fwinfo.bootarea_pa;
1508+ info->bootarea_size = iocb.fwinfo.bootarea_size;
1509+
1510+ return iocb.status;
1511+}
1512+
1513+int cfe_getstdhandle(int handletype)
1514+{
1515+ struct cfe_iocb iocb;
1516+ int err;
1517+
1518+ memset(&iocb, 0, sizeof(iocb));
1519+ iocb.fcode = CFE_CMD_DEV_GETHANDLE;
1520+ iocb.flags = handletype;
1521+
1522+ err = cfe_iocb_dispatch(&iocb);
1523+ if (CFE_ISERR(err))
1524+ return err;
1525+ if (CFE_ISERR(iocb.status))
1526+ return iocb.status;
1527+
1528+ return iocb.handle;
1529+}
1530+
1531+int cfe_getticks(s64 *ticks)
1532+{
1533+ struct cfe_iocb iocb;
1534+ int err;
1535+
1536+ memset(&iocb, 0, sizeof(iocb));
1537+ iocb.fcode = CFE_CMD_FW_GETTIME;
1538+ iocb.psize = sizeof(struct cfe_iocb_time);
1539+
1540+ err = cfe_iocb_dispatch(&iocb);
1541+ if (CFE_ISERR(err))
1542+ return err;
1543+ if (!CFE_ISERR(iocb.status))
1544+ *ticks = iocb.time.ticks;
1545+
1546+ return iocb.status;
1547+}
1548+
1549+int cfe_inpstat(int handle)
1550+{
1551+ struct cfe_iocb iocb;
1552+ int err;
1553+
1554+ memset(&iocb, 0, sizeof(iocb));
1555+ iocb.fcode = CFE_CMD_DEV_INPSTAT;
1556+ iocb.handle = handle;
1557+ iocb.psize = sizeof(struct cfe_iocb_inpstat);
1558+
1559+ err = cfe_iocb_dispatch(&iocb);
1560+ if (CFE_ISERR(err))
1561+ return err;
1562+ if (CFE_ISERR(iocb.status))
1563+ return iocb.status;
1564+
1565+ return iocb.inpstat.status;
1566+}
1567+
1568+int cfe_ioctl(int handle, unsigned int ioctlnum,
1569+ unsigned char *buffer, int length,
1570+ int *retlen, u64 offset)
1571+{
1572+ struct cfe_iocb iocb;
1573+ int err;
1574+
1575+ memset(&iocb, 0, sizeof(iocb));
1576+ iocb.fcode = CFE_CMD_DEV_IOCTL;
1577+ iocb.handle = handle;
1578+ iocb.psize = sizeof(struct cfe_iocb_buf);
1579+ iocb.buffer.offset = offset;
1580+ iocb.buffer.ioctlcmd = ioctlnum;
1581+ iocb.buffer.ptr = PTR_TO_CFE(buffer);
1582+ iocb.buffer.length = length;
1583+
1584+ err = cfe_iocb_dispatch(&iocb);
1585+ if (CFE_ISERR(err))
1586+ return err;
1587+ if (CFE_ISERR(iocb.status))
1588+ return iocb.status;
1589+ if (retlen)
1590+ *retlen = iocb.buffer.retlen;
1591+
1592+ return iocb.status;
1593+}
1594+
1595+int cfe_open(char *name)
1596+{
1597+ struct cfe_iocb iocb;
1598+ int err;
1599+
1600+ memset(&iocb, 0, sizeof(iocb));
1601+ iocb.fcode = CFE_CMD_DEV_OPEN;
1602+ iocb.psize = sizeof(struct cfe_iocb_buf);
1603+ iocb.buffer.ptr = PTR_TO_CFE(name);
1604+ iocb.buffer.length = strlen(name);
1605+
1606+ err = cfe_iocb_dispatch(&iocb);
1607+ if (CFE_ISERR(err))
1608+ return err;
1609+ if (CFE_ISERR(iocb.status))
1610+ return iocb.status;
1611+
1612+ return iocb.handle;
1613+}
1614+
1615+int cfe_read(int handle, unsigned char *buffer, int length)
1616+{
1617+ return cfe_readblk(handle, 0, buffer, length);
1618+}
1619+
1620+int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
1621+{
1622+ struct cfe_iocb iocb;
1623+ int err;
1624+
1625+ memset(&iocb, 0, sizeof(iocb));
1626+ iocb.fcode = CFE_CMD_DEV_READ;
1627+ iocb.handle = handle;
1628+ iocb.psize = sizeof(struct cfe_iocb_buf);
1629+ iocb.buffer.offset = offset;
1630+ iocb.buffer.ptr = PTR_TO_CFE(buffer);
1631+ iocb.buffer.length = length;
1632+
1633+ err = cfe_iocb_dispatch(&iocb);
1634+ if (CFE_ISERR(err))
1635+ return err;
1636+ if (CFE_ISERR(iocb.status))
1637+ return iocb.status;
1638+
1639+ return iocb.buffer.retlen;
1640+}
1641+
1642+int cfe_setenv(char *name, char *val)
1643+{
1644+ struct cfe_iocb iocb;
1645+ int err;
1646+
1647+ memset(&iocb, 0, sizeof(iocb));
1648+ iocb.fcode = CFE_CMD_ENV_SET;
1649+ iocb.psize = sizeof(struct cfe_iocb_envbuf);
1650+ iocb.envbuf.name = PTR_TO_CFE(name);
1651+ iocb.envbuf.name_len = strlen(name);
1652+ iocb.envbuf.val = PTR_TO_CFE(val);
1653+ iocb.envbuf.val_len = strlen(val);
1654+
1655+ err = cfe_iocb_dispatch(&iocb);
1656+
1657+ return (CFE_ISERR(err)) ? err : iocb.status;
1658+}
1659+
1660+int cfe_write(int handle, unsigned char *buffer, int length)
1661+{
1662+ return cfe_writeblk(handle, 0, buffer, length);
1663+}
1664+
1665+int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, int length)
1666+{
1667+ struct cfe_iocb iocb;
1668+ int err;
1669+
1670+ memset(&iocb, 0, sizeof(iocb));
1671+ iocb.fcode = CFE_CMD_DEV_WRITE;
1672+ iocb.handle = handle;
1673+ iocb.psize = sizeof(struct cfe_iocb_buf);
1674+ iocb.buffer.offset = offset;
1675+ iocb.buffer.ptr = PTR_TO_CFE(buffer);
1676+ iocb.buffer.length = length;
1677+
1678+ err = cfe_iocb_dispatch(&iocb);
1679+ if (CFE_ISERR(err))
1680+ return err;
1681+ if (CFE_ISERR(iocb.status))
1682+ return iocb.status;
1683+
1684+ return iocb.buffer.retlen;
1685+}
1686diff --git a/arch/mips/cfe/cfe_private.h b/arch/mips/cfe/cfe_private.h
1687new file mode 100644
1688index 0000000..0a604d3
1689--- /dev/null
1690+++ b/arch/mips/cfe/cfe_private.h
1691@@ -0,0 +1,176 @@
1692+/*
1693+ * Broadcom Common Firmware Environment (CFE) support
1694+ *
1695+ * Copyright 2000, 2001, 2002
1696+ * Broadcom Corporation. All rights reserved.
1697+ *
1698+ * Copyright (C) 2006 Michael Buesch
1699+ *
1700+ * Original Authors: Mitch Lichtenberg, Chris Demetriou
1701+ *
1702+ * This software is furnished under license and may be used and copied only
1703+ * in accordance with the following terms and conditions. Subject to these
1704+ * conditions, you may download, copy, install, use, modify and distribute
1705+ * modified or unmodified copies of this software in source and/or binary
1706+ * form. No title or ownership is transferred hereby.
1707+ *
1708+ * 1) Any source code used, modified or distributed must reproduce and
1709+ * retain this copyright notice and list of conditions as they appear in
1710+ * the source file.
1711+ *
1712+ * 2) No right is granted to use any trade name, trademark, or logo of
1713+ * Broadcom Corporation. The "Broadcom Corporation" name may not be
1714+ * used to endorse or promote products derived from this software
1715+ * without the prior written permission of Broadcom Corporation.
1716+ *
1717+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
1718+ * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
1719+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
1720+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
1721+ * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
1722+ * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1723+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1724+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
1725+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
1726+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
1727+ * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1728+ */
1729+
1730+#ifndef LINUX_CFE_PRIVATE_H_
1731+#define LINUX_CFE_PRIVATE_H_
1732+
1733+#ifndef __ASSEMBLY__
1734+
1735+/* Seal indicating CFE's presence, passed to the kernel. */
1736+#define CFE_EPTSEAL 0x43464531
1737+
1738+#define CFE_CMD_FW_GETINFO 0
1739+#define CFE_CMD_FW_RESTART 1
1740+#define CFE_CMD_FW_BOOT 2
1741+#define CFE_CMD_FW_CPUCTL 3
1742+#define CFE_CMD_FW_GETTIME 4
1743+#define CFE_CMD_FW_MEMENUM 5
1744+#define CFE_CMD_FW_FLUSHCACHE 6
1745+
1746+#define CFE_CMD_DEV_GETHANDLE 9
1747+#define CFE_CMD_DEV_ENUM 10
1748+#define CFE_CMD_DEV_OPEN 11
1749+#define CFE_CMD_DEV_INPSTAT 12
1750+#define CFE_CMD_DEV_READ 13
1751+#define CFE_CMD_DEV_WRITE 14
1752+#define CFE_CMD_DEV_IOCTL 15
1753+#define CFE_CMD_DEV_CLOSE 16
1754+#define CFE_CMD_DEV_GETINFO 17
1755+
1756+#define CFE_CMD_ENV_ENUM 20
1757+#define CFE_CMD_ENV_GET 22
1758+#define CFE_CMD_ENV_SET 23
1759+#define CFE_CMD_ENV_DEL 24
1760+
1761+#define CFE_CMD_MAX 32
1762+
1763+#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */
1764+
1765+typedef u64 cfe_uint_t;
1766+typedef s64 cfe_int_t;
1767+typedef s64 cfe_ptr_t;
1768+
1769+/* Cast a pointer from native to CFE-API pointer and back */
1770+#define CFE_TO_PTR(p) ((void *)(unsigned long)(p))
1771+#define PTR_TO_CFE(p) ((cfe_ptr_t)(unsigned long)(p))
1772+
1773+struct cfe_iocb_buf {
1774+ cfe_uint_t offset; /* offset on device (bytes) */
1775+ cfe_ptr_t ptr; /* pointer to a buffer */
1776+ cfe_uint_t length; /* length of this buffer */
1777+ cfe_uint_t retlen; /* returned length (for read ops) */
1778+ union {
1779+ cfe_uint_t ioctlcmd; /* IOCTL command (used only for IOCTLs) */
1780+ cfe_uint_t devflags; /* Returned device info flags */
1781+ };
1782+};
1783+
1784+struct cfe_iocb_inpstat {
1785+ cfe_uint_t status; /* 1 means input available */
1786+};
1787+
1788+struct cfe_iocb_envbuf {
1789+ cfe_int_t index; /* 0-based enumeration index */
1790+ cfe_ptr_t name; /* name string buffer */
1791+ cfe_int_t name_len; /* size of name buffer */
1792+ cfe_ptr_t val; /* value string buffer */
1793+ cfe_int_t val_len; /* size of value string buffer */
1794+};
1795+
1796+struct cfe_iocb_cpuctl {
1797+ cfe_uint_t number; /* cpu number to control */
1798+ cfe_uint_t command; /* command to issue to CPU */
1799+ cfe_uint_t start_addr; /* CPU start address */
1800+ cfe_uint_t gp; /* starting GP value */
1801+ cfe_uint_t sp; /* starting SP value */
1802+ cfe_uint_t a1; /* starting A1 value */
1803+};
1804+
1805+struct cfe_iocb_time {
1806+ cfe_int_t ticks; /* current time in ticks */
1807+};
1808+
1809+struct cfe_iocb_exitstat {
1810+ cfe_int_t status;
1811+};
1812+
1813+struct cfe_iocb_meminfo {
1814+ cfe_int_t index; /* 0-based enumeration index */
1815+ cfe_int_t type; /* type of memory block */
1816+ cfe_uint_t addr; /* physical start address */
1817+ cfe_uint_t size; /* block size */
1818+};
1819+
1820+struct cfe_iocb_fwinfo {
1821+ cfe_int_t version; /* major, minor, eco version */
1822+ cfe_int_t totalmem; /* total installed mem */
1823+ cfe_int_t flags; /* various flags */
1824+ cfe_int_t boardid; /* board ID */
1825+ cfe_int_t bootarea_va; /* VA of boot area */
1826+ cfe_int_t bootarea_pa; /* PA of boot area */
1827+ cfe_int_t bootarea_size; /* size of boot area */
1828+ cfe_int_t reserved1;
1829+ cfe_int_t reserved2;
1830+ cfe_int_t reserved3;
1831+};
1832+
1833+/* CFE I/O Control Block */
1834+struct cfe_iocb {
1835+ cfe_uint_t fcode; /* IOCB function code */
1836+ cfe_int_t status; /* return status */
1837+ cfe_int_t handle; /* file/device handle */
1838+ cfe_uint_t flags; /* flags for this IOCB */
1839+ cfe_uint_t psize; /* size of parameter list */
1840+ union {
1841+ struct cfe_iocb_buf buffer; /* buffer parameters */
1842+ struct cfe_iocb_inpstat inpstat; /* input status parameters */
1843+ struct cfe_iocb_envbuf envbuf; /* environment function parameters */
1844+ struct cfe_iocb_cpuctl cpuctl; /* CPU control parameters */
1845+ struct cfe_iocb_time time; /* timer parameters */
1846+ struct cfe_iocb_meminfo meminfo; /* memory arena info parameters */
1847+ struct cfe_iocb_fwinfo fwinfo; /* firmware information */
1848+ struct cfe_iocb_exitstat exitstat; /* Exit Status */
1849+ };
1850+};
1851+
1852+
1853+#include <linux/init.h>
1854+
1855+void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
1856+ unsigned long fwarg2, unsigned long fwarg3);
1857+
1858+#else /* __ASSEMBLY__ */
1859+
1860+ .macro cfe_early_init
1861+#ifdef CONFIG_CFE
1862+ jal cfe_setup
1863+#endif
1864+ .endm
1865+
1866+#endif /* __ASSEMBLY__ */
1867+#endif /* LINUX_CFE_PRIVATE_H_ */
1868diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
1869index 8485af3..fb5e5aa 100644
1870--- a/arch/mips/kernel/cpu-probe.c
1871+++ b/arch/mips/kernel/cpu-probe.c
1872@@ -723,6 +723,28 @@ static inline void cpu_probe_philips(str
1873 }
1874
1875
1876+static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
1877+{
1878+ decode_config1(c);
1879+ switch (c->processor_id & 0xff00) {
1880+ case PRID_IMP_BCM3302:
1881+ c->cputype = CPU_BCM3302;
1882+ c->isa_level = MIPS_CPU_ISA_M32R1;
1883+ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
1884+ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
1885+ break;
1886+ case PRID_IMP_BCM4710:
1887+ c->cputype = CPU_BCM4710;
1888+ c->isa_level = MIPS_CPU_ISA_M32R1;
1889+ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
1890+ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
1891+ break;
1892+ default:
1893+ c->cputype = CPU_UNKNOWN;
1894+ break;
1895+ }
1896+}
1897+
1898 __init void cpu_probe(void)
1899 {
1900 struct cpuinfo_mips *c = &current_cpu_data;
1901@@ -745,6 +767,9 @@ __init void cpu_probe(void)
1902 case PRID_COMP_SIBYTE:
1903 cpu_probe_sibyte(c);
1904 break;
1905+ case PRID_COMP_BROADCOM:
1906+ cpu_probe_broadcom(c);
1907+ break;
1908 case PRID_COMP_SANDCRAFT:
1909 cpu_probe_sandcraft(c);
1910 break;
1911diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
1912index ddc1b71..252db66 100644
1913--- a/arch/mips/kernel/head.S
1914+++ b/arch/mips/kernel/head.S
1915@@ -129,6 +129,9 @@
1916 #endif
1917 .endm
1918
1919+ j kernel_entry
1920+ nop
1921+
1922 /*
1923 * Reserved space for exception handlers.
1924 * Necessary for machines which link their kernels at KSEG0.
1925diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
1926index 4ed37ba..2acfa19 100644
1927--- a/arch/mips/kernel/proc.c
1928+++ b/arch/mips/kernel/proc.c
1929@@ -83,6 +83,8 @@ static const char *cpu_name[] = {
1930 [CPU_VR4181] = "NEC VR4181",
1931 [CPU_VR4181A] = "NEC VR4181A",
1932 [CPU_SR71000] = "Sandcraft SR71000",
1933+ [CPU_BCM3302] = "Broadcom BCM3302",
1934+ [CPU_BCM4710] = "Broadcom BCM4710",
1935 [CPU_PR4450] = "Philips PR4450",
1936 };
1937
1938diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
1939index fec318a..3045432 100644
1940--- a/arch/mips/mm/tlbex.c
1941+++ b/arch/mips/mm/tlbex.c
1942@@ -880,6 +880,8 @@ static __init void build_tlb_write_entry
1943 case CPU_4KSC:
1944 case CPU_20KC:
1945 case CPU_25KF:
1946+ case CPU_BCM3302:
1947+ case CPU_BCM4710:
1948 tlbw(p);
1949 break;
1950
1951diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
1952index 702ae4c..35cd1c8 100644
1953--- a/drivers/mtd/chips/cfi_cmdset_0002.c
1954+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
1955@@ -296,9 +296,6 @@ struct mtd_info *cfi_cmdset_0002(struct
1956 printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
1957 "version %c.%c.\n", extp->MajorVersion,
1958 extp->MinorVersion);
1959- kfree(extp);
1960- kfree(mtd);
1961- return NULL;
1962 }
1963
1964 /* Install our own private info structure */
1965diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
1966index 24747bd..fec2769 100644
1967--- a/drivers/mtd/maps/Kconfig
1968+++ b/drivers/mtd/maps/Kconfig
1969@@ -299,6 +299,12 @@ config MTD_CFI_FLAGADM
1970 Mapping for the Flaga digital module. If you don't have one, ignore
1971 this setting.
1972
1973+config MTD_BCM47XX
1974+ tristate "BCM47xx flash device"
1975+ depends on MIPS && MTD_CFI && BCM947XX
1976+ help
1977+ Support for the flash chips on the BCM947xx board.
1978+
1979 config MTD_BEECH
1980 tristate "CFI Flash device mapped on IBM 405LP Beech"
1981 depends on MTD_CFI && BEECH
1982diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
1983index 191c192..5881584 100644
1984--- a/drivers/mtd/maps/Makefile
1985+++ b/drivers/mtd/maps/Makefile
1986@@ -29,6 +29,7 @@ obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
1987 obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
1988 obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
1989 obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
1990+obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o
1991 obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
1992 obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
1993 obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
1994diff --git a/drivers/mtd/maps/bcm47xx-flash.c b/drivers/mtd/maps/bcm47xx-flash.c
1995new file mode 100644
1996index 0000000..334432d
1997--- /dev/null
1998+++ b/drivers/mtd/maps/bcm47xx-flash.c
1999@@ -0,0 +1,477 @@
2000+/*
2001+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
2002+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
2003+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
2004+ *
2005+ * original functions for finding root filesystem from Mike Baker
2006+ *
2007+ * This program is free software; you can redistribute it and/or modify it
2008+ * under the terms of the GNU General Public License as published by the
2009+ * Free Software Foundation; either version 2 of the License, or (at your
2010+ * option) any later version.
2011+ *
2012+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
2013+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2014+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
2015+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2016+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2017+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2018+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2019+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2020+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2021+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2022+ *
2023+ * You should have received a copy of the GNU General Public License along
2024+ * with this program; if not, write to the Free Software Foundation, Inc.,
2025+ * 675 Mass Ave, Cambridge, MA 02139, USA.
2026+ *
2027+ * Copyright 2001-2003, Broadcom Corporation
2028+ * All Rights Reserved.
2029+ *
2030+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
2031+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
2032+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
2033+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
2034+ *
2035+ * Flash mapping for BCM947XX boards
2036+ */
2037+
2038+#include <linux/init.h>
2039+#include <linux/module.h>
2040+#include <linux/types.h>
2041+#include <linux/kernel.h>
2042+#include <linux/wait.h>
2043+#include <linux/mtd/mtd.h>
2044+#include <linux/mtd/map.h>
2045+#ifdef CONFIG_MTD_PARTITIONS
2046+#include <linux/mtd/partitions.h>
2047+#endif
2048+#ifdef CONFIG_SQUASHFS
2049+#include <linux/squashfs_fs.h>
2050+#endif
2051+#include <linux/jffs2.h>
2052+#include <linux/crc32.h>
2053+#include <linux/ssb.h>
2054+#include <asm/io.h>
2055+
2056+
2057+#define TRX_MAGIC 0x30524448 /* "HDR0" */
2058+#define TRX_VERSION 1
2059+#define TRX_MAX_LEN 0x3A0000
2060+#define TRX_NO_HEADER 1 /* Do not write TRX header */
2061+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
2062+#define TRX_MAX_OFFSET 3
2063+
2064+struct trx_header {
2065+ u32 magic; /* "HDR0" */
2066+ u32 len; /* Length of file including header */
2067+ u32 crc32; /* 32-bit CRC from flag_version to end of file */
2068+ u32 flag_version; /* 0:15 flags, 16:31 version */
2069+ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
2070+};
2071+
2072+#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
2073+#define NVRAM_SPACE 0x8000
2074+#define WINDOW_ADDR 0x1fc00000
2075+#define WINDOW_SIZE 0x400000
2076+#define BUSWIDTH 2
2077+
2078+extern struct ssb_bus ssb;
2079+static struct mtd_info *bcm947xx_mtd;
2080+
2081+static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
2082+{
2083+#define MIPS_MEMCPY_ALIGN 4
2084+ map_word ret;
2085+ ssize_t transfer;
2086+ ssize_t done = 0;
2087+ if ((len >= MIPS_MEMCPY_ALIGN) && (!(from & (MIPS_MEMCPY_ALIGN - 1))) && (!(((unsigned int)to & (MIPS_MEMCPY_ALIGN - 1))))) {
2088+ done = len & ~(MIPS_MEMCPY_ALIGN - 1);
2089+ memcpy_fromio(to, map->virt + from, done);
2090+ }
2091+ while (done < len) {
2092+ ret = map->read(map, from + done);
2093+ transfer = len - done;
2094+ if (transfer > map->bankwidth)
2095+ transfer = map->bankwidth;
2096+ memcpy((void *)((unsigned long)to + done), &ret.x[0], transfer);
2097+ done += transfer;
2098+ }
2099+}
2100+
2101+static struct map_info bcm947xx_map = {
2102+ name: "Physically mapped flash",
2103+ size: WINDOW_SIZE,
2104+ bankwidth: BUSWIDTH,
2105+ phys: WINDOW_ADDR,
2106+};
2107+
2108+#ifdef CONFIG_MTD_PARTITIONS
2109+
2110+static struct mtd_partition bcm947xx_parts[] = {
2111+ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
2112+ { name: "linux", offset: 0, size: 0, },
2113+ { name: "rootfs", offset: 0, size: 0, },
2114+ { name: "nvram", offset: 0, size: 0, },
2115+ { name: "OpenWrt", offset: 0, size: 0, },
2116+ { name: NULL, },
2117+};
2118+
2119+static int __init
2120+find_cfe_size(struct mtd_info *mtd, size_t size)
2121+{
2122+ struct trx_header *trx;
2123+ unsigned char buf[512];
2124+ int off;
2125+ size_t len;
2126+ int blocksize;
2127+
2128+ trx = (struct trx_header *) buf;
2129+
2130+ blocksize = mtd->erasesize;
2131+ if (blocksize < 0x10000)
2132+ blocksize = 0x10000;
2133+
2134+ for (off = (128*1024); off < size; off += blocksize) {
2135+ memset(buf, 0xe5, sizeof(buf));
2136+
2137+ /*
2138+ * Read into buffer
2139+ */
2140+ if (mtd->read(mtd, off, sizeof(buf), &len, buf) ||
2141+ len != sizeof(buf))
2142+ continue;
2143+
2144+ /* found a TRX header */
2145+ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
2146+ goto found;
2147+ }
2148+ }
2149+
2150+ printk(KERN_NOTICE
2151+ "%s: Couldn't find bootloader size\n",
2152+ mtd->name);
2153+ return -1;
2154+
2155+ found:
2156+ printk(KERN_NOTICE "bootloader size: %d\n", off);
2157+ return off;
2158+
2159+}
2160+
2161+/*
2162+ * Copied from mtdblock.c
2163+ *
2164+ * Cache stuff...
2165+ *
2166+ * Since typical flash erasable sectors are much larger than what Linux's
2167+ * buffer cache can handle, we must implement read-modify-write on flash
2168+ * sectors for each block write requests. To avoid over-erasing flash sectors
2169+ * and to speed things up, we locally cache a whole flash sector while it is
2170+ * being written to until a different sector is required.
2171+ */
2172+
2173+static void erase_callback(struct erase_info *done)
2174+{
2175+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
2176+ wake_up(wait_q);
2177+}
2178+
2179+static int erase_write (struct mtd_info *mtd, unsigned long pos,
2180+ int len, const char *buf)
2181+{
2182+ struct erase_info erase;
2183+ DECLARE_WAITQUEUE(wait, current);
2184+ wait_queue_head_t wait_q;
2185+ size_t retlen;
2186+ int ret;
2187+
2188+ /*
2189+ * First, let's erase the flash block.
2190+ */
2191+
2192+ init_waitqueue_head(&wait_q);
2193+ erase.mtd = mtd;
2194+ erase.callback = erase_callback;
2195+ erase.addr = pos;
2196+ erase.len = len;
2197+ erase.priv = (u_long)&wait_q;
2198+
2199+ set_current_state(TASK_INTERRUPTIBLE);
2200+ add_wait_queue(&wait_q, &wait);
2201+
2202+ ret = mtd->erase(mtd, &erase);
2203+ if (ret) {
2204+ set_current_state(TASK_RUNNING);
2205+ remove_wait_queue(&wait_q, &wait);
2206+ printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
2207+ "on \"%s\" failed\n",
2208+ pos, len, mtd->name);
2209+ return ret;
2210+ }
2211+
2212+ schedule(); /* Wait for erase to finish. */
2213+ remove_wait_queue(&wait_q, &wait);
2214+
2215+ /*
2216+ * Next, writhe data to flash.
2217+ */
2218+
2219+ ret = mtd->write (mtd, pos, len, &retlen, buf);
2220+ if (ret)
2221+ return ret;
2222+ if (retlen != len)
2223+ return -EIO;
2224+ return 0;
2225+}
2226+
2227+
2228+
2229+
2230+static int __init
2231+find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
2232+{
2233+ struct trx_header trx, *trx2;
2234+ unsigned char buf[512], *block;
2235+ int off, blocksize;
2236+ u32 i, crc = ~0;
2237+ size_t len;
2238+#ifdef CONFIG_SQUASHFS
2239+ struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
2240+#endif
2241+
2242+ blocksize = mtd->erasesize;
2243+ if (blocksize < 0x10000)
2244+ blocksize = 0x10000;
2245+
2246+ for (off = (128*1024); off < size; off += blocksize) {
2247+ memset(&trx, 0xe5, sizeof(trx));
2248+
2249+ /*
2250+ * Read into buffer
2251+ */
2252+ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
2253+ len != sizeof(trx))
2254+ continue;
2255+
2256+ /* found a TRX header */
2257+ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
2258+ part->offset = le32_to_cpu(trx.offsets[2]) ? :
2259+ le32_to_cpu(trx.offsets[1]);
2260+ part->size = le32_to_cpu(trx.len);
2261+
2262+ part->size -= part->offset;
2263+ part->offset += off;
2264+
2265+ goto found;
2266+ }
2267+ }
2268+
2269+ printk(KERN_NOTICE
2270+ "%s: Couldn't find root filesystem\n",
2271+ mtd->name);
2272+ return -1;
2273+
2274+ found:
2275+ if (part->size == 0)
2276+ return 0;
2277+
2278+ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
2279+ return 0;
2280+#ifdef CONFIG_SQUASHFS
2281+ if (*((__u32 *) buf) == SQUASHFS_MAGIC) {
2282+ printk(KERN_INFO "%s: Filesystem type: squashfs, size=0x%x\n", mtd->name, (u32) sb->bytes_used);
2283+
2284+ /* Update the squashfs partition size based on the superblock info */
2285+ part->size = sb->bytes_used;
2286+ len = part->offset + part->size;
2287+ len += (mtd->erasesize - 1);
2288+ len &= ~(mtd->erasesize - 1);
2289+ part->size = len - part->offset;
2290+ } else
2291+#endif
2292+ if (*((__u16 *) buf) == JFFS2_MAGIC_BITMASK) {
2293+ printk(KERN_INFO "%s: Filesystem type: jffs2\n", mtd->name);
2294+
2295+ /* Move the squashfs outside of the trx */
2296+ part->size = 0;
2297+ } else {
2298+ printk(KERN_INFO "%s: Filesystem type: unknown\n", mtd->name);
2299+ return 0;
2300+ }
2301+
2302+ if (trx.len != part->offset + part->size - off) {
2303+ /* Update the trx offsets and length */
2304+ trx.len = part->offset + part->size - off;
2305+
2306+ /* Update the trx crc32 */
2307+ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
2308+ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
2309+ return 0;
2310+ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
2311+ }
2312+ trx.crc32 = crc;
2313+
2314+ /* read first eraseblock from the trx */
2315+ block = kmalloc(mtd->erasesize, GFP_KERNEL);
2316+ trx2 = (struct trx_header *) block;
2317+ if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) {
2318+ printk("Error accessing the first trx eraseblock\n");
2319+ return 0;
2320+ }
2321+
2322+ printk("Updating TRX offsets and length:\n");
2323+ printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
2324+ printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
2325+
2326+ /* Write updated trx header to the flash */
2327+ memcpy(block, &trx, sizeof(trx));
2328+ if (mtd->unlock)
2329+ mtd->unlock(mtd, off, mtd->erasesize);
2330+ erase_write(mtd, off, mtd->erasesize, block);
2331+ if (mtd->sync)
2332+ mtd->sync(mtd);
2333+ kfree(block);
2334+ printk("Done\n");
2335+ }
2336+
2337+ return part->size;
2338+}
2339+
2340+struct mtd_partition * __init
2341+init_mtd_partitions(struct mtd_info *mtd, size_t size)
2342+{
2343+ int cfe_size;
2344+
2345+ if ((cfe_size = find_cfe_size(mtd,size)) < 0)
2346+ return NULL;
2347+
2348+ /* boot loader */
2349+ bcm947xx_parts[0].offset = 0;
2350+ bcm947xx_parts[0].size = cfe_size;
2351+
2352+ /* nvram */
2353+ if (cfe_size != 384 * 1024) {
2354+ bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
2355+ bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
2356+ } else {
2357+ /* nvram (old 128kb config partition on netgear wgt634u) */
2358+ bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
2359+ bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
2360+ }
2361+
2362+ /* linux (kernel and rootfs) */
2363+ if (cfe_size != 384 * 1024) {
2364+ bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
2365+ bcm947xx_parts[1].size = bcm947xx_parts[3].offset -
2366+ bcm947xx_parts[1].offset;
2367+ } else {
2368+ /* do not count the elf loader, which is on one block */
2369+ bcm947xx_parts[1].offset = bcm947xx_parts[0].size +
2370+ bcm947xx_parts[3].size + mtd->erasesize;
2371+ bcm947xx_parts[1].size = size -
2372+ bcm947xx_parts[0].size -
2373+ (2*bcm947xx_parts[3].size) -
2374+ mtd->erasesize;
2375+ }
2376+
2377+ /* find and size rootfs */
2378+ if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
2379+ /* entirely jffs2 */
2380+ bcm947xx_parts[4].name = NULL;
2381+ bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset -
2382+ bcm947xx_parts[3].size;
2383+ } else {
2384+ /* legacy setup */
2385+ /* calculate leftover flash, and assign it to the jffs2 partition */
2386+ if (cfe_size != 384 * 1024) {
2387+ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
2388+ bcm947xx_parts[2].size;
2389+ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
2390+ bcm947xx_parts[4].offset += mtd->erasesize -
2391+ (bcm947xx_parts[4].offset % mtd->erasesize);
2392+ }
2393+ bcm947xx_parts[4].size = bcm947xx_parts[3].offset -
2394+ bcm947xx_parts[4].offset;
2395+ } else {
2396+ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
2397+ bcm947xx_parts[2].size;
2398+ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
2399+ bcm947xx_parts[4].offset += mtd->erasesize -
2400+ (bcm947xx_parts[4].offset % mtd->erasesize);
2401+ }
2402+ bcm947xx_parts[4].size = size - bcm947xx_parts[3].size -
2403+ bcm947xx_parts[4].offset;
2404+ }
2405+ }
2406+
2407+ return bcm947xx_parts;
2408+}
2409+#endif
2410+
2411+int __init init_bcm947xx_map(void)
2412+{
2413+ struct ssb_mipscore *mcore = &ssb.mipscore;
2414+ size_t size;
2415+ int ret = 0;
2416+#ifdef CONFIG_MTD_PARTITIONS
2417+ struct mtd_partition *parts;
2418+ int i;
2419+#endif
2420+ u32 window = mcore->flash_window;
2421+ u32 window_size = mcore->flash_window_size;
2422+
2423+ printk("flash init: 0x%08x 0x%08x\n", window, window_size);
2424+ bcm947xx_map.virt = ioremap(window, window_size);
2425+
2426+ if (!bcm947xx_map.virt) {
2427+ printk("Failed to ioremap\n");
2428+ return -EIO;
2429+ }
2430+ simple_map_init(&bcm947xx_map);
2431+
2432+ bcm947xx_map.copy_from = bcm947xx_map_copy_from;
2433+
2434+ if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
2435+ printk("Failed to do_map_probe\n");
2436+ iounmap((void *)bcm947xx_map.virt);
2437+ return -ENXIO;
2438+ }
2439+
2440+ bcm947xx_mtd->owner = THIS_MODULE;
2441+
2442+ size = bcm947xx_mtd->size;
2443+
2444+ printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
2445+
2446+#ifdef CONFIG_MTD_PARTITIONS
2447+ parts = init_mtd_partitions(bcm947xx_mtd, size);
2448+ for (i = 0; parts[i].name; i++);
2449+ ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
2450+ if (ret) {
2451+ printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
2452+ goto fail;
2453+ }
2454+#endif
2455+ return 0;
2456+
2457+ fail:
2458+ if (bcm947xx_mtd)
2459+ map_destroy(bcm947xx_mtd);
2460+ if (bcm947xx_map.virt)
2461+ iounmap((void *)bcm947xx_map.virt);
2462+ bcm947xx_map.virt = 0;
2463+ return ret;
2464+}
2465+
2466+void __exit cleanup_bcm947xx_map(void)
2467+{
2468+#ifdef CONFIG_MTD_PARTITIONS
2469+ del_mtd_partitions(bcm947xx_mtd);
2470+#endif
2471+ map_destroy(bcm947xx_mtd);
2472+ iounmap((void *)bcm947xx_map.virt);
2473+}
2474+
2475+module_init(init_bcm947xx_map);
2476+module_exit(cleanup_bcm947xx_map);
2477diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
2478index 6e863aa..a09a8e4 100644
2479--- a/drivers/net/Kconfig
2480+++ b/drivers/net/Kconfig
2481@@ -1402,7 +1402,7 @@ config APRICOT
2482
2483 config B44
2484 tristate "Broadcom 4400 ethernet support"
2485- depends on NET_PCI && PCI
2486+ depends on SSB && EXPERIMENTAL
2487 select MII
2488 help
2489 If you have a network (Ethernet) controller of this type, say Y and
2490diff --git a/drivers/net/b44.c b/drivers/net/b44.c
2491index 474a4e3..eb29c71 100644
2492--- a/drivers/net/b44.c
2493+++ b/drivers/net/b44.c
2494@@ -1,7 +1,9 @@
2495-/* b44.c: Broadcom 4400 device driver.
2496+/* b44.c: Broadcom 4400/47xx device driver.
2497 *
2498 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
2499- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
2500+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
2501+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
2502+ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
2503 * Copyright (C) 2006 Broadcom Corporation.
2504 *
2505 * Distribute under GPL.
2506@@ -20,11 +22,13 @@
2507 #include <linux/delay.h>
2508 #include <linux/init.h>
2509 #include <linux/dma-mapping.h>
2510+#include <linux/ssb.h>
2511
2512 #include <asm/uaccess.h>
2513 #include <asm/io.h>
2514 #include <asm/irq.h>
2515
2516+
2517 #include "b44.h"
2518
2519 #define DRV_MODULE_NAME "b44"
2520@@ -87,8 +91,8 @@
2521 static char version[] __devinitdata =
2522 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
2523
2524-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
2525-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
2526+MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
2527+MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
2528 MODULE_LICENSE("GPL");
2529 MODULE_VERSION(DRV_MODULE_VERSION);
2530
2531@@ -96,24 +100,18 @@ static int b44_debug = -1; /* -1 == use
2532 module_param(b44_debug, int, 0);
2533 MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
2534
2535-static struct pci_device_id b44_pci_tbl[] = {
2536- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
2537- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
2538- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0,
2539- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
2540- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
2541- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
2542- { } /* terminate list with empty entry */
2543+static struct ssb_device_id b44_ssb_tbl[] = {
2544+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
2545+ SSB_DEVTABLE_END
2546 };
2547
2548-MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
2549-
2550 static void b44_halt(struct b44 *);
2551 static void b44_init_rings(struct b44 *);
2552 static void b44_init_hw(struct b44 *, int);
2553
2554 static int dma_desc_align_mask;
2555 static int dma_desc_sync_size;
2556+static int instance;
2557
2558 static const char b44_gstrings[][ETH_GSTRING_LEN] = {
2559 #define _B44(x...) # x,
2560@@ -121,35 +119,24 @@ B44_STAT_REG_DECLARE
2561 #undef _B44
2562 };
2563
2564-static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
2565- dma_addr_t dma_base,
2566- unsigned long offset,
2567- enum dma_data_direction dir)
2568-{
2569- dma_sync_single_range_for_device(&pdev->dev, dma_base,
2570- offset & dma_desc_align_mask,
2571- dma_desc_sync_size, dir);
2572-}
2573-
2574-static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
2575- dma_addr_t dma_base,
2576- unsigned long offset,
2577- enum dma_data_direction dir)
2578-{
2579- dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
2580- offset & dma_desc_align_mask,
2581- dma_desc_sync_size, dir);
2582-}
2583-
2584-static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
2585+static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
2586+ dma_addr_t dma_base,
2587+ unsigned long offset,
2588+ enum dma_data_direction dir)
2589 {
2590- return readl(bp->regs + reg);
2591+ dma_sync_single_range_for_device(&sdev->dev, dma_base,
2592+ offset & dma_desc_align_mask,
2593+ dma_desc_sync_size, dir);
2594 }
2595
2596-static inline void bw32(const struct b44 *bp,
2597- unsigned long reg, unsigned long val)
2598+static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
2599+ dma_addr_t dma_base,
2600+ unsigned long offset,
2601+ enum dma_data_direction dir)
2602 {
2603- writel(val, bp->regs + reg);
2604+ dma_sync_single_range_for_cpu(&sdev->dev, dma_base,
2605+ offset & dma_desc_align_mask,
2606+ dma_desc_sync_size, dir);
2607 }
2608
2609 static int b44_wait_bit(struct b44 *bp, unsigned long reg,
2610@@ -177,117 +164,29 @@ static int b44_wait_bit(struct b44 *bp,
2611 return 0;
2612 }
2613
2614-/* Sonics SiliconBackplane support routines. ROFL, you should see all the
2615- * buzz words used on this company's website :-)
2616- *
2617- * All of these routines must be invoked with bp->lock held and
2618- * interrupts disabled.
2619- */
2620-
2621-#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
2622-#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */
2623-
2624-static u32 ssb_get_core_rev(struct b44 *bp)
2625-{
2626- return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
2627-}
2628-
2629-static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
2630-{
2631- u32 bar_orig, pci_rev, val;
2632-
2633- pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
2634- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
2635- pci_rev = ssb_get_core_rev(bp);
2636-
2637- val = br32(bp, B44_SBINTVEC);
2638- val |= cores;
2639- bw32(bp, B44_SBINTVEC, val);
2640-
2641- val = br32(bp, SSB_PCI_TRANS_2);
2642- val |= SSB_PCI_PREF | SSB_PCI_BURST;
2643- bw32(bp, SSB_PCI_TRANS_2, val);
2644-
2645- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
2646-
2647- return pci_rev;
2648-}
2649-
2650-static void ssb_core_disable(struct b44 *bp)
2651-{
2652- if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
2653- return;
2654-
2655- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
2656- b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
2657- b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
2658- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
2659- SBTMSLOW_REJECT | SBTMSLOW_RESET));
2660- br32(bp, B44_SBTMSLOW);
2661- udelay(1);
2662- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
2663- br32(bp, B44_SBTMSLOW);
2664- udelay(1);
2665-}
2666-
2667-static void ssb_core_reset(struct b44 *bp)
2668+static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
2669 {
2670 u32 val;
2671
2672- ssb_core_disable(bp);
2673- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
2674- br32(bp, B44_SBTMSLOW);
2675- udelay(1);
2676-
2677- /* Clear SERR if set, this is a hw bug workaround. */
2678- if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
2679- bw32(bp, B44_SBTMSHIGH, 0);
2680-
2681- val = br32(bp, B44_SBIMSTATE);
2682- if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
2683- bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
2684-
2685- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
2686- br32(bp, B44_SBTMSLOW);
2687- udelay(1);
2688-
2689- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
2690- br32(bp, B44_SBTMSLOW);
2691- udelay(1);
2692-}
2693+ bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
2694+ (index << CAM_CTRL_INDEX_SHIFT)));
2695
2696-static int ssb_core_unit(struct b44 *bp)
2697-{
2698-#if 0
2699- u32 val = br32(bp, B44_SBADMATCH0);
2700- u32 base;
2701+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
2702
2703- type = val & SBADMATCH0_TYPE_MASK;
2704- switch (type) {
2705- case 0:
2706- base = val & SBADMATCH0_BS0_MASK;
2707- break;
2708+ val = br32(bp, B44_CAM_DATA_LO);
2709
2710- case 1:
2711- base = val & SBADMATCH0_BS1_MASK;
2712- break;
2713+ data[2] = (val >> 24) & 0xFF;
2714+ data[3] = (val >> 16) & 0xFF;
2715+ data[4] = (val >> 8) & 0xFF;
2716+ data[5] = (val >> 0) & 0xFF;
2717
2718- case 2:
2719- default:
2720- base = val & SBADMATCH0_BS2_MASK;
2721- break;
2722- };
2723-#endif
2724- return 0;
2725-}
2726+ val = br32(bp, B44_CAM_DATA_HI);
2727
2728-static int ssb_is_core_up(struct b44 *bp)
2729-{
2730- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
2731- == SBTMSLOW_CLOCK);
2732+ data[0] = (val >> 8) & 0xFF;
2733+ data[1] = (val >> 0) & 0xFF;
2734 }
2735
2736-static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
2737+static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
2738 {
2739 u32 val;
2740
2741@@ -323,14 +222,14 @@ static void b44_enable_ints(struct b44 *
2742 bw32(bp, B44_IMASK, bp->imask);
2743 }
2744
2745-static int b44_readphy(struct b44 *bp, int reg, u32 *val)
2746+static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
2747 {
2748 int err;
2749
2750 bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
2751 bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
2752 (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
2753- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
2754+ (phy_addr << MDIO_DATA_PMD_SHIFT) |
2755 (reg << MDIO_DATA_RA_SHIFT) |
2756 (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
2757 err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
2758@@ -339,18 +238,34 @@ static int b44_readphy(struct b44 *bp, i
2759 return err;
2760 }
2761
2762-static int b44_writephy(struct b44 *bp, int reg, u32 val)
2763+static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
2764 {
2765 bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
2766 bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
2767 (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
2768- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
2769+ (phy_addr << MDIO_DATA_PMD_SHIFT) |
2770 (reg << MDIO_DATA_RA_SHIFT) |
2771 (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
2772 (val & MDIO_DATA_DATA)));
2773 return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
2774 }
2775
2776+static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
2777+{
2778+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
2779+ return 0;
2780+
2781+ return __b44_readphy(bp, bp->phy_addr, reg, val);
2782+}
2783+
2784+static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
2785+{
2786+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
2787+ return 0;
2788+
2789+ return __b44_writephy(bp, bp->phy_addr, reg, val);
2790+}
2791+
2792 /* miilib interface */
2793 /* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
2794 * due to code existing before miilib use was added to this driver.
2795@@ -379,6 +294,8 @@ static int b44_phy_reset(struct b44 *bp)
2796 u32 val;
2797 int err;
2798
2799+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
2800+ return 0;
2801 err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
2802 if (err)
2803 return err;
2804@@ -437,11 +354,27 @@ static void b44_set_flow_ctrl(struct b44
2805 __b44_set_flow_ctrl(bp, pause_enab);
2806 }
2807
2808+
2809+extern char *nvram_get(char *name); //FIXME: move elsewhere
2810 static int b44_setup_phy(struct b44 *bp)
2811 {
2812 u32 val;
2813 int err;
2814
2815+ /*
2816+ * workaround for bad hardware design in Linksys WAP54G v1.0
2817+ * see https://dev.openwrt.org/ticket/146
2818+ * check and reset bit "isolate"
2819+ */
2820+ if ((atoi(nvram_get("boardnum")) == 2) &&
2821+ (__b44_readphy(bp, 0, MII_BMCR, &val) == 0) &&
2822+ (val & BMCR_ISOLATE) &&
2823+ (__b44_writephy(bp, 0, MII_BMCR, val & ~BMCR_ISOLATE) != 0)) {
2824+ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
2825+ }
2826+
2827+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
2828+ return 0;
2829 if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
2830 goto out;
2831 if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
2832@@ -537,6 +470,19 @@ static void b44_check_phy(struct b44 *bp
2833 {
2834 u32 bmsr, aux;
2835
2836+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
2837+ bp->flags |= B44_FLAG_100_BASE_T;
2838+ bp->flags |= B44_FLAG_FULL_DUPLEX;
2839+ if (!netif_carrier_ok(bp->dev)) {
2840+ u32 val = br32(bp, B44_TX_CTRL);
2841+ val |= TX_CTRL_DUPLEX;
2842+ bw32(bp, B44_TX_CTRL, val);
2843+ netif_carrier_on(bp->dev);
2844+ b44_link_report(bp);
2845+ }
2846+ return;
2847+ }
2848+
2849 if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
2850 !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
2851 (bmsr != 0xffff)) {
2852@@ -613,10 +559,10 @@ static void b44_tx(struct b44 *bp)
2853
2854 BUG_ON(skb == NULL);
2855
2856- pci_unmap_single(bp->pdev,
2857+ dma_unmap_single(&bp->sdev->dev,
2858 pci_unmap_addr(rp, mapping),
2859 skb->len,
2860- PCI_DMA_TODEVICE);
2861+ DMA_TO_DEVICE);
2862 rp->skb = NULL;
2863 dev_kfree_skb_irq(skb);
2864 }
2865@@ -652,10 +598,10 @@ static int b44_alloc_rx_skb(struct b44 *
2866 skb = dev_alloc_skb(RX_PKT_BUF_SZ);
2867 if (skb == NULL)
2868 return -ENOMEM;
2869-
2870- mapping = pci_map_single(bp->pdev, skb->data,
2871+
2872+ mapping = dma_map_single(&bp->sdev->dev, skb->data,
2873 RX_PKT_BUF_SZ,
2874- PCI_DMA_FROMDEVICE);
2875+ DMA_FROM_DEVICE);
2876
2877 /* Hardware bug work-around, the chip is unable to do PCI DMA
2878 to/from anything above 1GB :-( */
2879@@ -663,18 +609,18 @@ static int b44_alloc_rx_skb(struct b44 *
2880 mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
2881 /* Sigh... */
2882 if (!dma_mapping_error(mapping))
2883- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
2884+ dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
2885 dev_kfree_skb_any(skb);
2886 skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA);
2887 if (skb == NULL)
2888 return -ENOMEM;
2889- mapping = pci_map_single(bp->pdev, skb->data,
2890+ mapping = dma_map_single(&bp->sdev->dev, skb->data,
2891 RX_PKT_BUF_SZ,
2892- PCI_DMA_FROMDEVICE);
2893+ DMA_FROM_DEVICE);
2894 if (dma_mapping_error(mapping) ||
2895 mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
2896 if (!dma_mapping_error(mapping))
2897- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
2898+ dma_unmap_single(&bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
2899 dev_kfree_skb_any(skb);
2900 return -ENOMEM;
2901 }
2902@@ -703,9 +649,9 @@ static int b44_alloc_rx_skb(struct b44 *
2903 dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
2904
2905 if (bp->flags & B44_FLAG_RX_RING_HACK)
2906- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
2907- dest_idx * sizeof(dp),
2908- DMA_BIDIRECTIONAL);
2909+ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
2910+ dest_idx * sizeof(dp),
2911+ DMA_BIDIRECTIONAL);
2912
2913 return RX_PKT_BUF_SZ;
2914 }
2915@@ -732,9 +678,9 @@ static void b44_recycle_rx(struct b44 *b
2916 pci_unmap_addr(src_map, mapping));
2917
2918 if (bp->flags & B44_FLAG_RX_RING_HACK)
2919- b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
2920- src_idx * sizeof(src_desc),
2921- DMA_BIDIRECTIONAL);
2922+ b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma,
2923+ src_idx * sizeof(src_desc),
2924+ DMA_BIDIRECTIONAL);
2925
2926 ctrl = src_desc->ctrl;
2927 if (dest_idx == (B44_RX_RING_SIZE - 1))
2928@@ -748,13 +694,13 @@ static void b44_recycle_rx(struct b44 *b
2929 src_map->skb = NULL;
2930
2931 if (bp->flags & B44_FLAG_RX_RING_HACK)
2932- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
2933- dest_idx * sizeof(dest_desc),
2934- DMA_BIDIRECTIONAL);
2935+ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
2936+ dest_idx * sizeof(dest_desc),
2937+ DMA_BIDIRECTIONAL);
2938
2939- pci_dma_sync_single_for_device(bp->pdev, src_desc->addr,
2940+ dma_sync_single_for_device(&bp->sdev->dev, src_desc->addr,
2941 RX_PKT_BUF_SZ,
2942- PCI_DMA_FROMDEVICE);
2943+ DMA_FROM_DEVICE);
2944 }
2945
2946 static int b44_rx(struct b44 *bp, int budget)
2947@@ -774,9 +720,9 @@ static int b44_rx(struct b44 *bp, int bu
2948 struct rx_header *rh;
2949 u16 len;
2950
2951- pci_dma_sync_single_for_cpu(bp->pdev, map,
2952+ dma_sync_single_for_cpu(&bp->sdev->dev, map,
2953 RX_PKT_BUF_SZ,
2954- PCI_DMA_FROMDEVICE);
2955+ DMA_FROM_DEVICE);
2956 rh = (struct rx_header *) skb->data;
2957 len = cpu_to_le16(rh->len);
2958 if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
2959@@ -808,11 +754,11 @@ static int b44_rx(struct b44 *bp, int bu
2960 skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
2961 if (skb_size < 0)
2962 goto drop_it;
2963- pci_unmap_single(bp->pdev, map,
2964- skb_size, PCI_DMA_FROMDEVICE);
2965+ dma_unmap_single(&bp->sdev->dev, map,
2966+ skb_size, DMA_FROM_DEVICE);
2967 /* Leave out rx_header */
2968- skb_put(skb, len+bp->rx_offset);
2969- skb_pull(skb,bp->rx_offset);
2970+ skb_put(skb, len+bp->rx_offset);
2971+ skb_pull(skb,bp->rx_offset);
2972 } else {
2973 struct sk_buff *copy_skb;
2974
2975@@ -980,23 +926,23 @@ static int b44_start_xmit(struct sk_buff
2976 goto err_out;
2977 }
2978
2979- mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
2980+ mapping = dma_map_single(&bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
2981 if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) {
2982 /* Chip can't handle DMA to/from >1GB, use bounce buffer */
2983 if (!dma_mapping_error(mapping))
2984- pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
2985+ dma_unmap_single(&bp->sdev->dev, mapping, len, DMA_TO_DEVICE);
2986
2987 bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
2988 GFP_ATOMIC|GFP_DMA);
2989 if (!bounce_skb)
2990 goto err_out;
2991
2992- mapping = pci_map_single(bp->pdev, bounce_skb->data,
2993- len, PCI_DMA_TODEVICE);
2994+ mapping = dma_map_single(&bp->sdev->dev, bounce_skb->data,
2995+ len, DMA_TO_DEVICE);
2996 if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) {
2997 if (!dma_mapping_error(mapping))
2998- pci_unmap_single(bp->pdev, mapping,
2999- len, PCI_DMA_TODEVICE);
3000+ dma_unmap_single(&bp->sdev->dev, mapping,
3001+ len, DMA_TO_DEVICE);
3002 dev_kfree_skb_any(bounce_skb);
3003 goto err_out;
3004 }
3005@@ -1019,9 +965,9 @@ static int b44_start_xmit(struct sk_buff
3006 bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
3007
3008 if (bp->flags & B44_FLAG_TX_RING_HACK)
3009- b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
3010- entry * sizeof(bp->tx_ring[0]),
3011- DMA_TO_DEVICE);
3012+ b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma,
3013+ entry * sizeof(bp->tx_ring[0]),
3014+ DMA_TO_DEVICE);
3015
3016 entry = NEXT_TX(entry);
3017
3018@@ -1094,10 +1040,10 @@ static void b44_free_rings(struct b44 *b
3019
3020 if (rp->skb == NULL)
3021 continue;
3022- pci_unmap_single(bp->pdev,
3023+ dma_unmap_single(&bp->sdev->dev,
3024 pci_unmap_addr(rp, mapping),
3025 RX_PKT_BUF_SZ,
3026- PCI_DMA_FROMDEVICE);
3027+ DMA_FROM_DEVICE);
3028 dev_kfree_skb_any(rp->skb);
3029 rp->skb = NULL;
3030 }
3031@@ -1108,10 +1054,10 @@ static void b44_free_rings(struct b44 *b
3032
3033 if (rp->skb == NULL)
3034 continue;
3035- pci_unmap_single(bp->pdev,
3036+ dma_unmap_single(&bp->sdev->dev,
3037 pci_unmap_addr(rp, mapping),
3038 rp->skb->len,
3039- PCI_DMA_TODEVICE);
3040+ DMA_TO_DEVICE);
3041 dev_kfree_skb_any(rp->skb);
3042 rp->skb = NULL;
3043 }
3044@@ -1133,14 +1079,14 @@ static void b44_init_rings(struct b44 *b
3045 memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
3046
3047 if (bp->flags & B44_FLAG_RX_RING_HACK)
3048- dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
3049- DMA_TABLE_BYTES,
3050- PCI_DMA_BIDIRECTIONAL);
3051+ dma_sync_single_for_device(&bp->sdev->dev, bp->rx_ring_dma,
3052+ DMA_TABLE_BYTES,
3053+ DMA_BIDIRECTIONAL);
3054
3055 if (bp->flags & B44_FLAG_TX_RING_HACK)
3056- dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
3057- DMA_TABLE_BYTES,
3058- PCI_DMA_TODEVICE);
3059+ dma_sync_single_for_device(&bp->sdev->dev, bp->tx_ring_dma,
3060+ DMA_TABLE_BYTES,
3061+ DMA_TO_DEVICE);
3062
3063 for (i = 0; i < bp->rx_pending; i++) {
3064 if (b44_alloc_rx_skb(bp, -1, i) < 0)
3065@@ -1160,24 +1106,24 @@ static void b44_free_consistent(struct b
3066 bp->tx_buffers = NULL;
3067 if (bp->rx_ring) {
3068 if (bp->flags & B44_FLAG_RX_RING_HACK) {
3069- dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
3070- DMA_TABLE_BYTES,
3071- DMA_BIDIRECTIONAL);
3072+ dma_unmap_single(&bp->sdev->dev, bp->rx_ring_dma,
3073+ DMA_TABLE_BYTES,
3074+ DMA_BIDIRECTIONAL);
3075 kfree(bp->rx_ring);
3076 } else
3077- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
3078+ dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES,
3079 bp->rx_ring, bp->rx_ring_dma);
3080 bp->rx_ring = NULL;
3081 bp->flags &= ~B44_FLAG_RX_RING_HACK;
3082 }
3083 if (bp->tx_ring) {
3084 if (bp->flags & B44_FLAG_TX_RING_HACK) {
3085- dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
3086- DMA_TABLE_BYTES,
3087- DMA_TO_DEVICE);
3088+ dma_unmap_single(&bp->sdev->dev, bp->tx_ring_dma,
3089+ DMA_TABLE_BYTES,
3090+ DMA_TO_DEVICE);
3091 kfree(bp->tx_ring);
3092 } else
3093- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
3094+ dma_free_coherent(&bp->sdev->dev, DMA_TABLE_BYTES,
3095 bp->tx_ring, bp->tx_ring_dma);
3096 bp->tx_ring = NULL;
3097 bp->flags &= ~B44_FLAG_TX_RING_HACK;
3098@@ -1203,7 +1149,7 @@ static int b44_alloc_consistent(struct b
3099 goto out_err;
3100
3101 size = DMA_TABLE_BYTES;
3102- bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
3103+ bp->rx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC);
3104 if (!bp->rx_ring) {
3105 /* Allocation may have failed due to pci_alloc_consistent
3106 insisting on use of GFP_DMA, which is more restrictive
3107@@ -1215,9 +1161,9 @@ static int b44_alloc_consistent(struct b
3108 if (!rx_ring)
3109 goto out_err;
3110
3111- rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
3112- DMA_TABLE_BYTES,
3113- DMA_BIDIRECTIONAL);
3114+ rx_ring_dma = dma_map_single(&bp->sdev->dev, rx_ring,
3115+ DMA_TABLE_BYTES,
3116+ DMA_BIDIRECTIONAL);
3117
3118 if (dma_mapping_error(rx_ring_dma) ||
3119 rx_ring_dma + size > B44_DMA_MASK) {
3120@@ -1230,9 +1176,9 @@ static int b44_alloc_consistent(struct b
3121 bp->flags |= B44_FLAG_RX_RING_HACK;
3122 }
3123
3124- bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
3125+ bp->tx_ring = dma_alloc_coherent(&bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC);
3126 if (!bp->tx_ring) {
3127- /* Allocation may have failed due to pci_alloc_consistent
3128+ /* Allocation may have failed due to dma_alloc_coherent
3129 insisting on use of GFP_DMA, which is more restrictive
3130 than necessary... */
3131 struct dma_desc *tx_ring;
3132@@ -1242,9 +1188,9 @@ static int b44_alloc_consistent(struct b
3133 if (!tx_ring)
3134 goto out_err;
3135
3136- tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
3137- DMA_TABLE_BYTES,
3138- DMA_TO_DEVICE);
3139+ tx_ring_dma = dma_map_single(&bp->sdev->dev, tx_ring,
3140+ DMA_TABLE_BYTES,
3141+ DMA_TO_DEVICE);
3142
3143 if (dma_mapping_error(tx_ring_dma) ||
3144 tx_ring_dma + size > B44_DMA_MASK) {
3145@@ -1279,7 +1225,9 @@ static void b44_clear_stats(struct b44 *
3146 /* bp->lock is held. */
3147 static void b44_chip_reset(struct b44 *bp)
3148 {
3149- if (ssb_is_core_up(bp)) {
3150+ struct ssb_device *sdev = bp->sdev;
3151+
3152+ if (ssb_device_is_enabled(bp->sdev)) {
3153 bw32(bp, B44_RCV_LAZY, 0);
3154 bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
3155 b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1);
3156@@ -1291,19 +1239,23 @@ static void b44_chip_reset(struct b44 *b
3157 }
3158 bw32(bp, B44_DMARX_CTRL, 0);
3159 bp->rx_prod = bp->rx_cons = 0;
3160- } else {
3161- ssb_pci_setup(bp, (bp->core_unit == 0 ?
3162- SBINTVEC_ENET0 :
3163- SBINTVEC_ENET1));
3164 }
3165
3166- ssb_core_reset(bp);
3167-
3168+ ssb_device_enable(bp->sdev, 0);
3169 b44_clear_stats(bp);
3170
3171- /* Make PHY accessible. */
3172- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
3173+ switch (sdev->bus->bustype) {
3174+ case SSB_BUSTYPE_SSB:
3175+ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
3176+ (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
3177+ & MDIO_CTRL_MAXF_MASK)));
3178+ break;
3179+ case SSB_BUSTYPE_PCI:
3180+ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
3181 (0x0d & MDIO_CTRL_MAXF_MASK)));
3182+ break;
3183+ }
3184+
3185 br32(bp, B44_MDIO_CTRL);
3186
3187 if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
3188@@ -1346,6 +1298,7 @@ static int b44_set_mac_addr(struct net_d
3189 {
3190 struct b44 *bp = netdev_priv(dev);
3191 struct sockaddr *addr = p;
3192+ u32 val;
3193
3194 if (netif_running(dev))
3195 return -EBUSY;
3196@@ -1356,7 +1309,11 @@ static int b44_set_mac_addr(struct net_d
3197 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3198
3199 spin_lock_irq(&bp->lock);
3200- __b44_set_mac_addr(bp);
3201+
3202+ val = br32(bp, B44_RXCONFIG);
3203+ if (!(val & RXCONFIG_CAM_ABSENT))
3204+ __b44_set_mac_addr(bp);
3205+
3206 spin_unlock_irq(&bp->lock);
3207
3208 return 0;
3209@@ -1442,18 +1399,6 @@ out:
3210 return err;
3211 }
3212
3213-#if 0
3214-/*static*/ void b44_dump_state(struct b44 *bp)
3215-{
3216- u32 val32, val32_2, val32_3, val32_4, val32_5;
3217- u16 val16;
3218-
3219- pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
3220- printk("DEBUG: PCI status [%04x] \n", val16);
3221-
3222-}
3223-#endif
3224-
3225 #ifdef CONFIG_NET_POLL_CONTROLLER
3226 /*
3227 * Polling receive - used by netconsole and other diagnostic tools
3228@@ -1568,7 +1513,6 @@ static void b44_setup_pseudo_magicp(stru
3229 static void b44_setup_wol(struct b44 *bp)
3230 {
3231 u32 val;
3232- u16 pmval;
3233
3234 bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
3235
3236@@ -1592,13 +1536,6 @@ static void b44_setup_wol(struct b44 *bp
3237 } else {
3238 b44_setup_pseudo_magicp(bp);
3239 }
3240-
3241- val = br32(bp, B44_SBTMSLOW);
3242- bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
3243-
3244- pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
3245- pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
3246-
3247 }
3248
3249 static int b44_close(struct net_device *dev)
3250@@ -1698,7 +1635,7 @@ static void __b44_set_rx_mode(struct net
3251
3252 val = br32(bp, B44_RXCONFIG);
3253 val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
3254- if (dev->flags & IFF_PROMISC) {
3255+ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
3256 val |= RXCONFIG_PROMISC;
3257 bw32(bp, B44_RXCONFIG, val);
3258 } else {
3259@@ -1745,12 +1682,8 @@ static void b44_set_msglevel(struct net_
3260
3261 static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
3262 {
3263- struct b44 *bp = netdev_priv(dev);
3264- struct pci_dev *pci_dev = bp->pdev;
3265-
3266 strcpy (info->driver, DRV_MODULE_NAME);
3267 strcpy (info->version, DRV_MODULE_VERSION);
3268- strcpy (info->bus_info, pci_name(pci_dev));
3269 }
3270
3271 static int b44_nway_reset(struct net_device *dev)
3272@@ -2034,6 +1967,245 @@ static const struct ethtool_ops b44_etht
3273 .get_perm_addr = ethtool_op_get_perm_addr,
3274 };
3275
3276+static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
3277+{
3278+ struct b44 *bp = dev->priv;
3279+ u32 ethcmd;
3280+
3281+ if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
3282+ return -EFAULT;
3283+
3284+ switch (ethcmd) {
3285+ case ETHTOOL_GDRVINFO: {
3286+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
3287+ strcpy (info.driver, DRV_MODULE_NAME);
3288+ strcpy (info.version, DRV_MODULE_VERSION);
3289+ memset(&info.fw_version, 0, sizeof(info.fw_version));
3290+ info.eedump_len = 0;
3291+ info.regdump_len = 0;
3292+ if (copy_to_user (useraddr, &info, sizeof (info)))
3293+ return -EFAULT;
3294+ return 0;
3295+ }
3296+
3297+ case ETHTOOL_GSET: {
3298+ struct ethtool_cmd cmd = { ETHTOOL_GSET };
3299+
3300+ if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
3301+ return -EAGAIN;
3302+ cmd.supported = (SUPPORTED_Autoneg);
3303+ cmd.supported |= (SUPPORTED_100baseT_Half |
3304+ SUPPORTED_100baseT_Full |
3305+ SUPPORTED_10baseT_Half |
3306+ SUPPORTED_10baseT_Full |
3307+ SUPPORTED_MII);
3308+
3309+ cmd.advertising = 0;
3310+ if (bp->flags & B44_FLAG_ADV_10HALF)
3311+ cmd.advertising |= ADVERTISE_10HALF;
3312+ if (bp->flags & B44_FLAG_ADV_10FULL)
3313+ cmd.advertising |= ADVERTISE_10FULL;
3314+ if (bp->flags & B44_FLAG_ADV_100HALF)
3315+ cmd.advertising |= ADVERTISE_100HALF;
3316+ if (bp->flags & B44_FLAG_ADV_100FULL)
3317+ cmd.advertising |= ADVERTISE_100FULL;
3318+ cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
3319+ cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ?
3320+ SPEED_100 : SPEED_10;
3321+ cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
3322+ DUPLEX_FULL : DUPLEX_HALF;
3323+ cmd.port = 0;
3324+ cmd.phy_address = bp->phy_addr;
3325+ cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
3326+ XCVR_INTERNAL : XCVR_EXTERNAL;
3327+ cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
3328+ AUTONEG_DISABLE : AUTONEG_ENABLE;
3329+ cmd.maxtxpkt = 0;
3330+ cmd.maxrxpkt = 0;
3331+ if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
3332+ return -EFAULT;
3333+ return 0;
3334+ }
3335+ case ETHTOOL_SSET: {
3336+ struct ethtool_cmd cmd;
3337+
3338+ if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
3339+ return -EAGAIN;
3340+
3341+ if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
3342+ return -EFAULT;
3343+
3344+ /* We do not support gigabit. */
3345+ if (cmd.autoneg == AUTONEG_ENABLE) {
3346+ if (cmd.advertising &
3347+ (ADVERTISED_1000baseT_Half |
3348+ ADVERTISED_1000baseT_Full))
3349+ return -EINVAL;
3350+ } else if ((cmd.speed != SPEED_100 &&
3351+ cmd.speed != SPEED_10) ||
3352+ (cmd.duplex != DUPLEX_HALF &&
3353+ cmd.duplex != DUPLEX_FULL)) {
3354+ return -EINVAL;
3355+ }
3356+
3357+ spin_lock_irq(&bp->lock);
3358+
3359+ if (cmd.autoneg == AUTONEG_ENABLE) {
3360+ bp->flags &= ~B44_FLAG_FORCE_LINK;
3361+ bp->flags &= ~(B44_FLAG_ADV_10HALF |
3362+ B44_FLAG_ADV_10FULL |
3363+ B44_FLAG_ADV_100HALF |
3364+ B44_FLAG_ADV_100FULL);
3365+ if (cmd.advertising & ADVERTISE_10HALF)
3366+ bp->flags |= B44_FLAG_ADV_10HALF;
3367+ if (cmd.advertising & ADVERTISE_10FULL)
3368+ bp->flags |= B44_FLAG_ADV_10FULL;
3369+ if (cmd.advertising & ADVERTISE_100HALF)
3370+ bp->flags |= B44_FLAG_ADV_100HALF;
3371+ if (cmd.advertising & ADVERTISE_100FULL)
3372+ bp->flags |= B44_FLAG_ADV_100FULL;
3373+ } else {
3374+ bp->flags |= B44_FLAG_FORCE_LINK;
3375+ if (cmd.speed == SPEED_100)
3376+ bp->flags |= B44_FLAG_100_BASE_T;
3377+ if (cmd.duplex == DUPLEX_FULL)
3378+ bp->flags |= B44_FLAG_FULL_DUPLEX;
3379+ }
3380+
3381+ b44_setup_phy(bp);
3382+
3383+ spin_unlock_irq(&bp->lock);
3384+
3385+ return 0;
3386+ }
3387+
3388+ case ETHTOOL_GMSGLVL: {
3389+ struct ethtool_value edata = { ETHTOOL_GMSGLVL };
3390+ edata.data = bp->msg_enable;
3391+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
3392+ return -EFAULT;
3393+ return 0;
3394+ }
3395+ case ETHTOOL_SMSGLVL: {
3396+ struct ethtool_value edata;
3397+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
3398+ return -EFAULT;
3399+ bp->msg_enable = edata.data;
3400+ return 0;
3401+ }
3402+ case ETHTOOL_NWAY_RST: {
3403+ u32 bmcr;
3404+ int r;
3405+
3406+ spin_lock_irq(&bp->lock);
3407+ b44_readphy(bp, MII_BMCR, &bmcr);
3408+ b44_readphy(bp, MII_BMCR, &bmcr);
3409+ r = -EINVAL;
3410+ if (bmcr & BMCR_ANENABLE) {
3411+ b44_writephy(bp, MII_BMCR,
3412+ bmcr | BMCR_ANRESTART);
3413+ r = 0;
3414+ }
3415+ spin_unlock_irq(&bp->lock);
3416+
3417+ return r;
3418+ }
3419+ case ETHTOOL_GLINK: {
3420+ struct ethtool_value edata = { ETHTOOL_GLINK };
3421+ edata.data = netif_carrier_ok(bp->dev) ? 1 : 0;
3422+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
3423+ return -EFAULT;
3424+ return 0;
3425+ }
3426+ case ETHTOOL_GRINGPARAM: {
3427+ struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
3428+
3429+ ering.rx_max_pending = B44_RX_RING_SIZE - 1;
3430+ ering.rx_pending = bp->rx_pending;
3431+
3432+ /* XXX ethtool lacks a tx_max_pending, oops... */
3433+
3434+ if (copy_to_user(useraddr, &ering, sizeof(ering)))
3435+ return -EFAULT;
3436+ return 0;
3437+ }
3438+ case ETHTOOL_SRINGPARAM: {
3439+ struct ethtool_ringparam ering;
3440+
3441+ if (copy_from_user(&ering, useraddr, sizeof(ering)))
3442+ return -EFAULT;
3443+
3444+ if ((ering.rx_pending > B44_RX_RING_SIZE - 1) ||
3445+ (ering.rx_mini_pending != 0) ||
3446+ (ering.rx_jumbo_pending != 0) ||
3447+ (ering.tx_pending > B44_TX_RING_SIZE - 1))
3448+ return -EINVAL;
3449+
3450+ spin_lock_irq(&bp->lock);
3451+
3452+ bp->rx_pending = ering.rx_pending;
3453+ bp->tx_pending = ering.tx_pending;
3454+
3455+ b44_halt(bp);
3456+ b44_init_rings(bp);
3457+ b44_init_hw(bp, 1);
3458+ netif_wake_queue(bp->dev);
3459+ spin_unlock_irq(&bp->lock);
3460+
3461+ b44_enable_ints(bp);
3462+
3463+ return 0;
3464+ }
3465+ case ETHTOOL_GPAUSEPARAM: {
3466+ struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
3467+
3468+ epause.autoneg =
3469+ (bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
3470+ epause.rx_pause =
3471+ (bp->flags & B44_FLAG_RX_PAUSE) != 0;
3472+ epause.tx_pause =
3473+ (bp->flags & B44_FLAG_TX_PAUSE) != 0;
3474+ if (copy_to_user(useraddr, &epause, sizeof(epause)))
3475+ return -EFAULT;
3476+ return 0;
3477+ }
3478+ case ETHTOOL_SPAUSEPARAM: {
3479+ struct ethtool_pauseparam epause;
3480+
3481+ if (copy_from_user(&epause, useraddr, sizeof(epause)))
3482+ return -EFAULT;
3483+
3484+ spin_lock_irq(&bp->lock);
3485+ if (epause.autoneg)
3486+ bp->flags |= B44_FLAG_PAUSE_AUTO;
3487+ else
3488+ bp->flags &= ~B44_FLAG_PAUSE_AUTO;
3489+ if (epause.rx_pause)
3490+ bp->flags |= B44_FLAG_RX_PAUSE;
3491+ else
3492+ bp->flags &= ~B44_FLAG_RX_PAUSE;
3493+ if (epause.tx_pause)
3494+ bp->flags |= B44_FLAG_TX_PAUSE;
3495+ else
3496+ bp->flags &= ~B44_FLAG_TX_PAUSE;
3497+ if (bp->flags & B44_FLAG_PAUSE_AUTO) {
3498+ b44_halt(bp);
3499+ b44_init_rings(bp);
3500+ b44_init_hw(bp, 1);
3501+ } else {
3502+ __b44_set_flow_ctrl(bp, bp->flags);
3503+ }
3504+ spin_unlock_irq(&bp->lock);
3505+
3506+ b44_enable_ints(bp);
3507+
3508+ return 0;
3509+ }
3510+ };
3511+
3512+ return -EOPNOTSUPP;
3513+}
3514+
3515 static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3516 {
3517 struct mii_ioctl_data *data = if_mii(ifr);
3518@@ -2043,40 +2215,64 @@ static int b44_ioctl(struct net_device *
3519 if (!netif_running(dev))
3520 goto out;
3521
3522- spin_lock_irq(&bp->lock);
3523- err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
3524- spin_unlock_irq(&bp->lock);
3525-out:
3526- return err;
3527-}
3528+ switch (cmd) {
3529+ case SIOCETHTOOL:
3530+ return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data);
3531
3532-/* Read 128-bytes of EEPROM. */
3533-static int b44_read_eeprom(struct b44 *bp, u8 *data)
3534-{
3535- long i;
3536- u16 *ptr = (u16 *) data;
3537+ case SIOCGMIIPHY:
3538+ data->phy_id = bp->phy_addr;
3539
3540- for (i = 0; i < 128; i += 2)
3541- ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
3542+ /* fallthru */
3543+ case SIOCGMIIREG: {
3544+ u32 mii_regval;
3545+ spin_lock_irq(&bp->lock);
3546+ err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
3547+ spin_unlock_irq(&bp->lock);
3548
3549- return 0;
3550+ data->val_out = mii_regval;
3551+
3552+ return err;
3553+ }
3554+
3555+ case SIOCSMIIREG:
3556+ if (!capable(CAP_NET_ADMIN))
3557+ return -EPERM;
3558+
3559+ spin_lock_irq(&bp->lock);
3560+ err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
3561+ spin_unlock_irq(&bp->lock);
3562+
3563+ return err;
3564+
3565+ default:
3566+ break;
3567+ };
3568+ return -EOPNOTSUPP;
3569+
3570+out:
3571+ return err;
3572 }
3573
3574 static int __devinit b44_get_invariants(struct b44 *bp)
3575 {
3576- u8 eeprom[128];
3577- int err;
3578+ struct ssb_device *sdev = bp->sdev;
3579+ int err = 0;
3580+ u8 *addr;
3581
3582- err = b44_read_eeprom(bp, &eeprom[0]);
3583- if (err)
3584- goto out;
3585+ bp->dma_offset = ssb_dma_offset(sdev);
3586
3587- bp->dev->dev_addr[0] = eeprom[79];
3588- bp->dev->dev_addr[1] = eeprom[78];
3589- bp->dev->dev_addr[2] = eeprom[81];
3590- bp->dev->dev_addr[3] = eeprom[80];
3591- bp->dev->dev_addr[4] = eeprom[83];
3592- bp->dev->dev_addr[5] = eeprom[82];
3593+ switch (instance) {
3594+ case 1:
3595+ addr = sdev->bus->sprom.r1.et0mac;
3596+ bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr;
3597+ break;
3598+ default:
3599+ addr = sdev->bus->sprom.r1.et1mac;
3600+ bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr;
3601+ break;
3602+ }
3603+
3604+ memcpy(bp->dev->dev_addr, addr, 6);
3605
3606 if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
3607 printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
3608@@ -2085,108 +2281,52 @@ static int __devinit b44_get_invariants(
3609
3610 memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
3611
3612- bp->phy_addr = eeprom[90] & 0x1f;
3613-
3614 /* With this, plus the rx_header prepended to the data by the
3615 * hardware, we'll land the ethernet header on a 2-byte boundary.
3616 */
3617 bp->rx_offset = 30;
3618-
3619 bp->imask = IMASK_DEF;
3620-
3621- bp->core_unit = ssb_core_unit(bp);
3622- bp->dma_offset = SB_PCI_DMA;
3623-
3624 /* XXX - really required?
3625 bp->flags |= B44_FLAG_BUGGY_TXPTR;
3626- */
3627+ */
3628
3629- if (ssb_get_core_rev(bp) >= 7)
3630- bp->flags |= B44_FLAG_B0_ANDLATER;
3631-
3632-out:
3633 return err;
3634 }
3635
3636-static int __devinit b44_init_one(struct pci_dev *pdev,
3637- const struct pci_device_id *ent)
3638+static int __devinit b44_init_one(struct ssb_device *sdev,
3639+ const struct ssb_device_id *ent)
3640 {
3641 static int b44_version_printed = 0;
3642- unsigned long b44reg_base, b44reg_len;
3643 struct net_device *dev;
3644 struct b44 *bp;
3645 int err, i;
3646
3647+ instance++;
3648+
3649 if (b44_version_printed++ == 0)
3650 printk(KERN_INFO "%s", version);
3651
3652- err = pci_enable_device(pdev);
3653- if (err) {
3654- dev_err(&pdev->dev, "Cannot enable PCI device, "
3655- "aborting.\n");
3656- return err;
3657- }
3658-
3659- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
3660- dev_err(&pdev->dev,
3661- "Cannot find proper PCI device "
3662- "base address, aborting.\n");
3663- err = -ENODEV;
3664- goto err_out_disable_pdev;
3665- }
3666-
3667- err = pci_request_regions(pdev, DRV_MODULE_NAME);
3668- if (err) {
3669- dev_err(&pdev->dev,
3670- "Cannot obtain PCI resources, aborting.\n");
3671- goto err_out_disable_pdev;
3672- }
3673-
3674- pci_set_master(pdev);
3675-
3676- err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
3677- if (err) {
3678- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
3679- goto err_out_free_res;
3680- }
3681-
3682- err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
3683- if (err) {
3684- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
3685- goto err_out_free_res;
3686- }
3687-
3688- b44reg_base = pci_resource_start(pdev, 0);
3689- b44reg_len = pci_resource_len(pdev, 0);
3690-
3691 dev = alloc_etherdev(sizeof(*bp));
3692 if (!dev) {
3693- dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
3694+ dev_err(&sdev->dev, "Etherdev alloc failed, aborting.\n");
3695 err = -ENOMEM;
3696- goto err_out_free_res;
3697+ goto out;
3698 }
3699
3700 SET_MODULE_OWNER(dev);
3701- SET_NETDEV_DEV(dev,&pdev->dev);
3702+ SET_NETDEV_DEV(dev,&sdev->dev);
3703
3704 /* No interesting netdevice features in this card... */
3705 dev->features |= 0;
3706
3707 bp = netdev_priv(dev);
3708- bp->pdev = pdev;
3709+ bp->sdev = sdev;
3710 bp->dev = dev;
3711
3712 bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
3713
3714 spin_lock_init(&bp->lock);
3715
3716- bp->regs = ioremap(b44reg_base, b44reg_len);
3717- if (bp->regs == 0UL) {
3718- dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
3719- err = -ENOMEM;
3720- goto err_out_free_dev;
3721- }
3722-
3723 bp->rx_pending = B44_DEF_RX_RING_PENDING;
3724 bp->tx_pending = B44_DEF_TX_RING_PENDING;
3725
3726@@ -2205,16 +2345,16 @@ static int __devinit b44_init_one(struct
3727 dev->poll_controller = b44_poll_controller;
3728 #endif
3729 dev->change_mtu = b44_change_mtu;
3730- dev->irq = pdev->irq;
3731+ dev->irq = sdev->irq;
3732 SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
3733
3734 netif_carrier_off(dev);
3735
3736 err = b44_get_invariants(bp);
3737 if (err) {
3738- dev_err(&pdev->dev,
3739+ dev_err(&sdev->dev,
3740 "Problem fetching invariants of chip, aborting.\n");
3741- goto err_out_iounmap;
3742+ goto err_out_free_dev;
3743 }
3744
3745 bp->mii_if.dev = dev;
3746@@ -2233,61 +2373,52 @@ static int __devinit b44_init_one(struct
3747
3748 err = register_netdev(dev);
3749 if (err) {
3750- dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
3751- goto err_out_iounmap;
3752+ dev_err(&sdev->dev, "Cannot register net device, aborting.\n");
3753+ goto out;
3754 }
3755
3756- pci_set_drvdata(pdev, dev);
3757-
3758- pci_save_state(bp->pdev);
3759+ ssb_set_drvdata(sdev, dev);
3760
3761 /* Chip reset provides power to the b44 MAC & PCI cores, which
3762 * is necessary for MAC register access.
3763 */
3764 b44_chip_reset(bp);
3765
3766- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
3767+ printk(KERN_INFO "%s: Broadcom 10/100BaseT Ethernet ", dev->name);
3768 for (i = 0; i < 6; i++)
3769 printk("%2.2x%c", dev->dev_addr[i],
3770 i == 5 ? '\n' : ':');
3771
3772- return 0;
3773+ /* Initialize phy */
3774+ spin_lock_irq(&bp->lock);
3775+ b44_chip_reset(bp);
3776+ spin_unlock_irq(&bp->lock);
3777
3778-err_out_iounmap:
3779- iounmap(bp->regs);
3780+ return 0;
3781
3782 err_out_free_dev:
3783 free_netdev(dev);
3784
3785-err_out_free_res:
3786- pci_release_regions(pdev);
3787-
3788-err_out_disable_pdev:
3789- pci_disable_device(pdev);
3790- pci_set_drvdata(pdev, NULL);
3791+out:
3792 return err;
3793 }
3794
3795-static void __devexit b44_remove_one(struct pci_dev *pdev)
3796+static void __devexit b44_remove_one(struct ssb_device *pdev)
3797 {
3798- struct net_device *dev = pci_get_drvdata(pdev);
3799- struct b44 *bp = netdev_priv(dev);
3800+ struct net_device *dev = ssb_get_drvdata(pdev);
3801
3802 unregister_netdev(dev);
3803- iounmap(bp->regs);
3804 free_netdev(dev);
3805- pci_release_regions(pdev);
3806- pci_disable_device(pdev);
3807- pci_set_drvdata(pdev, NULL);
3808+ ssb_set_drvdata(pdev, NULL);
3809 }
3810
3811-static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
3812+static int b44_suspend(struct ssb_device *pdev, pm_message_t state)
3813 {
3814- struct net_device *dev = pci_get_drvdata(pdev);
3815+ struct net_device *dev = ssb_get_drvdata(pdev);
3816 struct b44 *bp = netdev_priv(dev);
3817
3818 if (!netif_running(dev))
3819- return 0;
3820+ return 0;
3821
3822 del_timer_sync(&bp->timer);
3823
3824@@ -2305,19 +2436,15 @@ static int b44_suspend(struct pci_dev *p
3825 b44_init_hw(bp, 0);
3826 b44_setup_wol(bp);
3827 }
3828- pci_disable_device(pdev);
3829+
3830 return 0;
3831 }
3832
3833-static int b44_resume(struct pci_dev *pdev)
3834+static int b44_resume(struct ssb_device *pdev)
3835 {
3836- struct net_device *dev = pci_get_drvdata(pdev);
3837+ struct net_device *dev = ssb_get_drvdata(pdev);
3838 struct b44 *bp = netdev_priv(dev);
3839
3840- pci_restore_state(pdev);
3841- pci_enable_device(pdev);
3842- pci_set_master(pdev);
3843-
3844 if (!netif_running(dev))
3845 return 0;
3846
3847@@ -2339,29 +2466,31 @@ static int b44_resume(struct pci_dev *pd
3848 return 0;
3849 }
3850
3851-static struct pci_driver b44_driver = {
3852+static struct ssb_driver b44_driver = {
3853 .name = DRV_MODULE_NAME,
3854- .id_table = b44_pci_tbl,
3855+ .id_table = b44_ssb_tbl,
3856 .probe = b44_init_one,
3857 .remove = __devexit_p(b44_remove_one),
3858- .suspend = b44_suspend,
3859- .resume = b44_resume,
3860+ .suspend = b44_suspend,
3861+ .resume = b44_resume,
3862 };
3863
3864 static int __init b44_init(void)
3865 {
3866 unsigned int dma_desc_align_size = dma_get_cache_alignment();
3867
3868+ instance = 0;
3869+
3870 /* Setup paramaters for syncing RX/TX DMA descriptors */
3871 dma_desc_align_mask = ~(dma_desc_align_size - 1);
3872 dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
3873
3874- return pci_register_driver(&b44_driver);
3875+ return ssb_driver_register(&b44_driver);
3876 }
3877
3878 static void __exit b44_cleanup(void)
3879 {
3880- pci_unregister_driver(&b44_driver);
3881+ ssb_driver_unregister(&b44_driver);
3882 }
3883
3884 module_init(b44_init);
3885diff --git a/drivers/net/b44.h b/drivers/net/b44.h
3886index 4944507..7e3ea87 100644
3887--- a/drivers/net/b44.h
3888+++ b/drivers/net/b44.h
3889@@ -129,6 +129,7 @@
3890 #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
3891 #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
3892 #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
3893+#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */
3894 #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
3895 #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
3896 #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
3897@@ -227,75 +228,9 @@
3898 #define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */
3899 #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */
3900
3901-/* Silicon backplane register definitions */
3902-#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
3903-#define SBIMSTATE_PC 0x0000000f /* Pipe Count */
3904-#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
3905-#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */
3906-#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */
3907-#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */
3908-#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */
3909-#define SBIMSTATE_IBE 0x00020000 /* In Band Error */
3910-#define SBIMSTATE_TO 0x00040000 /* Timeout */
3911-#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */
3912-#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
3913-#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */
3914-#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */
3915-#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */
3916-#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */
3917-#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */
3918-#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */
3919-#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */
3920-#define SBTMSLOW_RESET 0x00000001 /* Reset */
3921-#define SBTMSLOW_REJECT 0x00000002 /* Reject */
3922-#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */
3923-#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
3924-#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */
3925-#define SBTMSLOW_BE 0x80000000 /* BIST Enable */
3926-#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */
3927-#define SBTMSHIGH_SERR 0x00000001 /* S-error */
3928-#define SBTMSHIGH_INT 0x00000002 /* Interrupt */
3929-#define SBTMSHIGH_BUSY 0x00000004 /* Busy */
3930-#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */
3931-#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */
3932-#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */
3933-#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */
3934-#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */
3935-#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
3936-#define SBIDHIGH_CC_SHIFT 4
3937-#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */
3938-#define SBIDHIGH_VC_SHIFT 16
3939-
3940-/* SSB PCI config space registers. */
3941-#define SSB_PMCSR 0x44
3942-#define SSB_PE 0x100
3943-#define SSB_BAR0_WIN 0x80
3944-#define SSB_BAR1_WIN 0x84
3945-#define SSB_SPROM_CONTROL 0x88
3946-#define SSB_BAR1_CONTROL 0x8c
3947-
3948-/* SSB core and host control registers. */
3949-#define SSB_CONTROL 0x0000UL
3950-#define SSB_ARBCONTROL 0x0010UL
3951-#define SSB_ISTAT 0x0020UL
3952-#define SSB_IMASK 0x0024UL
3953-#define SSB_MBOX 0x0028UL
3954-#define SSB_BCAST_ADDR 0x0050UL
3955-#define SSB_BCAST_DATA 0x0054UL
3956-#define SSB_PCI_TRANS_0 0x0100UL
3957-#define SSB_PCI_TRANS_1 0x0104UL
3958-#define SSB_PCI_TRANS_2 0x0108UL
3959-#define SSB_SPROM 0x0800UL
3960-
3961-#define SSB_PCI_MEM 0x00000000
3962-#define SSB_PCI_IO 0x00000001
3963-#define SSB_PCI_CFG0 0x00000002
3964-#define SSB_PCI_CFG1 0x00000003
3965-#define SSB_PCI_PREF 0x00000004
3966-#define SSB_PCI_BURST 0x00000008
3967-#define SSB_PCI_MASK0 0xfc000000
3968-#define SSB_PCI_MASK1 0xfc000000
3969-#define SSB_PCI_MASK2 0xc0000000
3970+#define br32(bp, REG) ssb_read32((bp)->sdev, (REG))
3971+#define bw32(bp, REG, VAL) ssb_write32((bp)->sdev, (REG), (VAL))
3972+#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
3973
3974 /* 4400 PHY registers */
3975 #define B44_MII_AUXCTRL 24 /* Auxiliary Control */
3976@@ -346,10 +281,12 @@ struct rx_header {
3977
3978 struct ring_info {
3979 struct sk_buff *skb;
3980- DECLARE_PCI_UNMAP_ADDR(mapping);
3981+ dma_addr_t mapping;
3982 };
3983
3984 #define B44_MCAST_TABLE_SIZE 32
3985+#define B44_PHY_ADDR_NO_PHY 30
3986+#define B44_MDC_RATIO 5000000
3987
3988 #define B44_STAT_REG_DECLARE \
3989 _B44(tx_good_octets) \
3990@@ -425,9 +362,10 @@ struct b44 {
3991
3992 u32 dma_offset;
3993 u32 flags;
3994-#define B44_FLAG_B0_ANDLATER 0x00000001
3995+#define B44_FLAG_INIT_COMPLETE 0x00000001
3996 #define B44_FLAG_BUGGY_TXPTR 0x00000002
3997 #define B44_FLAG_REORDER_BUG 0x00000004
3998+#define B44_FLAG_B0_ANDLATER 0x00000008
3999 #define B44_FLAG_PAUSE_AUTO 0x00008000
4000 #define B44_FLAG_FULL_DUPLEX 0x00010000
4001 #define B44_FLAG_100_BASE_T 0x00020000
4002@@ -452,8 +390,7 @@ struct b44 {
4003 struct net_device_stats stats;
4004 struct b44_hw_stats hw_stats;
4005
4006- void __iomem *regs;
4007- struct pci_dev *pdev;
4008+ struct ssb_device *sdev;
4009 struct net_device *dev;
4010
4011 dma_addr_t rx_ring_dma, tx_ring_dma;
4012diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
4013index 1e5ccda..fd5cc13 100644
4014--- a/include/asm-mips/bootinfo.h
4015+++ b/include/asm-mips/bootinfo.h
4016@@ -212,6 +212,12 @@
4017 #define MACH_GROUP_NEC_EMMA2RH 25 /* NEC EMMA2RH (was 23) */
4018 #define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */
4019
4020+/*
4021+ * Valid machtype for group Broadcom
4022+ */
4023+#define MACH_GROUP_BRCM 23 /* Broadcom */
4024+#define MACH_BCM47XX 1 /* Broadcom BCM47xx */
4025+
4026 #define CL_SIZE COMMAND_LINE_SIZE
4027
4028 const char *get_system_type(void);
4029diff --git a/include/asm-mips/cfe.h b/include/asm-mips/cfe.h
4030new file mode 100644
4031index 0000000..47c3f56
4032--- /dev/null
4033+++ b/include/asm-mips/cfe.h
4034@@ -0,0 +1,189 @@
4035+/*
4036+ * Broadcom Common Firmware Environment (CFE) support
4037+ *
4038+ * Copyright 2000, 2001, 2002
4039+ * Broadcom Corporation. All rights reserved.
4040+ *
4041+ * Copyright (C) 2006 Michael Buesch
4042+ *
4043+ * Original Authors: Mitch Lichtenberg, Chris Demetriou
4044+ *
4045+ * This software is furnished under license and may be used and copied only
4046+ * in accordance with the following terms and conditions. Subject to these
4047+ * conditions, you may download, copy, install, use, modify and distribute
4048+ * modified or unmodified copies of this software in source and/or binary
4049+ * form. No title or ownership is transferred hereby.
4050+ *
4051+ * 1) Any source code used, modified or distributed must reproduce and
4052+ * retain this copyright notice and list of conditions as they appear in
4053+ * the source file.
4054+ *
4055+ * 2) No right is granted to use any trade name, trademark, or logo of
4056+ * Broadcom Corporation. The "Broadcom Corporation" name may not be
4057+ * used to endorse or promote products derived from this software
4058+ * without the prior written permission of Broadcom Corporation.
4059+ *
4060+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
4061+ * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
4062+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
4063+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
4064+ * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
4065+ * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4066+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4067+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4068+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4069+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
4070+ * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4071+ */
4072+
4073+#ifndef LINUX_CFE_API_H_
4074+#define LINUX_CFE_API_H_
4075+
4076+#include <linux/types.h>
4077+
4078+
4079+#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */
4080+#define CFE_MI_AVAILABLE 1 /* memory is available */
4081+
4082+#define CFE_FLG_WARMSTART 0x00000001
4083+#define CFE_FLG_FULL_ARENA 0x00000001
4084+#define CFE_FLG_ENV_PERMANENT 0x00000001
4085+
4086+#define CFE_CPU_CMD_START 1
4087+#define CFE_CPU_CMD_STOP 0
4088+
4089+#define CFE_STDHANDLE_CONSOLE 0
4090+
4091+#define CFE_DEV_NETWORK 1
4092+#define CFE_DEV_DISK 2
4093+#define CFE_DEV_FLASH 3
4094+#define CFE_DEV_SERIAL 4
4095+#define CFE_DEV_CPU 5
4096+#define CFE_DEV_NVRAM 6
4097+#define CFE_DEV_CLOCK 7
4098+#define CFE_DEV_OTHER 8
4099+#define CFE_DEV_MASK 0x0F
4100+
4101+#define CFE_CACHE_FLUSH_D 1
4102+#define CFE_CACHE_INVAL_I 2
4103+#define CFE_CACHE_INVAL_D 4
4104+#define CFE_CACHE_INVAL_L2 8
4105+
4106+#define CFE_FWI_64BIT 0x00000001
4107+#define CFE_FWI_32BIT 0x00000002
4108+#define CFE_FWI_RELOC 0x00000004
4109+#define CFE_FWI_UNCACHED 0x00000008
4110+#define CFE_FWI_MULTICPU 0x00000010
4111+#define CFE_FWI_FUNCSIM 0x00000020
4112+#define CFE_FWI_RTLSIM 0x00000040
4113+
4114+struct cfe_fwinfo {
4115+ s64 version; /* major, minor, eco version */
4116+ s64 totalmem; /* total installed mem */
4117+ s64 flags; /* various flags */
4118+ s64 boardid; /* board ID */
4119+ s64 bootarea_va; /* VA of boot area */
4120+ s64 bootarea_pa; /* PA of boot area */
4121+ s64 bootarea_size; /* size of boot area */
4122+};
4123+
4124+
4125+/* The public CFE API */
4126+
4127+int cfe_present(void); /* Check if we booted from CFE. Returns bool */
4128+
4129+int cfe_getticks(s64 *ticks);
4130+int cfe_close(int handle);
4131+int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1);
4132+int cfe_cpu_stop(int cpu);
4133+int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen);
4134+int cfe_enumdev(int idx, char *name, int namelen);
4135+int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
4136+ u64 *type);
4137+int cfe_exit(int warm, int status);
4138+int cfe_flushcache(int flags);
4139+int cfe_getdevinfo(char *name);
4140+int cfe_getenv(char *name, char *dest, int destlen);
4141+int cfe_getfwinfo(struct cfe_fwinfo *info);
4142+int cfe_getstdhandle(int handletype);
4143+int cfe_inpstat(int handle);
4144+int cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer,
4145+ int length, int *retlen, u64 offset);
4146+int cfe_open(char *name);
4147+int cfe_read(int handle, unsigned char *buffer, int length);
4148+int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length);
4149+int cfe_setenv(char *name, char *val);
4150+int cfe_write(int handle, unsigned char *buffer, int length);
4151+int cfe_writeblk(int handle, s64 offset, unsigned char *buffer,
4152+ int length);
4153+
4154+
4155+/* High level API */
4156+
4157+/* Print some information to CFE's console (most likely serial line) */
4158+int cfe_printk(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
4159+int cfe_vprintk(const char *fmt, va_list args);
4160+
4161+
4162+
4163+/* Error codes returned by the low API functions */
4164+
4165+#define CFE_ISERR(errcode) (errcode < 0)
4166+
4167+#define CFE_OK 0
4168+#define CFE_ERR -1 /* generic error */
4169+#define CFE_ERR_INV_COMMAND -2
4170+#define CFE_ERR_EOF -3
4171+#define CFE_ERR_IOERR -4
4172+#define CFE_ERR_NOMEM -5
4173+#define CFE_ERR_DEVNOTFOUND -6
4174+#define CFE_ERR_DEVOPEN -7
4175+#define CFE_ERR_INV_PARAM -8
4176+#define CFE_ERR_ENVNOTFOUND -9
4177+#define CFE_ERR_ENVREADONLY -10
4178+
4179+#define CFE_ERR_NOTELF -11
4180+#define CFE_ERR_NOT32BIT -12
4181+#define CFE_ERR_WRONGENDIAN -13
4182+#define CFE_ERR_BADELFVERS -14
4183+#define CFE_ERR_NOTMIPS -15
4184+#define CFE_ERR_BADELFFMT -16
4185+#define CFE_ERR_BADADDR -17
4186+
4187+#define CFE_ERR_FILENOTFOUND -18
4188+#define CFE_ERR_UNSUPPORTED -19
4189+
4190+#define CFE_ERR_HOSTUNKNOWN -20
4191+
4192+#define CFE_ERR_TIMEOUT -21
4193+
4194+#define CFE_ERR_PROTOCOLERR -22
4195+
4196+#define CFE_ERR_NETDOWN -23
4197+#define CFE_ERR_NONAMESERVER -24
4198+
4199+#define CFE_ERR_NOHANDLES -25
4200+#define CFE_ERR_ALREADYBOUND -26
4201+
4202+#define CFE_ERR_CANNOTSET -27
4203+#define CFE_ERR_NOMORE -28
4204+#define CFE_ERR_BADFILESYS -29
4205+#define CFE_ERR_FSNOTAVAIL -30
4206+
4207+#define CFE_ERR_INVBOOTBLOCK -31
4208+#define CFE_ERR_WRONGDEVTYPE -32
4209+#define CFE_ERR_BBCHECKSUM -33
4210+#define CFE_ERR_BOOTPROGCHKSUM -34
4211+
4212+#define CFE_ERR_LDRNOTAVAIL -35
4213+
4214+#define CFE_ERR_NOTREADY -36
4215+
4216+#define CFE_ERR_GETMEM -37
4217+#define CFE_ERR_SETMEM -38
4218+
4219+#define CFE_ERR_NOTCONN -39
4220+#define CFE_ERR_ADDRINUSE -40
4221+
4222+
4223+#endif /* LINUX_CFE_API_H_ */
4224diff --git a/include/asm-mips/cpu.h b/include/asm-mips/cpu.h
4225index d38fdbf..4621876 100644
4226--- a/include/asm-mips/cpu.h
4227+++ b/include/asm-mips/cpu.h
4228@@ -104,6 +104,13 @@
4229 #define PRID_IMP_SR71000 0x0400
4230
4231 /*
4232+ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
4233+ */
4234+
4235+#define PRID_IMP_BCM4710 0x4000
4236+#define PRID_IMP_BCM3302 0x9000
4237+
4238+/*
4239 * Definitions for 7:0 on legacy processors
4240 */
4241
4242@@ -200,7 +207,9 @@
4243 #define CPU_SB1A 62
4244 #define CPU_74K 63
4245 #define CPU_R14000 64
4246-#define CPU_LAST 64
4247+#define CPU_BCM3302 65
4248+#define CPU_BCM4710 66
4249+#define CPU_LAST 66
4250
4251 /*
4252 * ISA Level encodings
4253diff --git a/include/asm-mips/mach-bcm947xx/kernel-entry-init.h b/include/asm-mips/mach-bcm947xx/kernel-entry-init.h
4254new file mode 100644
4255index 0000000..7df0dc2
4256--- /dev/null
4257+++ b/include/asm-mips/mach-bcm947xx/kernel-entry-init.h
4258@@ -0,0 +1,26 @@
4259+/*
4260+ * This file is subject to the terms and conditions of the GNU General Public
4261+ * License. See the file "COPYING" in the main directory of this archive
4262+ * for more details.
4263+ *
4264+ * Copyright (C) 2005 Embedded Alley Solutions, Inc
4265+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
4266+ * Copyright (C) 2006 Michael Buesch
4267+ */
4268+#ifndef __ASM_MACH_GENERIC_KERNEL_ENTRY_H
4269+#define __ASM_MACH_GENERIC_KERNEL_ENTRY_H
4270+
4271+/* Intentionally empty macro, used in head.S. Override in
4272+ * arch/mips/mach-xxx/kernel-entry-init.h when necessary.
4273+ */
4274+ .macro kernel_entry_setup
4275+ .endm
4276+
4277+/*
4278+ * Do SMP slave processor setup necessary before we can savely execute C code.
4279+ */
4280+ .macro smp_slave_setup
4281+ .endm
4282+
4283+
4284+#endif /* __ASM_MACH_GENERIC_KERNEL_ENTRY_H */
4285diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
4286index fa4e1d7..cbc4de7 100644
4287--- a/include/linux/pci_ids.h
4288+++ b/include/linux/pci_ids.h
4289@@ -1950,6 +1950,7 @@
4290 #define PCI_DEVICE_ID_TIGON3_5906M 0x1713
4291 #define PCI_DEVICE_ID_BCM4401 0x4401
4292 #define PCI_DEVICE_ID_BCM4401B0 0x4402
4293+#define PCI_DEVICE_ID_BCM4713 0x4713
4294
4295 #define PCI_VENDOR_ID_TOPIC 0x151f
4296 #define PCI_DEVICE_ID_TOPIC_TP560 0x0000
4297--
42981.4.4.1
4299
Note: See TracBrowser for help on using the repository browser.