Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
  [MIPS] Treat R14000 like R10000.
  [MIPS] Remove EXPERIMENTAL from PAGE_SIZE_16KB
  [MIPS] Update/Fix instruction definitions
  [MIPS] DSP and MDMX share the same config flag bit.
  [MIPS] Fix deadlock on MP with cache aliases.
  [MIPS] Use generic STABS_DEBUG macro.
  [MIPS] Create consistency in "system type" selection.
  [MIPS] Use generic DWARF_DEBUG
  [MIPS] Fix kgdb exception handler from user mode.
  [MIPS] Update struct sigcontext member names
  [MIPS] Update/fix futex assembly
  [MIPS] Remove support for sysmips(2) SETNAME and MIPS_RDNVRAM operations.
  [MIPS] Fix detection and handling of the 74K processor.
  [MIPS] Add missing 34K processor IDs
  [MIPS] Fix marking buddy of pte global for MIPS32 w/36-bit physical address
  [MIPS] AU1xxx mips_timer_interrupt() fixes
  [MIPS] Fix typo
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index f14b2d0..95273de 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -376,7 +376,7 @@
 		ecc_mask = 0;
 	}
 
-	if (cpu_arch <= CPU_ARCH_ARMv5TEJ) {
+	if (cpu_arch <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) {
 		for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
 			if (mem_types[i].prot_l1)
 				mem_types[i].prot_l1 |= PMD_BIT4;
@@ -631,7 +631,7 @@
 		pgd = init_mm.pgd;
 
 	base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
-	if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ)
+	if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
 		base_pmdval |= PMD_BIT4;
 
 	for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index df2343e..c896ce8 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1157,6 +1157,7 @@
 /* some quirks for platform function decoding */
 enum {
 	pmac_i2c_quirk_invmask = 0x00000001u,
+	pmac_i2c_quirk_skip = 0x00000002u,
 };
 
 static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
@@ -1172,6 +1173,15 @@
 		/* XXX Study device-tree's & apple drivers are get the quirks
 		 * right !
 		 */
+		/* Workaround: It seems that running the clockspreading
+		 * properties on the eMac will cause lockups during boot.
+		 * The machine seems to work fine without that. So for now,
+		 * let's make sure i2c-hwclock doesn't match about "imic"
+		 * clocks and we'll figure out if we really need to do
+		 * something special about those later.
+		 */
+		{ "i2c-hwclock", "imic5002", pmac_i2c_quirk_skip },
+		{ "i2c-hwclock", "imic5003", pmac_i2c_quirk_skip },
 		{ "i2c-hwclock", NULL, pmac_i2c_quirk_invmask },
 		{ "i2c-cpu-voltage", NULL, 0},
 		{  "temp-monitor", NULL, 0 },
@@ -1198,6 +1208,8 @@
 				if (p->compatible &&
 				    !device_is_compatible(np, p->compatible))
 					continue;
+				if (p->quirks & pmac_i2c_quirk_skip)
+					break;
 				callback(np, p->quirks);
 				break;
 			}
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 662209d..2a769cc 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -8,7 +8,6 @@
  *
  */
 
-#include <linux/vt_kern.h>
 #include <linux/device.h>
 #include <linux/kallsyms.h>
 #include <linux/pm.h>
@@ -66,6 +65,7 @@
 	return error;
 }
 
