Merge "WindCharger: Flush data cache to memory before system restart."
diff --git a/arch/mips/configs/gfmn100_defconfig b/arch/mips/configs/gfmn100_defconfig
index 89302d8..4ebae82 100644
--- a/arch/mips/configs/gfmn100_defconfig
+++ b/arch/mips/configs/gfmn100_defconfig
@@ -9,10 +9,11 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_KALLSYMS is not set
+CONFIG_PRINTK_PERSIST=y
 # CONFIG_ELF_CORE is not set
 # CONFIG_BASE_FULL is not set
 # CONFIG_AIO is not set
@@ -198,7 +199,7 @@
 CONFIG_DEBUG_INFO=y
 # CONFIG_FTRACE is not set
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="board=MN100"
+CONFIG_CMDLINE="board=MN100 log_buf_len=262144"
 CONFIG_CRYPTO_CCM=y
 CONFIG_CRYPTO_GCM=y
 CONFIG_CRYPTO_AES=y
diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
index d775f16..bde43a5 100644
--- a/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
+++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
@@ -14,6 +14,46 @@
 
 #include "ag71xx.h"
 
+#define AR934X_PHY_SPECIFIC_STATUS_REG 0x11
+
+#define AR934X_PORT_STATUS_SPEED_MASK 0xc000
+#define AR934X_PORT_STATUS_SPEED_10  (0 << 14)
+#define AR934X_PORT_STATUS_SPEED_100 (1 << 14)
+#define AR934X_PORT_STATUS_DUPLEX    (1 << 13)
+
+static int ag71xx_ethtool_get_settings_switchport(struct net_device *dev,
+				       struct ethtool_cmd *cmd)
+{
+	struct ag71xx *ag = netdev_priv(dev);
+	struct platform_device *pdev = ag->pdev;
+	struct net_device *netdev = ag->dev;
+	uint16_t status;
+
+	status = ag->mii_bus->read(ag->mii_bus, netdev->dev_id,
+			AR934X_PHY_SPECIFIC_STATUS_REG);
+	if (status == 0xffff)
+		return -ENODEV;
+
+	switch (status & AR934X_PORT_STATUS_SPEED_MASK) {
+	case AR934X_PORT_STATUS_SPEED_10:
+		ethtool_cmd_speed_set(cmd, 10);
+		break;
+	case AR934X_PORT_STATUS_SPEED_100:
+		ethtool_cmd_speed_set(cmd, 100);
+		break;
+	default:
+		ethtool_cmd_speed_set(cmd, 0);
+		break;
+	}
+
+	cmd->duplex = !!(status & AR934X_PORT_STATUS_DUPLEX);
+	cmd->port = PORT_MII;
+	cmd->transceiver = XCVR_EXTERNAL;
+	cmd->autoneg = 1;
+
+	return 0;
+}
+
 static int ag71xx_ethtool_get_settings(struct net_device *dev,
 				       struct ethtool_cmd *cmd)
 {
@@ -21,7 +61,7 @@
 	struct phy_device *phydev = ag->phy_dev;
 
 	if (!phydev)
-		return -ENODEV;
+		return ag71xx_ethtool_get_settings_switchport(dev, cmd);
 
 	return phy_ethtool_gset(phydev, cmd);
 }
diff --git a/init/Kconfig b/init/Kconfig
index 7e75262..42b4e8b 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1044,6 +1044,20 @@
 	  very difficult to diagnose system problems, saying N here is
 	  strongly discouraged.
 
+
+config PRINTK_PERSIST
+	default n
+	bool "printk log persists across reboots" if PRINTK
+	help
+	  This option tries to keep the printk memory buffer in a well-known
+	  location in physical memory. It isn't cleared on reboot (unless RAM
+	  is wiped by your boot loader or BIOS) so if your system crashes
+	  or panics, you might get to examine all the log messages next time you
+	  boot. The persisted log messages show up in your 'dmesg' output.
+	  Note: you must supply the log_buf_len= kernel parameter to
+	  activate this feature.
+
+
 config BUG
 	bool "BUG() support" if EXPERT
 	default y
diff --git a/kernel/printk.c b/kernel/printk.c
index ff14e1c..938b14d 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -42,6 +42,7 @@
 #include <linux/notifier.h>
 #include <linux/rculist.h>
 #include <linux/poll.h>
