diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c
index 1f8b204..a7deae5 100644
--- a/drivers/acpi/acpi_pnp.c
+++ b/drivers/acpi/acpi_pnp.c
@@ -134,9 +134,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
 	{"FUJ02bf"},
 	{"FUJ02B1"},
 	{"FUJ02E3"},
-	/* system */
-	{"PNP0c02"},		/* General ID for reserving resources */
-	{"PNP0c01"},		/* memory controller */
 	/* rtc_cmos */
 	{"PNP0b00"},
 	{"PNP0b01"},
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 0a817ad..674518b 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -11,6 +11,7 @@
 #include <linux/kthread.h>
 #include <linux/dmi.h>
 #include <linux/nls.h>
+#include <linux/pci.h>
 
 #include <asm/pgtable.h>
 
@@ -1781,12 +1782,201 @@ static bool acpi_object_is_system_bus(acpi_handle handle)
 	return false;
 }
 
+static bool acpi_is_motherboard_resource(char *id)
+{
+	return !(strncmp(id, "PNP0C01", sizeof("PNP0C01")) &&
+		 strncmp(id, "PNP0C02", sizeof("PNP0C02")));
+}
+
+static LIST_HEAD(acpi_motherboard_resource_list);
+
+struct acpi_motherboard_resource {
+	acpi_handle handle;
+	struct list_head node;
+};
+
+static void acpi_record_motherboard_resource(acpi_handle handle)
+{
+	struct acpi_motherboard_resource *res;
+
+	res = kzalloc(sizeof(struct acpi_motherboard_resource), GFP_KERNEL);
+	if (!res)
+		return;
+	res->handle = handle;
+	list_add(&res->node, &acpi_motherboard_resource_list);
+}
+
+static void reserve_range(struct acpi_device *device, struct resource *r, int port)
+{
+	char *regionid;
+	resource_size_t start = r->start, end = r->end;
+	struct resource *res;
+	int result;
+
+	regionid = kmalloc(20, GFP_KERNEL);
+	if (!regionid)
+		return;
+
+	snprintf(regionid, 20, "ACPI %s", dev_name(&device->dev));
+		
+	if (port)
+		res = request_region(start, end - start + 1, regionid);
+	else
+		res = request_mem_region(start, end - start + 1, regionid);
+	if (res)
+		res->flags &= ~IORESOURCE_BUSY;
+	else
+		kfree(regionid);
+
+	dev_info(&device->dev, "%pR %s reserved\n", r,
+			res ? "has been" : "could not be");
+}
+
+static int is_pci_reserved(struct resource *res)
+{
+	struct pci_dev *pdev = NULL;
+	resource_size_t acpi_start, acpi_end, pci_start, pci_end;
+	int i;
+
+	/*
+	 * Some BIOSes have motherboard devices with resources that
+	 * partially overlap PCI BARs.
+	 * Those resources should not be reserved, or else, it will
+	 * prevent the normal PCI driver from requesting them later.
+	 */
+	for_each_pci_dev(pdev) {
+		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+			unsigned long type;
+
+			type = pci_resource_flags(pdev, i) & res->flags
+			       & (IORESOURCE_IO | IORESOURCE_MEM);
+			if (!type || pci_resource_len(pdev, i) == 0)
+				continue;
+
+			pci_start = pci_resource_start(pdev, i);
+			pci_end = pci_resource_end(pdev, i);
+
+			if (res->start == 0 && res->end == 0)
+				continue;
+
+			acpi_start = res->start;
+			acpi_end = res->end;
+
+			/*
+			 * If the ACPI region doesn't overlap the PCI
+			 * region at all, there's no problem.
+			 */
+			if (acpi_end < pci_start || acpi_start > pci_end)
+				continue;
+
+			/*
+			 * If the PNP region completely encloses (or is
+			 * at least as large as) the PCI region, that's
+			 * also OK.  For example, this happens when the
+			 * PNP device describes a bridge with PCI
+			 * behind it.
+			 */
+			if (acpi_start <= pci_start && acpi_end >= pci_end)
+				continue;
+
+			/*
+			 * Otherwise, the ACPI region overlaps *part* of
+			 * the PCI region, and that might prevent a PCI
+			 * driver from requesting its resources.
+			 */
+			return true;
+		}
+	}
+	return false;
+}
+
+static acpi_status __init __acpi_reserve_motherboard_resource(struct acpi_resource *res,
+							void *data)
+{
+	struct resource r = {0};
+	acpi_handle handle = data;
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	if (result)
+		return AE_OK;
+
+	if (!device->status.present)
+		return AE_OK;
+
+	switch (res->type) {
+	case ACPI_RESOURCE_TYPE_MEMORY24:
+	case ACPI_RESOURCE_TYPE_MEMORY32:
+	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+		if (!acpi_dev_resource_memory(res, &r))
+			return AE_OK;
+		break;
+	case ACPI_RESOURCE_TYPE_IO:
+	case ACPI_RESOURCE_TYPE_FIXED_IO:
+		if (!acpi_dev_resource_io(res, &r))
+			return AE_OK;
+		break;
+	case ACPI_RESOURCE_TYPE_ADDRESS16:
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+		if (!acpi_dev_resource_address_space(res, &r))
+			return AE_OK;
+		break;
+	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+		if (!acpi_dev_resource_ext_address_space(res, &r))
+			return AE_OK;
+		break;
+	default:
+		return AE_OK;
+	}
+
+	if (r.flags & IORESOURCE_DISABLED)
+		return AE_OK;
+
+	if (is_pci_reserved(&r))
+		return AE_OK;
+
+	if (r.flags & IORESOURCE_IO) {
+		if (r.start < 0x100)
+		/*
+		 * Below 0x100 is only standard PC hardware
+		 * (pics, kbd, timer, dma, ...)
+		 * We should not get resource conflicts there,
+		 * and the kernel reserves these anyway
+		 * (see arch/i386/kernel/setup.c).
+		 * So, do nothing
+		 */
+			return AE_OK;
+		if (r.end < r.start)
+			return AE_OK;       /* invalid */
+                reserve_range(device, &r, 1);
+        } else if (r.flags & IORESOURCE_MEM) {
+                reserve_range(device, &r, 0);
+        }
+
+	return AE_OK;
+}
+
+static int __init acpi_reserve_motherboard_resource(void)
+{
+	struct acpi_motherboard_resource *res;
+
+	list_for_each_entry(res, &acpi_motherboard_resource_list, node)
+		acpi_walk_resources(res->handle, METHOD_NAME__CRS,
+			__acpi_reserve_motherboard_resource, res->handle);
+
+	return 0;
+}
+fs_initcall(acpi_reserve_motherboard_resource);
+
 static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
 				int device_type)
 {
 	acpi_status status;
 	struct acpi_device_info *info;
 	struct acpi_pnp_device_id_list *cid_list;
+	int is_mb_resource = 0;
 	int i;
 
 	switch (device_type) {
@@ -1804,13 +1994,20 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
 		}
 
 		if (info->valid & ACPI_VALID_HID) {
-			acpi_add_id(pnp, info->hardware_id.string);
-			pnp->type.platform_id = 1;
+			if (!acpi_is_motherboard_resource(info->hardware_id.string)) {
+				acpi_add_id(pnp, info->hardware_id.string);
+				pnp->type.platform_id = 1;
+			} else
+				is_mb_resource = 1;
 		}
 		if (info->valid & ACPI_VALID_CID) {
 			cid_list = &info->compatible_id_list;
-			for (i = 0; i < cid_list->count; i++)
-				acpi_add_id(pnp, cid_list->ids[i].string);
+			for (i = 0; i < cid_list->count; i++) {
+				if (!acpi_is_motherboard_resource(cid_list->ids[i].string))
+					acpi_add_id(pnp, cid_list->ids[i].string);
+				else
+					is_mb_resource = 1;
+			}
 		}
 		if (info->valid & ACPI_VALID_ADR) {
 			pnp->bus_address = info->address;
@@ -1822,6 +2019,9 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
 
 		kfree(info);
 
+		if (is_mb_resource)
+			acpi_record_motherboard_resource(handle);
+
 		/*
 		 * Some devices don't reliably have _HIDs & _CIDs, so add
 		 * synthetic HIDs to make sure drivers can find them.