+
 /**
  *	device_suspend - Save state and stop all devices in system.
  *	@state:		Power state to put each device in.
@@ -85,9 +85,6 @@
 {
 	int error = 0;
 
-	if (!is_console_suspend_safe())
-		return -EINVAL;
-
 	down(&dpm_sem);
 	down(&dpm_list_sem);
 	while (!list_empty(&dpm_active) && error == 0) {
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index b36eef0..02a7dd7 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1184,20 +1184,20 @@
 static void port_cleanup(struct smi_info *info)
 {
 	unsigned int addr = info->io.addr_data;
-	int          mapsize;
+	int          idx;
 
 	if (addr) {
-		mapsize = ((info->io_size * info->io.regspacing)
-			   - (info->io.regspacing - info->io.regsize));
-
-		release_region (addr, mapsize);
+	  	for (idx = 0; idx < info->io_size; idx++) {
+			release_region(addr + idx * info->io.regspacing,
+				       info->io.regsize);
+		}
 	}
 }
 
 static int port_setup(struct smi_info *info)
 {
 	unsigned int addr = info->io.addr_data;
-	int          mapsize;
+	int          idx;
 
 	if (!addr)
 		return -ENODEV;
@@ -1225,16 +1225,22 @@
 		return -EINVAL;
 	}
 
-	/* Calculate the total amount of memory to claim.  This is an
-	 * unusual looking calculation, but it avoids claiming any
-	 * more memory than it has to.  It will claim everything
-	 * between the first address to the end of the last full
-	 * register. */
-	mapsize = ((info->io_size * info->io.regspacing)
-		   - (info->io.regspacing - info->io.regsize));
-
-	if (request_region(addr, mapsize, DEVICE_NAME) == NULL)
-		return -EIO;
+	/* Some BIOSes reserve disjoint I/O regions in their ACPI
+	 * tables.  This causes problems when trying to register the
+	 * entire I/O region.  Therefore we must register each I/O
+	 * port separately.
+	 */
+  	for (idx = 0; idx < info->io_size; idx++) {
+		if (request_region(addr + idx * info->io.regspacing,
+				   info->io.regsize, DEVICE_NAME) == NULL) {
+			/* Undo allocations */
+			while (idx--) {
+				release_region(addr + idx * info->io.regspacing,
+					       info->io.regsize);
+			}
+			return -EIO;
+		}
+	}
 	return 0;
 }
 
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index e45f0d3..a611972 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -105,6 +105,12 @@
 	"Non-Host Info"
 };
 
+struct tcpa_pc_event {
+	u32 event_id;
+	u32 event_size;
+	u8 event_data[0];
+};
+
 enum tcpa_pc_event_ids {
 	SMBIOS = 1,
 	BIS_CERT,
@@ -114,14 +120,15 @@
 	NVRAM,
 	OPTION_ROM_EXEC,
 	OPTION_ROM_CONFIG,
-	OPTION_ROM_MICROCODE,
+	OPTION_ROM_MICROCODE = 10,
 	S_CRTM_VERSION,
 	S_CRTM_CONTENTS,
 	POST_CONTENTS,
+	HOST_TABLE_OF_DEVICES,
 };
 
 static const char* tcpa_pc_event_id_strings[] = {
-	""
+	"",
 	"SMBIOS",
 	"BIS Certificate",
 	"POST BIOS ",
@@ -130,11 +137,12 @@
 	"NVRAM",
 	"Option ROM",
 	"Option ROM config",
-	"Option ROM microcode",
+	"",
+	"Option ROM microcode ",
 	"S-CRTM Version",
-	"S-CRTM Contents",
-	"S-CRTM POST Contents",
-	"POST Contents",
+	"S-CRTM Contents ",
+	"POST Contents ",
+	"Table of Devices",
 };
 
 /* returns pointer to start of pos. entry of tcg log */
@@ -206,7 +214,7 @@
 	const char *name = "";
 	char data[40] = "";
 	int i, n_len = 0, d_len = 0;
-	u32 event_id;
+	struct tcpa_pc_event *pc_event;
 
 	switch(event->event_type) {
 	case PREBOOT:
@@ -235,31 +243,32 @@
 		}
 		break;
 	case EVENT_TAG:
-		event_id = be32_to_cpu(*((u32 *)event_entry));
+		pc_event = (struct tcpa_pc_event *)event_entry;
 
 		/* ToDo Row data -> Base64 */
 