+#include <linux/crc32.h>
 
 #include <asm/uaccess.h>
 
@@ -64,6 +65,30 @@
 
 DECLARE_WAIT_QUEUE_HEAD(log_wait);
 
+struct log {
+	u64 ts_nsec;		/* timestamp in nanoseconds */
+	u16 len;		/* length of entire record */
+	u16 text_len;		/* length of text buffer */
+	u16 dict_len;		/* length of dictionary buffer */
+	u8 facility;		/* syslog facility */
+#ifdef CONFIG_PRINTK_PERSIST
+	u32 crc;		/* The flags may change, so don't include them. */
+#endif
+	u8 flags:5;		/* internal record flags */
+	u8 level:3;		/* syslog level */
+};
+
+/* record buffer */
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+#define LOG_ALIGN 4
+#else
+#define LOG_ALIGN __alignof__(struct log)
+#endif
+#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
+static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
+static char *log_buf = __log_buf;
+#define LOG_LINE_MAX 1024
+
 int console_printk[4] = {
 	DEFAULT_CONSOLE_LOGLEVEL,	/* console_loglevel */
 	DEFAULT_MESSAGE_LOGLEVEL,	/* default_message_loglevel */
@@ -200,22 +225,14 @@
 	LOG_CONT	= 8,	/* text is a fragment of a continuation line */
 };
 
-struct log {
-	u64 ts_nsec;		/* timestamp in nanoseconds */
-	u16 len;		/* length of entire record */
-	u16 text_len;		/* length of text buffer */
-	u16 dict_len;		/* length of dictionary buffer */
-	u8 facility;		/* syslog facility */
-	u8 flags:5;		/* internal record flags */
-	u8 level:3;		/* syslog level */
-};
-
 /*
  * The logbuf_lock protects kmsg buffer, indices, counters. It is also
  * used in interesting ways to provide interlocking in console_unlock();
  */
 static DEFINE_RAW_SPINLOCK(logbuf_lock);
 
+#ifdef CONFIG_PRINTK
+#ifndef CONFIG_PRINTK_PERSIST
 /* the next printk record to read by syslog(READ) or /proc/kmsg */
 static u64 syslog_seq;
 static u32 syslog_idx;
@@ -228,25 +245,173 @@
 
 /* index and sequence number of the next record to store in the buffer */
 static u64 log_next_seq;
-#ifdef CONFIG_PRINTK
 static u32 log_next_idx;
 
 /* the next printk record to read after the last 'clear' command */
 static u64 clear_seq;
 static u32 clear_idx;
 
-#define LOG_LINE_MAX 1024
+/* the next printk record to write to the console */
+static u64 console_seq;
+static u32 console_idx;
+static enum log_flags console_prev;
 
-/* record buffer */
-#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
-#define LOG_ALIGN 4
-#else
-#define LOG_ALIGN __alignof__(struct log)
-#endif
-#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
-static char *log_buf = __log_buf;
 static u32 log_buf_len = __LOG_BUF_LEN;
