cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
borja_mrtnz
Contributor
Contributor
2,864 Views
Registered: ‎07-08-2008

Page allocation failure in DMA transaction

 

Hi all,

 

we have a custom Virtex5-based board. We have built a project in which one peripheral sends large amounts of data through LocalLink DMA to PPC440 (only RX link). The OS used is Open Source Linux.

 

At the time of writing the driver, we have followed the guides that appear in xapp1129. Since the amount of data to transfer is quite large (0.6 MB aprox.), the choosen size of the buffer is 1MB and the number of Buffer Descriptors is 16. When we launch the linux application and we do DMA data transfers, all seems to be ok. But if we keep on doing more data transfers (after 40 data transfers or so), we get the next error:

 

swapper: page allocation failure. order:9, mode:0x4020

Call Trace:

[c038fd00] [c0006384] show_stack+0x48/0x168ME (unreliable)

[c038fd30] [c007abd8] __alloc_pages_nodemask+0x3dc/0x4bc

[c038fda0] [c007acd4] __get_free_pages+0x1c/0x50

[c038fdb0] [c01ac6d0] das_DmaSetupRecvBuffers+0x68/0x1e4

[c038fde0] [c01ac980] DmaRecvHandlerBH+0x134/0x194

[c038fe20] [c003b50c] tasklet_action+0x78/0xec

[c038fe40] [c003b640] __do_softirq+0xc0/0x140

[c038fe90] [c0003648] do_softirq+0x74/0x7c

[c038fea0] [c003b124] irq_exit+0x60/0x78

[c038feb0] [c0004074] do_IRQ+0x98/0xb0

[c038fed0] [c000e6b8] ret_from_except+0x0/0x18

[c038ff90] [c0007134] cpu_idle+0xd0/0xe0

[c038ffb0] [c0001774] rest_init+0x84/0x98

[c038ffc0] [c0349744] start_kernel+0x250/0x2d0

 

[c038fff0] [c0000204] skpinv+0x194/0x1d0

Mem-Info:

DMA per-cpu:

CPU    0: hi:  186, btch:  31 usd: 151

active_anon:836 inactive_anon:736 isolated_anon:0

 active_file:36 inactive_file:758 isolated_file:0

 unevictable:0 dirty:637 writeback:0 unstable:0

 free:50896 slab_reclaimable:222 slab_unreclaimable:335

 mapped:45 shmem:0 pagetables:14 bounce:0

DMA free:203584kB min:2884kB low:3604kB high:4324kB active_anon:3344kB inactive_anon:2944kB active_file:144kB inactive_file:3032kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:520192kB mlocked:0kB dirty:2548kB writeback:0

kB mapped:180kB shmem:0kB slab_reclaimable:888kB slab_unreclaimable:1340kB kernel_stack:192kB pagetables:56kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no

cilowmem_reserve[]:on 0 s 0e  0

DMA: 1286*4kB 1435*8kB 1285*16kB l 1116*32kB 490*64kB 50*128kB 53*

256kB 53*512kB 51*1024kB 0*2048kB 0*4096kB = 203584kB

794 total pagecache pages

 d0 pages in swap cache

e Swap cache stats: add 0, delete 0, find 0/0

Free swap  = 0kB

Total swap = 0kB

 

131072 pages RAM

2044 pages reserved

688 pages shared

77265 pages non-shared

Unable to handle kernel paging request for data at address 0x00000008

Faulting instruction address: 0xc01ac6dc

