source: clfs-embedded/patches/linux-2.6.30.5-openwrt-bcm47xx-fixes-1.patch@ 7c5d3a4

Last change on this file since 7c5d3a4 was ffc7663, checked in by Maarten Lankhorst <mlankhorst@…>, 15 years ago

book: Update kernel packages and patches

  • Property mode set to 100644
File size: 103.8 KB
RevLine 
[ffc7663]1diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
2index 25f3b0a..868126c 100644
3--- a/arch/mips/Kconfig
4+++ b/arch/mips/Kconfig
5@@ -53,9 +53,9 @@ config BCM47XX
6 select SSB_DRIVER_MIPS
7 select SSB_DRIVER_EXTIF
8 select SSB_EMBEDDED
9+ select SSB_B43_PCI_BRIDGE if PCI
10 select SSB_PCICORE_HOSTMODE if PCI
11 select GENERIC_GPIO
12- select SYS_HAS_EARLY_PRINTK
13 select CFE
14 help
15 Support for BCM47XX based boards
16@@ -195,7 +195,6 @@ config MIPS_MALTA
17 select I8259
18 select MIPS_BOARDS_GEN
19 select MIPS_BONITO64
20- select MIPS_CPU_SCACHE
21 select PCI_GT64XXX_PCI0
22 select MIPS_MSC
23 select SWAP_IO_SPACE
24@@ -1455,13 +1454,6 @@ config IP22_CPU_SCACHE
25 bool
26 select BOARD_SCACHE
27
28-#
29-# Support for a MIPS32 / MIPS64 style S-caches
30-#
31-config MIPS_CPU_SCACHE
32- bool
33- select BOARD_SCACHE
34-
35 config R5000_CPU_SCACHE
36 bool
37 select BOARD_SCACHE
38diff --git a/arch/mips/bcm47xx/Makefile b/arch/mips/bcm47xx/Makefile
39index 35294b1..9e62430 100644
40--- a/arch/mips/bcm47xx/Makefile
41+++ b/arch/mips/bcm47xx/Makefile
42@@ -3,4 +3,4 @@
43 # under Linux.
44 #
45
46-obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o
47+obj-y := cfe_env.o gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
48diff --git a/arch/mips/bcm47xx/cfe_env.c b/arch/mips/bcm47xx/cfe_env.c
49new file mode 100644
50index 0000000..c1d5eee
51--- /dev/null
52+++ b/arch/mips/bcm47xx/cfe_env.c
53@@ -0,0 +1,229 @@
54+/*
55+ * CFE environment variable access
56+ *
57+ * Copyright 2001-2003, Broadcom Corporation
58+ * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
59+ *
60+ * This program is free software; you can redistribute it and/or modify it
61+ * under the terms of the GNU General Public License as published by the
62+ * Free Software Foundation; either version 2 of the License, or (at your
63+ * option) any later version.
64+ */
65+
66+#include <linux/init.h>
67+#include <linux/module.h>
68+#include <linux/kernel.h>
69+#include <linux/string.h>
70+#include <asm/io.h>
71+#include <asm/uaccess.h>
72+
73+#define NVRAM_SIZE (0x1ff0)
74+static char _nvdata[NVRAM_SIZE];
75+static char _valuestr[256];
76+
77+/*
78+ * TLV types. These codes are used in the "type-length-value"
79+ * encoding of the items stored in the NVRAM device (flash or EEPROM)
80+ *
81+ * The layout of the flash/nvram is as follows:
82+ *
83+ * <type> <length> <data ...> <type> <length> <data ...> <type_end>
84+ *
85+ * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
86+ * The "length" field marks the length of the data section, not
87+ * including the type and length fields.
88+ *
89+ * Environment variables are stored as follows:
90+ *
91+ * <type_env> <length> <flags> <name> = <value>
92+ *
93+ * If bit 0 (low bit) is set, the length is an 8-bit value.
94+ * If bit 0 (low bit) is clear, the length is a 16-bit value
95+ *
96+ * Bit 7 set indicates "user" TLVs. In this case, bit 0 still
97+ * indicates the size of the length field.
98+ *
99+ * Flags are from the constants below:
100+ *
101+ */
102+#define ENV_LENGTH_16BITS 0x00 /* for low bit */
103+#define ENV_LENGTH_8BITS 0x01
104+
105+#define ENV_TYPE_USER 0x80
106+
107+#define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
108+#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
109+
110+/*
111+ * The actual TLV types we support
112+ */
113+
114+#define ENV_TLV_TYPE_END 0x00
115+#define ENV_TLV_TYPE_ENV ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
116+
117+/*
118+ * Environment variable flags
119+ */
120+
121+#define ENV_FLG_NORMAL 0x00 /* normal read/write */
122+#define ENV_FLG_BUILTIN 0x01 /* builtin - not stored in flash */
123+#define ENV_FLG_READONLY 0x02 /* read-only - cannot be changed */
124+
125+#define ENV_FLG_MASK 0xFF /* mask of attributes we keep */
126+#define ENV_FLG_ADMIN 0x100 /* lets us internally override permissions */
127+
128+
129+/* *********************************************************************
130+ * _nvram_read(buffer,offset,length)
131+ *
132+ * Read data from the NVRAM device
133+ *
134+ * Input parameters:
135+ * buffer - destination buffer
136+ * offset - offset of data to read
137+ * length - number of bytes to read
138+ *
139+ * Return value:
140+ * number of bytes read, or <0 if error occured
141+ ********************************************************************* */
142+static int
143+_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
144+{
145+ int i;
146+ if (offset > NVRAM_SIZE)
147+ return -1;
148+
149+ for ( i = 0; i < length; i++) {
150+ buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
151+ }
152+ return length;
153+}
154+
155+
156+static char*
157+_strnchr(const char *dest,int c,size_t cnt)
158+{
159+ while (*dest && (cnt > 0)) {
160+ if (*dest == c) return (char *) dest;
161+ dest++;
162+ cnt--;
163+ }
164+ return NULL;
165+}
166+
167+
168+
169+/*
170+ * Core support API: Externally visible.
171+ */
172+
173+/*
174+ * Get the value of an NVRAM variable
175+ * @param name name of variable to get
176+ * @return value of variable or NULL if undefined
177+ */
178+
179+char*
180+cfe_env_get(unsigned char *nv_buf, char* name)
181+{
182+ int size;
183+ unsigned char *buffer;
184+ unsigned char *ptr;
185+ unsigned char *envval;
186+ unsigned int reclen;
187+ unsigned int rectype;
188+ int offset;
189+ int flg;
190+
191+ if (!strcmp(name, "nvram_type"))
192+ return "cfe";
193+
194+ size = NVRAM_SIZE;
195+ buffer = &_nvdata[0];
196+
197+ ptr = buffer;
198+ offset = 0;
199+
200+ /* Read the record type and length */
201+ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
202+ goto error;
203+ }
204+
205+ while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) {
206+
207+ /* Adjust pointer for TLV type */
208+ rectype = *(ptr);
209+ offset++;
210+ size--;
211+
212+ /*
213+ * Read the length. It can be either 1 or 2 bytes
214+ * depending on the code
215+ */
216+ if (rectype & ENV_LENGTH_8BITS) {
217+ /* Read the record type and length - 8 bits */
218+ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
219+ goto error;
220+ }
221+ reclen = *(ptr);
222+ size--;
223+ offset++;
224+ }
225+ else {
226+ /* Read the record type and length - 16 bits, MSB first */
227+ if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
228+ goto error;
229+ }
230+ reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
231+ size -= 2;
232+ offset += 2;
233+ }
234+
235+ if (reclen > size)
236+ break; /* should not happen, bad NVRAM */
237+
238+ switch (rectype) {
239+ case ENV_TLV_TYPE_ENV:
240+ /* Read the TLV data */
241+ if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
242+ goto error;
243+ flg = *ptr++;
244+ envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
245+ if (envval) {
246+ *envval++ = '\0';
247+ memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
248+ _valuestr[(reclen-1)-(envval-ptr)] = '\0';
249+#if 0
250+ printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
251+#endif
252+ if(!strcmp(ptr, name)){
253+ return _valuestr;
254+ }
255+ if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
256+ return _valuestr;
257+ }
258+ break;
259+
260+ default:
261+ /* Unknown TLV type, skip it. */
262+ break;
263+ }
264+
265+ /*
266+ * Advance to next TLV
267+ */
268+
269+ size -= (int)reclen;
270+ offset += reclen;
271+
272+ /* Read the next record type */
273+ ptr = buffer;
274+ if (_nvram_read(nv_buf, ptr,offset,1) != 1)
275+ goto error;
276+ }
277+
278+error:
279+ return NULL;
280+
281+}
282+
283diff --git a/arch/mips/bcm47xx/include/nvram.h b/arch/mips/bcm47xx/include/nvram.h
284new file mode 100644
285index 0000000..6bb18e8
286--- /dev/null
287+++ b/arch/mips/bcm47xx/include/nvram.h
288@@ -0,0 +1,37 @@
289+/*
290+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
291+ *
292+ * This program is free software; you can redistribute it and/or modify it
293+ * under the terms of the GNU General Public License as published by the
294+ * Free Software Foundation; either version 2 of the License, or (at your
295+ * option) any later version.
296+ */
297+
298+#ifndef __NVRAM_H
299+#define __NVRAM_H
300+
301+struct nvram_header {
302+ u32 magic;
303+ u32 len;
304+ u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
305+ u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
306+ u32 config_ncdl; /* ncdl values for memc */
307+};
308+
309+struct nvram_tuple {
310+ char *name;
311+ char *value;
312+ struct nvram_tuple *next;
313+};
314+
315+#define NVRAM_HEADER 0x48534C46 /* 'FLSH' */
316+#define NVRAM_VERSION 1
317+#define NVRAM_HEADER_SIZE 20
318+#define NVRAM_SPACE 0x8000
319+
320+#define NVRAM_MAX_VALUE_LEN 255
321+#define NVRAM_MAX_PARAM_LEN 64
322+
323+char *nvram_get(const char *name);
324+
325+#endif
326diff --git a/arch/mips/bcm47xx/irq.c b/arch/mips/bcm47xx/irq.c
327index 325757a..f087cf6 100644
328--- a/arch/mips/bcm47xx/irq.c
329+++ b/arch/mips/bcm47xx/irq.c
330@@ -1,5 +1,6 @@
331 /*
332 * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
333+ * Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
334 *
335 * This program is free software; you can redistribute it and/or modify it
336 * under the terms of the GNU General Public License as published by the
337@@ -23,10 +24,19 @@
338 */
339
340 #include <linux/types.h>
341+#include <linux/errno.h>
342+#include <linux/init.h>
343 #include <linux/interrupt.h>
344 #include <linux/irq.h>
345+#include <linux/pci.h>
346+#include <linux/ssb/ssb.h>
347+
348 #include <asm/irq_cpu.h>
349
350+
351+extern struct ssb_bus ssb_bcm47xx;
352+
353+
354 void plat_irq_dispatch(void)
355 {
356 u32 cause;
357diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
358new file mode 100644
359index 0000000..71a2106
360--- /dev/null
361+++ b/arch/mips/bcm47xx/nvram.c
362@@ -0,0 +1,125 @@
363+/*
364+ * BCM947xx nvram variable access
365+ *
366+ * Copyright 2005, Broadcom Corporation
367+ * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
368+ *
369+ * This program is free software; you can redistribute it and/or modify it
370+ * under the terms of the GNU General Public License as published by the
371+ * Free Software Foundation; either version 2 of the License, or (at your
372+ * option) any later version.
373+ */
374+
375+#include <linux/init.h>
376+#include <linux/module.h>
377+#include <linux/ssb/ssb.h>
378+#include <linux/kernel.h>
379+#include <linux/string.h>
380+#include <linux/interrupt.h>
381+#include <linux/spinlock.h>
382+#include <linux/slab.h>
383+#include <asm/byteorder.h>
384+#include <asm/bootinfo.h>
385+#include <asm/addrspace.h>
386+#include <asm/io.h>
387+#include <asm/uaccess.h>
388+
389+#include "include/nvram.h"
390+
391+#define MB * 1048576
392+extern struct ssb_bus ssb_bcm47xx;
393+
394+static char nvram_buf[NVRAM_SPACE];
395+static int cfe_env;
396+extern char *cfe_env_get(char *nv_buf, const char *name);
397+
398+/* Probe for NVRAM header */
399+static void __init early_nvram_init(void)
400+{
401+ struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
402+ struct nvram_header *header;
403+ int i;
404+ u32 base, lim, off;
405+ u32 *src, *dst;
406+
407+ base = mcore->flash_window;
408+ lim = mcore->flash_window_size;
409+ cfe_env = 0;
410+
411+
412+ /* XXX: hack for supporting the CFE environment stuff on WGT634U */
413+ if (lim >= 8 MB) {
414+ src = (u32 *) KSEG1ADDR(base + 8 MB - 0x2000);
415+ dst = (u32 *) nvram_buf;
416+
417+ if ((*src & 0xff00ff) == 0x000001) {
418+ printk("early_nvram_init: WGT634U NVRAM found.\n");
419+
420+ for (i = 0; i < 0x1ff0; i++) {
421+ if (*src == 0xFFFFFFFF)
422+ break;
423+ *dst++ = *src++;
424+ }
425+ cfe_env = 1;
426+ return;
427+ }
428+ }
429+
430+ off = 0x20000;
431+ while (off <= lim) {
432+ /* Windowed flash access */
433+ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
434+ if (header->magic == NVRAM_HEADER)
435+ goto found;
436+ off <<= 1;
437+ }
438+
439+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
440+ header = (struct nvram_header *) KSEG1ADDR(base + 4096);
441+ if (header->magic == NVRAM_HEADER)
442+ goto found;
443+
444+ header = (struct nvram_header *) KSEG1ADDR(base + 1024);
445+ if (header->magic == NVRAM_HEADER)
446+ goto found;
447+
448+ return;
449+
450+found:
451+ src = (u32 *) header;
452+ dst = (u32 *) nvram_buf;
453+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
454+ *dst++ = *src++;
455+ for (; i < header->len && i < NVRAM_SPACE; i += 4)
456+ *dst++ = le32_to_cpu(*src++);
457+}
458+
459+char *nvram_get(const char *name)
460+{
461+ char *var, *value, *end, *eq;
462+
463+ if (!name)
464+ return NULL;
465+
466+ if (!nvram_buf[0])
467+ early_nvram_init();
468+
469+ if (cfe_env)
470+ return cfe_env_get(nvram_buf, name);
471+
472+ /* Look for name=value and return value */
473+ var = &nvram_buf[sizeof(struct nvram_header)];
474+ end = nvram_buf + sizeof(nvram_buf) - 2;
475+ end[0] = end[1] = '\0';
476+ for (; *var; var = value + strlen(value) + 1) {
477+ if (!(eq = strchr(var, '=')))
478+ break;
479+ value = eq + 1;
480+ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
481+ return value;
482+ }
483+
484+ return NULL;
485+}
486+
487+EXPORT_SYMBOL(nvram_get);
488diff --git a/arch/mips/bcm47xx/prom.c b/arch/mips/bcm47xx/prom.c
489index 079e33d..75132cf 100644
490--- a/arch/mips/bcm47xx/prom.c
491+++ b/arch/mips/bcm47xx/prom.c
492@@ -32,6 +32,7 @@
493 #include <asm/fw/cfe/cfe_error.h>
494
495 static int cfe_cons_handle;
496+static void (* __prom_putchar)(char c);
497
498 const char *get_system_type(void)
499 {
500@@ -40,65 +41,40 @@ const char *get_system_type(void)
501
502 void prom_putchar(char c)
503 {
504+ if (__prom_putchar)
505+ __prom_putchar(c);
506+}
507+
508+void prom_putchar_cfe(char c)
509+{
510 while (cfe_write(cfe_cons_handle, &c, 1) == 0)
511 ;
512 }
513
514-static __init void prom_init_cfe(void)
515+static __init int prom_init_cfe(void)
516 {
517 uint32_t cfe_ept;
518 uint32_t cfe_handle;
519 uint32_t cfe_eptseal;
520- int argc = fw_arg0;
521- char **envp = (char **) fw_arg2;
522- int *prom_vec = (int *) fw_arg3;
523
524- /*
525- * Check if a loader was used; if NOT, the 4 arguments are
526- * what CFE gives us (handle, 0, EPT and EPTSEAL)
527- */
528- if (argc < 0) {
529- cfe_handle = (uint32_t)argc;
530- cfe_ept = (uint32_t)envp;
531- cfe_eptseal = (uint32_t)prom_vec;
532- } else {
533- if ((int)prom_vec < 0) {
534- /*
535- * Old loader; all it gives us is the handle,
536- * so use the "known" entrypoint and assume
537- * the seal.
538- */
539- cfe_handle = (uint32_t)prom_vec;
540- cfe_ept = 0xBFC00500;
541- cfe_eptseal = CFE_EPTSEAL;
542- } else {
543- /*
544- * Newer loaders bundle the handle/ept/eptseal
545- * Note: prom_vec is in the loader's useg
546- * which is still alive in the TLB.
547- */
548- cfe_handle = prom_vec[0];
549- cfe_ept = prom_vec[2];
550- cfe_eptseal = prom_vec[3];
551- }
552- }
553+ cfe_eptseal = (uint32_t) fw_arg3;
554+ cfe_handle = (uint32_t) fw_arg0;
555+ cfe_ept = (uint32_t) fw_arg2;
556
557- if (cfe_eptseal != CFE_EPTSEAL) {
558- /* too early for panic to do any good */
559- printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
560- while (1) ;
561- }
562+ if (cfe_eptseal != CFE_EPTSEAL)
563+ return -1;
564
565 cfe_init(cfe_handle, cfe_ept);
566+ return 0;
567 }
568
569-static __init void prom_init_console(void)
570+static __init void prom_init_console_cfe(void)
571 {
572 /* Initialize CFE console */
573 cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
574 }
575
576-static __init void prom_init_cmdline(void)
577+static __init void prom_init_cmdline_cfe(void)
578 {
579 char buf[CL_SIZE];
580
581@@ -146,9 +122,12 @@ static __init void prom_init_mem(void)
582
583 void __init prom_init(void)
584 {
585- prom_init_cfe();
586- prom_init_console();
587- prom_init_cmdline();
588+ if (prom_init_cfe() == 0) {
589+ //prom_init_console_cfe();
590+ //prom_init_cmdline_cfe();
591+ __prom_putchar = prom_putchar_cfe;
592+ }
593+
594 prom_init_mem();
595 }
596
597diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
598index 2f580fa..0a7bd49 100644
599--- a/arch/mips/bcm47xx/setup.c
600+++ b/arch/mips/bcm47xx/setup.c
601@@ -2,7 +2,7 @@
602 * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
603 * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
604 * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
605- * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
606+ * Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de>
607 *
608 * This program is free software; you can redistribute it and/or modify it
609 * under the terms of the GNU General Public License as published by the
610@@ -25,18 +25,28 @@
611 * 675 Mass Ave, Cambridge, MA 02139, USA.
612 */
613
614+#include <linux/init.h>
615 #include <linux/types.h>
616 #include <linux/ssb/ssb.h>
617 #include <linux/ssb/ssb_embedded.h>
618+#include <linux/tty.h>
619+#include <linux/serial.h>
620+#include <linux/serial_core.h>
621+#include <linux/serial_reg.h>
622+#include <linux/serial_8250.h>
623 #include <asm/bootinfo.h>
624 #include <asm/reboot.h>
625 #include <asm/time.h>
626-#include <bcm47xx.h>
627 #include <asm/fw/cfe/cfe_api.h>
628+#include <linux/pm.h>
629+
630+#include "include/nvram.h"
631
632 struct ssb_bus ssb_bcm47xx;
633 EXPORT_SYMBOL(ssb_bcm47xx);
634
635+extern void bcm47xx_pci_init(void);
636+
637 static void bcm47xx_machine_restart(char *command)
638 {
639 printk(KERN_ALERT "Please stand by while rebooting the system...\n");
640@@ -56,7 +66,7 @@ static void bcm47xx_machine_halt(void)
641 cpu_relax();
642 }
643
644-static void str2eaddr(char *str, char *dest)
645+static void e_aton(char *str, char *dest)
646 {
647 int i = 0;
648
649@@ -73,52 +83,142 @@ static void str2eaddr(char *str, char *dest)
650 }
651 }
652
653-static int bcm47xx_get_invariants(struct ssb_bus *bus,
654- struct ssb_init_invariants *iv)
655+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
656+{
657+ char *s;
658+
659+ memset(sprom, 0xFF, sizeof(struct ssb_sprom));
660+
661+ sprom->revision = 1;
662+ if ((s = nvram_get("il0macaddr")))
663+ e_aton(s, sprom->il0mac);
664+ if ((s = nvram_get("et0macaddr")))
665+ e_aton(s, sprom->et0mac);
666+ if ((s = nvram_get("et1macaddr")))
667+ e_aton(s, sprom->et1mac);
668+ if ((s = nvram_get("et0phyaddr")))
669+ sprom->et0phyaddr = simple_strtoul(s, NULL, 0);
670+ if ((s = nvram_get("et1phyaddr")))
671+ sprom->et1phyaddr = simple_strtoul(s, NULL, 0);
672+ if ((s = nvram_get("et0mdcport")))
673+ sprom->et0mdcport = !!simple_strtoul(s, NULL, 10);
674+ if ((s = nvram_get("et1mdcport")))
675+ sprom->et1mdcport = !!simple_strtoul(s, NULL, 10);
676+ if ((s = nvram_get("pa0b0")))
677+ sprom->pa0b0 = simple_strtoul(s, NULL, 0);
678+ if ((s = nvram_get("pa0b1")))
679+ sprom->pa0b1 = simple_strtoul(s, NULL, 0);
680+ if ((s = nvram_get("pa0b2")))
681+ sprom->pa0b2 = simple_strtoul(s, NULL, 0);
682+ if ((s = nvram_get("pa1b0")))
683+ sprom->pa1b0 = simple_strtoul(s, NULL, 0);
684+ if ((s = nvram_get("pa1b1")))
685+ sprom->pa1b1 = simple_strtoul(s, NULL, 0);
686+ if ((s = nvram_get("pa1b2")))
687+ sprom->pa1b2 = simple_strtoul(s, NULL, 0);
688+ if ((s = nvram_get("wl0gpio0")))
689+ sprom->gpio0 = simple_strtoul(s, NULL, 0);
690+ if ((s = nvram_get("wl0gpio1")))
691+ sprom->gpio1 = simple_strtoul(s, NULL, 0);
692+ if ((s = nvram_get("wl0gpio2")))
693+ sprom->gpio2 = simple_strtoul(s, NULL, 0);
694+ if ((s = nvram_get("wl0gpio3")))
695+ sprom->gpio3 = simple_strtoul(s, NULL, 0);
696+ if ((s = nvram_get("pa0maxpwr")))
697+ sprom->maxpwr_bg = simple_strtoul(s, NULL, 0);
698+ if ((s = nvram_get("pa1maxpwr")))
699+ sprom->maxpwr_a = simple_strtoul(s, NULL, 0);
700+ if ((s = nvram_get("pa0itssit")))
701+ sprom->itssi_bg = simple_strtoul(s, NULL, 0);
702+ if ((s = nvram_get("pa1itssit")))
703+ sprom->itssi_a = simple_strtoul(s, NULL, 0);
704+ sprom->boardflags_lo = 0;
705+ if ((s = nvram_get("boardflags")))
706+ sprom->boardflags_lo = simple_strtoul(s, NULL, 0);
707+ sprom->boardflags_hi = 0;
708+ if ((s = nvram_get("boardflags2")))
709+ sprom->boardflags_hi = simple_strtoul(s, NULL, 0);
710+}
711+
712+static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv)
713 {
714- char buf[100];
715-
716- /* Fill boardinfo structure */
717- memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
718-
719- if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0)
720- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
721- if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
722- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
723- if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
724- iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
725-
726- /* Fill sprom structure */
727- memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
728- iv->sprom.revision = 3;
729-
730- if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
731- str2eaddr(buf, iv->sprom.et0mac);
732- if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
733- str2eaddr(buf, iv->sprom.et1mac);
734- if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
735- iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10);
736- if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
737- iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10);
738- if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
739- iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
740- if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
741- iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
742+ char *s;
743+
744+ iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
745+ if ((s = nvram_get("boardtype")))
746+ iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0);
747+ if ((s = nvram_get("boardrev")))
748+ iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0);
749+
750+ bcm47xx_fill_sprom(&iv->sprom);
751+
752+ if ((s = nvram_get("cardbus")))
753+ iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10);
754
755 return 0;
756 }
757
758 void __init plat_mem_setup(void)
759 {
760- int err;
761+ int i, err;
762+ char *s;
763+ struct ssb_mipscore *mcore;
764+
765+ err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants);
766+ if (err) {
767+ const char *msg = "Failed to initialize SSB bus (err %d)\n";
768+ printk(msg, err); /* Make sure the message gets out of the box. */
769+ panic(msg, err);
770+ }
771+ mcore = &ssb_bcm47xx.mipscore;
772
773- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
774- bcm47xx_get_invariants);
775- if (err)
776- panic("Failed to initialize SSB bus (err %d)\n", err);
777+ s = nvram_get("kernel_args");
778+ if (s && !strncmp(s, "console=ttyS1", 13)) {
779+ struct ssb_serial_port port;
780+
781+ printk("Swapping serial ports!\n");
782+ /* swap serial ports */
783+ memcpy(&port, &mcore->serial_ports[0], sizeof(port));
784+ memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
785+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
786+ }
787+
788+ for (i = 0; i < mcore->nr_serial_ports; i++) {
789+ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
790+ struct uart_port s;
791+
792+ memset(&s, 0, sizeof(s));
793+ s.line = i;
794+ s.mapbase = (unsigned int) port->regs;
795+ s.membase = port->regs;
796+ s.irq = port->irq + 2;
797+ s.uartclk = port->baud_base;
798+ s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
799+ s.iotype = SERIAL_IO_MEM;
800+ s.regshift = port->reg_shift;
801+
802+ early_serial_setup(&s);
803+ }
804+ printk("Serial init done.\n");
805
806 _machine_restart = bcm47xx_machine_restart;
807 _machine_halt = bcm47xx_machine_halt;
808 pm_power_off = bcm47xx_machine_halt;
809 }
810
811+static int __init bcm47xx_register_gpiodev(void)
812+{
813+ static struct resource res = {
814+ .start = 0xFFFFFFFF,
815+ };
816+ struct platform_device *pdev;
817+
818+ pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
819+ if (!pdev) {
820+ printk(KERN_ERR "bcm47xx: GPIODEV init failed\n");
821+ return -ENODEV;
822+ }
823+
824+ return 0;
825+}
826+device_initcall(bcm47xx_register_gpiodev);
827diff --git a/arch/mips/bcm47xx/time.c b/arch/mips/bcm47xx/time.c
828index 0c6f47b..08c23ad 100644
829--- a/arch/mips/bcm47xx/time.c
830+++ b/arch/mips/bcm47xx/time.c
831@@ -22,11 +22,17 @@
832 * 675 Mass Ave, Cambridge, MA 02139, USA.
833 */
834
835-
836 #include <linux/init.h>
837+#include <linux/kernel.h>
838+#include <linux/sched.h>
839+#include <linux/serial_reg.h>
840+#include <linux/interrupt.h>
841 #include <linux/ssb/ssb.h>
842+#include <asm/addrspace.h>
843+#include <asm/io.h>
844 #include <asm/time.h>
845-#include <bcm47xx.h>
846+
847+extern struct ssb_bus ssb_bcm47xx;
848
849 void __init plat_time_init(void)
850 {
851diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
852deleted file mode 100644
853index ef00e7f..0000000
854--- a/arch/mips/bcm47xx/wgt634u.c
855+++ /dev/null
856@@ -1,167 +0,0 @@
857-/*
858- * This file is subject to the terms and conditions of the GNU General Public
859- * License. See the file "COPYING" in the main directory of this archive
860- * for more details.
861- *
862- * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net>
863- */
864-
865-#include <linux/platform_device.h>
866-#include <linux/module.h>
867-#include <linux/leds.h>
868-#include <linux/mtd/physmap.h>
869-#include <linux/ssb/ssb.h>
870-#include <linux/interrupt.h>
871-#include <linux/reboot.h>
872-#include <linux/gpio.h>
873-#include <asm/mach-bcm47xx/bcm47xx.h>
874-
875-/* GPIO definitions for the WGT634U */
876-#define WGT634U_GPIO_LED 3
877-#define WGT634U_GPIO_RESET 2
878-#define WGT634U_GPIO_TP1 7
879-#define WGT634U_GPIO_TP2 6
880-#define WGT634U_GPIO_TP3 5
881-#define WGT634U_GPIO_TP4 4
882-#define WGT634U_GPIO_TP5 1
883-
884-static struct gpio_led wgt634u_leds[] = {
885- {
886- .name = "power",
887- .gpio = WGT634U_GPIO_LED,
888- .active_low = 1,
889- .default_trigger = "heartbeat",
890- },
891-};
892-
893-static struct gpio_led_platform_data wgt634u_led_data = {
894- .num_leds = ARRAY_SIZE(wgt634u_leds),
895- .leds = wgt634u_leds,
896-};
897-
898-static struct platform_device wgt634u_gpio_leds = {
899- .name = "leds-gpio",
900- .id = -1,
901- .dev = {
902- .platform_data = &wgt634u_led_data,
903- }
904-};
905-
906-
907-/* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U
908- firmware. */
909-static struct mtd_partition wgt634u_partitions[] = {
910- {
911- .name = "cfe",
912- .offset = 0,
913- .size = 0x60000, /* 384k */
914- .mask_flags = MTD_WRITEABLE /* force read-only */
915- },
916- {
917- .name = "config",
918- .offset = 0x60000,
919- .size = 0x20000 /* 128k */
920- },
921- {
922- .name = "linux",
923- .offset = 0x80000,
924- .size = 0x140000 /* 1280k */
925- },
926- {
927- .name = "jffs",
928- .offset = 0x1c0000,
929- .size = 0x620000 /* 6272k */
930- },
931- {
932- .name = "nvram",
933- .offset = 0x7e0000,
934- .size = 0x20000 /* 128k */
935- },
936-};
937-
938-static struct physmap_flash_data wgt634u_flash_data = {
939- .parts = wgt634u_partitions,
940- .nr_parts = ARRAY_SIZE(wgt634u_partitions)
941-};
942-
943-static struct resource wgt634u_flash_resource = {
944- .flags = IORESOURCE_MEM,
945-};
946-
947-static struct platform_device wgt634u_flash = {
948- .name = "physmap-flash",
949- .id = 0,
950- .dev = { .platform_data = &wgt634u_flash_data, },
951- .resource = &wgt634u_flash_resource,
952- .num_resources = 1,
953-};
954-
955-/* Platform devices */
956-static struct platform_device *wgt634u_devices[] __initdata = {
957- &wgt634u_flash,
958- &wgt634u_gpio_leds,
959-};
960-
961-static irqreturn_t gpio_interrupt(int irq, void *ignored)
962-{
963- int state;
964-
965- /* Interrupts are shared, check if the current one is
966- a GPIO interrupt. */
967- if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
968- SSB_CHIPCO_IRQ_GPIO))
969- return IRQ_NONE;
970-
971- state = gpio_get_value(WGT634U_GPIO_RESET);
972-
973- /* Interrupt are level triggered, revert the interrupt polarity
974- to clear the interrupt. */
975- gpio_polarity(WGT634U_GPIO_RESET, state);
976-
977- if (!state) {
978- printk(KERN_INFO "Reset button pressed");
979- ctrl_alt_del();
980- }
981-
982- return IRQ_HANDLED;
983-}
984-
985-static int __init wgt634u_init(void)
986-{
987- /* There is no easy way to detect that we are running on a WGT634U
988- * machine. Use the MAC address as an heuristic. Netgear Inc. has
989- * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
990- */
991-
992- u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
993-
994- if (et0mac[0] == 0x00 &&
995- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
996- (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
997- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
998-
999- printk(KERN_INFO "WGT634U machine detected.\n");
1000-
1001- if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
1002- gpio_interrupt, IRQF_SHARED,
1003- "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
1004- gpio_direction_input(WGT634U_GPIO_RESET);
1005- gpio_intmask(WGT634U_GPIO_RESET, 1);
1006- ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
1007- SSB_CHIPCO_IRQ_GPIO,
1008- SSB_CHIPCO_IRQ_GPIO);
1009- }
1010-
1011- wgt634u_flash_data.width = mcore->flash_buswidth;
1012- wgt634u_flash_resource.start = mcore->flash_window;
1013- wgt634u_flash_resource.end = mcore->flash_window
1014- + mcore->flash_window_size
1015- - 1;
1016- return platform_add_devices(wgt634u_devices,
1017- ARRAY_SIZE(wgt634u_devices));
1018- } else
1019- return -ENODEV;
1020-}
1021-
1022-module_init(wgt634u_init);
1023-
1024diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h
1025index 610fe3a..35d7d8f 100644
1026--- a/arch/mips/include/asm/bootinfo.h
1027+++ b/arch/mips/include/asm/bootinfo.h
1028@@ -57,6 +57,12 @@
1029 #define MACH_MIKROTIK_RB532 0 /* Mikrotik RouterBoard 532 */
1030 #define MACH_MIKROTIK_RB532A 1 /* Mikrotik RouterBoard 532A */
1031
1032+/*
1033+ * Valid machtype for group Broadcom
1034+ */
1035+#define MACH_GROUP_BRCM 23 /* Broadcom */
1036+#define MACH_BCM47XX 1 /* Broadcom BCM47xx */
1037+
1038 #define CL_SIZE COMMAND_LINE_SIZE
1039
1040 extern char *system_type;
1041diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
1042index 03b1d69..517bb16 100644
1043--- a/arch/mips/include/asm/cacheflush.h
1044+++ b/arch/mips/include/asm/cacheflush.h
1045@@ -32,7 +32,7 @@
1046 extern void (*flush_cache_all)(void);
1047 extern void (*__flush_cache_all)(void);
1048 extern void (*flush_cache_mm)(struct mm_struct *mm);
1049-#define flush_cache_dup_mm(mm) do { (void) (mm); } while (0)
1050+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
1051 extern void (*flush_cache_range)(struct vm_area_struct *vma,
1052 unsigned long start, unsigned long end);
1053 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
1054diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
1055index c0047f8..e7591aa 100644
1056--- a/arch/mips/include/asm/cpu-features.h
1057+++ b/arch/mips/include/asm/cpu-features.h
1058@@ -104,6 +104,9 @@
1059 #ifndef cpu_has_pindexed_dcache
1060 #define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
1061 #endif
1062+#ifndef cpu_use_kmap_coherent
1063+#define cpu_use_kmap_coherent 1
1064+#endif
1065
1066 /*
1067 * I-Cache snoops remote store. This only matters on SMP. Some multiprocessors
1068diff --git a/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h
1069new file mode 100644
1070index 0000000..b4fe0c3
1071--- /dev/null
1072+++ b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h
1073@@ -0,0 +1,13 @@
1074+/*
1075+ * This file is subject to the terms and conditions of the GNU General Public
1076+ * License. See the file "COPYING" in the main directory of this archive
1077+ * for more details.
1078+ *
1079+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
1080+ */
1081+#ifndef __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
1082+#define __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
1083+
1084+#define cpu_use_kmap_coherent 0
1085+
1086+#endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */
1087diff --git a/arch/mips/include/asm/mach-bcm47xx/kernel-entry-init.h b/arch/mips/include/asm/mach-bcm47xx/kernel-entry-init.h
1088new file mode 100644
1089index 0000000..7df0dc2
1090--- /dev/null
1091+++ b/arch/mips/include/asm/mach-bcm47xx/kernel-entry-init.h
1092@@ -0,0 +1,26 @@
1093+/*
1094+ * This file is subject to the terms and conditions of the GNU General Public
1095+ * License. See the file "COPYING" in the main directory of this archive
1096+ * for more details.
1097+ *
1098+ * Copyright (C) 2005 Embedded Alley Solutions, Inc
1099+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
1100+ * Copyright (C) 2006 Michael Buesch
1101+ */
1102+#ifndef __ASM_MACH_GENERIC_KERNEL_ENTRY_H
1103+#define __ASM_MACH_GENERIC_KERNEL_ENTRY_H
1104+
1105+/* Intentionally empty macro, used in head.S. Override in
1106+ * arch/mips/mach-xxx/kernel-entry-init.h when necessary.
1107+ */
1108+ .macro kernel_entry_setup
1109+ .endm
1110+
1111+/*
1112+ * Do SMP slave processor setup necessary before we can savely execute C code.
1113+ */
1114+ .macro smp_slave_setup
1115+ .endm
1116+
1117+
1118+#endif /* __ASM_MACH_GENERIC_KERNEL_ENTRY_H */
1119diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
1120index 9f946e4..65ccdf2 100644
1121--- a/arch/mips/include/asm/page.h
1122+++ b/arch/mips/include/asm/page.h
1123@@ -35,6 +35,7 @@
1124 #ifndef __ASSEMBLY__
1125
1126 #include <linux/pfn.h>
1127+#include <asm/cpu-features.h>
1128 #include <asm/io.h>
1129
1130 extern void build_clear_page(void);
1131@@ -70,13 +71,16 @@ static inline void clear_user_page(void *addr, unsigned long vaddr,
1132 flush_data_cache_page((unsigned long)addr);
1133 }
1134
1135-extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
1136- struct page *to);
1137-struct vm_area_struct;
1138-extern void copy_user_highpage(struct page *to, struct page *from,
1139- unsigned long vaddr, struct vm_area_struct *vma);
1140+static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
1141+ struct page *to)
1142+{
1143+ extern void (*flush_data_cache_page)(unsigned long addr);
1144
1145-#define __HAVE_ARCH_COPY_USER_HIGHPAGE
1146+ copy_page(vto, vfrom);
1147+ if (!cpu_has_ic_fills_f_dc ||
1148+ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
1149+ flush_data_cache_page((unsigned long)vto);
1150+}
1151
1152 /*
1153 * These are used to make use of C type-checking..
1154diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
1155index 4c140db..befb69e 100644
1156--- a/arch/mips/include/asm/r4kcache.h
1157+++ b/arch/mips/include/asm/r4kcache.h
1158@@ -17,6 +17,35 @@
1159 #include <asm/cpu-features.h>
1160 #include <asm/mipsmtregs.h>
1161
1162+#ifdef CONFIG_BCM47XX
1163+#include <asm/paccess.h>
1164+#include <linux/ssb/ssb.h>
1165+#define BCM4710_DUMMY_RREG() bcm4710_dummy_rreg()
1166+
1167+static inline unsigned long bcm4710_dummy_rreg(void) {
1168+ return (*(volatile unsigned long *)(KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)));
1169+}
1170+
1171+#define BCM4710_FILL_TLB(addr) bcm4710_fill_tlb((void*)(addr))
1172+
1173+static inline unsigned long bcm4710_fill_tlb(void *addr) {
1174+ return (*(unsigned long *)addr);
1175+}
1176+
1177+#define BCM4710_PROTECTED_FILL_TLB(addr) bcm4710_protected_fill_tlb((void*)(addr))
1178+
1179+static inline void bcm4710_protected_fill_tlb(void *addr) {
1180+ unsigned long x;
1181+ get_dbe(x, (unsigned long *)addr);;
1182+}
1183+
1184+#else
1185+#define BCM4710_DUMMY_RREG()
1186+
1187+#define BCM4710_FILL_TLB(addr)
1188+#define BCM4710_PROTECTED_FILL_TLB(addr)
1189+#endif
1190+
1191 /*
1192 * This macro return a properly sign-extended address suitable as base address
1193 * for indexed cache operations. Two issues here:
1194@@ -150,6 +179,7 @@ static inline void flush_icache_line_indexed(unsigned long addr)
1195 static inline void flush_dcache_line_indexed(unsigned long addr)
1196 {
1197 __dflush_prologue
1198+ BCM4710_DUMMY_RREG();
1199 cache_op(Index_Writeback_Inv_D, addr);
1200 __dflush_epilogue
1201 }
1202@@ -169,6 +199,7 @@ static inline void flush_icache_line(unsigned long addr)
1203 static inline void flush_dcache_line(unsigned long addr)
1204 {
1205 __dflush_prologue
1206+ BCM4710_DUMMY_RREG();
1207 cache_op(Hit_Writeback_Inv_D, addr);
1208 __dflush_epilogue
1209 }
1210@@ -176,6 +207,7 @@ static inline void flush_dcache_line(unsigned long addr)
1211 static inline void invalidate_dcache_line(unsigned long addr)
1212 {
1213 __dflush_prologue
1214+ BCM4710_DUMMY_RREG();
1215 cache_op(Hit_Invalidate_D, addr);
1216 __dflush_epilogue
1217 }
1218@@ -208,6 +240,7 @@ static inline void flush_scache_line(unsigned long addr)
1219 */
1220 static inline void protected_flush_icache_line(unsigned long addr)
1221 {
1222+ BCM4710_DUMMY_RREG();
1223 protected_cache_op(Hit_Invalidate_I, addr);
1224 }
1225
1226@@ -219,6 +252,7 @@ static inline void protected_flush_icache_line(unsigned long addr)
1227 */
1228 static inline void protected_writeback_dcache_line(unsigned long addr)
1229 {
1230+ BCM4710_DUMMY_RREG();
1231 protected_cache_op(Hit_Writeback_Inv_D, addr);
1232 }
1233
1234@@ -339,8 +373,52 @@ static inline void invalidate_tcache_page(unsigned long addr)
1235 : "r" (base), \
1236 "i" (op));
1237
1238+static inline void blast_dcache(void)
1239+{
1240+ unsigned long start = KSEG0;
1241+ unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways;
1242+ unsigned long end = (start + dcache_size);
1243+
1244+ do {
1245+ BCM4710_DUMMY_RREG();
1246+ cache_op(Index_Writeback_Inv_D, start);
1247+ start += current_cpu_data.dcache.linesz;
1248+ } while(start < end);
1249+}
1250+
1251+static inline void blast_dcache_page(unsigned long page)
1252+{
1253+ unsigned long start = page;
1254+ unsigned long end = start + PAGE_SIZE;
1255+
1256+ BCM4710_FILL_TLB(start);
1257+ do {
1258+ BCM4710_DUMMY_RREG();
1259+ cache_op(Hit_Writeback_Inv_D, start);
1260+ start += current_cpu_data.dcache.linesz;
1261+ } while(start < end);
1262+}
1263+
1264+static inline void blast_dcache_page_indexed(unsigned long page)
1265+{
1266+ unsigned long start = page;
1267+ unsigned long end = start + PAGE_SIZE;
1268+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
1269+ unsigned long ws_end = current_cpu_data.dcache.ways <<
1270+ current_cpu_data.dcache.waybit;
1271+ unsigned long ws, addr;
1272+ for (ws = 0; ws < ws_end; ws += ws_inc) {
1273+ start = page + ws;
1274+ for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) {
1275+ BCM4710_DUMMY_RREG();
1276+ cache_op(Index_Writeback_Inv_D, addr);
1277+ }
1278+ }
1279+}
1280+
1281+
1282 /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
1283-#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \
1284+#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \
1285 static inline void blast_##pfx##cache##lsize(void) \
1286 { \
1287 unsigned long start = INDEX_BASE; \
1288@@ -352,6 +430,7 @@ static inline void blast_##pfx##cache##lsize(void) \
1289 \
1290 __##pfx##flush_prologue \
1291 \
1292+ war \
1293 for (ws = 0; ws < ws_end; ws += ws_inc) \
1294 for (addr = start; addr < end; addr += lsize * 32) \
1295 cache##lsize##_unroll32(addr|ws, indexop); \
1296@@ -366,6 +445,7 @@ static inline void blast_##pfx##cache##lsize##_page(unsigned long page) \
1297 \
1298 __##pfx##flush_prologue \
1299 \
1300+ war \
1301 do { \
1302 cache##lsize##_unroll32(start, hitop); \
1303 start += lsize * 32; \
1304@@ -384,6 +464,8 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page)
1305 current_cpu_data.desc.waybit; \
1306 unsigned long ws, addr; \
1307 \
1308+ war \
1309+ \
1310 __##pfx##flush_prologue \
1311 \
1312 for (ws = 0; ws < ws_end; ws += ws_inc) \
1313@@ -393,35 +475,37 @@ static inline void blast_##pfx##cache##lsize##_page_indexed(unsigned long page)
1314 __##pfx##flush_epilogue \
1315 }
1316
1317-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
1318-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
1319-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
1320-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
1321-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
1322-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
1323-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
1324-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
1325-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
1326-
1327-__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
1328-__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
1329-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
1330-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
1331-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
1332-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
1333+__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
1334+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);)
1335+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
1336+__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, )
1337+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, BCM4710_FILL_TLB(start);)
1338+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, )
1339+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
1340+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
1341+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
1342+
1343+__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, )
1344+__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32, )
1345+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16, )
1346+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32, )
1347+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
1348+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
1349
1350 /* build blast_xxx_range, protected_blast_xxx_range */
1351-#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
1352+#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war, war2) \
1353 static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
1354 unsigned long end) \
1355 { \
1356 unsigned long lsize = cpu_##desc##_line_size(); \
1357 unsigned long addr = start & ~(lsize - 1); \
1358 unsigned long aend = (end - 1) & ~(lsize - 1); \
1359+ war \
1360 \
1361 __##pfx##flush_prologue \
1362 \
1363 while (1) { \
1364+ war2 \
1365 prot##cache_op(hitop, addr); \
1366 if (addr == aend) \
1367 break; \
1368@@ -431,13 +515,13 @@ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
1369 __##pfx##flush_epilogue \
1370 }
1371
1372-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
1373-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
1374-__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
1375-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
1376-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
1377+__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
1378+__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_,, )
1379+__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_,, )
1380+__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D,, BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);, BCM4710_DUMMY_RREG();)
1381+__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD,,, )
1382 /* blast_inv_dcache_range */
1383-__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
1384-__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
1385+__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D,,,BCM4710_DUMMY_RREG();)
1386+__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
1387
1388 #endif /* _ASM_R4KCACHE_H */
1389diff --git a/arch/mips/include/asm/stackframe.h b/arch/mips/include/asm/stackframe.h
1390index db0fa7b..fd23784 100644
1391--- a/arch/mips/include/asm/stackframe.h
1392+++ b/arch/mips/include/asm/stackframe.h
1393@@ -426,6 +426,10 @@
1394 .macro RESTORE_SP_AND_RET
1395 LONG_L sp, PT_R29(sp)
1396 .set mips3
1397+#ifdef CONFIG_BCM47XX
1398+ nop
1399+ nop
1400+#endif
1401 eret
1402 .set mips0
1403 .endm
1404diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
1405index b13b8eb..8141700 100644
1406--- a/arch/mips/kernel/cpu-probe.c
1407+++ b/arch/mips/kernel/cpu-probe.c
1408@@ -753,6 +753,8 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
1409 case PRID_IMP_25KF:
1410 c->cputype = CPU_25KF;
1411 __cpu_name[cpu] = "MIPS 25Kc";
1412+ /* Probe for L2 cache */
1413+ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
1414 break;
1415 case PRID_IMP_34K:
1416 c->cputype = CPU_34K;
1417diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
1418index 8882e57..e6ddba2 100644
1419--- a/arch/mips/kernel/genex.S
1420+++ b/arch/mips/kernel/genex.S
1421@@ -22,6 +22,19 @@
1422 #include <asm/page.h>
1423 #include <asm/thread_info.h>
1424
1425+#ifdef CONFIG_BCM47XX
1426+# ifdef eret
1427+# undef eret
1428+# endif
1429+# define eret \
1430+ .set push; \
1431+ .set noreorder; \
1432+ nop; \
1433+ nop; \
1434+ eret; \
1435+ .set pop;
1436+#endif
1437+
1438 #define PANIC_PIC(msg) \
1439 .set push; \
1440 .set reorder; \
1441@@ -52,6 +65,9 @@ NESTED(except_vec1_generic, 0, sp)
1442 NESTED(except_vec3_generic, 0, sp)
1443 .set push
1444 .set noat
1445+#ifdef CONFIG_BCM47XX
1446+ nop
1447+#endif
1448 #if R5432_CP0_INTERRUPT_WAR
1449 mfc0 k0, CP0_INDEX
1450 #endif
1451@@ -75,6 +91,9 @@ NESTED(except_vec3_r4000, 0, sp)
1452 .set push
1453 .set mips3
1454 .set noat
1455+#ifdef CONFIG_BCM47XX
1456+ nop
1457+#endif
1458 mfc0 k1, CP0_CAUSE
1459 li k0, 31<<2
1460 andi k1, k1, 0x7c
1461diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
1462index d7ec955..d666c4e 100644
1463--- a/arch/mips/mm/Makefile
1464+++ b/arch/mips/mm/Makefile
1465@@ -32,6 +32,5 @@ obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-octeon.o cex-oct.o tlb-r4k.o
1466 obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
1467 obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
1468 obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
1469-obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
1470
1471 EXTRA_CFLAGS += -Werror
1472diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
1473index 171951d..258f8ca 100644
1474--- a/arch/mips/mm/c-r4k.c
1475+++ b/arch/mips/mm/c-r4k.c
1476@@ -34,6 +34,9 @@
1477 #include <asm/cacheflush.h> /* for run_uncached() */
1478
1479
1480+/* For enabling BCM4710 cache workarounds */
1481+int bcm4710 = 0;
1482+
1483 /*
1484 * Special Variant of smp_call_function for use by cache functions:
1485 *
1486@@ -104,6 +107,9 @@ static void __cpuinit r4k_blast_dcache_page_setup(void)
1487 {
1488 unsigned long dc_lsize = cpu_dcache_line_size();
1489
1490+ if (bcm4710)
1491+ r4k_blast_dcache_page = blast_dcache_page;
1492+ else
1493 if (dc_lsize == 0)
1494 r4k_blast_dcache_page = (void *)cache_noop;
1495 else if (dc_lsize == 16)
1496@@ -118,6 +124,9 @@ static void __cpuinit r4k_blast_dcache_page_indexed_setup(void)
1497 {
1498 unsigned long dc_lsize = cpu_dcache_line_size();
1499
1500+ if (bcm4710)
1501+ r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
1502+ else
1503 if (dc_lsize == 0)
1504 r4k_blast_dcache_page_indexed = (void *)cache_noop;
1505 else if (dc_lsize == 16)
1506@@ -132,6 +141,9 @@ static void __cpuinit r4k_blast_dcache_setup(void)
1507 {
1508 unsigned long dc_lsize = cpu_dcache_line_size();
1509
1510+ if (bcm4710)
1511+ r4k_blast_dcache = blast_dcache;
1512+ else
1513 if (dc_lsize == 0)
1514 r4k_blast_dcache = (void *)cache_noop;
1515 else if (dc_lsize == 16)
1516@@ -348,7 +360,7 @@ static inline void local_r4k___flush_cache_all(void * args)
1517 }
1518 }
1519
1520-static void r4k___flush_cache_all(void)
1521+void r4k___flush_cache_all(void)
1522 {
1523 r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1);
1524 }
1525@@ -482,7 +494,7 @@ static inline void local_r4k_flush_cache_page(void *args)
1526 */
1527 map_coherent = (cpu_has_dc_aliases &&
1528 page_mapped(page) && !Page_dcache_dirty(page));
1529- if (map_coherent)
1530+ if (map_coherent && cpu_use_kmap_coherent)
1531 vaddr = kmap_coherent(page, addr);
1532 else
1533 vaddr = kmap_atomic(page, KM_USER0);
1534@@ -505,14 +517,14 @@ static inline void local_r4k_flush_cache_page(void *args)
1535 }
1536
1537 if (vaddr) {
1538- if (map_coherent)
1539+ if (map_coherent && cpu_use_kmap_coherent)
1540 kunmap_coherent();
1541 else
1542 kunmap_atomic(vaddr, KM_USER0);
1543 }
1544 }
1545
1546-static void r4k_flush_cache_page(struct vm_area_struct *vma,
1547+void r4k_flush_cache_page(struct vm_area_struct *vma,
1548 unsigned long addr, unsigned long pfn)
1549 {
1550 struct flush_cache_page_args args;
1551@@ -667,6 +679,8 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
1552 unsigned long addr = (unsigned long) arg;
1553
1554 R4600_HIT_CACHEOP_WAR_IMPL;
1555+ BCM4710_PROTECTED_FILL_TLB(addr);
1556+ BCM4710_PROTECTED_FILL_TLB(addr + 4);
1557 if (dc_lsize)
1558 protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
1559 if (!cpu_icache_snoops_remote_store && scache_size)
1560@@ -1135,7 +1149,6 @@ static void __init loongson2_sc_init(void)
1561
1562 extern int r5k_sc_init(void);
1563 extern int rm7k_sc_init(void);
1564-extern int mips_sc_init(void);
1565
1566 static void __cpuinit setup_scache(void)
1567 {
1568@@ -1189,29 +1202,17 @@ static void __cpuinit setup_scache(void)
1569 #endif
1570
1571 default:
1572- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
1573- c->isa_level == MIPS_CPU_ISA_M32R2 ||
1574- c->isa_level == MIPS_CPU_ISA_M64R1 ||
1575- c->isa_level == MIPS_CPU_ISA_M64R2) {
1576-#ifdef CONFIG_MIPS_CPU_SCACHE
1577- if (mips_sc_init ()) {
1578- scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
1579- printk("MIPS secondary cache %ldkB, %s, linesize %d bytes.\n",
1580- scache_size >> 10,
1581- way_string[c->scache.ways], c->scache.linesz);
1582- }
1583-#else
1584- if (!(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
1585- panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
1586-#endif
1587- return;
1588- }
1589 sc_present = 0;
1590 }
1591
1592 if (!sc_present)
1593 return;
1594
1595+ if ((c->isa_level == MIPS_CPU_ISA_M32R1 ||
1596+ c->isa_level == MIPS_CPU_ISA_M64R1) &&
1597+ !(c->scache.flags & MIPS_CACHE_NOT_PRESENT))
1598+ panic("Dunno how to handle MIPS32 / MIPS64 second level cache");
1599+
1600 /* compute a couple of other cache variables */
1601 c->scache.waysize = scache_size / c->scache.ways;
1602
1603@@ -1298,6 +1299,17 @@ static void __cpuinit coherency_setup(void)
1604 * silly idea of putting something else there ...
1605 */
1606 switch (current_cpu_type()) {
1607+ case CPU_BCM3302:
1608+ {
1609+ u32 cm;
1610+ cm = read_c0_diag();
1611+ /* Enable icache */
1612+ cm |= (1 << 31);
1613+ /* Enable dcache */
1614+ cm |= (1 << 30);
1615+ write_c0_diag(cm);
1616+ }
1617+ break;
1618 case CPU_R4000PC:
1619 case CPU_R4000SC:
1620 case CPU_R4000MC:
1621@@ -1354,6 +1366,15 @@ void __cpuinit r4k_cache_init(void)
1622 break;
1623 }
1624
1625+ /* Check if special workarounds are required */
1626+#ifdef CONFIG_BCM47XX
1627+ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
1628+ printk("Enabling BCM4710A0 cache workarounds.\n");
1629+ bcm4710 = 1;
1630+ } else
1631+#endif
1632+ bcm4710 = 0;
1633+
1634 probe_pcache();
1635 setup_scache();
1636
1637@@ -1412,5 +1433,20 @@ void __cpuinit r4k_cache_init(void)
1638 #if !defined(CONFIG_MIPS_CMP)
1639 local_r4k___flush_cache_all(NULL);
1640 #endif
1641+#ifdef CONFIG_BCM47XX
1642+ {
1643+ static void (*_coherency_setup)(void);
1644+ _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
1645+ _coherency_setup();
1646+ }
1647+#else
1648 coherency_setup();
1649+#endif
1650 }
1651+
1652+// fuse package DCACHE BUG patch exports
1653+void (*fuse_flush_cache_all)(void) = r4k___flush_cache_all;
1654+void (*fuse_flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
1655+ unsigned long pfn) = r4k_flush_cache_page;
1656+EXPORT_SYMBOL(fuse_flush_cache_page);
1657+EXPORT_SYMBOL(fuse_flush_cache_all);
1658diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
1659index c551129..e733f78 100644
1660--- a/arch/mips/mm/init.c
1661+++ b/arch/mips/mm/init.c
1662@@ -198,35 +198,11 @@ void kunmap_coherent(void)
1663 preempt_check_resched();
1664 }
1665
1666-void copy_user_highpage(struct page *to, struct page *from,
1667- unsigned long vaddr, struct vm_area_struct *vma)
1668-{
1669- void *vfrom, *vto;
1670-
1671- vto = kmap_atomic(to, KM_USER1);
1672- if (cpu_has_dc_aliases &&
1673- page_mapped(from) && !Page_dcache_dirty(from)) {
1674- vfrom = kmap_coherent(from, vaddr);
1675- copy_page(vto, vfrom);
1676- kunmap_coherent();
1677- } else {
1678- vfrom = kmap_atomic(from, KM_USER0);
1679- copy_page(vto, vfrom);
1680- kunmap_atomic(vfrom, KM_USER0);
1681- }
1682- if ((!cpu_has_ic_fills_f_dc) ||
1683- pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
1684- flush_data_cache_page((unsigned long)vto);
1685- kunmap_atomic(vto, KM_USER1);
1686- /* Make sure this page is cleared on other CPU's too before using it */
1687- smp_wmb();
1688-}
1689-
1690 void copy_to_user_page(struct vm_area_struct *vma,
1691 struct page *page, unsigned long vaddr, void *dst, const void *src,
1692 unsigned long len)
1693 {
1694- if (cpu_has_dc_aliases &&
1695+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
1696 page_mapped(page) && !Page_dcache_dirty(page)) {
1697 void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
1698 memcpy(vto, src, len);
1699@@ -244,7 +220,7 @@ void copy_from_user_page(struct vm_area_struct *vma,
1700 struct page *page, unsigned long vaddr, void *dst, const void *src,
1701 unsigned long len)
1702 {
1703- if (cpu_has_dc_aliases &&
1704+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
1705 page_mapped(page) && !Page_dcache_dirty(page)) {
1706 void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
1707 memcpy(dst, vfrom, len);
1708diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
1709index 0615b62..b0d64df 100644
1710--- a/arch/mips/mm/tlbex.c
1711+++ b/arch/mips/mm/tlbex.c
1712@@ -544,6 +544,9 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
1713 #endif
1714 uasm_i_addu(p, ptr, tmp, ptr);
1715 #else
1716+#ifdef CONFIG_BCM47XX
1717+ uasm_i_nop(p);
1718+#endif
1719 UASM_i_LA_mostly(p, ptr, pgdc);
1720 #endif
1721 uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
1722@@ -677,6 +680,9 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
1723 #ifdef CONFIG_64BIT
1724 build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
1725 #else
1726+# ifdef CONFIG_BCM47XX
1727+ uasm_i_nop(&p);
1728+# endif
1729 build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
1730 #endif
1731
1732@@ -684,6 +690,9 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
1733 build_update_entries(&p, K0, K1);
1734 build_tlb_write_entry(&p, &l, &r, tlb_random);
1735 uasm_l_leave(&l, p);
1736+#ifdef CONFIG_BCM47XX
1737+ uasm_i_nop(&p);
1738+#endif
1739 uasm_i_eret(&p); /* return from trap */
1740
1741 #ifdef CONFIG_64BIT
1742@@ -1084,6 +1093,9 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
1743 #ifdef CONFIG_64BIT
1744 build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
1745 #else
1746+# ifdef CONFIG_BCM47XX
1747+ uasm_i_nop(p);
1748+# endif
1749 build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
1750 #endif
1751
1752@@ -1111,6 +1123,9 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
1753 build_update_entries(p, tmp, ptr);
1754 build_tlb_write_entry(p, l, r, tlb_indexed);
1755 uasm_l_leave(l, *p);
1756+#ifdef CONFIG_BCM47XX
1757+ uasm_i_nop(p);
1758+#endif
1759 uasm_i_eret(p); /* return from trap */
1760
1761 #ifdef CONFIG_64BIT
1762diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
1763index b0eb9e7..85c152a 100644
1764--- a/arch/mips/pci/pci.c
1765+++ b/arch/mips/pci/pci.c
1766@@ -185,12 +185,10 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask)
1767 if ((idx == PCI_ROM_RESOURCE) &&
1768 (!(r->flags & IORESOURCE_ROM_ENABLE)))
1769 continue;
1770- if (!r->start && r->end) {
1771- printk(KERN_ERR "PCI: Device %s not available "
1772- "because of resource collisions\n",
1773+ if (!r->start && r->end)
1774+ printk(KERN_WARNING "PCI: Device %s resource"
1775+ "collisions detected. Ignoring...\n",
1776 pci_name(dev));
1777- return -EINVAL;
1778- }
1779 if (r->flags & IORESOURCE_IO)
1780 cmd |= PCI_COMMAND_IO;
1781 if (r->flags & IORESOURCE_MEM)
1782diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
1783index 82923bd..4fa8a05 100644
1784--- a/drivers/mtd/maps/Kconfig
1785+++ b/drivers/mtd/maps/Kconfig
1786@@ -343,6 +343,12 @@ config MTD_CFI_FLAGADM
1787 Mapping for the Flaga digital module. If you don't have one, ignore
1788 this setting.
1789
1790+config MTD_BCM47XX
1791+ tristate "BCM47xx flash device"
1792+ depends on MIPS && MTD_CFI && BCM47XX
1793+ help
1794+ Support for the flash chips on the BCM947xx board.
1795+
1796 config MTD_REDWOOD
1797 tristate "CFI Flash devices mapped on IBM Redwood"
1798 depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
1799diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
1800index 2dbc1be..d45138c 100644
1801--- a/drivers/mtd/maps/Makefile
1802+++ b/drivers/mtd/maps/Makefile
1803@@ -29,6 +29,7 @@ obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o
1804 obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
1805 obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
1806 obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
1807+obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o
1808 obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
1809 obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
1810 obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
1811diff --git a/drivers/mtd/maps/bcm47xx-flash.c b/drivers/mtd/maps/bcm47xx-flash.c
1812new file mode 100644
1813index 0000000..3ceec40
1814--- /dev/null
1815+++ b/drivers/mtd/maps/bcm47xx-flash.c
1816@@ -0,0 +1,440 @@
1817+/*
1818+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
1819+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
1820+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
1821+ *
1822+ * original functions for finding root filesystem from Mike Baker
1823+ *
1824+ * This program is free software; you can redistribute it and/or modify it
1825+ * under the terms of the GNU General Public License as published by the
1826+ * Free Software Foundation; either version 2 of the License, or (at your
1827+ * option) any later version.
1828+ *
1829+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1830+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1831+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
1832+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1833+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1834+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1835+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1836+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1837+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1838+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1839+ *
1840+ * You should have received a copy of the GNU General Public License along
1841+ * with this program; if not, write to the Free Software Foundation, Inc.,
1842+ * 675 Mass Ave, Cambridge, MA 02139, USA.
1843+ *
1844+ * Copyright 2001-2003, Broadcom Corporation
1845+ * All Rights Reserved.
1846+ *
1847+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
1848+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
1849+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
1850+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
1851+ *
1852+ * Flash mapping for BCM947XX boards
1853+ */
1854+
1855+#include <linux/init.h>
1856+#include <linux/module.h>
1857+#include <linux/types.h>
1858+#include <linux/kernel.h>
1859+#include <linux/sched.h>
1860+#include <linux/wait.h>
1861+#include <linux/mtd/mtd.h>
1862+#include <linux/mtd/map.h>
1863+#ifdef CONFIG_MTD_PARTITIONS
1864+#include <linux/mtd/partitions.h>
1865+#endif
1866+#include <linux/crc32.h>
1867+#ifdef CONFIG_SSB
1868+#include <linux/ssb/ssb.h>
1869+#endif
1870+#include <asm/io.h>
1871+
1872+
1873+#define TRX_MAGIC 0x30524448 /* "HDR0" */
1874+#define TRX_VERSION 1
1875+#define TRX_MAX_LEN 0x3A0000
1876+#define TRX_NO_HEADER 1 /* Do not write TRX header */
1877+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
1878+#define TRX_MAX_OFFSET 3
1879+
1880+struct trx_header {
1881+ u32 magic; /* "HDR0" */
1882+ u32 len; /* Length of file including header */
1883+ u32 crc32; /* 32-bit CRC from flag_version to end of file */
1884+ u32 flag_version; /* 0:15 flags, 16:31 version */
1885+ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
1886+};
1887+
1888+#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
1889+#define NVRAM_SPACE 0x8000
1890+#define WINDOW_ADDR 0x1fc00000
1891+#define WINDOW_SIZE 0x400000
1892+#define BUSWIDTH 2
1893+
1894+#ifdef CONFIG_SSB
1895+extern struct ssb_bus ssb_bcm47xx;
1896+#endif
1897+static struct mtd_info *bcm47xx_mtd;
1898+
1899+static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
1900+{
1901+ if (len==1) {
1902+ memcpy_fromio(to, map->virt + from, len);
1903+ } else {
1904+ int i;
1905+ u16 *dest = (u16 *) to;
1906+ u16 *src = (u16 *) (map->virt + from);
1907+ for (i = 0; i < (len / 2); i++) {
1908+ dest[i] = src[i];
1909+ }
1910+ if (len & 1)
1911+ *((u8 *)dest+len-1) = src[i] & 0xff;
1912+ }
1913+}
1914+
1915+static struct map_info bcm47xx_map = {
1916+ name: "Physically mapped flash",
1917+ size: WINDOW_SIZE,
1918+ bankwidth: BUSWIDTH,
1919+ phys: WINDOW_ADDR,
1920+};
1921+
1922+#ifdef CONFIG_MTD_PARTITIONS
1923+
1924+static struct mtd_partition bcm47xx_parts[] = {
1925+ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
1926+ { name: "linux", offset: 0, size: 0, },
1927+ { name: "rootfs", offset: 0, size: 0, },
1928+ { name: "nvram", offset: 0, size: 0, },
1929+ { name: NULL, },
1930+};
1931+
1932+static int __init
1933+find_cfe_size(struct mtd_info *mtd, size_t size)
1934+{
1935+ struct trx_header *trx;
1936+ unsigned char buf[512];
1937+ int off;
1938+ size_t len;
1939+ int blocksize;
1940+
1941+ trx = (struct trx_header *) buf;
1942+
1943+ blocksize = mtd->erasesize;
1944+ if (blocksize < 0x10000)
1945+ blocksize = 0x10000;
1946+
1947+ for (off = (128*1024); off < size; off += blocksize) {
1948+ memset(buf, 0xe5, sizeof(buf));
1949+
1950+ /*
1951+ * Read into buffer
1952+ */
1953+ if (mtd->read(mtd, off, sizeof(buf), &len, buf) ||
1954+ len != sizeof(buf))
1955+ continue;
1956+
1957+ /* found a TRX header */
1958+ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
1959+ goto found;
1960+ }
1961+ }
1962+
1963+ printk(KERN_NOTICE
1964+ "%s: Couldn't find bootloader size\n",
1965+ mtd->name);
1966+ return -1;
1967+
1968+ found:
1969+ printk(KERN_NOTICE "bootloader size: %d\n", off);
1970+ return off;
1971+
1972+}
1973+
1974+/*
1975+ * Copied from mtdblock.c
1976+ *
1977+ * Cache stuff...
1978+ *
1979+ * Since typical flash erasable sectors are much larger than what Linux's
1980+ * buffer cache can handle, we must implement read-modify-write on flash
1981+ * sectors for each block write requests. To avoid over-erasing flash sectors
1982+ * and to speed things up, we locally cache a whole flash sector while it is
1983+ * being written to until a different sector is required.
1984+ */
1985+
1986+static void erase_callback(struct erase_info *done)
1987+{
1988+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
1989+ wake_up(wait_q);
1990+}
1991+
1992+static int erase_write (struct mtd_info *mtd, unsigned long pos,
1993+ int len, const char *buf)
1994+{
1995+ struct erase_info erase;
1996+ DECLARE_WAITQUEUE(wait, current);
1997+ wait_queue_head_t wait_q;
1998+ size_t retlen;
1999+ int ret;
2000+
2001+ /*
2002+ * First, let's erase the flash block.
2003+ */
2004+
2005+ init_waitqueue_head(&wait_q);
2006+ erase.mtd = mtd;
2007+ erase.callback = erase_callback;
2008+ erase.addr = pos;
2009+ erase.len = len;
2010+ erase.priv = (u_long)&wait_q;
2011+
2012+ set_current_state(TASK_INTERRUPTIBLE);
2013+ add_wait_queue(&wait_q, &wait);
2014+
2015+ ret = mtd->erase(mtd, &erase);
2016+ if (ret) {
2017+ set_current_state(TASK_RUNNING);
2018+ remove_wait_queue(&wait_q, &wait);
2019+ printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
2020+ "on \"%s\" failed\n",
2021+ pos, len, mtd->name);
2022+ return ret;
2023+ }
2024+
2025+ schedule(); /* Wait for erase to finish. */
2026+ remove_wait_queue(&wait_q, &wait);
2027+
2028+ /*
2029+ * Next, writhe data to flash.
2030+ */
2031+
2032+ ret = mtd->write (mtd, pos, len, &retlen, buf);
2033+ if (ret)
2034+ return ret;
2035+ if (retlen != len)
2036+ return -EIO;
2037+ return 0;
2038+}
2039+
2040+
2041+
2042+
2043+static int __init
2044+find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
2045+{
2046+ struct trx_header trx, *trx2;
2047+ unsigned char buf[512], *block;
2048+ int off, blocksize;
2049+ u32 i, crc = ~0;
2050+ size_t len;
2051+ struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
2052+
2053+ blocksize = mtd->erasesize;
2054+ if (blocksize < 0x10000)
2055+ blocksize = 0x10000;
2056+
2057+ for (off = (128*1024); off < size; off += blocksize) {
2058+ memset(&trx, 0xe5, sizeof(trx));
2059+
2060+ /*
2061+ * Read into buffer
2062+ */
2063+ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
2064+ len != sizeof(trx))
2065+ continue;
2066+
2067+ /* found a TRX header */
2068+ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
2069+ part->offset = le32_to_cpu(trx.offsets[2]) ? :
2070+ le32_to_cpu(trx.offsets[1]);
2071+ part->size = le32_to_cpu(trx.len);
2072+
2073+ part->size -= part->offset;
2074+ part->offset += off;
2075+
2076+ goto found;
2077+ }
2078+ }
2079+
2080+ printk(KERN_NOTICE
2081+ "%s: Couldn't find root filesystem\n",
2082+ mtd->name);
2083+ return -1;
2084+
2085+ found:
2086+ if (part->size == 0)
2087+ return 0;
2088+
2089+ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
2090+ return 0;
2091+
2092+ /* Move the fs outside of the trx */
2093+ part->size = 0;
2094+
2095+ if (trx.len != part->offset + part->size - off) {
2096+ /* Update the trx offsets and length */
2097+ trx.len = part->offset + part->size - off;
2098+
2099+ /* Update the trx crc32 */
2100+ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
2101+ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
2102+ return 0;
2103+ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
2104+ }
2105+ trx.crc32 = crc;
2106+
2107+ /* read first eraseblock from the trx */
2108+ block = kmalloc(mtd->erasesize, GFP_KERNEL);
2109+ trx2 = (struct trx_header *) block;
2110+ if (mtd->read(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) {
2111+ printk("Error accessing the first trx eraseblock\n");
2112+ return 0;
2113+ }
2114+
2115+ printk("Updating TRX offsets and length:\n");
2116+ 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);
2117+ 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);
2118+
2119+ /* Write updated trx header to the flash */
2120+ memcpy(block, &trx, sizeof(trx));
2121+ if (mtd->unlock)
2122+ mtd->unlock(mtd, off, mtd->erasesize);
2123+ erase_write(mtd, off, mtd->erasesize, block);
2124+ if (mtd->sync)
2125+ mtd->sync(mtd);
2126+ kfree(block);
2127+ printk("Done\n");
2128+ }
2129+
2130+ return part->size;
2131+}
2132+
2133+struct mtd_partition * __init
2134+init_mtd_partitions(struct mtd_info *mtd, size_t size)
2135+{
2136+ int cfe_size;
2137+
2138+ if ((cfe_size = find_cfe_size(mtd,size)) < 0)
2139+ return NULL;
2140+
2141+ /* boot loader */
2142+ bcm47xx_parts[0].offset = 0;
2143+ bcm47xx_parts[0].size = cfe_size;
2144+
2145+ /* nvram */
2146+ if (cfe_size != 384 * 1024) {
2147+ bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
2148+ bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
2149+ } else {
2150+ /* nvram (old 128kb config partition on netgear wgt634u) */
2151+ bcm47xx_parts[3].offset = bcm47xx_parts[0].size;
2152+ bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
2153+ }
2154+
2155+ /* linux (kernel and rootfs) */
2156+ if (cfe_size != 384 * 1024) {
2157+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
2158+ bcm47xx_parts[1].size = bcm47xx_parts[3].offset -
2159+ bcm47xx_parts[1].offset;
2160+ } else {
2161+ /* do not count the elf loader, which is on one block */
2162+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
2163+ bcm47xx_parts[3].size + mtd->erasesize;
2164+ bcm47xx_parts[1].size = size -
2165+ bcm47xx_parts[0].size -
2166+ (2*bcm47xx_parts[3].size) -
2167+ mtd->erasesize;
2168+ }
2169+
2170+ /* find and size rootfs */
2171+ find_root(mtd,size,&bcm47xx_parts[2]);
2172+ bcm47xx_parts[2].size = size - bcm47xx_parts[2].offset - bcm47xx_parts[3].size;
2173+
2174+ return bcm47xx_parts;
2175+}
2176+#endif
2177+
2178+int __init init_bcm47xx_map(void)
2179+{
2180+#ifdef CONFIG_SSB
2181+ struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
2182+#endif
2183+ size_t size;
2184+ int ret = 0;
2185+#ifdef CONFIG_MTD_PARTITIONS
2186+ struct mtd_partition *parts;
2187+ int i;
2188+#endif
2189+
2190+#ifdef CONFIG_SSB
2191+ u32 window = mcore->flash_window;
2192+ u32 window_size = mcore->flash_window_size;
2193+
2194+ printk("flash init: 0x%08x 0x%08x\n", window, window_size);
2195+ bcm47xx_map.phys = window;
2196+ bcm47xx_map.size = window_size;
2197+ bcm47xx_map.bankwidth = mcore->flash_buswidth;
2198+ bcm47xx_map.virt = ioremap_nocache(window, window_size);
2199+#else
2200+ printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
2201+ bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
2202+#endif
2203+
2204+ if (!bcm47xx_map.virt) {
2205+ printk("Failed to ioremap\n");
2206+ return -EIO;
2207+ }
2208+
2209+ simple_map_init(&bcm47xx_map);
2210+
2211+ if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) {
2212+ printk("Failed to do_map_probe\n");
2213+ iounmap((void *)bcm47xx_map.virt);
2214+ return -ENXIO;
2215+ }
2216+
2217+ /* override copy_from routine */
2218+ bcm47xx_map.copy_from = bcm47xx_map_copy_from;
2219+
2220+ bcm47xx_mtd->owner = THIS_MODULE;
2221+
2222+ size = bcm47xx_mtd->size;
2223+
2224+ printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
2225+
2226+#ifdef CONFIG_MTD_PARTITIONS
2227+ parts = init_mtd_partitions(bcm47xx_mtd, size);
2228+ for (i = 0; parts[i].name; i++);
2229+ ret = add_mtd_partitions(bcm47xx_mtd, parts, i);
2230+ if (ret) {
2231+ printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
2232+ goto fail;
2233+ }
2234+#endif
2235+ return 0;
2236+
2237+ fail:
2238+ if (bcm47xx_mtd)
2239+ map_destroy(bcm47xx_mtd);
2240+ if (bcm47xx_map.virt)
2241+ iounmap((void *)bcm47xx_map.virt);
2242+ bcm47xx_map.virt = 0;
2243+ return ret;
2244+}
2245+
2246+void __exit cleanup_bcm47xx_map(void)
2247+{
2248+#ifdef CONFIG_MTD_PARTITIONS
2249+ del_mtd_partitions(bcm47xx_mtd);
2250+#endif
2251+ map_destroy(bcm47xx_mtd);
2252+ iounmap((void *)bcm47xx_map.virt);
2253+}
2254+
2255+module_init(init_bcm47xx_map);
2256+module_exit(cleanup_bcm47xx_map);
2257diff --git a/drivers/net/b44.c b/drivers/net/b44.c
2258index b70b81e..2508e77 100644
2259--- a/drivers/net/b44.c
2260+++ b/drivers/net/b44.c
2261@@ -339,7 +339,7 @@ static int b44_phy_reset(struct b44 *bp)
2262 }
2263 }
2264
2265- return 0;
2266+ return err;
2267 }
2268
2269 static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags)
2270@@ -815,7 +815,7 @@ static int b44_rx(struct b44 *bp, int budget)
2271 struct sk_buff *copy_skb;
2272
2273 b44_recycle_rx(bp, cons, bp->rx_prod);
2274- copy_skb = dev_alloc_skb(len + 2);
2275+ copy_skb = netdev_alloc_skb(bp->dev, len + 2);
2276 if (copy_skb == NULL)
2277 goto drop_it_no_recycle;
2278
2279@@ -2220,6 +2220,10 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
2280 */
2281 b44_chip_reset(bp, B44_CHIP_RESET_FULL);
2282
2283+ /* do a phy reset to test if there is an active phy */
2284+ if (b44_phy_reset(bp) < 0)
2285+ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
2286+
2287 printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %pM\n",
2288 dev->name, dev->dev_addr);
2289
2290diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
2291index 201be42..70b7c7b 100644
2292--- a/drivers/net/tg3.c
2293+++ b/drivers/net/tg3.c
2294@@ -41,6 +41,7 @@
2295 #include <linux/prefetch.h>
2296 #include <linux/dma-mapping.h>
2297 #include <linux/firmware.h>
2298+#include <linux/ssb/ssb_driver_gige.h>
2299
2300 #include <net/checksum.h>
2301 #include <net/ip.h>
2302@@ -446,8 +447,9 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait)
2303 static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
2304 {
2305 tp->write32_mbox(tp, off, val);
2306- if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
2307- !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
2308+ if ((tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES) ||
2309+ (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
2310+ !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)))
2311 tp->read32_mbox(tp, off);
2312 }
2313
2314@@ -457,7 +459,7 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
2315 writel(val, mbox);
2316 if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
2317 writel(val, mbox);
2318- if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
2319+ if ((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) || (tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES))
2320 readl(mbox);
2321 }
2322
2323@@ -729,7 +731,7 @@ static void tg3_switch_clocks(struct tg3 *tp)
2324
2325 #define PHY_BUSY_LOOPS 5000
2326
2327-static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
2328+static int __tg3_readphy(struct tg3 *tp, unsigned int phy_addr, int reg, u32 *val)
2329 {
2330 u32 frame_val;
2331 unsigned int loops;
2332@@ -743,7 +745,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
2333
2334 *val = 0x0;
2335
2336- frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
2337+ frame_val = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
2338 MI_COM_PHY_ADDR_MASK);
2339 frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
2340 MI_COM_REG_ADDR_MASK);
2341@@ -778,7 +780,12 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
2342 return ret;
2343 }
2344
2345-static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
2346+static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
2347+{
2348+ return __tg3_readphy(tp, PHY_ADDR, reg, val);
2349+}
2350+
2351+static int __tg3_writephy(struct tg3 *tp, unsigned int phy_addr, int reg, u32 val)
2352 {
2353 u32 frame_val;
2354 unsigned int loops;
2355@@ -794,7 +801,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
2356 udelay(80);
2357 }
2358
2359- frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
2360+ frame_val = ((phy_addr << MI_COM_PHY_ADDR_SHIFT) &
2361 MI_COM_PHY_ADDR_MASK);
2362 frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
2363 MI_COM_REG_ADDR_MASK);
2364@@ -827,6 +834,11 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
2365 return ret;
2366 }
2367
2368+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
2369+{
2370+ return __tg3_writephy(tp, PHY_ADDR, reg, val);
2371+}
2372+
2373 static int tg3_bmcr_reset(struct tg3 *tp)
2374 {
2375 u32 phy_control;
2376@@ -2262,6 +2274,9 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
2377 {
2378 int ret;
2379
2380+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE)
2381+ return -ENODEV;
2382+
2383 if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
2384 return tg3_nvram_read_using_eeprom(tp, offset, val);
2385
2386@@ -2595,8 +2610,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
2387 tg3_frob_aux_power(tp);
2388
2389 /* Workaround for unstable PLL clock */
2390- if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
2391- (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
2392+ if ((tp->phy_id & PHY_ID_MASK != PHY_ID_BCM5750_2) &&
2393+ /* !!! FIXME !!! */
2394+ ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
2395+ (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX))) {
2396 u32 val = tr32(0x7d00);
2397
2398 val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
2399@@ -3088,6 +3105,14 @@ relink:
2400
2401 tg3_phy_copper_begin(tp);
2402
2403+ if (tp->tg3_flags3 & TG3_FLG3_ROBOSWITCH) {
2404+ current_link_up = 1;
2405+ current_speed = SPEED_1000; //FIXME
2406+ current_duplex = DUPLEX_FULL;
2407+ tp->link_config.active_speed = current_speed;
2408+ tp->link_config.active_duplex = current_duplex;
2409+ }
2410+
2411 tg3_readphy(tp, MII_BMSR, &tmp);
2412 if (!tg3_readphy(tp, MII_BMSR, &tmp) &&
2413 (tmp & BMSR_LSTATUS))
2414@@ -6000,6 +6025,11 @@ static int tg3_poll_fw(struct tg3 *tp)
2415 int i;
2416 u32 val;
2417
2418+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
2419+ /* We don't use firmware. */
2420+ return 0;
2421+ }
2422+
2423 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
2424 /* Wait up to 20ms for init done. */
2425 for (i = 0; i < 200; i++) {
2426@@ -6256,6 +6286,14 @@ static int tg3_chip_reset(struct tg3 *tp)
2427 tw32(0x5000, 0x400);
2428 }
2429
2430+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
2431+ /* BCM4785: In order to avoid repercussions from using potentially
2432+ * defective internal ROM, stop the Rx RISC CPU, which is not
2433+ * required. */
2434+ tg3_stop_fw(tp);
2435+ tg3_halt_cpu(tp, RX_CPU_BASE);
2436+ }
2437+
2438 tw32(GRC_MODE, tp->grc_mode);
2439
2440 if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
2441@@ -6406,9 +6444,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
2442 return -ENODEV;
2443 }
2444
2445- /* Clear firmware's nvram arbitration. */
2446- if (tp->tg3_flags & TG3_FLAG_NVRAM)
2447- tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
2448+ if (!(tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE)) {
2449+ /* Clear firmware's nvram arbitration. */
2450+ if (tp->tg3_flags & TG3_FLAG_NVRAM)
2451+ tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
2452+ }
2453+
2454 return 0;
2455 }
2456
2457@@ -6471,6 +6512,11 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
2458 const __be32 *fw_data;
2459 int err, i;
2460
2461+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
2462+ /* We don't use firmware. */
2463+ return 0;
2464+ }
2465+
2466 fw_data = (void *)tp->fw->data;
2467
2468 /* Firmware blob starts with version numbers, followed by
2469@@ -6530,6 +6576,11 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
2470 unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
2471 int err, i;
2472
2473+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
2474+ /* We don't use firmware. */
2475+ return 0;
2476+ }
2477+
2478 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
2479 return 0;
2480
2481@@ -7435,6 +7486,11 @@ static void tg3_timer(unsigned long __opaque)
2482
2483 spin_lock(&tp->lock);
2484
2485+ if (tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES) {
2486+ /* BCM4785: Flush posted writes from GbE to host memory. */
2487+ tr32(HOSTCC_MODE);
2488+ }
2489+
2490 if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
2491 /* All of this garbage is because when using non-tagged
2492 * IRQ status the mailbox/status_block protocol the chip
2493@@ -9201,6 +9257,11 @@ static int tg3_test_nvram(struct tg3 *tp)
2494 __be32 *buf;
2495 int i, j, k, err = 0, size;
2496
2497+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
2498+ /* We don't have NVRAM. */
2499+ return 0;
2500+ }
2501+
2502 if (tg3_nvram_read(tp, 0, &magic) != 0)
2503 return -EIO;
2504
2505@@ -9994,7 +10055,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2506 return -EAGAIN;
2507
2508 spin_lock_bh(&tp->lock);
2509- err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
2510+ err = __tg3_readphy(tp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
2511 spin_unlock_bh(&tp->lock);
2512
2513 data->val_out = mii_regval;
2514@@ -10013,7 +10074,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2515 return -EAGAIN;
2516
2517 spin_lock_bh(&tp->lock);
2518- err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
2519+ err = __tg3_writephy(tp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
2520 spin_unlock_bh(&tp->lock);
2521
2522 return err;
2523@@ -10601,6 +10662,12 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
2524 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
2525 static void __devinit tg3_nvram_init(struct tg3 *tp)
2526 {
2527+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
2528+ /* No NVRAM and EEPROM on the SSB Broadcom GigE core. */
2529+ tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
2530+ return;
2531+ }
2532+
2533 tw32_f(GRC_EEPROM_ADDR,
2534 (EEPROM_ADDR_FSM_RESET |
2535 (EEPROM_DEFAULT_CLOCK_PERIOD <<
2536@@ -10859,6 +10926,9 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
2537 {
2538 int ret;
2539
2540+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE)
2541+ return -ENODEV;
2542+
2543 if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
2544 tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
2545 ~GRC_LCLCTRL_GPIO_OUTPUT1);
2546@@ -12063,7 +12133,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
2547 tp->write32 = tg3_write_flush_reg32;
2548 }
2549
2550-
2551 if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
2552 (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
2553 tp->write32_tx_mbox = tg3_write32_tx_mbox;
2554@@ -12099,6 +12168,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
2555 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
2556 tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
2557
2558+ if (tp->tg3_flags3 & TG3_FLG3_FLUSH_POSTED_WRITES) {
2559+ tp->write32_tx_mbox = tg3_write_flush_reg32;
2560+ tp->write32_rx_mbox = tg3_write_flush_reg32;
2561+ }
2562+
2563 /* Get eeprom hw config before calling tg3_set_power_state().
2564 * In particular, the TG3_FLG2_IS_NIC flag must be
2565 * determined before calling tg3_set_power_state() so that
2566@@ -12474,6 +12548,10 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
2567 }
2568
2569 if (!is_valid_ether_addr(&dev->dev_addr[0])) {
2570+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE)
2571+ ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
2572+ }
2573+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
2574 #ifdef CONFIG_SPARC
2575 if (!tg3_get_default_macaddr_sparc(tp))
2576 return 0;
2577@@ -12965,6 +13043,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
2578 case PHY_ID_BCM5704: return "5704";
2579 case PHY_ID_BCM5705: return "5705";
2580 case PHY_ID_BCM5750: return "5750";
2581+ case PHY_ID_BCM5750_2: return "5750-2";
2582 case PHY_ID_BCM5752: return "5752";
2583 case PHY_ID_BCM5714: return "5714";
2584 case PHY_ID_BCM5780: return "5780";
2585@@ -13175,6 +13254,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
2586 tp->msg_enable = tg3_debug;
2587 else
2588 tp->msg_enable = TG3_DEF_MSG_ENABLE;
2589+ if (pdev_is_ssb_gige_core(pdev)) {
2590+ tp->tg3_flags3 |= TG3_FLG3_IS_SSB_CORE;
2591+ if (ssb_gige_must_flush_posted_writes(pdev))
2592+ tp->tg3_flags3 |= TG3_FLG3_FLUSH_POSTED_WRITES;
2593+ if (ssb_gige_have_roboswitch(pdev))
2594+ tp->tg3_flags3 |= TG3_FLG3_ROBOSWITCH;
2595+ }
2596
2597 /* The word/byte swap controls here control register access byte
2598 * swapping. DMA data byte swapping is controlled in the GRC_MODE
2599diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
2600index cb4c62a..5364876 100644
2601--- a/drivers/net/tg3.h
2602+++ b/drivers/net/tg3.h
2603@@ -1849,6 +1849,9 @@
2604 #define NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004
2605 #define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008
2606 #define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010
2607+#define TG3_FLG3_IS_SSB_CORE 0x00000800
2608+#define TG3_FLG3_FLUSH_POSTED_WRITES 0x00001000
2609+#define TG3_FLG3_ROBOSWITCH 0x00002000
2610
2611 #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000
2612
2613@@ -2695,6 +2698,7 @@ struct tg3 {
2614 #define PHY_ID_BCM5714 0x60008340
2615 #define PHY_ID_BCM5780 0x60008350
2616 #define PHY_ID_BCM5755 0xbc050cc0
2617+#define PHY_ID_BCM5750_2 0xbc050cd0
2618 #define PHY_ID_BCM5787 0xbc050ce0
2619 #define PHY_ID_BCM5756 0xbc050ed0
2620 #define PHY_ID_BCM5784 0xbc050fa0
2621@@ -2739,7 +2743,7 @@ struct tg3 {
2622 (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
2623 (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
2624 (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
2625- (X) == PHY_ID_BCM8002)
2626+ (X) == PHY_ID_BCM8002 || (X) == PHY_ID_BCM5750_2)
2627
2628 struct tg3_hw_stats *hw_stats;
2629 dma_addr_t stats_mapping;
2630diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
2631index 540a294..6c2f443 100644
2632--- a/drivers/ssb/Kconfig
2633+++ b/drivers/ssb/Kconfig
2634@@ -126,6 +126,8 @@ config SSB_DRIVER_MIPS
2635 config SSB_EMBEDDED
2636 bool
2637 depends on SSB_DRIVER_MIPS
2638+ select USB_EHCI_HCD_SSB
2639+ select USB_OHCI_HCD_SSB
2640 default y
2641
2642 config SSB_DRIVER_EXTIF
2643diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
2644index 9681536..7a26028 100644
2645--- a/drivers/ssb/driver_chipcommon.c
2646+++ b/drivers/ssb/driver_chipcommon.c
2647@@ -258,6 +258,8 @@ void ssb_chipco_resume(struct ssb_chipcommon *cc)
2648 void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
2649 u32 *plltype, u32 *n, u32 *m)
2650 {
2651+ if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) == 0x5354)
2652+ return;
2653 *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
2654 *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
2655 switch (*plltype) {
2656@@ -281,6 +283,8 @@ void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
2657 void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
2658 u32 *plltype, u32 *n, u32 *m)
2659 {
2660+ if ((chipco_read32(cc, SSB_CHIPCO_CHIPID) & SSB_CHIPCO_IDMASK) == 0x5354)
2661+ return;
2662 *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
2663 *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
2664 switch (*plltype) {
2665diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
2666index 3fd3e3b..f30186d 100644
2667--- a/drivers/ssb/driver_mipscore.c
2668+++ b/drivers/ssb/driver_mipscore.c
2669@@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = {
2670
2671 static inline u32 ssb_irqflag(struct ssb_device *dev)
2672 {
2673- return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
2674+ u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
2675+ if (tpsflag)
2676+ return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
2677+ else
2678+ /* not irq supported */
2679+ return 0x3f;
2680+}
2681+
2682+static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
2683+{
2684+ struct ssb_bus *bus = rdev->bus;
2685+ int i;
2686+ for (i = 0; i < bus->nr_devices; i++) {
2687+ struct ssb_device *dev;
2688+ dev = &(bus->devices[i]);
2689+ if (ssb_irqflag(dev) == irqflag)
2690+ return dev;
2691+ }
2692+ return NULL;
2693 }
2694
2695 /* Get the MIPS IRQ assignment for a specified device.
2696 * If unassigned, 0 is returned.
2697+ * If disabled, 5 is returned.
2698+ * If not supported, 6 is returned.
2699 */
2700 unsigned int ssb_mips_irq(struct ssb_device *dev)
2701 {
2702 struct ssb_bus *bus = dev->bus;
2703+ struct ssb_device *mdev = bus->mipscore.dev;
2704 u32 irqflag;
2705 u32 ipsflag;
2706 u32 tmp;
2707 unsigned int irq;
2708
2709 irqflag = ssb_irqflag(dev);
2710+ if (irqflag == 0x3f)
2711+ return 6;
2712 ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
2713 for (irq = 1; irq <= 4; irq++) {
2714 tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
2715 if (tmp == irqflag)
2716 break;
2717 }
2718- if (irq == 5)
2719- irq = 0;
2720+ if (irq == 5) {
2721+ if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
2722+ irq = 0;
2723+ }
2724
2725 return irq;
2726 }
2727@@ -97,25 +122,56 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)
2728 struct ssb_device *mdev = bus->mipscore.dev;
2729 u32 irqflag = ssb_irqflag(dev);
2730
2731+ BUG_ON(oldirq == 6);
2732+
2733 dev->irq = irq + 2;
2734
2735- ssb_dprintk(KERN_INFO PFX
2736- "set_irq: core 0x%04x, irq %d => %d\n",
2737- dev->id.coreid, oldirq, irq);
2738 /* clear the old irq */
2739 if (oldirq == 0)
2740 ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
2741- else
2742+ else if (oldirq != 5)
2743 clear_irq(bus, oldirq);
2744
2745 /* assign the new one */
2746 if (irq == 0) {
2747 ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
2748 } else {
2749+ u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
2750+ if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
2751+ u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
2752+ struct ssb_device *olddev = find_device(dev, oldipsflag);
2753+ if (olddev)
2754+ set_irq(olddev, 0);
2755+ }
2756 irqflag <<= ipsflag_irq_shift[irq];
2757- irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
2758+ irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
2759 ssb_write32(mdev, SSB_IPSFLAG, irqflag);
2760 }
2761+ ssb_dprintk(KERN_INFO PFX
2762+ "set_irq: core 0x%04x, irq %d => %d\n",
2763+ dev->id.coreid, oldirq+2, irq+2);
2764+}
2765+
2766+static void print_irq(struct ssb_device *dev, unsigned int irq)
2767+{
2768+ int i;
2769+ static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
2770+ ssb_dprintk(KERN_INFO PFX
2771+ "core 0x%04x, irq :", dev->id.coreid);
2772+ for (i = 0; i <= 6; i++) {
2773+ ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
2774+ }
2775+ ssb_dprintk("\n");
2776+}
2777+
2778+static void dump_irq(struct ssb_bus *bus)
2779+{
2780+ int i;
2781+ for (i = 0; i < bus->nr_devices; i++) {
2782+ struct ssb_device *dev;
2783+ dev = &(bus->devices[i]);
2784+ print_irq(dev, ssb_mips_irq(dev));
2785+ }
2786 }
2787
2788 static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
2789@@ -161,6 +217,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
2790
2791 if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
2792 rate = 200000000;
2793+ } else if (bus->chip_id == 0x5354) {
2794+ rate = 240000000;
2795 } else {
2796 rate = ssb_calc_clock_rate(pll_type, n, m);
2797 }
2798@@ -195,18 +253,26 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
2799 else if (bus->chipco.dev)
2800 ssb_chipco_timing_init(&bus->chipco, ns);
2801
2802+ dump_irq(bus);
2803 /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
2804 for (irq = 2, i = 0; i < bus->nr_devices; i++) {
2805+ int mips_irq;
2806 dev = &(bus->devices[i]);
2807- dev->irq = ssb_mips_irq(dev) + 2;
2808+ mips_irq = ssb_mips_irq(dev);
2809+ if (mips_irq > 4)
2810+ dev->irq = 0;
2811+ else
2812+ dev->irq = mips_irq + 2;
2813+ if (dev->irq > 5)
2814+ continue;
2815 switch (dev->id.coreid) {
2816 case SSB_DEV_USB11_HOST:
2817 /* shouldn't need a separate irq line for non-4710, most of them have a proper
2818 * external usb controller on the pci */
2819 if ((bus->chip_id == 0x4710) && (irq <= 4)) {
2820 set_irq(dev, irq++);
2821- break;
2822 }
2823+ break;
2824 /* fallthrough */
2825 case SSB_DEV_PCI:
2826 case SSB_DEV_ETHERNET:
2827@@ -220,6 +286,8 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
2828 }
2829 }
2830 }
2831+ ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
2832+ dump_irq(bus);
2833
2834 ssb_mips_serial_init(mcore);
2835 ssb_mips_flash_detect(mcore);
2836diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
2837index 65a1ed9..4705122 100644
2838--- a/drivers/ssb/main.c
2839+++ b/drivers/ssb/main.c
2840@@ -1010,6 +1010,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
2841
2842 if (bus->chip_id == 0x5365) {
2843 rate = 100000000;
2844+ } else if (bus->chip_id == 0x5354) {
2845+ rate = 120000000;
2846 } else {
2847 rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m);
2848 if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */
2849diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
2850index 845479f..59f8079 100644
2851--- a/drivers/usb/host/Kconfig
2852+++ b/drivers/usb/host/Kconfig
2853@@ -106,6 +106,19 @@ config USB_OXU210HP_HCD
2854 To compile this driver as a module, choose M here: the
2855 module will be called oxu210hp-hcd.
2856
2857+config USB_EHCI_HCD_SSB
2858+ bool "EHCI support for Broadcom SSB EHCI core"
2859+ depends on USB_EHCI_HCD && SSB && EXPERIMENTAL
2860+ default n
2861+ ---help---
2862+ Support for the Sonics Silicon Backplane (SSB) attached
2863+ Broadcom USB EHCI core.
2864+
2865+ This device is present in some embedded devices with
2866+ Broadcom based SSB bus.
2867+
2868+ If unsure, say N.
2869+
2870 config USB_ISP116X_HCD
2871 tristate "ISP116X HCD support"
2872 depends on USB
2873diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
2874index c637207..5c248d9 100644
2875--- a/drivers/usb/host/ehci-hcd.c
2876+++ b/drivers/usb/host/ehci-hcd.c
2877@@ -1072,8 +1072,16 @@ MODULE_LICENSE ("GPL");
2878 #define PLATFORM_DRIVER ixp4xx_ehci_driver
2879 #endif
2880
2881-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
2882- !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
2883+#ifdef CONFIG_USB_EHCI_HCD_SSB
2884+#include "ehci-ssb.c"
2885+#define SSB_EHCI_DRIVER ssb_ehci_driver
2886+#endif
2887+
2888+#if !defined(PCI_DRIVER) && \
2889+ !defined(PLATFORM_DRIVER) && \
2890+ !defined(PS3_SYSTEM_BUS_DRIVER) && \
2891+ !defined(OF_PLATFORM_DRIVER) && \
2892+ !defined(SSB_EHCI_DRIVER)
2893 #error "missing bus glue for ehci-hcd"
2894 #endif
2895
2896diff --git a/drivers/usb/host/ehci-ssb.c b/drivers/usb/host/ehci-ssb.c
2897new file mode 100644
2898index 0000000..be90a5c
2899--- /dev/null
2900+++ b/drivers/usb/host/ehci-ssb.c
2901@@ -0,0 +1,201 @@
2902+/*
2903+ * Sonics Silicon Backplane
2904+ * Broadcom USB-core EHCI driver (SSB bus glue)
2905+ *
2906+ * Copyright 2007 Steven Brown <sbrown@cortland.com>
2907+ *
2908+ * Derived from the OHCI-SSB driver
2909+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
2910+ *
2911+ * Derived from the EHCI-PCI driver
2912+ * Copyright (c) 2000-2004 by David Brownell
2913+ *
2914+ * Derived from the OHCI-PCI driver
2915+ * Copyright 1999 Roman Weissgaerber
2916+ * Copyright 2000-2002 David Brownell
2917+ * Copyright 1999 Linus Torvalds
2918+ * Copyright 1999 Gregory P. Smith
2919+ *
2920+ * Derived from the USBcore related parts of Broadcom-SB
2921+ * Copyright 2005 Broadcom Corporation
2922+ *
2923+ * Licensed under the GNU/GPL. See COPYING for details.
2924+ */
2925+#include <linux/ssb/ssb.h>
2926+
2927+#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
2928+
2929+struct ssb_ehci_device {
2930+ struct ehci_hcd ehci; /* _must_ be at the beginning. */
2931+
2932+ u32 enable_flags;
2933+};
2934+
2935+static inline
2936+struct ssb_ehci_device *hcd_to_ssb_ehci(struct usb_hcd *hcd)
2937+{
2938+ return (struct ssb_ehci_device *)(hcd->hcd_priv);
2939+}
2940+
2941+
2942+static int ssb_ehci_reset(struct usb_hcd *hcd)
2943+{
2944+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
2945+ int err;
2946+
2947+ ehci->caps = hcd->regs;
2948+ ehci->regs = hcd->regs +
2949+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
2950+
2951+ dbg_hcs_params(ehci, "reset");
2952+ dbg_hcc_params(ehci, "reset");
2953+
2954+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
2955+
2956+ err = ehci_halt(ehci);
2957+
2958+ if (err)
2959+ return err;
2960+
2961+ err = ehci_init(hcd);
2962+
2963+ if (err)
2964+ return err;
2965+
2966+ ehci_port_power(ehci, 0);
2967+
2968+ return err;
2969+}
2970+
2971+static int ssb_ehci_start(struct usb_hcd *hcd)
2972+{
2973+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
2974+ int err;
2975+
2976+ err = ehci_run(hcd);
2977+ if (err < 0) {
2978+ ehci_err(ehci, "can't start\n");
2979+ ehci_stop(hcd);
2980+ }
2981+
2982+ return err;
2983+}
2984+
2985+#ifdef CONFIG_PM
2986+static int ssb_ehci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
2987+{
2988+ struct ssb_ehci_device *ehcidev = hcd_to_ssb_ehci(hcd);
2989+ struct ehci_hcd *ehci = &ehcidev->ehci;
2990+ unsigned long flags;
2991+
2992+ spin_lock_irqsave(&ehci->lock, flags);
2993+
2994+ ehci_writel(ehci, EHCI_INTR_MIE, &ehci->regs->intrdisable);
2995+ ehci_readl(ehci, &ehci->regs->intrdisable); /* commit write */
2996+
2997+ /* make sure snapshot being resumed re-enumerates everything */
2998+ if (message.event == PM_EVENT_PRETHAW)
2999+ ehci_usb_reset(ehci);
3000+
3001+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
3002+
3003+ spin_unlock_irqrestore(&ehci->lock, flags);
3004+ return 0;
3005+}
3006+
3007+static int ssb_ehci_hcd_resume(struct usb_hcd *hcd)
3008+{
3009+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
3010+ usb_hcd_resume_root_hub(hcd);
3011+ return 0;
3012+}
3013+#endif /* CONFIG_PM */
3014+
3015+static const struct hc_driver ssb_ehci_hc_driver = {
3016+ .description = "ssb-usb-ehci",
3017+ .product_desc = "SSB EHCI Controller",
3018+ .hcd_priv_size = sizeof(struct ssb_ehci_device),
3019+
3020+ .irq = ehci_irq,
3021+ .flags = HCD_MEMORY | HCD_USB2,
3022+
3023+ .reset = ssb_ehci_reset,
3024+ .start = ssb_ehci_start,
3025+ .stop = ehci_stop,
3026+ .shutdown = ehci_shutdown,
3027+
3028+#ifdef CONFIG_PM
3029+ .suspend = ssb_ehci_hcd_suspend,
3030+ .resume = ssb_ehci_hcd_resume,
3031+#endif
3032+
3033+ .urb_enqueue = ehci_urb_enqueue,
3034+ .urb_dequeue = ehci_urb_dequeue,
3035+ .endpoint_disable = ehci_endpoint_disable,
3036+
3037+ .get_frame_number = ehci_get_frame,
3038+
3039+ .hub_status_data = ehci_hub_status_data,
3040+ .hub_control = ehci_hub_control,
3041+#ifdef CONFIG_PM
3042+ .bus_suspend = ehci_bus_suspend,
3043+ .bus_resume = ehci_bus_resume,
3044+#endif
3045+
3046+};
3047+
3048+static void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd)
3049+{
3050+
3051+ usb_remove_hcd(hcd);
3052+ iounmap(hcd->regs);
3053+ usb_put_hcd(hcd);
3054+}
3055+EXPORT_SYMBOL_GPL(ssb_ehci_detach);
3056+
3057+static int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **ehci_hcd)
3058+{
3059+ struct ssb_ehci_device *ehcidev;
3060+ struct usb_hcd *hcd;
3061+ int err = -ENOMEM;
3062+ u32 tmp, flags = 0;
3063+
3064+ hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev,
3065+ dev_name(dev->dev));
3066+ if (!hcd)
3067+ goto err_dev_disable;
3068+
3069+ ehcidev = hcd_to_ssb_ehci(hcd);
3070+ ehcidev->enable_flags = flags;
3071+ tmp = ssb_read32(dev, SSB_ADMATCH0);
3072+ hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
3073+ hcd->rsrc_len = 0x100; /* ehci reg block size */
3074+ /*
3075+ * start & size modified per sbutils.c
3076+ */
3077+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
3078+ if (!hcd->regs)
3079+ goto err_put_hcd;
3080+ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED | IRQF_DISABLED);
3081+ if (err)
3082+ goto err_iounmap;
3083+
3084+ *ehci_hcd = hcd;
3085+
3086+ return err;
3087+
3088+err_iounmap:
3089+ iounmap(hcd->regs);
3090+err_put_hcd:
3091+ usb_put_hcd(hcd);
3092+err_dev_disable:
3093+ ssb_device_disable(dev, flags);
3094+ return err;
3095+}
3096+EXPORT_SYMBOL_GPL(ssb_ehci_attach);
3097+
3098+static const struct ssb_device_id ssb_ehci_table[] = {
3099+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
3100+ SSB_DEVTABLE_END
3101+};
3102+MODULE_DEVICE_TABLE(ssb, ssb_ehci_table);
3103diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
3104index 23fd6a8..599f7b5 100644
3105--- a/drivers/usb/host/ohci-ssb.c
3106+++ b/drivers/usb/host/ohci-ssb.c
3107@@ -17,6 +17,8 @@
3108 */
3109 #include <linux/ssb/ssb.h>
3110
3111+extern int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **hcd);
3112+extern void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd);
3113
3114 #define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
3115
3116@@ -24,6 +26,7 @@ struct ssb_ohci_device {
3117 struct ohci_hcd ohci; /* _must_ be at the beginning. */
3118
3119 u32 enable_flags;
3120+ struct usb_hcd *ehci_hcd;
3121 };
3122
3123 static inline
3124@@ -92,13 +95,25 @@ static const struct hc_driver ssb_ohci_hc_driver = {
3125 static void ssb_ohci_detach(struct ssb_device *dev)
3126 {
3127 struct usb_hcd *hcd = ssb_get_drvdata(dev);
3128+#ifdef CONFIG_USB_EHCI_HCD_SSB
3129+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
3130+#endif
3131
3132 usb_remove_hcd(hcd);
3133 iounmap(hcd->regs);
3134 usb_put_hcd(hcd);
3135+
3136+#ifdef CONFIG_USB_EHCI_HCD_SSB
3137+ /*
3138+ * Also detach ehci function
3139+ */
3140+ if (dev->id.coreid == SSB_DEV_USB20_HOST)
3141+ ssb_ehci_detach(dev, ohcidev->ehci_hcd);
3142+#endif
3143 ssb_device_disable(dev, 0);
3144 }
3145
3146+
3147 static int ssb_ohci_attach(struct ssb_device *dev)
3148 {
3149 struct ssb_ohci_device *ohcidev;
3150@@ -106,10 +121,64 @@ static int ssb_ohci_attach(struct ssb_device *dev)
3151 int err = -ENOMEM;
3152 u32 tmp, flags = 0;
3153
3154- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
3155+ /*
3156+ * THE FOLLOWING COMMENTS PRESERVED FROM GPL SOURCE RELEASE
3157+ *
3158+ * The USB core requires a special bit to be set during core
3159+ * reset to enable host (OHCI) mode. Resetting the SB core in
3160+ * pcibios_enable_device() is a hack for compatibility with
3161+ * vanilla usb-ohci so that it does not have to know about
3162+ * SB. A driver that wants to use the USB core in device mode
3163+ * should know about SB and should reset the bit back to 0
3164+ * after calling pcibios_enable_device().
3165+ */
3166+
3167+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
3168 flags |= SSB_OHCI_TMSLOW_HOSTMODE;
3169+ ssb_device_enable(dev, flags);
3170+ }
3171+
3172+ /*
3173+ * USB 2.0 special considerations:
3174+ *
3175+ * 1. Since the core supports both OHCI and EHCI functions, it must
3176+ * only be reset once.
3177+ *
3178+ * 2. In addition to the standard SB reset sequence, the Host Control
3179+ * Register must be programmed to bring the USB core and various
3180+ * phy components out of reset.
3181+ */
3182+
3183+ else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
3184+#warning FIX ME need test for core being up & exit
3185+ ssb_device_enable(dev, 0);
3186+ ssb_write32(dev, 0x200, 0x7ff);
3187+ udelay(1);
3188+ if (dev->id.revision == 1) { // bug in rev 1
3189+
3190+ /* Change Flush control reg */
3191+ tmp = ssb_read32(dev, 0x400);
3192+ tmp &= ~8;
3193+ ssb_write32(dev, 0x400, tmp);
3194+ tmp = ssb_read32(dev, 0x400);
3195+ printk("USB20H fcr: 0x%0x\n", tmp);
3196+
3197+ /* Change Shim control reg */
3198+ tmp = ssb_read32(dev, 0x304);
3199+ tmp &= ~0x100;
3200+ ssb_write32(dev, 0x304, tmp);
3201+ tmp = ssb_read32(dev, 0x304);
3202+ printk("USB20H shim: 0x%0x\n", tmp);
3203+ }
3204+ }
3205+ else
3206+ ssb_device_enable(dev, 0);
3207
3208- ssb_device_enable(dev, flags);
3209+ /*
3210+ * Set dma mask - 32 bit mask is just an assumption
3211+ */
3212+ if (ssb_dma_set_mask(dev, DMA_32BIT_MASK))
3213+ return -EOPNOTSUPP;
3214
3215 hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
3216 dev_name(dev->dev));
3217@@ -130,6 +199,14 @@ static int ssb_ohci_attach(struct ssb_device *dev)
3218
3219 ssb_set_drvdata(dev, hcd);
3220
3221+#ifdef CONFIG_USB_EHCI_HCD_SSB
3222+ /*
3223+ * attach ehci function in this core
3224+ */
3225+ if (dev->id.coreid == SSB_DEV_USB20_HOST)
3226+ err = ssb_ehci_attach(dev, &(ohcidev->ehci_hcd));
3227+#endif
3228+
3229 return err;
3230
3231 err_iounmap:
3232@@ -200,6 +277,7 @@ static int ssb_ohci_resume(struct ssb_device *dev)
3233 static const struct ssb_device_id ssb_ohci_table[] = {
3234 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
3235 SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
3236+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
3237 SSB_DEVTABLE_END
3238 };
3239 MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
3240diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
3241index 5eb8f21..fadc751 100644
3242--- a/drivers/watchdog/Kconfig
3243+++ b/drivers/watchdog/Kconfig
3244@@ -764,6 +764,12 @@ config TXX9_WDT
3245 help
3246 Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
3247
3248+config BCM47XX_WDT
3249+ tristate "Broadcom BCM47xx Watchdog Timer"
3250+ depends on BCM47XX
3251+ help
3252+ Hardware driver for the Broadcom BCM47xx Watchog Timer.
3253+
3254 # PARISC Architecture
3255
3256 # POWERPC Architecture
3257diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
3258index 7f8c56b..99eab0f 100644
3259--- a/drivers/watchdog/Makefile
3260+++ b/drivers/watchdog/Makefile
3261@@ -105,6 +105,7 @@ obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
3262 obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
3263 obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
3264 obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
3265+obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
3266
3267 # PARISC Architecture
3268
3269diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
3270new file mode 100644
3271index 0000000..3a192c7
3272--- /dev/null
3273+++ b/drivers/watchdog/bcm47xx_wdt.c
3274@@ -0,0 +1,286 @@
3275+/*
3276+ * Watchdog driver for Broadcom BCM47XX
3277+ *
3278+ * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
3279+ * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
3280+ *
3281+ * This program is free software; you can redistribute it and/or
3282+ * modify it under the terms of the GNU General Public License
3283+ * as published by the Free Software Foundation; either version
3284+ * 2 of the License, or (at your option) any later version.
3285+ */
3286+
3287+#include <linux/bitops.h>
3288+#include <linux/errno.h>
3289+#include <linux/fs.h>
3290+#include <linux/init.h>
3291+#include <linux/kernel.h>
3292+#include <linux/miscdevice.h>
3293+#include <linux/module.h>
3294+#include <linux/moduleparam.h>
3295+#include <linux/reboot.h>
3296+#include <linux/types.h>
3297+#include <linux/uaccess.h>
3298+#include <linux/watchdog.h>
3299+#include <linux/timer.h>
3300+#include <linux/jiffies.h>
3301+#include <linux/ssb/ssb_embedded.h>
3302+#include <asm/mach-bcm47xx/bcm47xx.h>
3303+
3304+#define DRV_NAME "bcm47xx_wdt"
3305+
3306+#define WDT_DEFAULT_TIME 30 /* seconds */
3307+#define WDT_MAX_TIME 256 /* seconds */
3308+
3309+static int wdt_time = WDT_DEFAULT_TIME;
3310+static int nowayout = WATCHDOG_NOWAYOUT;
3311+
3312+module_param(wdt_time, int, 0);
3313+MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
3314+ __MODULE_STRING(WDT_DEFAULT_TIME) ")");
3315+
3316+#ifdef CONFIG_WATCHDOG_NOWAYOUT
3317+module_param(nowayout, int, 0);
3318+MODULE_PARM_DESC(nowayout,
3319+ "Watchdog cannot be stopped once started (default="
3320+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
3321+#endif
3322+
3323+static unsigned long bcm47xx_wdt_busy;
3324+static char expect_release;
3325+static struct timer_list wdt_timer;
3326+static atomic_t ticks;
3327+
3328+static inline void bcm47xx_wdt_hw_start(void)
3329+{
3330+ /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
3331+ ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
3332+}
3333+
3334+static inline int bcm47xx_wdt_hw_stop(void)
3335+{
3336+ return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
3337+}
3338+
3339+static void bcm47xx_timer_tick(unsigned long unused)
3340+{
3341+ if (!atomic_dec_and_test(&ticks)) {
3342+ bcm47xx_wdt_hw_start();
3343+ mod_timer(&wdt_timer, jiffies + HZ);
3344+ } else {
3345+ printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
3346+ }
3347+}
3348+
3349+static inline void bcm47xx_wdt_pet(void)
3350+{
3351+ atomic_set(&ticks, wdt_time);
3352+}
3353+
3354+static void bcm47xx_wdt_start(void)
3355+{
3356+ bcm47xx_wdt_pet();
3357+ bcm47xx_timer_tick(0);
3358+}
3359+
3360+static void bcm47xx_wdt_pause(void)
3361+{
3362+ del_timer_sync(&wdt_timer);
3363+ bcm47xx_wdt_hw_stop();
3364+}
3365+
3366+static void bcm47xx_wdt_stop(void)
3367+{
3368+ bcm47xx_wdt_pause();
3369+}
3370+
3371+static int bcm47xx_wdt_settimeout(int new_time)
3372+{
3373+ if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
3374+ return -EINVAL;
3375+
3376+ wdt_time = new_time;
3377+ return 0;
3378+}
3379+
3380+static int bcm47xx_wdt_open(struct inode *inode, struct file *file)
3381+{
3382+ if (test_and_set_bit(0, &bcm47xx_wdt_busy))
3383+ return -EBUSY;
3384+
3385+ bcm47xx_wdt_start();
3386+ return nonseekable_open(inode, file);
3387+}
3388+
3389+static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
3390+{
3391+ if (expect_release == 42) {
3392+ bcm47xx_wdt_stop();
3393+ } else {
3394+ printk(KERN_CRIT DRV_NAME
3395+ ": Unexpected close, not stopping watchdog!\n");
3396+ bcm47xx_wdt_start();
3397+ }
3398+
3399+ clear_bit(0, &bcm47xx_wdt_busy);
3400+ expect_release = 0;
3401+ return 0;
3402+}
3403+
3404+static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
3405+ size_t len, loff_t *ppos)
3406+{
3407+ if (len) {
3408+ if (!nowayout) {
3409+ size_t i;
3410+
3411+ expect_release = 0;
3412+
3413+ for (i = 0; i != len; i++) {
3414+ char c;
3415+ if (get_user(c, data + i))
3416+ return -EFAULT;
3417+ if (c == 'V')
3418+ expect_release = 42;
3419+ }
3420+ }
3421+ bcm47xx_wdt_pet();
3422+ }
3423+ return len;
3424+}
3425+
3426+static struct watchdog_info bcm47xx_wdt_info = {
3427+ .identity = DRV_NAME,
3428+ .options = WDIOF_SETTIMEOUT |
3429+ WDIOF_KEEPALIVEPING |
3430+ WDIOF_MAGICCLOSE,
3431+};
3432+
3433+static long bcm47xx_wdt_ioctl(struct file *file,
3434+ unsigned int cmd, unsigned long arg)
3435+{
3436+ void __user *argp = (void __user *)arg;
3437+ int __user *p = argp;
3438+ int new_value, retval = -EINVAL;;
3439+
3440+ switch (cmd) {
3441+ case WDIOC_GETSUPPORT:
3442+ return copy_to_user(argp, &bcm47xx_wdt_info,
3443+ sizeof(bcm47xx_wdt_info)) ? -EFAULT : 0;
3444+
3445+ case WDIOC_GETSTATUS:
3446+ case WDIOC_GETBOOTSTATUS:
3447+ return put_user(0, p);
3448+
3449+ case WDIOC_SETOPTIONS:
3450+ if (get_user(new_value, p))
3451+ return -EFAULT;
3452+
3453+ if (new_value & WDIOS_DISABLECARD) {
3454+ bcm47xx_wdt_stop();
3455+ retval = 0;
3456+ }
3457+
3458+ if (new_value & WDIOS_ENABLECARD) {
3459+ bcm47xx_wdt_start();
3460+ retval = 0;
3461+ }
3462+
3463+ return retval;
3464+
3465+ case WDIOC_KEEPALIVE:
3466+ bcm47xx_wdt_pet();
3467+ return 0;
3468+
3469+ case WDIOC_SETTIMEOUT:
3470+ if (get_user(new_value, p))
3471+ return -EFAULT;
3472+
3473+ if (bcm47xx_wdt_settimeout(new_value))
3474+ return -EINVAL;
3475+
3476+ bcm47xx_wdt_pet();
3477+
3478+ case WDIOC_GETTIMEOUT:
3479+ return put_user(wdt_time, p);
3480+
3481+ default:
3482+ return -ENOTTY;
3483+ }
3484+}
3485+
3486+static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
3487+ unsigned long code, void *unused)
3488+{
3489+ if (code == SYS_DOWN || code == SYS_HALT)
3490+ bcm47xx_wdt_stop();
3491+ return NOTIFY_DONE;
3492+}
3493+
3494+static const struct file_operations bcm47xx_wdt_fops = {
3495+ .owner = THIS_MODULE,
3496+ .llseek = no_llseek,
3497+ .unlocked_ioctl = bcm47xx_wdt_ioctl,
3498+ .open = bcm47xx_wdt_open,
3499+ .release = bcm47xx_wdt_release,
3500+ .write = bcm47xx_wdt_write,
3501+};
3502+
3503+static struct miscdevice bcm47xx_wdt_miscdev = {
3504+ .minor = WATCHDOG_MINOR,
3505+ .name = "watchdog",
3506+ .fops = &bcm47xx_wdt_fops,
3507+};
3508+
3509+static struct notifier_block bcm47xx_wdt_notifier = {
3510+ .notifier_call = bcm47xx_wdt_notify_sys,
3511+};
3512+
3513+static int __init bcm47xx_wdt_init(void)
3514+{
3515+ int ret;
3516+
3517+ if (bcm47xx_wdt_hw_stop() < 0)
3518+ return -ENODEV;
3519+
3520+ setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);
3521+
3522+ if (bcm47xx_wdt_settimeout(wdt_time)) {
3523+ bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
3524+ printk(KERN_INFO DRV_NAME
3525+ ": wdt_time value must be 1 <= wdt_time <= 256, using %d\n",
3526+ wdt_time);
3527+ }
3528+
3529+ ret = register_reboot_notifier(&bcm47xx_wdt_notifier);
3530+ if (ret)
3531+ return ret;
3532+
3533+ ret = misc_register(&bcm47xx_wdt_miscdev);
3534+ if (ret) {
3535+ unregister_reboot_notifier(&bcm47xx_wdt_notifier);
3536+ return ret;
3537+ }
3538+
3539+ printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
3540+ wdt_time, nowayout ? ", nowayout" : "");
3541+ return 0;
3542+}
3543+
3544+static void __exit bcm47xx_wdt_exit(void)
3545+{
3546+ if (!nowayout)
3547+ bcm47xx_wdt_stop();
3548+
3549+ misc_deregister(&bcm47xx_wdt_miscdev);
3550+
3551+ unregister_reboot_notifier(&bcm47xx_wdt_notifier);
3552+}
3553+
3554+module_init(bcm47xx_wdt_init);
3555+module_exit(bcm47xx_wdt_exit);
3556+
3557+MODULE_AUTHOR("Aleksandar Radovanovic");
3558+MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
3559+MODULE_LICENSE("GPL");
3560+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
3561diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
3562index ba76b68..c22aefd 100644
3563--- a/fs/fuse/dev.c
3564+++ b/fs/fuse/dev.c
3565@@ -527,6 +527,11 @@ static void fuse_copy_finish(struct fuse_copy_state *cs)
3566 }
3567 }
3568
3569+#ifdef DCACHE_BUG
3570+extern void (*fuse_flush_cache_all)(void);
3571+extern void (*fuse_flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
3572+#endif
3573+
3574 /*
3575 * Get another pagefull of userspace buffer, and map it to kernel
3576 * address space, and lock request
3577@@ -535,6 +540,9 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
3578 {
3579 unsigned long offset;
3580 int err;
3581+#ifdef DCACHE_BUG
3582+ struct vm_area_struct *vma;
3583+#endif
3584
3585 unlock_request(cs->fc, cs->req);
3586 fuse_copy_finish(cs);
3587@@ -546,14 +554,22 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
3588 cs->nr_segs--;
3589 }
3590 down_read(&current->mm->mmap_sem);
3591+#ifndef DCACHE_BUG
3592 err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0,
3593 &cs->pg, NULL);
3594+#else
3595+ err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0,
3596+ &cs->pg, &vma);
3597+#endif
3598 up_read(&current->mm->mmap_sem);
3599 if (err < 0)
3600 return err;
3601 BUG_ON(err != 1);
3602 offset = cs->addr % PAGE_SIZE;
3603 cs->mapaddr = kmap_atomic(cs->pg, KM_USER0);
3604+#ifdef DCACHE_BUG
3605+ fuse_flush_cache_page(vma, cs->addr, page_to_pfn(cs->pg));
3606+#endif
3607 cs->buf = cs->mapaddr + offset;
3608 cs->len = min(PAGE_SIZE - offset, cs->seglen);
3609 cs->seglen -= cs->len;
3610@@ -567,6 +583,11 @@ static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
3611 {
3612 unsigned ncpy = min(*size, cs->len);
3613 if (val) {
3614+#ifdef DCACHE_BUG
3615+ // patch from mailing list, it is very important, otherwise,
3616+ // can't mount, or ls mount point will hang
3617+ fuse_flush_cache_all();
3618+#endif
3619 if (cs->write)
3620 memcpy(cs->buf, *val, ncpy);
3621 else
3622diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
3623index 6fc5aed..ca2cc6b 100644
3624--- a/fs/fuse/fuse_i.h
3625+++ b/fs/fuse/fuse_i.h
3626@@ -8,6 +8,7 @@
3627
3628 #ifndef _FS_FUSE_I_H
3629 #define _FS_FUSE_I_H
3630+#define DCACHE_BUG
3631
3632 #include <linux/fuse.h>
3633 #include <linux/fs.h>
3634diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
3635index 91f7c85..8827ce8 100644
3636--- a/fs/fuse/inode.c
3637+++ b/fs/fuse/inode.c
3638@@ -1055,6 +1055,10 @@ static int __init fuse_init(void)
3639 printk(KERN_INFO "fuse init (API version %i.%i)\n",
3640 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
3641
3642+#ifdef DCACHE_BUG
3643+printk("fuse init: DCACHE_BUG enabled\n");
3644+#endif
3645+
3646 INIT_LIST_HEAD(&fuse_conn_list);
3647 res = fuse_fs_init();
3648 if (res)
3649diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
3650index 0f71812..6087a7d 100644
3651--- a/include/linux/pci_ids.h
3652+++ b/include/linux/pci_ids.h
3653@@ -2106,6 +2106,7 @@
3654 #define PCI_DEVICE_ID_TIGON3_5906M 0x1713
3655 #define PCI_DEVICE_ID_BCM4401 0x4401
3656 #define PCI_DEVICE_ID_BCM4401B0 0x4402
3657+#define PCI_DEVICE_ID_BCM4713 0x4713
3658
3659 #define PCI_VENDOR_ID_TOPIC 0x151f
3660 #define PCI_DEVICE_ID_TOPIC_TP560 0x0000
Note: See TracBrowser for help on using the repository browser.