+#else  /* CONFIG_PRINTK_PERSIST */
+struct log_state {
+	u32 magic;
+	u32 _log_buf_len;
+	u64 _syslog_seq;
+	u32 _syslog_idx;
+	enum log_flags _syslog_prev;
+	size_t _syslog_partial;
+
+	u64 _log_first_seq;
+	u32 _log_first_idx;
+
+	u64 _log_next_seq;
+	u32 _log_next_idx;
+
+	u64 _console_seq;
+	u32 _console_idx;
+	enum log_flags _console_prev;
+
+	u64 _clear_seq;
+	u32 _clear_idx;
+};
+static struct log_state __log_state = {
+	._log_buf_len = __LOG_BUF_LEN,
+};
+static struct log_state *log_state = &__log_state;
+#define log_buf_len			log_state->_log_buf_len
+#define syslog_seq			log_state->_syslog_seq
+#define syslog_idx			log_state->_syslog_idx
+#define syslog_prev			log_state->_syslog_prev
+#define syslog_partial	log_state->_syslog_partial
+#define log_first_seq		log_state->_log_first_seq
+#define log_first_idx		log_state->_log_first_idx
+#define log_next_seq		log_state->_log_next_seq
+#define log_next_idx		log_state->_log_next_idx
+#define console_seq			log_state->_console_seq
+#define console_idx			log_state->_console_idx
+#define console_prev		log_state->_console_prev
+#define clear_seq				log_state->_clear_seq
+#define clear_idx				log_state->_clear_idx
+
+#define PERSIST_SEARCH_START 0
+/* TODO(awdavies): Hard coded addr.  Determined through guess/check.
+ *
+ * As such it is not likely that this address is entirely reliable. For a more
+ * portable solution, the bootloader should inform the kernel that there is a
+ * specific location of free memory that will it will not touch.
+ */
+#define PERSIST_SEARCH_END 0x17f0000
+#define PERSIST_SEARCH_JUMP 0x1000000
+#define PERSIST_MAGIC 0xcafef00d
+
+/*
+ * Size is a power of 2 so that the printk offset mask will work.  A little
+ * extra space is added to the end of the buffer for extra data, but that
+ * doesn't change the offset of the buffers.
+ */
+static __init struct log_state *log_buf_alloc(unsigned long size,
+		char **new_logbuf)
+{
+	unsigned long where;
+	char *buf;
+	unsigned long full_size = size + sizeof(struct log_state);
+	struct log_state *new_log_state;
+	struct log *pklog;
+	u64 idx, lost_entries, seq;
+	u32 curr_crc;
+
+	for (where = PERSIST_SEARCH_END - size;
+	     where >= PERSIST_SEARCH_START;
+	     where -= PERSIST_SEARCH_JUMP) {
+		if (reserve_bootmem(where, full_size, BOOTMEM_EXCLUSIVE)) {
+			continue;
+		}
+		buf = phys_to_virt(where);
+		*new_logbuf = buf;
+		new_log_state = phys_to_virt(where + size);
+		pr_info("printk_persist: memory reserved @ 0x%08lx\n", where);
+		if ((new_log_state->magic != PERSIST_MAGIC) ||
+				(new_log_state->_log_buf_len != size) ||
+					(new_log_state->_log_first_seq >
+						new_log_state->_log_next_seq) ||
+					(new_log_state->_log_first_idx > size) ||
+					(new_log_state->_syslog_idx > size) ||
+					(new_log_state->_syslog_seq >
+						new_log_state->_log_next_seq) ||
+					(new_log_state->_log_next_idx > size) ||
+					(new_log_state->_console_seq >
+						new_log_state->_log_next_seq) ||
+					(new_log_state->_console_idx > size) ||
+					(new_log_state->_clear_seq >
+						new_log_state->_log_next_seq) ||
+					(new_log_state->_clear_idx > size)) {
+			pr_info("printk_persist: header invalid. Clearing.\n");
+			memset(buf, 0, full_size);
+			memset(new_log_state, 0, sizeof(*new_log_state));
+			new_log_state->magic = PERSIST_MAGIC;
+			new_log_state->_log_buf_len = size;
+		} else {
+			pr_info("printk_persist: Valid header: "
+					"\tlog_first_idx=%d\n"
+					"\tlog_next_idx=%d\n"
+					"\tlog_first_seq=%lld\n"
+					"\tlog_next_seq=%lld\n"
+					"\tconsole_seq=%lld\n"
+					"\tconsole_idx=%d\n"
+					"\tsyslog_seq=%lld\n"
+					"\tsyslog_idx=%d\n",
+					new_log_state->_log_first_idx,
+					new_log_state->_log_next_idx,
+					new_log_state->_log_first_seq,
+					new_log_state->_log_next_seq,
+					new_log_state->_console_seq,
+					new_log_state->_console_idx,
+					new_log_state->_syslog_seq,
+					new_log_state->_syslog_idx);
+			pr_info("printk_persist: validating records.\n");
+			for (seq = new_log_state->_log_first_seq,
+			     idx = new_log_state->_log_first_idx;
+			     seq < new_log_state->_log_next_seq;
+			     ++seq) {
+				pklog = (struct log *) &buf[idx];
+				/* If crc doesn't match, move the next pointer to be here. */
+				curr_crc = crc32(~0, pklog, offsetof(struct log, crc));
+				if (pklog->crc != curr_crc) {
+					lost_entries = new_log_state->_log_next_seq - seq;
+					pr_info("printk_persist: corruption encountered. lost %llu entries\n",
+						lost_entries);
+					new_log_state->_log_next_seq = seq;
+					new_log_state->_log_next_idx = idx;
+					break;
+				}
+				if (pklog->len == 0) {
+					idx = 0;
+					/* Do not increment the sequence counter for the record that's used
+					 * to indicate wrapping.  We still want to verify its CRC above,
+					 * however. */
+					--seq;
+				} else {
+					idx += pklog->len;
+				}
+			}
+		}
+		return new_log_state;
+	}
+	printk(KERN_ERR "printk_persist: failed to reserve bootmem "
+			"area.  persistence disabled.\n");
+	buf = alloc_bootmem(full_size);
+	*new_logbuf = buf;
+	new_log_state = (struct log_state *)(buf + size);
+	memset(buf, 0, full_size);
+	return new_log_state;
+}
+
+#endif  /* CONFIG_PRINTK_PERSIST */
 
 /* cpu currently holding logbuf_lock */
 static volatile unsigned int logbuf_cpu = UINT_MAX;