-		switch (event_id) {
+		switch (pc_event->event_id) {
 		case SMBIOS:
 		case BIS_CERT:
 		case CMOS:
 		case NVRAM:
 		case OPTION_ROM_EXEC:
 		case OPTION_ROM_CONFIG:
-		case OPTION_ROM_MICROCODE:
 		case S_CRTM_VERSION:
-		case S_CRTM_CONTENTS:
-		case POST_CONTENTS:
-			name = tcpa_pc_event_id_strings[event_id];
+			name = tcpa_pc_event_id_strings[pc_event->event_id];
 			n_len = strlen(name);
 			break;
+		/* hash data */
 		case POST_BIOS_ROM:
 		case ESCD:
-			name = tcpa_pc_event_id_strings[event_id];
+		case OPTION_ROM_MICROCODE:
+		case S_CRTM_CONTENTS:
+		case POST_CONTENTS:
+			name = tcpa_pc_event_id_strings[pc_event->event_id];
 			n_len = strlen(name);
 			for (i = 0; i < 20; i++)
-				d_len += sprintf(data, "%02x",
-						event_entry[8 + i]);
+				d_len += sprintf(&data[2*i], "%02x",
+						pc_event->event_data[i]);
 			break;
 		default:
 			break;
@@ -275,53 +284,13 @@
 
 static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
 {
+	struct tcpa_event *event = v;
+	char *data = v;
+	int i;
 
-	char *eventname;
-	char data[4];
-	u32 help;
-	int i, len;
-	struct tcpa_event *event = (struct tcpa_event *) v;
-	unsigned char *event_entry =
-	    (unsigned char *) (v + sizeof(struct tcpa_event));
-
-	eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
-	if (!eventname) {
-		printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
-		       __func__);
-		return -ENOMEM;
-	}
-
-	/* 1st: PCR used is in little-endian format (4 bytes) */
-	help = le32_to_cpu(event->pcr_index);
-	memcpy(data, &help, 4);
-	for (i = 0; i < 4; i++)
+	for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++)
 		seq_putc(m, data[i]);
 
-	/* 2nd: SHA1 (20 bytes) */
-	for (i = 0; i < 20; i++)
-		seq_putc(m, event->pcr_value[i]);
-
-	/* 3rd: event type identifier (4 bytes) */
-	help = le32_to_cpu(event->event_type);
-	memcpy(data, &help, 4);
-	for (i = 0; i < 4; i++)
-		seq_putc(m, data[i]);
-
-	len = 0;
-
-	len += get_event_name(eventname, event, event_entry);
-
-	/* 4th:  filename <= 255 + \'0' delimiter */
-	if (len > TCG_EVENT_NAME_LEN_MAX)
-		len = TCG_EVENT_NAME_LEN_MAX;
-
-	for (i = 0; i < len; i++)
-		seq_putc(m, eventname[i]);
-
-	/* 5th: delimiter */
-	seq_putc(m, '\0');
-
-	kfree(eventname);
 	return 0;
 }
 
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index acc5d47..6c94879 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -3238,14 +3238,6 @@
 	}
 }
 
-int is_console_suspend_safe(void)
-{
-	/* It is unsafe to suspend devices while X has control of the
-	 * hardware. Make sure we are running on a kernel-controlled console.
-	 */
-	return vc_cons[fg_console].d->vc_mode == KD_TEXT;
-}
-
 /*
  *	Visible symbols for modules
  */
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 43b96e2..27c9eb9 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -345,17 +345,17 @@
 static u8
 sgiioc4_INB(unsigned long port)
 {
-	u8 reg = (u8) inb(port);
+	u8 reg = (u8) readb((void __iomem *) port);
 
 	if ((port & 0xFFF) == 0x11C) {	/* Status register of IOC4 */
 		if (reg & 0x51) {	/* Not busy...check for interrupt */
 			unsigned long other_ir = port - 0x110;
-			unsigned int intr_reg = (u32) inl(other_ir);
+			unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
 
 			/* Clear the Interrupt, Error bits on the IOC4 */
 			if (intr_reg & 0x03) {
-				outl(0x03, other_ir);
-				intr_reg = (u32) inl(other_ir);
+				writel(0x03, (void __iomem *) other_ir);
+				intr_reg = (u32) readl((void __iomem *) other_ir);
 			}
 		}
 	}
@@ -606,6 +606,12 @@
 	hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off;
 	hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
 	hwif->ide_dma_timeout = &__ide_dma_timeout;
+
+	/*
+	 * The IOC4 uses MMIO rather than Port IO.
+	 * It also needs special workarounds for INB.
+	 */
+	default_hwif_mmiops(hwif);
 	hwif->INB = &sgiioc4_INB;
 }
 
