📄 mm.c
字号:
*bus_addr = 0; DBG("%s:%d: dma_sb_map_pages failed (%d)\n", __func__, __LINE__, result); spin_unlock_irqrestore(&r->chunk_list.lock, flags); return result; } c->usage_count = 1; spin_unlock_irqrestore(&r->chunk_list.lock, flags); return result;}static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr, unsigned long len, unsigned long *bus_addr, u64 iopte_flag){ int result; unsigned long flags; struct dma_chunk *c; unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) : virt_addr; unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, 1 << r->page_size); DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__, virt_addr, len); DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__, phys_addr, aligned_phys, aligned_len); spin_lock_irqsave(&r->chunk_list.lock, flags); c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len); if (c) { /* FIXME */ BUG(); *bus_addr = c->bus_addr + phys_addr - aligned_phys; c->usage_count++; spin_unlock_irqrestore(&r->chunk_list.lock, flags); return 0; } result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag); if (result) { *bus_addr = 0; DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n", __func__, __LINE__, result); spin_unlock_irqrestore(&r->chunk_list.lock, flags); return result; } *bus_addr = c->bus_addr + phys_addr - aligned_phys; DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__, virt_addr, phys_addr, aligned_phys, *bus_addr); c->usage_count = 1; spin_unlock_irqrestore(&r->chunk_list.lock, flags); return result;}/** * dma_sb_unmap_area - Unmap an area of memory from a device dma region. * @r: Pointer to a struct ps3_dma_region. * @bus_addr: The starting ioc bus address of the area to unmap. * @len: Length in bytes of the area to unmap. * * This is the common dma unmap routine. */static int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len){ unsigned long flags; struct dma_chunk *c; spin_lock_irqsave(&r->chunk_list.lock, flags); c = dma_find_chunk(r, bus_addr, len); if (!c) { unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); unsigned long aligned_len = _ALIGN_UP(len + bus_addr - aligned_bus, 1 << r->page_size); DBG("%s:%d: not found: bus_addr %lxh\n", __func__, __LINE__, bus_addr); DBG("%s:%d: not found: len %lxh\n", __func__, __LINE__, len); DBG("%s:%d: not found: aligned_bus %lxh\n", __func__, __LINE__, aligned_bus); DBG("%s:%d: not found: aligned_len %lxh\n", __func__, __LINE__, aligned_len); BUG(); } c->usage_count--; if (!c->usage_count) { list_del(&c->link); dma_sb_free_chunk(c); } spin_unlock_irqrestore(&r->chunk_list.lock, flags); return 0;}static int dma_ioc0_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len){ unsigned long flags; struct dma_chunk *c; DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len); spin_lock_irqsave(&r->chunk_list.lock, flags); c = dma_find_chunk(r, bus_addr, len); if (!c) { unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); unsigned long aligned_len = _ALIGN_UP(len + bus_addr - aligned_bus, 1 << r->page_size); DBG("%s:%d: not found: bus_addr %lxh\n", __func__, __LINE__, bus_addr); DBG("%s:%d: not found: len %lxh\n", __func__, __LINE__, len); DBG("%s:%d: not found: aligned_bus %lxh\n", __func__, __LINE__, aligned_bus); DBG("%s:%d: not found: aligned_len %lxh\n", __func__, __LINE__, aligned_len); BUG(); } c->usage_count--; if (!c->usage_count) { list_del(&c->link); dma_ioc0_free_chunk(c); } spin_unlock_irqrestore(&r->chunk_list.lock, flags); DBG("%s: end\n", __func__); return 0;}/** * dma_sb_region_create_linear - Setup a linear dma mapping for a device. * @r: Pointer to a struct ps3_dma_region. * * This routine creates an HV dma region for the device and maps all available * ram into the io controller bus address space. */static int dma_sb_region_create_linear(struct ps3_dma_region *r){ int result; unsigned long virt_addr, len, tmp; if (r->len > 16*1024*1024) { /* FIXME: need proper fix */ /* force 16M dma pages for linear mapping */ if (r->page_size != PS3_DMA_16M) { pr_info("%s:%d: forcing 16M pages for linear map\n", __func__, __LINE__); r->page_size = PS3_DMA_16M; r->len = _ALIGN_UP(r->len, 1 << r->page_size); } } result = dma_sb_region_create(r); BUG_ON(result); if (r->offset < map.rm.size) { /* Map (part of) 1st RAM chunk */ virt_addr = map.rm.base + r->offset; len = map.rm.size - r->offset; if (len > r->len) len = r->len; result = dma_sb_map_area(r, virt_addr, len, &tmp, IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); BUG_ON(result); } if (r->offset + r->len > map.rm.size) { /* Map (part of) 2nd RAM chunk */ virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; len = r->len; if (r->offset >= map.rm.size) virt_addr += r->offset - map.rm.size; else len -= map.rm.size - r->offset; result = dma_sb_map_area(r, virt_addr, len, &tmp, IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); BUG_ON(result); } return result;}/** * dma_sb_region_free_linear - Free a linear dma mapping for a device. * @r: Pointer to a struct ps3_dma_region. * * This routine will unmap all mapped areas and free the HV dma region. */static int dma_sb_region_free_linear(struct ps3_dma_region *r){ int result; unsigned long bus_addr, len, lpar_addr; if (r->offset < map.rm.size) { /* Unmap (part of) 1st RAM chunk */ lpar_addr = map.rm.base + r->offset; len = map.rm.size - r->offset; if (len > r->len) len = r->len; bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); result = dma_sb_unmap_area(r, bus_addr, len); BUG_ON(result); } if (r->offset + r->len > map.rm.size) { /* Unmap (part of) 2nd RAM chunk */ lpar_addr = map.r1.base; len = r->len; if (r->offset >= map.rm.size) lpar_addr += r->offset - map.rm.size; else len -= map.rm.size - r->offset; bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); result = dma_sb_unmap_area(r, bus_addr, len); BUG_ON(result); } result = dma_sb_region_free(r); BUG_ON(result); return result;}/** * dma_sb_map_area_linear - Map an area of memory into a device dma region. * @r: Pointer to a struct ps3_dma_region. * @virt_addr: Starting virtual address of the area to map. * @len: Length in bytes of the area to map. * @bus_addr: A pointer to return the starting ioc bus address of the area to * map. * * This routine just returns the corresponding bus address. Actual mapping * occurs in dma_region_create_linear(). */static int dma_sb_map_area_linear(struct ps3_dma_region *r, unsigned long virt_addr, unsigned long len, unsigned long *bus_addr, u64 iopte_flag){ unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) : virt_addr; *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); return 0;}/** * dma_unmap_area_linear - Unmap an area of memory from a device dma region. * @r: Pointer to a struct ps3_dma_region. * @bus_addr: The starting ioc bus address of the area to unmap. * @len: Length in bytes of the area to unmap. * * This routine does nothing. Unmapping occurs in dma_sb_region_free_linear(). */static int dma_sb_unmap_area_linear(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len){ return 0;};static const struct ps3_dma_region_ops ps3_dma_sb_region_ops = { .create = dma_sb_region_create, .free = dma_sb_region_free, .map = dma_sb_map_area, .unmap = dma_sb_unmap_area};static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = { .create = dma_sb_region_create_linear, .free = dma_sb_region_free_linear, .map = dma_sb_map_area_linear, .unmap = dma_sb_unmap_area_linear};static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = { .create = dma_ioc0_region_create, .free = dma_ioc0_region_free, .map = dma_ioc0_map_area, .unmap = dma_ioc0_unmap_area};int ps3_dma_region_init(struct ps3_system_bus_device *dev, struct ps3_dma_region *r, enum ps3_dma_page_size page_size, enum ps3_dma_region_type region_type, void *addr, unsigned long len){ unsigned long lpar_addr; lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0; r->dev = dev; r->page_size = page_size; r->region_type = region_type; r->offset = lpar_addr; if (r->offset >= map.rm.size) r->offset -= map.r1.offset; r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size); switch (dev->dev_type) { case PS3_DEVICE_TYPE_SB: r->region_ops = (USE_DYNAMIC_DMA) ? &ps3_dma_sb_region_ops : &ps3_dma_sb_region_linear_ops; break; case PS3_DEVICE_TYPE_IOC0: r->region_ops = &ps3_dma_ioc0_region_ops; break; default: BUG(); return -EINVAL; } return 0;}EXPORT_SYMBOL(ps3_dma_region_init);int ps3_dma_region_create(struct ps3_dma_region *r){ BUG_ON(!r); BUG_ON(!r->region_ops); BUG_ON(!r->region_ops->create); return r->region_ops->create(r);}EXPORT_SYMBOL(ps3_dma_region_create);int ps3_dma_region_free(struct ps3_dma_region *r){ BUG_ON(!r); BUG_ON(!r->region_ops); BUG_ON(!r->region_ops->free); return r->region_ops->free(r);}EXPORT_SYMBOL(ps3_dma_region_free);int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr, unsigned long len, unsigned long *bus_addr, u64 iopte_flag){ return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag);}int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len){ return r->region_ops->unmap(r, bus_addr, len);}/*============================================================================*//* system startup routines *//*============================================================================*//** * ps3_mm_init - initialize the address space state variables */void __init ps3_mm_init(void){ int result; DBG(" -> %s:%d\n", __func__, __LINE__); result = ps3_repository_read_mm_info(&map.rm.base, &map.rm.size, &map.total); if (result) panic("ps3_repository_read_mm_info() failed"); map.rm.offset = map.rm.base; map.vas_id = map.htab_size = 0; /* this implementation assumes map.rm.base is zero */ BUG_ON(map.rm.base); BUG_ON(!map.rm.size); /* arrange to do this in ps3_mm_add_memory */ ps3_mm_region_create(&map.r1, map.total - map.rm.size); /* correct map.total for the real total amount of memory we use */ map.total = map.rm.size + map.r1.size; DBG(" <- %s:%d\n", __func__, __LINE__);}/** * ps3_mm_shutdown - final cleanup of address space */void ps3_mm_shutdown(void){ ps3_mm_region_destroy(&map.r1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -