⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		*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 + -