@@ -743,6 +749,6 @@
 module_init(ioc4_ide_init);
 module_exit(ioc4_ide_exit);
 
-MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
+MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
 MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
 MODULE_LICENSE("GPL");
diff --git a/drivers/md/md.c b/drivers/md/md.c
index ec80291..f19b874 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -167,6 +167,15 @@
 }
 EXPORT_SYMBOL_GPL(md_new_event);
 
+/* Alternate version that can be called from interrupts
+ * when calling sysfs_notify isn't needed.
+ */
+void md_new_event_inintr(mddev_t *mddev)
+{
+	atomic_inc(&md_event_count);
+	wake_up(&md_event_waiters);
+}
+
 /*
  * Enables to iterate over all existing md arrays
  * all_mddevs_lock protects this list.
@@ -4149,7 +4158,7 @@
 	set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 	md_wakeup_thread(mddev->thread);
-	md_new_event(mddev);
+	md_new_event_inintr(mddev);
 }
 
 /* seq_file implementation /proc/mdstat */
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 3d04b2d..789450b 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -214,10 +214,13 @@
  */
 int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
 {
-	struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
-	u32 *palette = fbdev->regs->lcd_pallettebase;
+	struct au1100fb_device *fbdev;
+	u32 *palette;
 	u32 value;
 
+	fbdev = to_au1100fb_device(fbi);
+	palette = fbdev->regs->lcd_pallettebase;
+
 	if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1))
 		return -EINVAL;
 
@@ -316,9 +319,11 @@
  */
 int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
 {
-	struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
+	struct au1100fb_device *fbdev;
 	int dy;
 
+	fbdev = to_au1100fb_device(fbi);
+
 	print_dbg("fb_pan_display %p %p", var, fbi);
 
 	if (!var || !fbdev) {
@@ -382,10 +387,12 @@
  */
 int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 {
-	struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
+	struct au1100fb_device *fbdev;
 	unsigned int len;
 	unsigned long start=0, off;
 
+	fbdev = to_au1100fb_device(fbi);
+
 	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
 		return -EINVAL;
 	}
@@ -467,7 +474,7 @@
 
 	if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len,
 				DRIVER_NAME)) {
-		print_err("fail to lock memory region at 0x%08x",
+		print_err("fail to lock memory region at 0x%08lx",
 				au1100fb_fix.mmio_start);
 		return -EBUSY;
 	}
@@ -595,13 +602,13 @@
 	return 0;
 }
 
-int au1100fb_drv_suspend(struct device *dev, u32 state, u32 level)
+int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
 {
 	/* TODO */
 	return 0;
 }
 
-int au1100fb_drv_resume(struct device *dev, u32 level)
+int au1100fb_drv_resume(struct device *dev)
 {
 	/* TODO */
 	return 0;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index ca020719..953eb8c 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2631,7 +2631,7 @@
 					scr_memcpyw((u16 *) q, (u16 *) p,
 						    vc->vc_size_row);
 				}