@@ -295,6 +460,33 @@
 	return idx + msg->len;
 }
 
+static int logbuf_has_space(u32 msg_size, bool empty)
+{
+	u32 free;
+
+	if (log_next_idx > log_first_idx || empty)
+		free = max(log_buf_len - log_next_idx, log_first_idx);
+	else
+		free = log_first_idx - log_next_idx;
+
+	return free >= msg_size + sizeof(struct log);
+}
+
+static int log_make_free_space(u32 msg_size)
+{
+	while (log_first_seq < log_next_seq) {
+		if (logbuf_has_space(msg_size, false))
+			return 0;
+		log_first_idx = log_next(log_first_idx);
+		log_first_seq++;
+	}
+
+	if (logbuf_has_space(msg_size, true))
+		return 0;
+
+	return -ENOMEM;
+}
+
 /* insert record into the buffer, discard old ones, update heads */
 static void log_store(int facility, int level,
 		      enum log_flags flags, u64 ts_nsec,
@@ -332,6 +524,10 @@
 		 * to signify a wrap around.
 		 */
 		memset(log_buf + log_next_idx, 0, sizeof(struct log));
+#ifdef CONFIG_PRINTK_PERSIST
+		((struct log *) (log_buf + log_next_idx))->crc =
+			crc32(~0, log_buf + log_next_idx, offsetof(struct log, crc));
+#endif
 		log_next_idx = 0;
 	}
 
@@ -350,6 +546,9 @@
 		msg->ts_nsec = local_clock();
 	memset(log_dict(msg) + dict_len, 0, pad_len);
 	msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+#ifdef CONFIG_PRINTK_PERSIST
+	msg->crc = crc32(~0, msg, offsetof(struct log, crc));
+#endif
 
 	/* insert message */
 	log_next_idx += msg->len;
@@ -671,13 +870,21 @@
 	unsigned long flags;
 	char *new_log_buf;
 	int free;
+#ifdef CONFIG_PRINTK_PERSIST
+	struct log_state *new_log_state;
+	struct log_state *old_log_state;
+	struct log *pklog;
+	u64 seq;
+	u32 idx;
+	int console_found=0, syslog_found=0;
+#endif
 
 	if (!new_log_buf_len)
 		return;
 
+#ifndef CONFIG_PRINTK_PERSIST
 	if (early) {
 		unsigned long mem;
-
 		mem = memblock_alloc(new_log_buf_len, PAGE_SIZE);
 		if (!mem)
 			return;
@@ -685,6 +892,9 @@
 	} else {
 		new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
 	}
