KAMEZAWA, please udpate to use kmalloc/kfree directly instead of acpi_os_allocate/acpi_os_free. The later are intended only for inside the core (and have already been delted by another patch in the works:-) thanks, -Len >-----Original Message----- >From: linux-acpi-owner@xxxxxxxxxxxxxxx >[mailto:linux-acpi-owner@xxxxxxxxxxxxxxx] On Behalf Of akpm@xxxxxxxx >Sent: Tuesday, March 28, 2006 5:04 PM >To: Brown, Len >Cc: linux-acpi@xxxxxxxxxxxxxxx; akpm@xxxxxxxx; >kamezawa.hiroyu@xxxxxxxxxxxxxx; kaneshige.kenji@xxxxxxxxxxxxxx >Subject: [patch 22/26] acpi memory hotplug cannot manage _CRS >with plural resoureces > > >From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx> > >Current acpi memory hotplug just looks into the first entry of >resources in >_CRS. But, _CRS can contain plural resources. So, if _CRS >contains plural >resoureces, acpi memory hot add cannot add all memory. > >With this patch, acpi memory hotplug can deal with Memory Device, whose >_CRS contains plural resources. > >Tested on ia64 memory hotplug test envrionment (not emulation, >uses alpha >version firmware which supports dynamic reconfiguration of NUMA.) > >Note: Microsoft's Windows Server 2003 requires big >(>4G)resoureces to be > divided into small (<4G) resources. looks crazy, but not invalid. > (See >http://www.microsoft.com/whdc/system/pnppwr/hotadd/hotaddmem.mspx) > For this reason, a firmware vendor who supports Windows >writes plural > resources in a _CRS even if they are contiguous. > >[akpm@xxxxxxxx: export acpi_os_allocate] >Signed-off-by: Kenji Kaneshige <kaneshige.kenji@xxxxxxxxxxxxxx> >Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx> >Cc: "Brown, Len" <len.brown@xxxxxxxxx> >Signed-off-by: Andrew Morton <akpm@xxxxxxxx> >--- > > drivers/acpi/acpi_memhotplug.c | 109 ++++++++++++++++++++++--------- > drivers/acpi/osl.c | 1 > 2 files changed, 79 insertions(+), 31 deletions(-) > >diff -puN >drivers/acpi/acpi_memhotplug.c~acpi-memory-hotplug-cannot-manag e-_crs-with-plural-resoureces drivers/acpi/acpi_memhotplug.c >--- >devel/drivers/acpi/acpi_memhotplug.c~acpi-memory-hotplug-cannot -manage-_crs-with-plural-resoureces 2006-03-28 >14:03:07.000000000 -0800 >+++ devel-akpm/drivers/acpi/acpi_memhotplug.c 2006-03-28 >14:03:07.000000000 -0800 >@@ -68,44 +68,76 @@ static struct acpi_driver acpi_memory_de > }, > }; > >+struct acpi_memory_info { >+ struct list_head list; >+ u64 start_addr; /* Memory Range start physical addr */ >+ u64 length; /* Memory Range length */ >+ unsigned short caching; /* memory cache attribute */ >+ unsigned short write_protect; /* memory read/write >attribute */ >+ unsigned int enabled:1; >+}; >+ > struct acpi_memory_device { > acpi_handle handle; > unsigned int state; /* State of the memory device */ >- unsigned short caching; /* memory cache attribute */ >- unsigned short write_protect; /* memory read/write >attribute */ >- u64 start_addr; /* Memory Range start physical addr */ >- u64 length; /* Memory Range length */ >+ struct list_head res_list; > }; > >+static acpi_status >+acpi_memory_get_resource(struct acpi_resource *resource, void >*context) >+{ >+ struct acpi_memory_device *mem_device = context; >+ struct acpi_resource_address64 address64; >+ struct acpi_memory_info *info, *new; >+ acpi_status status; >+ >+ status = acpi_resource_to_address64(resource, &address64); >+ if (ACPI_FAILURE(status) || >+ (address64.resource_type != ACPI_MEMORY_RANGE)) >+ return AE_OK; >+ >+ list_for_each_entry(info, &mem_device->res_list, list) { >+ /* Can we combine the resource range information? */ >+ if ((info->caching == address64.info.mem.caching) && >+ (info->write_protect == >address64.info.mem.write_protect) && >+ (info->start_addr + info->length == >address64.minimum)) { >+ info->length += address64.address_length; >+ return AE_OK; >+ } >+ } >+ >+ new = acpi_os_allocate(sizeof(struct acpi_memory_info)); >+ if (!new) >+ return AE_ERROR; >+ >+ memset(new, 0, sizeof(*new)); >+ INIT_LIST_HEAD(&new->list); >+ new->caching = address64.info.mem.caching; >+ new->write_protect = address64.info.mem.write_protect; >+ new->start_addr = address64.minimum; >+ new->length = address64.address_length; >+ list_add_tail(&new->list, &mem_device->res_list); >+ >+ return AE_OK; >+} >+ > static int > acpi_memory_get_device_resources(struct acpi_memory_device >*mem_device) > { > acpi_status status; >- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; >- struct acpi_resource *resource = NULL; >- struct acpi_resource_address64 address64; >+ struct acpi_memory_info *info, *n; > > ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources"); > > /* Get the range from the _CRS */ >- status = acpi_get_current_resources(mem_device->handle, >&buffer); >- if (ACPI_FAILURE(status)) >+ status = acpi_walk_resources(mem_device->handle, >METHOD_NAME__CRS, >+ acpi_memory_get_resource, >mem_device); >+ if (ACPI_FAILURE(status)) { >+ list_for_each_entry_safe(info, n, >&mem_device->res_list, list) >+ acpi_os_free(info); > return_VALUE(-EINVAL); >- >- resource = (struct acpi_resource *)buffer.pointer; >- status = acpi_resource_to_address64(resource, &address64); >- if (ACPI_SUCCESS(status)) { >- if (address64.resource_type == ACPI_MEMORY_RANGE) { >- /* Populate the structure */ >- mem_device->caching = >address64.info.mem.caching; >- mem_device->write_protect = >- address64.info.mem.write_protect; >- mem_device->start_addr = address64.minimum; >- mem_device->length = address64.address_length; >- } > } > >- acpi_os_free(buffer.pointer); > return_VALUE(0); > } > >@@ -180,7 +212,8 @@ static int acpi_memory_check_device(stru > > static int acpi_memory_enable_device(struct >acpi_memory_device *mem_device) > { >- int result; >+ int result, num_enabled = 0; >+ struct acpi_memory_info *info; > > ACPI_FUNCTION_TRACE("acpi_memory_enable_device"); > >@@ -195,12 +228,21 @@ static int acpi_memory_enable_device(str > /* > * Tell the VM there is more memory here... > * Note: Assume that this function returns zero on success >+ * We don't have memory-hot-add rollback function,now. >+ * (i.e. memory-hot-remove function) > */ >- result = add_memory(mem_device->start_addr, mem_device->length); >- if (result) { >+ list_for_each_entry(info, &mem_device->res_list, list) { >+ result = add_memory(info->start_addr, info->length); >+ if (result) >+ continue; >+ info->enabled = 1; >+ num_enabled++; >+ } >+ >+ if (!num_enabled) { > ACPI_ERROR((AE_INFO, "add_memory failed")); > mem_device->state = MEMORY_INVALID_STATE; >- return result; >+ return -EINVAL; > } > > return result; >@@ -244,8 +286,7 @@ static int acpi_memory_powerdown_device( > static int acpi_memory_disable_device(struct >acpi_memory_device *mem_device) > { > int result; >- u64 start = mem_device->start_addr; >- u64 len = mem_device->length; >+ struct acpi_memory_info *info, *n; > > ACPI_FUNCTION_TRACE("acpi_memory_disable_device"); > >@@ -253,9 +294,14 @@ static int acpi_memory_disable_device(st > * Ask the VM to offline this memory range. > * Note: Assume that this function returns zero on success > */ >- result = remove_memory(start, len); >- if (result) >- return_VALUE(result); >+ list_for_each_entry_safe(info, n, &mem_device->res_list, list) { >+ if (info->enabled) { >+ result = >remove_memory(info->start_addr, info->length); >+ if (result) >+ return_VALUE(result); >+ } >+ acpi_os_free(info); >+ } > > /* Power-off and eject the device */ > result = acpi_memory_powerdown_device(mem_device); >@@ -347,6 +393,7 @@ static int acpi_memory_device_add(struct > return_VALUE(-ENOMEM); > memset(mem_device, 0, sizeof(struct acpi_memory_device)); > >+ INIT_LIST_HEAD(&mem_device->res_list); > mem_device->handle = device->handle; > sprintf(acpi_device_name(device), "%s", >ACPI_MEMORY_DEVICE_NAME); > sprintf(acpi_device_class(device), "%s", >ACPI_MEMORY_DEVICE_CLASS); >diff -puN >drivers/acpi/osl.c~acpi-memory-hotplug-cannot-manage-_crs-with- >plural-resoureces drivers/acpi/osl.c >--- >devel/drivers/acpi/osl.c~acpi-memory-hotplug-cannot-manage-_crs -with-plural-resoureces 2006-03-28 14:03:07.000000000 -0800 >+++ devel-akpm/drivers/acpi/osl.c 2006-03-28 >14:03:07.000000000 -0800 >@@ -145,6 +145,7 @@ void *acpi_os_allocate(acpi_size size) > else > return kmalloc(size, GFP_KERNEL); > } >+EXPORT_SYMBOL(acpi_os_allocate); > > void acpi_os_free(void *ptr) > { >_ >- >To unsubscribe from this list: send the line "unsubscribe >linux-acpi" in >the body of a message to majordomo@xxxxxxxxxxxxxxx >More majordomo info at http://vger.kernel.org/majordomo-info.html > - To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html