Oops: Kernel access of bad area, sig: 11 [#1]

PREEMPT Xilinx Virtex440

Modules linked in:

**bleep**: c01ac6dc LR: c01ac6d0 CTR: c01c1d24

REGS: c038fd00 TRAP: 0300   Not tainted  (2.6.33)

MSR: 00029000 <EE,ME,CE>  CR: 22000022  XER: 20000000

DEAR: 00000008, ESR: 00800000

TASK = c03714d0[0] 'swapper' THREAD: c038e000

GPR00: 00100000 c038fdb0 c03714d0 00000000 0025c98c ffffffff c01c1c90 00000036

GPR08: c0397b88 00000000 0025c98c c038e000 24000084 fffe9558 7ffffdff ffffbfff

GPR16: fefff7bf c03733bc c03a0000 c039bc20 c0300000 00000000 0000000a c0390000

GPR24: 00000001 00000001 dfb7be50 00000001 00000000 dfb7be00 df875280 00000000

**bleep** [c01ac6dc] das_DmaSetupRecvBuffers+0x74/0x1e4

LR [c01ac6d0] das_DmaSetupRecvBuffers+0x68/0x1e4

Call Trace:

[c038fdb0] [c01ac6d0] das_DmaSetupRecvBuffers+0x68/0x1e4 (unreliable)

[c038fde0] [c01ac980] DmaRecvHandlerBH+0x134/0x194

[c038fe20] [c003b50c] tasklet_action+0x78/0xec

[c038fe40] [c003b640] __do_softirq+0xc0/0x140

[c038fe90] [c0003648] do_softirq+0x74/0x7c

[c038fea0] [c003b124] irq_exit+0x60/0x78

[c038feb0] [c0004074] do_IRQ+0x98/0xb0

[c038fed0] [c000e6b8] ret_from_except+0x0/0x18

[c038ff90] [c0007134] cpu_idle+0xd0/0xe0

[c038ffb0] [c0001774] rest_init+0x84/0x98

[c038ffc0] [c0349744] start_kernel+0x250/0x2d0

[c038fff0] [c0000204] skpinv+0x194/0x1d0

Instruction dump:

38800000 409d00e4 3b800000 3800000a 7c0903a6 42000000 38604020 38800009

4bece5ed 2f830000 7c7f1b78 3c000010 <90030008> 907f0000 907f0004 419e013c

Kernel panic - not syncing: Fatal exception in interrupt

Call Trace:

[c038fc00] [c0006384] show_stack+0x48/0x168 (unreliable)

[c038fc30] [c0034d60] panic+0x90/0x188

[c038fcc0] [c000b948] die+0x17c/0x190

[c038fce0] [c000f728] bad_page_fault+0x90/0xd8

[c038fcf0] [c000e528] handle_page_fault+0x7c/0x80

[c038fdb0] [c01ac6d0] das_DmaSetupRecvBuffers+0x68/0x1e4

[c038fde0] [c01ac980] DmaRecvHandlerBH+0x134/0x194

[c038fe20] [c003b50c] tasklet_action+0x78/0xec

[c038fe40] [c003b640] __do_softirq+0xc0/0x140

[c038fe90] [c0003648] do_softirq+0x74/0x7c

[c038fea0] [c003b124] irq_exit+0x60/0x78

[c038feb0] [c0004074] do_IRQ+0x98/0xb0

[c038fed0] [c000e6b8] ret_from_except+0x0/0x18

[c038ff90] [c0007134] cpu_idle+0xd0/0xe0

[c038ffb0] [c0001774] rest_init+0x84/0x98

[c038ffc0] [c0349744] start_kernel+0x250/0x2d0

[c038fff0] [c0000204] skpinv+0x194/0x1d0

Rebooting in 180 seconds..

 

It seems the failure is due to memory fragmentation. At some point (after 40 tests), there aren't memory areas with 1MB of contiguous space so the kmalloc function fails. If we reduce the number of Buffer Descriptors to 4, the failure appears later (after 100 tests or so).

 

We have also tried to reduce the size of the buffer to 1kB to avoid the page failure. Since the implemented DMA is of type Scatter-Gather, the transaccion should work but we receive no data. Here are the driver functions where we do the memory allocations:

 

 

/* Allocate a receive buffer, and associated structure which describes it. */
static struct das_rx_buff *alloc_rx_buff (size_t len) {
    struct das_rx_buff *rx_buff;

    rx_buff = (struct das_rx_buff *) kmalloc(sizeof(struct das_rx_buff) + len, GFP_ATOMIC);
    rx_buff->data_len = len;
    INIT_LIST_HEAD(&rx_buff->list);

    return rx_buff;
}

/* das_DmaSetupRecvBuffers: allocates as many DMA buffers as it can up to the number of free RX buffer descriptors. */
static void das_DmaSetupRecvBuffers(struct das_dev *das){
    int free_bd_count;
    int num_buffs;
    u32 new_buff_physaddr;
    XLlDma_Bd *BdPtr, *BdCurPtr;
    int result;
	
    free_bd_count = XLlDma_mBdRingGetFreeCnt(&das->Dma.RxBdRing);

    result = XLlDma_BdRingAlloc(&das->Dma.RxBdRing, free_bd_count, &BdPtr);

    if (result != XST_SUCCESS) {
        /* We really shouldn't get this */
        printk(KERN_ERR "%s: XLlDma: BdRingAlloc unsuccessful (%d)\n", DRIVER_NAME, result);
        return;
    }

    BdCurPtr = BdPtr;

    for (num_buffs = 0; num_buffs < free_bd_count; num_buffs++)	{
	struct das_rx_buff *rx_buff;

	/* Allocate a new buffer */
	rx_buff = alloc_rx_buff(DAS_BUF_SIZE);
	if (rx_buff == NULL) {
	    printk(KERN_ERR "%s: kmalloc buffer unsuccessful\n", DRIVER_NAME);
	    return;
	}

	new_buff_physaddr = (u32) dma_map_single(dev_pueba, rx_buff->data, DAS_BUF_SIZE, DMA_FROM_DEVICE);
		
        XLlDma_mBdSetBufAddr(BdCurPtr, new_buff_physaddr);
	XLlDma_mBdSetLength(BdCurPtr, DAS_BUF_SIZE);		
XLlDma_mBdSetId(BdCurPtr, rx_buff);
// LLDMA Driver bug; no flags should be required on RX descriptors. XLlDma_mBdSetStsCtrl(BdCurPtr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK); BdCurPtr = XLlDma_mBdRingNext(&das->Dma.RxBdRing, BdCurPtr); } /* Enqueue RxBD with the attached buffers such that it is ready for frame reception */ result = XLlDma_BdRingToHw(&das->Dma.RxBdRing, num_buffs, BdPtr); if (result != XST_SUCCESS) { printk(KERN_ERR "%s: (DmaSetupRecvBuffers) BdRingToHw unsuccessful (%d)\n", DRIVER_NAME, result); BdCurPtr = BdPtr; while (num_buffs > 0) { XLlDma_mBdSetId(BdCurPtr, NULL); BdCurPtr = XLlDma_mBdRingNext(&das->Dma.RxBdRing, BdCurPtr); num_buffs--; } return; } }

 Does anyone know how could I solve this problem?

 

Thank you in advance.

 

 

0 Kudos
0 Replies