lkml.org 
[lkml]   [2007]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 7/7] pool: Improve memory usage for devices which can't cross boundaries
    Date
    The previous implementation simply refused to allocate more than a
    boundary's worth of data from an entire page. Some users didn't know
    this, so specified things like SMP_CACHE_BYTES, not realising the
    horrible waste of memory that this was. It's fairly easy to correct
    this problem, just by ensuring we don't cross a boundary within a page.
    This even helps drivers like EHCI (which can't cross a 4k boundary)
    on machines with larger page sizes.

    Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
    Acked-by: David S. Miller <davem@davemloft.net>
    ---
    mm/dmapool.c | 36 ++++++++++++++++++++----------------
    1 files changed, 20 insertions(+), 16 deletions(-)

    diff --git a/mm/dmapool.c b/mm/dmapool.c
    index 72e7ece..34aaac4 100644
    --- a/mm/dmapool.c
    +++ b/mm/dmapool.c
    @@ -43,6 +43,7 @@ struct dma_pool { /* the pool */
    size_t size;
    struct device *dev;
    size_t allocation;
    + size_t boundary;
    char name[32];
    wait_queue_head_t waitq;
    struct list_head pools;
    @@ -107,7 +108,7 @@ static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
    * @dev: device that will be doing the DMA
    * @size: size of the blocks in this pool.
    * @align: alignment requirement for blocks; must be a power of two
    - * @allocation: returned blocks won't cross this boundary (or zero)
    + * @boundary: returned blocks won't cross this power of two boundary
    * Context: !in_interrupt()
    *
    * Returns a dma allocation pool with the requested characteristics, or
    @@ -117,15 +118,16 @@ static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
    * cache flushing primitives. The actual size of blocks allocated may be
    * larger than requested because of alignment.
    *
    - * If allocation is nonzero, objects returned from dma_pool_alloc() won't
    + * If @boundary is nonzero, objects returned from dma_pool_alloc() won't
    * cross that size boundary. This is useful for devices which have
    * addressing restrictions on individual DMA transfers, such as not crossing
    * boundaries of 4KBytes.
    */
    struct dma_pool *dma_pool_create(const char *name, struct device *dev,
    - size_t size, size_t align, size_t allocation)
    + size_t size, size_t align, size_t boundary)
    {
    struct dma_pool *retval;
    + size_t allocation;

    if (align == 0) {
    align = 1;
    @@ -142,27 +144,26 @@ struct dma_pool *dma_pool_create(const char *name, struct device *dev,
    if ((size % align) != 0)
    size = ALIGN(size, align);

    - if (allocation == 0) {
    - if (PAGE_SIZE < size)
    - allocation = size;
    - else
    - allocation = PAGE_SIZE;
    - /* FIXME: round up for less fragmentation */
    - } else if (allocation < size)
    + allocation = max_t(size_t, size, PAGE_SIZE);
    +
    + if (!boundary) {
    + boundary = allocation;
    + } else if ((boundary < size) || (boundary & (boundary - 1))) {
    return NULL;
    + }

    - if (!
    - (retval =
    - kmalloc_node(sizeof *retval, GFP_KERNEL, dev_to_node(dev))))
    + retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev));
    + if (!retval)
    return retval;

    - strlcpy(retval->name, name, sizeof retval->name);
    + strlcpy(retval->name, name, sizeof(retval->name));

    retval->dev = dev;

    INIT_LIST_HEAD(&retval->page_list);
    spin_lock_init(&retval->lock);
    retval->size = size;
    + retval->boundary = boundary;
    retval->allocation = allocation;
    init_waitqueue_head(&retval->waitq);

    @@ -192,11 +193,14 @@ EXPORT_SYMBOL(dma_pool_create);
    static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page)
    {
    unsigned int offset = 0;
    + unsigned int next_boundary = pool->boundary;

    do {
    unsigned int next = offset + pool->size;
    - if (unlikely((next + pool->size) >= pool->allocation))
    - next = pool->allocation;
    + if (unlikely((next + pool->size) >= next_boundary)) {
    + next = next_boundary;
    + next_boundary += pool->boundary;
    + }
    *(int *)(page->vaddr + offset) = next;
    offset = next;
    } while (offset < pool->allocation);
    --
    1.4.4.4

    \
     
     \ /
      Last update: 2007-12-04 21:41    [W:0.023 / U:32.212 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site