๏ปฟ# DMA Pool ๐
๊ด๋ จ ์์ค:mm/dmapool.c,include/linux/dmapool.h,include/linux/dma-mapping.h
๊ฐ์ (Overview)
DMA Pool์ ์๊ณ ๊ณ ์ ๋ ํฌ๊ธฐ์ DMA-able(์ผ๊ด์ฑ ์๋, coherent) ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก์ ํจ์จ์ ์ผ๋ก ํ ๋นํ๊ธฐ ์ํ ํ ํ ๋น์์
๋๋ค. ๋๋ผ์ด๋ฒ๊ฐ ๋ฐ๋ณต์ ์ผ๋ก ์์ DMA ๋ฒํผ๋ฅผ ํ์๋ก ํ ๋๋ง๋ค ์ ์ฒด ํ์ด์ง ๋จ์๋ก dma_alloc_coherent()๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ฏ๋ก, DMA Pool์ ํ์ด์ง๋ฅผ ํ ๋ฒ ํ ๋นํ ํ ๋ฏธ๋ฆฌ ์๋ผ๋์ ๋ธ๋ก์ผ๋ก ์ฌ์ฌ์ฉํฉ๋๋ค.
๋ด๋ถ์ ์ผ๋ก dma_pool ๊ตฌ์กฐ์ฒด๊ฐ ํ ๋น๋ ํ์ด์ง๋ค์ ์ด์ค ์ฐ๊ฒฐ ๋ฆฌ์คํธ(page_list)๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ๊ฐ ํ์ด์ง๋ boundary ๊ฒฝ๊ณ์ ๋ฐ๋ผ ๋ธ๋ก์ผ๋ก ๋ถํ ๋ฉ๋๋ค. ํด์ ๋ ๋ธ๋ก์ ๋จ์ผ ์ฐ๊ฒฐ ๋ฆฌ์คํธ(next_block)๋ก ์ถ์ ๋๋ฉฐ, ์ฌ์ฉ ์ค์ธ ๋ธ๋ก์ ๋ณ๋๋ก ์ถ์ ํ์ง ์๊ณ nr_active ์นด์ดํธ๋ก ๊ด๋ฆฌํฉ๋๋ค.
// mm/dmapool.c
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# DMA pool sysfs ์ ๋ณด ํ์ธ (์ฅ์น๋ณ)
cat /sys/bus/platform/devices/*/dma_pool/pools 2>/dev/null
# ๋ชจ๋ DMA pool ์ ๋ณด ์ถ๋ ฅ
for f in /sys/bus/*/devices/*/dma_pool/pools; do echo "=== $f ==="; cat "$f" 2>/dev/null; done
# DMA ํ ๋น ์คํจ ํ์ธ
dmesg | grep -i "dma" | grep -i "error\|fail"
# IOMMU DMA ๊ด๋ จ ๋ก๊ทธ ํ์ธ
dmesg | grep -i "swiotlb\|dma-mapping"
# DMA ํ ๋น ํต๊ณ (DMA API debug ํ์ฑํ ์)
cat /sys/kernel/debug/dma/dma_bufstats 2>/dev/null
# ์ปค๋ DMA ๊ด๋ จ ์ค์ ํ์ธ
cat /proc/iomem | grep -i "dma\|swiotlb"
# ํน์ ๋๋ผ์ด๋ฒ DMA pool ์ฌ์ฉ ํ์ธ (์: xHCI)
cat /sys/bus/pci/devices/*/dma_pool/pools 2>/dev/null
# DMA coherent ํ ๋น๋ ํ์ธ
cat /proc/meminfo | grep -i "DMA"
# DMA API debug ํ์ฑํ ํ์ธ
grep -r "DMA_API_DEBUG" /boot/config-* 2>/dev/null
# DMA ์ฅ์น ๋ง์คํฌ ํ์ธ
cat /sys/bus/pci/devices/*/dma_mask 2>/dev/null
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct dma_pool (ํ ๊ด๋ฆฌ ๊ตฌ์กฐ์ฒด)
// mm/dmapool.c:48-62
struct dma_pool { /* DMA ํ ๋ฉํ๋ฐ์ดํฐ */
struct list_head page_list; /* ํ ๋น๋ dma_page ๋ชฉ๋ก (์ด์ค ์ฐ๊ฒฐ) */
spinlock_t lock; /* ๋์์ฑ ๋ณดํธ์ฉ ์คํ๋ฝ */
struct dma_block *next_block; /* ๋ค์ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ธ๋ก ํฌ์ธํฐ */
size_t nr_blocks; /* ์ด ๋ธ๋ก ์ */
size_t nr_active; /* ์ฌ์ฉ ์ค์ธ ๋ธ๋ก ์ */
size_t nr_pages; /* ํ ๋น๋ ํ์ด์ง ์ */
struct device *dev; /* ์ด ํ์ด ์ํ ์ฅ์น */
unsigned int size; /* ๊ฐ ๋ธ๋ก์ ํฌ๊ธฐ (alignment ์ ์ฉ ํ) */
unsigned int allocation; /* ํ ๋ฒ์ ํ ๋นํ๋ ๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ (max(size, PAGE_SIZE)) */
unsigned int boundary; /* ๋ธ๋ก์ด ๊ฒฝ๊ณ๋ฅผ ๋์ง ์๋๋ก ํ๋ ๊ฐ (2์ ๊ฑฐ๋ญ์ ๊ณฑ) */
int node; /* NUMA ๋
ธ๋ ๋ฒํธ */
char name[32]; /* ํ ์ด๋ฆ (์ง๋จ์ฉ) */
struct list_head pools; /* dev->dma_pools ๋ชฉ๋ก์ ์ฐ๊ฒฐ๋๋ ๋
ธ๋ */
};
page_list: DMA Pool์ด ๊ด๋ฆฌํ๋ ๋ชจ๋ ํ์ด์ง์ ๋ฆฌ์คํธ. ๊ฐ ํ์ด์ง๋ ์ต์ PAGE_SIZE ํฌ๊ธฐ๋ก dma_alloc_coherent()๋ก ํ ๋น๋จ.next_block: ํด์ ๋ ๋ธ๋ก์ ๋จ์ผ ์ฐ๊ฒฐ ๋ฆฌ์คํธ ํค๋. free ๋ธ๋ก์ด ์์ผ๋ฉด NULL.boundary: ํน์ ์ฅ์น์ DMA ์ ์ก ์ ๊ฒฝ๊ณ ์ ์ฝ. ์: 4KB ๊ฒฝ๊ณ๋ฅผ ์ง์ ํ๋ฉด ๋ธ๋ก์ด 4KB ๊ฒฝ๊ณ๋ฅผ ๋์ง ์์.allocation: max(size, PAGE_SIZE). ํ ๋ฒ์ ํ ๋นํ๋ ๋ฉ๋ชจ๋ฆฌ ์.struct dma_block (๊ฐ๋ณ ๋ธ๋ก ํค๋)
// mm/dmapool.c:43-46
struct dma_block {
struct dma_block *next_block; /* ๋ค์ free ๋ธ๋ก์ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ */
dma_addr_t dma; /* ์ด ๋ธ๋ก์ DMA ๋ฌผ๋ฆฌ ์ฃผ์ */
};
๊ฐ ๋ธ๋ก์ ์์ ๋ถ๋ถ์ ์ค๋ฒํค๋๋ก ์กด์ฌ. ํ ๋น ์ ์ด ๊ตฌ์กฐ์ฒด ํฌ๊ธฐ๋งํผ size๊ฐ ์ฆ๊ฐํ์ฌ ์ค์ ์ฌ์ฉ ๊ฐ๋ฅ ์์ญ์ block + sizeof(struct dma_block) ๋ถํฐ ์์.
struct dma_page (ํ์ด์ง ๊ด๋ฆฌ ๊ตฌ์กฐ์ฒด)
// mm/dmapool.c:64-68
struct dma_page { /* 'allocation' ๋ฐ์ดํธ์ง๋ฆฌ ์บ์ ๊ฐ๋ฅํ ํค๋ */
struct list_head page_list; /* pool->page_list์ ์ฐ๊ฒฐ๋๋ ๋
ธ๋ */
void *vaddr; /* ์ฝ์ด CPU ๊ฐ์ ์ฃผ์ */
dma_addr_t dma; /* DMA ์ฃผ์ */
};
์ค์ DMA ๋ฉ๋ชจ๋ฆฌ์ ๊ด๋ฆฌ ํค๋. dma_alloc_coherent()๋ก ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ์ vaddr๊ณผ dma ์ฃผ์๋ฅผ ๋ณด๊ด.
ํต์ฌ ํจ์
1. dma_pool_create_node() โ ํ ์์ฑ
// mm/dmapool.c:226-301
struct dma_pool *dma_pool_create_node(const char *name, struct device *dev,
size_t size, size_t align, size_t boundary, int node)
์ญํ : ์ง์ ๋ ํฌ๊ธฐ์ DMA coherent ๋ฉ๋ชจ๋ฆฌ ํ์ ์์ฑํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
dev == NULL โ NULL ๋ฐํalign์ด 0์ด๋ฉด 1๋ก ์ค์ , 2์ ๊ฑฐ๋ญ์ ๊ณฑ์ด ์๋๋ฉด NULL ๋ฐํsize == 0 ๋๋ size > INT_MAX โ NULL ๋ฐํsize < sizeof(struct dma_block) โ sizeof(struct dma_block)์ผ๋ก ์ฆ๊ฐ (์ค๋ฒํค๋ ํ๋ณด)size = ALIGN(size, align) ํ allocation = max(size, PAGE_SIZE)boundary == 0 โ boundary = allocation (๊ฒฝ๊ณ ์ ์ฝ ์์)boundary < size ๋๋ ๋น-2์ ๊ฑฐ๋ญ์ ๊ณฑ โ NULL ๋ฐํdevice_create_file()๋ก sysfs pools ํ์ผ ์์ฑ2. dma_pool_alloc() โ ๋ธ๋ก ํ ๋น
// mm/dmapool.c:407-441
void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
dma_addr_t *handle)
์ญํ : ํ์์ ์ฌ์ฉ ๊ฐ๋ฅํ DMA ๋ธ๋ก์ ํ ๋นํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. pool->lock ํ๋ ํ pool_block_pop()์ผ๋ก free ๋ธ๋ก ์๋
2. free ๋ธ๋ก์ด ์์ผ๋ฉด:
- pool->lock ํด์ (์คํ๋ฝ ํ์์ sleep ๋ถ๊ฐ)
- pool_alloc_page()๋ก ์ ํ์ด์ง ํ ๋น (dma_alloc_coherent())
- pool->lock ์ฌํ๋ ํ pool_initialise_page()๋ก ํ์ด์ง๋ฅผ ๋ธ๋ก์ผ๋ก ๋ถํ
- ๋ค์ pool_block_pop()์ผ๋ก ๋ธ๋ก ํ ๋น
3. *handle = block->dma (DMA ์ฃผ์ ๋ฐํ)
4. DMAPOOL_DEBUG ํ์ฑํ ์ pool_check_block()์ผ๋ก ํ์ง ๊ฒ์ฆ
3. dma_pool_free() โ ๋ธ๋ก ํด์
// mm/dmapool.c:453-465
void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
์ญํ : ํ ๋น๋ ๋ธ๋ก์ ํ์ ๋ฐํํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. pool->lock ํ๋
2. pool_block_err()๋ก ์ค๋ฅ ๊ฒ์ฆ (์๋ชป๋ DMA ์ฃผ์, ์ด๋ฏธ ํด์ ๋ ๋ธ๋ก ํ์ธ)
3. ์ค๋ฅ ์์ผ๋ฉด pool_block_push()๋ก free ๋ฆฌ์คํธ์ ์ถ๊ฐ, nr_active--
4. DMAPOOL_DEBUG ๋ฏธํ์ฑํ ์ want_init_on_free()์ด๋ฉด 0์ผ๋ก ์ด๊ธฐํ
4. dma_pool_destroy() โ ํ ํ๊ดด
// mm/dmapool.c:363-395
void dma_pool_destroy(struct dma_pool *pool)
์ญํ : ํ์ ์์ ํ ํด์ ํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. pool == NULL โ ์ฆ์ ๋ฐํ
2. pools_lock ํ์์ dev->dma_pools์์ ์ ๊ฑฐ
3. ์ฅ์น์ ๋ ์ด์ ํ์ด ์์ผ๋ฉด sysfs pools ํ์ผ ์ ๊ฑฐ
4. nr_active > 0์ด๋ฉด busy ๊ฒฝ๊ณ ์ถ๋ ฅ, ์ค์ DMA ๋ฉ๋ชจ๋ฆฌ ํด์ ๋ ๊ฑด๋๋
5. ๋ชจ๋ dma_page์ ๋ํด dma_free_coherent() ํธ์ถ ํ kfree
6. dma_pool ์์ฒด kfree
5. pool_initialise_page() โ ํ์ด์ง ๋ถํ
// mm/dmapool.c:303-335
static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page)
์ญํ : ํ ๋น๋ ํ์ด์ง๋ฅผ boundary ๊ฒฝ๊ณ๋ฅผ ๊ณ ๋ คํ์ฌ ๋ธ๋ก ๋จ์๋ก ๋ถํ ํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
offset + size > next_boundary โ boundary ๊ฒฝ๊ณ๋ฅผ ๊ฑด๋๋ (๋ธ๋ก ๋ฐฐ์น ์ ํจ)next_block ๋ฆฌ์คํธ์ ์ฐ๊ฒฐnr_blocks ์ฆ๊ฐํธ์ถ ํ๋ฆ
๋๋ผ์ด๋ฒ
โ
โโ dma_pool_create(name, dev, size, align, boundary)
โ โโ dma_pool_create_node(..., NUMA_NO_NODE)
โ โโ kzalloc_node() โ dma_pool ๊ตฌ์กฐ์ฒด ํ ๋น
โ โโ INIT_LIST_HEAD(page_list)
โ โโ list_add(pools, dev->dma_pools)
โ โโ device_create_file() โ sysfs pools ํ์ผ ์์ฑ
โ
โโ dma_pool_alloc(pool, GFP_KERNEL, &handle)
โ โโ spin_lock_irqsave(pool->lock)
โ โโ pool_block_pop(pool) โ free ๋ธ๋ก ์์ผ๋ฉด ๋ฐํ
โ โ โโ (์์ผ๋ฉด)
โ โโ spin_unlock_irqrestore(pool->lock)
โ โโ pool_alloc_page(pool, mem_flags)
โ โ โโ kmalloc_node() โ dma_page ๊ตฌ์กฐ์ฒด ํ ๋น
โ โ โโ dma_alloc_coherent() โ ์ค์ DMA ๋ฉ๋ชจ๋ฆฌ ํ ๋น
โ โโ spin_lock_irqsave(pool->lock)
โ โโ pool_initialise_page(pool, page) โ ํ์ด์ง๋ฅผ ๋ธ๋ก์ผ๋ก ๋ถํ
โ โ โโ ๋ฐ๋ณต: block = page->vaddr + offset
โ โโ pool_block_pop(pool) โ ์ ๋ธ๋ก ํ ๋น
โ โโ spin_unlock_irqrestore(pool->lock)
โ
โโ dma_pool_free(pool, vaddr, dma)
โ โโ spin_lock_irqsave(pool->lock)
โ โโ pool_block_err(pool, vaddr, dma) โ ์ค๋ฅ ๊ฒ์ฆ
โ โโ pool_block_push(pool, block, dma) โ free ๋ฆฌ์คํธ์ ์ถ๊ฐ
โ โโ spin_unlock_irqrestore(pool->lock)
โ
โโ dma_pool_destroy(pool)
โโ list_del(pools, dev->dma_pools)
โโ device_remove_file() โ sysfs pools ํ์ผ ์ ๊ฑฐ
โโ (busy๊ฐ ์๋๋ฉด) dma_free_coherent() ๋ฐ๋ณต
โโ kfree(page) ๋ฐ๋ณต
โโ kfree(pool)
์กฐ๊ฑด๋ณ ๋น๊ต
DMA Pool API ๋น๊ต
| API | NUMA ์ง์ | ๊ด๋ฆฌ ๋ฐฉ์ | ์ฃผ์ ์ฌ์ฉ์ฒ |
|---|---|---|---|
| `dma_pool_create()` | โ (NUMA_NO_NODE) | ์๋ ์์ฑ/ํ๊ดด | ์ผ๋ฐ ๋๋ผ์ด๋ฒ |
| `dma_pool_create_node()` | โ (node ํ๋ผ๋ฏธํฐ) | ์๋ ์์ฑ/ํ๊ดด | NUMA ์ธ์ ๋๋ผ์ด๋ฒ |
| `dmam_pool_create()` | โ | ์๋ ํด์ (devres) | ๋ฆฌ์์ค ๊ด๋ฆฌ๊ฐ ํ์ํ ๋๋ผ์ด๋ฒ |
DMA ๋ฉ๋ชจ๋ฆฌ ํ ๋น ๋ฐฉ์ ๋น๊ต
| ๋ฐฉ์ | ํฌ๊ธฐ ๋จ์ | ์ค๋ฒํค๋ | ์ฌ์ฌ์ฉ | ์ฌ์ฉ ์๋๋ฆฌ์ค |
|---|---|---|---|---|
| `dma_alloc_coherent()` | ํ์ด์ง ๋จ์ | ์์ | ์์ | ๋ํ DMA ๋ฒํผ |
| DMA Pool | ๊ณ ์ ํฌ๊ธฐ ๋ธ๋ก | `sizeof(dma_block)` | โ | ์๊ณ ๋ฐ๋ณต์ ์ธ DMA ํ ๋น |
| `dma_alloc_pages()` | ํ์ด์ง ๋จ์ | ์์ | ์์ | SG DMA |
| vmalloc | ์์ ํฌ๊ธฐ | ํ์ด์ง ํ ์ด๋ธ | ์์ | ์ปค๋ ๋ด๋ถ ์ฌ์ฉ |
boundary ์ค์ ๋์ ๋น๊ต
| boundary ๊ฐ | ๋ธ๋ก ๋ฐฐ์น ๊ท์น | ์์ |
|---|---|---|
| 0 (๋ฏธ์ง์ ) | allocation ๋จ์๋ก ์์ ๋กญ๊ฒ ๋ฐฐ์น | ๊ธฐ๋ณธ ๋์ |
| 4096 | 4KB ๊ฒฝ๊ณ๋ฅผ ๋์ง ์์ | xHCI HCI command ring |
| 65536 | 64KB ๊ฒฝ๊ณ๋ฅผ ๋์ง ์์ | ๊ณ ์ฑ๋ฅ NIC descriptor ring |
DMAPOOL_DEBUG ๋์ ๋น๊ต
| ์กฐ๊ฑด | ํ ๋น ์ | ํด์ ์ | ํ์ด์ง ์ด๊ธฐํ |
|---|---|---|---|
| DMAPOOL_DEBUG ON | `POOL_POISON_ALLOCATED`๋ก ๋ฎ์ด์ฐ๊ธฐ | `POOL_POISON_FREED` ๊ฒ์ฆ + ๋ฎ์ด์ฐ๊ธฐ | `POOL_POISON_FREED`๋ก ์ด๊ธฐํ |
| DMAPOOL_DEBUG OFF | `want_init_on_alloc`์ด๋ฉด 0 ์ด๊ธฐํ | `want_init_on_free`์ด๋ฉด 0 ์ด๊ธฐํ | ์์ |