ltq-adsl-mei: improve memory allocation

The ltq-adsl-mei driver allocates memory for the ADSL firmware in a
rather stupid way, leading to several 128k allocations, which fail when
many services are enabled. This patch tries to allocate 64 kiB chunks,
and only falls back to larger allocations if the returned pointers are
not correctly aligned. Fixes out-of-memory errors on Danube boards with
32 MiB RAM.

Signed-off-by: Matti Laakso <malaakso@elisanet.fi>

SVN-Revision: 40325
This commit is contained in:
John Crispin 2014-03-30 09:16:39 +00:00
parent 8b0507c9ca
commit 3fbffbb7b0

View file

@ -1513,13 +1513,31 @@ IFX_MEI_DFEMemoryAlloc (DSL_DEV_Device_t * pDev, long size)
allocate_size = size; allocate_size = size;
else else
allocate_size = SDRAM_SEGMENT_SIZE; allocate_size = SDRAM_SEGMENT_SIZE;
org_mem_ptr = kmalloc (allocate_size + 1024, GFP_KERNEL);
org_mem_ptr = kmalloc (allocate_size, GFP_KERNEL);
if (org_mem_ptr == NULL) { if (org_mem_ptr == NULL) {
IFX_MEI_EMSG ("%d: kmalloc %d bytes memory fail!\n", idx, allocate_size); IFX_MEI_EMSG ("%d: kmalloc %d bytes memory fail!\n", idx, allocate_size);
err = -ENOMEM; err = -ENOMEM;
goto allocate_error; goto allocate_error;
} }
if (((unsigned long)org_mem_ptr) & (1023)) {
/* Pointer not 1k aligned, so free it and allocate a larger chunk
* for further alignment.
*/
kfree(org_mem_ptr);
org_mem_ptr = kmalloc (allocate_size + 1024, GFP_KERNEL);
if (org_mem_ptr == NULL) {
IFX_MEI_EMSG ("%d: kmalloc %d bytes memory fail!\n",
idx, allocate_size + 1024);
err = -ENOMEM;
goto allocate_error;
}
mem_ptr = (unsigned long) (org_mem_ptr + 1023) & ~(1024 -1); mem_ptr = (unsigned long) (org_mem_ptr + 1023) & ~(1024 -1);
} else {
mem_ptr = (unsigned long) org_mem_ptr;
}
adsl_mem_info[idx].address = (char *) mem_ptr; adsl_mem_info[idx].address = (char *) mem_ptr;
adsl_mem_info[idx].org_address = org_mem_ptr; adsl_mem_info[idx].org_address = org_mem_ptr;
adsl_mem_info[idx].size = allocate_size; adsl_mem_info[idx].size = allocate_size;
@ -1591,6 +1609,7 @@ DSL_BSP_FWDownload (DSL_DEV_Device_t * pDev, const char *buf,
size_t nRead = 0, nCopy = 0; size_t nRead = 0, nCopy = 0;
char *mem_ptr; char *mem_ptr;
char *org_mem_ptr = NULL;
ssize_t retval = -ENOMEM; ssize_t retval = -ENOMEM;
int idx = 0; int idx = 0;
@ -1634,17 +1653,33 @@ DSL_BSP_FWDownload (DSL_DEV_Device_t * pDev, const char *buf,
DSL_DEV_PRIVATE(pDev)->img_hdr = DSL_DEV_PRIVATE(pDev)->img_hdr =
(ARC_IMG_HDR *) adsl_mem_info[0].address; (ARC_IMG_HDR *) adsl_mem_info[0].address;
adsl_mem_info[XDATA_REGISTER].org_address = kmalloc (SDRAM_SEGMENT_SIZE + 1024, GFP_KERNEL); org_mem_ptr = kmalloc (SDRAM_SEGMENT_SIZE, GFP_KERNEL);
adsl_mem_info[XDATA_REGISTER].address = if (org_mem_ptr == NULL) {
(char *) ((unsigned long) (adsl_mem_info[XDATA_REGISTER].org_address + 1023) & 0xFFFFFC00);
adsl_mem_info[XDATA_REGISTER].size = SDRAM_SEGMENT_SIZE;
if (adsl_mem_info[XDATA_REGISTER].address == NULL) {
IFX_MEI_EMSG ("kmalloc memory fail!\n"); IFX_MEI_EMSG ("kmalloc memory fail!\n");
retval = -ENOMEM; retval = -ENOMEM;
goto error; goto error;
} }
if (((unsigned long)org_mem_ptr) & (1023)) {
/* Pointer not 1k aligned, so free it and allocate a larger chunk
* for further alignment.
*/
kfree(org_mem_ptr);
org_mem_ptr = kmalloc (SDRAM_SEGMENT_SIZE + 1024, GFP_KERNEL);
if (org_mem_ptr == NULL) {
IFX_MEI_EMSG ("kmalloc memory fail!\n");
retval = -ENOMEM;
goto error;
}
adsl_mem_info[XDATA_REGISTER].address =
(char *) ((unsigned long) (org_mem_ptr + 1023) & ~(1024 -1));
} else {
adsl_mem_info[XDATA_REGISTER].address = org_mem_ptr;
}
adsl_mem_info[XDATA_REGISTER].org_address = org_mem_ptr;
adsl_mem_info[XDATA_REGISTER].size = SDRAM_SEGMENT_SIZE;
adsl_mem_info[XDATA_REGISTER].type = FREE_RELOAD; adsl_mem_info[XDATA_REGISTER].type = FREE_RELOAD;
IFX_MEI_DMSG("-> IFX_MEI_BarUpdate()\n"); IFX_MEI_DMSG("-> IFX_MEI_BarUpdate()\n");
IFX_MEI_BarUpdate (pDev, (DSL_DEV_PRIVATE(pDev)->nBar)); IFX_MEI_BarUpdate (pDev, (DSL_DEV_PRIVATE(pDev)->nBar));