+#else  /* CONFIG_PRINTK_PERSIST */
+	new_log_state = log_buf_alloc(new_log_buf_len, &new_log_buf);
+#endif  /* CONFIG_PRINTK_PERSIST */
 
 	if (unlikely(!new_log_buf)) {
 		pr_err("log_buf_len: %ld bytes not available\n",
@@ -697,7 +907,60 @@
 	log_buf = new_log_buf;
 	new_log_buf_len = 0;
 	free = __LOG_BUF_LEN - log_next_idx;
+#ifndef CONFIG_PRINTK_PERSIST
 	memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
+#else
+	old_log_state = log_state;
+	log_state = new_log_state;
+	for (seq = old_log_state->_log_first_seq, idx = old_log_state->_log_first_idx;
+				seq < old_log_state->_log_next_seq; ++seq) {
+		pklog = (struct log *)&__log_buf[idx];
+		if (pklog->len == 0) {
+			idx = 0;
+			pklog = (struct log *)&__log_buf[0];
+		}
+
+		if (log_make_free_space(pklog->len)) {
+			pr_err("not copying entry due to it being too large\n");
+			idx += pklog->len;
+			continue;
+		}
+
+		if (log_next_idx + pklog->len + sizeof(struct log) > log_buf_len) {
+			memset(log_buf + log_next_idx, 0, sizeof(struct log));
+			((struct log *) (log_buf + log_next_idx))->crc =
+				crc32(~0, log_buf + log_next_idx, offsetof(struct log, crc));
+			log_next_idx = 0;
+		}
+		memcpy(&log_buf[log_next_idx], &__log_buf[idx], pklog->len);
+
+		if (old_log_state->_syslog_seq == seq) {
+			syslog_seq = log_next_seq;
+			syslog_idx = log_next_idx;
+			syslog_found = 1;
+		}
+
+		if (old_log_state->_console_seq == seq) {
+			console_seq = log_next_seq;
+			console_idx = log_next_idx;
+			console_found = 1;
+		}
+
+		idx += pklog->len;
+		++log_next_seq;
+		log_next_idx += pklog->len;
+	}
+
+	if (!syslog_found) {
+		syslog_seq = log_next_seq;
+		syslog_idx = log_next_idx;
+	}
+
+	if (!console_found) {
+		console_seq = log_next_seq;
+		console_idx = log_next_idx;
+	}
+#endif  /* CONFIG_PRINTK_PERSIST */
 	raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 
 	pr_info("log_buf_len: %d\n", log_buf_len);
@@ -1616,7 +1879,7 @@
 }
 EXPORT_SYMBOL(printk);
 
-#else
+#else  /* CONFIG_PRINTK */
 
 #define LOG_LINE_MAX 0
 static struct cont {
@@ -1625,6 +1888,16 @@
 	u8 level;
 	bool flushed:1;
 } cont;
+static u64 syslog_seq;
+static u32 syslog_idx;
+static enum log_flags syslog_prev;
+static size_t syslog_partial;
+static u64 log_first_seq;
+static u32 log_first_idx;
+static u64 log_next_seq;
+static u64 console_seq;
+static u32 console_idx;
+static enum log_flags console_prev;
 static struct log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
 static void call_console_drivers(int level, const char *text, size_t len) {}
@@ -1896,11 +2169,6 @@
 		this_cpu_write(printk_pending, 1);
 }
 
-/* the next printk record to write to the console */
-static u64 console_seq;
-static u32 console_idx;
-static enum log_flags console_prev;
-
 /**
  * console_unlock - unlock the console system
  *
diff --git a/mm/bootmem.c b/mm/bootmem.c
index d5ba3ac..8a70c14 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -40,6 +40,7 @@
 static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
 
 static int bootmem_debug;
+static int bootmem_stopped = 0;
 
 static int __init bootmem_debug_setup(char *buf)
 {
@@ -184,6 +185,7 @@
 
 	bdebug("nid=%td start=%lx end=%lx\n",
 		bdata - bootmem_node_data, start, end);
+	bootmem_stopped = 1;
 
 	while (start < end) {
 		unsigned long *map, idx, vec;
@@ -281,6 +283,7 @@
 	unsigned long idx;
 	int exclusive = flags & BOOTMEM_EXCLUSIVE;
 
+	BUG_ON(bootmem_stopped);
 	bdebug("nid=%td start=%lx end=%lx flags=%x\n",
 		bdata - bootmem_node_data,
 		sidx + bdata->node_min_pfn,
@@ -350,7 +353,10 @@
 			return 0;
 		pos = bdata->node_low_pfn;
 	}
-	BUG();
+	if (reserve && (flags & BOOTMEM_EXCLUSIVE))
+		return -ENOENT;  /* not a bug as long as you use EXCLUSIVE. */
+	else
+		BUG();
 }
 
 /**