Hi, I was looking at trying to get soc_dma to call a fifo routine using soc_dma_port_add_fifo_in and hit a few problems that are fixed by the following patch.
1) Where there are two entries matching an address (i.e. a fifo registered for both input and output) soc_dma_lookup finds the last one in the list however soc_dma_ch_update_type then searches forward missing any other cases. (It would be good for someone to cast another eye over soc_dma_lookup to check it always gets the last one in the list) 2) soc_dma_ch_update_type in the memory case was marking the area as 'other' when it wasn't a constant address - I believe this is actually intended to be if it isn't linearly addressed. 3) I'm suspicious of the address check around line 147: if (entry->addr > ch->vaddr[port] || entry->addr + entry->u.mem.size <= ch->vaddr[port]) won't that break if the entry describes a block of RAM at the top of the address space and the address space is as large as the type of entry->addr such that entry->addr+entry->u.mem.size wraps? (I'm not sure what the clean fix for that is, so I left that alone). Note: Users of soc_dma might find that fix (2) might now cause the soc_dma internal memory->memory case to correctly trigger if they try and dma from memory->memory where it might not have done before. Dave diff --git a/hw/soc_dma.c b/hw/soc_dma.c index 3f0f414..4ef5316 100644 --- a/hw/soc_dma.c +++ b/hw/soc_dma.c @@ -129,9 +129,10 @@ static inline enum soc_dma_port_type soc_dma_ch_update_type( struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]); if (entry->type == soc_dma_port_fifo) { - while (entry < dma->memmap + dma->memmap_size && + while (entry > dma->memmap && entry->u.fifo.out != port) - entry ++; + entry --; + if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port) return soc_dma_port_other; @@ -148,11 +149,12 @@ static inline enum soc_dma_port_type soc_dma_ch_update_type( /* TODO: support constant memory address for source port as used for * drawing solid rectangles by PalmOS(R). */ - if (ch->type[port] != soc_dma_access_const) + if (ch->type[port] != soc_dma_access_linear) return soc_dma_port_other; ch->paddr[port] = (uint8_t *) entry->u.mem.base + (ch->vaddr[port] - entry->addr); + /* TODO: save bytes left to the end of the mapping somewhere so we * can check we're not reading beyond it. */ return soc_dma_port_mem;