-				softback_in = p;
+				softback_in = softback_curr = p;
 				update_region(vc, vc->vc_origin,
 					      logo_lines * vc->vc_cols);
 			}
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
index 743e7ad..f85421b 100644
--- a/drivers/video/maxinefb.c
+++ b/drivers/video/maxinefb.c
@@ -55,7 +55,7 @@
 };
 
 static struct fb_fix_screeninfo maxinefb_fix = {
-	.id =		"Maxine onboard graphics 1024x768x8",
+	.id =		"Maxine",
 	.smem_len =	(1024*768),
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_PSEUDOCOLOR,
@@ -107,8 +107,6 @@
 
 static struct fb_ops maxinefb_ops = {
 	.owner		= THIS_MODULE,
-	.fb_get_fix	= gen_get_fix,
-	.fb_get_var	= gen_get_var,
 	.fb_setcolreg	= maxinefb_setcolreg,
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 8aac533..34b39e9 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -767,7 +767,6 @@
 	if (input->group != sbi->s_groups_count) {
 		ext3_warning(sb, __FUNCTION__,
 			     "multiple resizers run on filesystem!");
-		unlock_super(sb);
 		err = -EBUSY;
 		goto exit_journal;
 	}
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 95b3abf..7c9568d 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -127,6 +127,12 @@
 }
 #endif
 
+#if !defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_CPU_XSC3)
+#define	cpu_is_xscale()	0
+#else
+#define	cpu_is_xscale()	1
+#endif
+
 #define set_cr(x)					\
 	__asm__ __volatile__(				\
 	"mcr	p15, 0, %0, c1, c0, 0	@ set CR"	\
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 530ae3f..fab5aed 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -73,11 +73,6 @@
 int vt_waitactive(int vt);
 void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
-#ifdef CONFIG_VT
-int is_console_suspend_safe(void);
-#else
-static inline int is_console_suspend_safe(void) { return 1; }
-#endif
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/net/compat.h b/include/net/compat.h
index 8662b8f..e65cbed 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -3,6 +3,8 @@
 
 #include <linux/config.h>
 
+struct sock;
+
 #if defined(CONFIG_COMPAT)
 
 #include <linux/compat.h>
@@ -23,7 +25,6 @@
 	compat_int_t	cmsg_type;
 };
 
-struct sock;
 extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
 
 #else /* defined(CONFIG_COMPAT) */
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index b7f0388..01fa2ae 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -456,6 +456,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(hrtimer_start);
 
 /**
  * hrtimer_try_to_cancel - try to deactivate a timer
@@ -484,6 +485,7 @@
 	return ret;
 
 }
+EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel);
 
 /**
  * hrtimer_cancel - cancel a timer and wait for the handler to finish.
@@ -504,6 +506,7 @@
 		cpu_relax();
 	}
 }
+EXPORT_SYMBOL_GPL(hrtimer_cancel);
 
 /**
  * hrtimer_get_remaining - get remaining time for the timer
@@ -522,6 +525,7 @@
 
 	return rem;
 }
+EXPORT_SYMBOL_GPL(hrtimer_get_remaining);
 
 #ifdef CONFIG_NO_IDLE_HZ
 /**
@@ -580,6 +584,7 @@
 	timer->base = &bases[clock_id];
 	timer->node.rb_parent = HRTIMER_INACTIVE;
 }
+EXPORT_SYMBOL_GPL(hrtimer_init);
 
 /**
  * hrtimer_get_res - get the timer resolution for a clock
@@ -599,6 +604,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(hrtimer_get_res);
 
 /*
  * Expire the per base hrtimer-queue:
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 1ae2b2c..70df5c0 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -91,8 +91,8 @@
 	if (start_pfn < zone->zone_start_pfn)
 		zone->zone_start_pfn = start_pfn;
 
-	if (end_pfn > old_zone_end_pfn)
-		zone->spanned_pages = end_pfn - zone->zone_start_pfn;
+	zone->spanned_pages = max(old_zone_end_pfn, end_pfn) -
+				zone->zone_start_pfn;
 
 	zone_span_writeunlock(zone);
 }
@@ -106,8 +106,8 @@
 	if (start_pfn < pgdat->node_start_pfn)
 		pgdat->node_start_pfn = start_pfn;
 
-	if (end_pfn > old_pgdat_end_pfn)
-		pgdat->node_spanned_pages = end_pfn - pgdat->node_start_pfn;
+	pgdat->node_spanned_pages = max(old_pgdat_end_pfn, end_pfn) -
+					pgdat->node_start_pfn;
 }
 
 int online_pages(unsigned long pfn, unsigned long nr_pages)