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

📄 pci_dma.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			dn = dn->parent;		if (dn) {			mydn->tce_table = dn->tce_table;		}	}}/* * iSeries token = iSeries_device_Node* * pSeries token = pci_controller* * */void create_pci_bus_tce_table( unsigned long token ) {	struct TceTable * newTceTable;	PPCDBG(PPCDBG_TCE, "Entering create_pci_bus_tce_table.\n");	PPCDBG(PPCDBG_TCE, "\ttoken = 0x%lx\n", token);	newTceTable = (struct TceTable *)kmalloc( sizeof(struct TceTable), GFP_KERNEL );	/*****************************************************************/ 	/* For the iSeries machines, the HvTce Table can be one of three */ 	/* flavors,                                                      */ 	/* - Single bus TCE table,                                       */ 	/* - Tce Table Share between buses,                              */ 	/* - Tce Table per logical slot.                                 */	/*****************************************************************/	if(naca->platform == PLATFORM_ISERIES_LPAR) {		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;		getTceTableParmsiSeries(DevNode,newTceTable);		/* Look for existing TCE table for this device.          */		DevNode->DevTceTable = findHwTceTable(newTceTable );		if( DevNode->DevTceTable == NULL) {			DevNode->DevTceTable = build_tce_table( newTceTable );		}		else {		    /* We're using a shared table, free this new one.    */		    kfree(newTceTable);		}		printk("Pci Device 0x%p TceTable: %p\n",DevNode,DevNode->DevTceTable); 		return;	}	/* pSeries Leg */	else {		struct device_node *dn;		struct pci_controller *phb;		dn = (struct device_node *)token;		phb = dn->phb;		if (naca->platform == PLATFORM_PSERIES)			getTceTableParmsPSeries(phb, dn, newTceTable);		else			getTceTableParmsPSeriesLP(phb, dn, newTceTable);		dn->tce_table  = build_tce_table( newTceTable );	}}/***********************************************************************//* This function compares the known Tce tables to find a TceTable that *//* has already been built for hardware TCEs.                           *//* Search the complete(all devices) for a TCE table assigned.  If the  *//* startOffset, index, and size match, then the TCE for this device has*//* already been built and it should be shared with this device         *//***********************************************************************/static struct TceTable* findHwTceTable(struct TceTable * newTceTable ){	struct list_head* Device_Node_Ptr    = iSeries_Global_Device_List.next;	/* Cache the compare values. */	u64  startOffset = newTceTable->startOffset;	u64  index       = newTceTable->index;	u64  size        = newTceTable->size;	while(Device_Node_Ptr != &iSeries_Global_Device_List) {		struct iSeries_Device_Node* CmprNode = (struct iSeries_Device_Node*)Device_Node_Ptr;		if( CmprNode->DevTceTable != NULL &&		    CmprNode->DevTceTable->tceType == TCE_PCI) {			if( CmprNode->DevTceTable->startOffset == startOffset &&			    CmprNode->DevTceTable->index       == index       &&			    CmprNode->DevTceTable->size        == size        ) {				printk("PCI TCE table matches 0x%p \n",CmprNode->DevTceTable);				return CmprNode->DevTceTable;			}		}		/* Get next Device Node in List             */		Device_Node_Ptr = Device_Node_Ptr->next;	}	return NULL;}/***********************************************************************//* Call Hv with the architected data structure to get TCE table info.  *//* info. Put the returned data into the Linux representation of the    *//* TCE table data.                                                     *//* The Hardware Tce table comes in three flavors.                      */ /* 1. TCE table shared between Buses.                                  *//* 2. TCE table per Bus.                                               *//* 3. TCE Table per IOA.                                               *//***********************************************************************/static void getTceTableParmsiSeries(struct iSeries_Device_Node* DevNode,				    struct TceTable* newTceTable ){	struct TceTableManagerCB* pciBusTceTableParms = (struct TceTableManagerCB*)kmalloc( sizeof(struct TceTableManagerCB), GFP_KERNEL );	if(pciBusTceTableParms == NULL) panic("PCI_DMA: TCE Table Allocation failed.");	memset( (void*)pciBusTceTableParms,0,sizeof(struct TceTableManagerCB) );	pciBusTceTableParms->busNumber      = ISERIES_BUS(DevNode);	pciBusTceTableParms->logicalSlot    = DevNode->LogicalSlot;	pciBusTceTableParms->virtualBusFlag = 0;	HvCallXm_getTceTableParms( REALADDR(pciBusTceTableParms) );        /* PciTceTableParms Bus:0x18 Slot:0x04 Start:0x000000 Offset:0x04c000 Size:0x0020 */	printk("PciTceTableParms Bus:0x%02lx Slot:0x%02x Start:0x%06lx Offset:0x%06lx Size:0x%04lx\n",	       pciBusTceTableParms->busNumber,	       pciBusTceTableParms->logicalSlot,	       pciBusTceTableParms->start,	       pciBusTceTableParms->startOffset,	       pciBusTceTableParms->size);	if(pciBusTceTableParms->size == 0) {		printk("PCI_DMA: Possible Structure mismatch, 0x%p\n",pciBusTceTableParms);		panic( "PCI_DMA: pciBusTceTableParms->size is zero, halt here!");	}	newTceTable->size        = pciBusTceTableParms->size;	newTceTable->busNumber   = pciBusTceTableParms->busNumber;	newTceTable->startOffset = pciBusTceTableParms->startOffset;	newTceTable->index       = pciBusTceTableParms->index;	newTceTable->tceType     = TCE_PCI;	kfree(pciBusTceTableParms);}static void getTceTableParmsPSeries(struct pci_controller *phb,				    struct device_node *dn,				    struct TceTable *newTceTable ) {	phandle node;	unsigned long i;	node = ((struct device_node *)(phb->arch_data))->node;	PPCDBG(PPCDBG_TCEINIT, "getTceTableParms: start\n"); 	PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table = 0x%lx\n", of_tce_table); 	PPCDBG(PPCDBG_TCEINIT, "\tphb          = 0x%lx\n", phb); 	PPCDBG(PPCDBG_TCEINIT, "\tdn           = 0x%lx\n", dn); 	PPCDBG(PPCDBG_TCEINIT, "\tdn->name     = %s\n", dn->name); 	PPCDBG(PPCDBG_TCEINIT, "\tdn->full_name= %s\n", dn->full_name); 	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable  = 0x%lx\n", newTceTable); 	PPCDBG(PPCDBG_TCEINIT, "\tdma_window_size = 0x%lx\n", phb->dma_window_size); 	i = 0;	while(of_tce_table[i].node) {		PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].node = 0x%lx\n", 		       i, of_tce_table[i].node);		PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].base = 0x%lx\n", 		       i, of_tce_table[i].base);		PPCDBG(PPCDBG_TCEINIT, "\tof_tce_table[%d].size = 0x%lx\n", 		       i, of_tce_table[i].size >> PAGE_SHIFT);		PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data->node = 0x%lx\n", 		       node);		if(of_tce_table[i].node == node) {			memset((void *)of_tce_table[i].base, 			       0, of_tce_table[i].size);			newTceTable->busNumber = phb->bus->number;			/* Units of tce entries.                        */			newTceTable->startOffset = phb->dma_window_base_cur;			/* Adjust the current table offset to the next  */			/* region.  Measured in TCE entries. Force an   */			/* alignment to the size alloted per IOA. This  */			/* makes it easier to remove the 1st 16MB.      */			phb->dma_window_base_cur += (phb->dma_window_size>>3);			phb->dma_window_base_cur &= 				~((phb->dma_window_size>>3)-1);			/* Set the tce table size - measured in units   */			/* of pages of tce table.                       */			newTceTable->size = ((phb->dma_window_base_cur -					      newTceTable->startOffset) << 3)					      >> PAGE_SHIFT;			/* Test if we are going over 2GB of DMA space.  */			if(phb->dma_window_base_cur > (1 << 19)) { 				panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); 			}			newTceTable->base = of_tce_table[i].base;			newTceTable->index = 0;						PPCDBG(PPCDBG_TCEINIT, 			       "\tnewTceTable->base        = 0x%lx\n",			       newTceTable->base);			PPCDBG(PPCDBG_TCEINIT, 			       "\tnewTceTable->startOffset = 0x%lx"			       "(# tce entries)\n", 			       newTceTable->startOffset);			PPCDBG(PPCDBG_TCEINIT, 			       "\tnewTceTable->size        = 0x%lx"			       "(# pages of tce table)\n", 			       newTceTable->size);		}		i++;	}}/* * getTceTableParmsPSeriesLP * * Function: On pSeries LPAR systems, return TCE table info, given a pci bus. * * ToDo: properly interpret the ibm,dma-window property.  The definition is: *	logical-bus-number	(1 word) *	phys-address		(#address-cells words) *	size			(#cell-size words) * * Currently we hard code these sizes (more or less). */static void getTceTableParmsPSeriesLP(struct pci_controller *phb,				    struct device_node *dn,				    struct TceTable *newTceTable ) {	u32 *dma_window = (u32 *)get_property(dn, "ibm,dma-window", 0);	if (!dma_window) {		panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name);	}	newTceTable->busNumber = dn->busno;	newTceTable->size = (((((unsigned long)dma_window[4] << 32) | (unsigned long)dma_window[5]) >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;	newTceTable->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12);	newTceTable->base = 0;	newTceTable->index = dma_window[0];	PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->busno);	PPCDBG(PPCDBG_TCEINIT, "\tDevice = %s\n", dn->full_name);	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->index       = 0x%lx\n", newTceTable->index);	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->startOffset = 0x%lx\n", newTceTable->startOffset);	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->size        = 0x%lx\n", newTceTable->size);}/* Allocates a contiguous real buffer and creates TCEs over it. * Returns the virtual address of the buffer and sets dma_handle * to the dma address (tce) of the first page. */void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,			   dma_addr_t *dma_handle){	struct TceTable * tbl;	void *ret = NULL;	unsigned order, nPages;	dma_addr_t tce;	PPCDBG(PPCDBG_TCE, "pci_alloc_consistent:\n");	PPCDBG(PPCDBG_TCE, "\thwdev      = 0x%16.16lx\n", hwdev);	PPCDBG(PPCDBG_TCE, "\tsize       = 0x%16.16lx\n", size);	PPCDBG(PPCDBG_TCE, "\tdma_handle = 0x%16.16lx\n", dma_handle);		size = PAGE_ALIGN(size);	order = get_order(size);	nPages = 1 << order; 	/* Client asked for way to much space.  This is checked later anyway */	/* It is easier to debug here for the drivers than in the tce tables.*/ 	if(order >= NUM_TCE_LEVELS) { 		printk("PCI_DMA: pci_alloc_consistent size to large: 0x%lx \n",size); 		return (void *)NO_TCE; 	}	tbl = get_tce_table(hwdev); 	if ( tbl ) {		/* Alloc enough pages (and possibly more) */		ret = (void *)__get_free_pages( GFP_ATOMIC, order );		if ( ret ) {			/* Page allocation succeeded */			memset(ret, 0, nPages << PAGE_SHIFT);			/* Set up tces to cover the allocated range */			tce = get_tces( tbl, order, ret, nPages, PCI_DMA_BIDIRECTIONAL );			if ( tce == NO_TCE ) {				PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tces failed\n" );				free_pages( (unsigned long)ret, order );				ret = NULL;			}			else			{				*dma_handle = tce;			}		}		else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: __get_free_pages failed for order = %d\n", order);	}	else PPCDBG(PPCDBG_TCE, "pci_alloc_consistent: get_tce_table failed for 0x%016lx\n", hwdev);	PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: dma_handle = 0x%16.16lx\n", *dma_handle);		PPCDBG(PPCDBG_TCE, "\tpci_alloc_consistent: return     = 0x%16.16lx\n", ret);		return ret;}void pci_free_consistent(struct pci_dev *hwdev, size_t size,			 void *vaddr, dma_addr_t dma_handle){	struct TceTable * tbl;	unsigned order, nPages;		PPCDBG(PPCDBG_TCE, "pci_free_consistent:\n");	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, dma_handle = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, dma_handle, vaddr);		size = PAGE_ALIGN(size);	order = get_order(size);	nPages = 1 << order; 	/* Client asked for way to much space.  This is checked later anyway */	/* It is easier to debug here for the drivers than in the tce tables.*/ 	if(order >= NUM_TCE_LEVELS) { 		printk("PCI_DMA: pci_free_consistent size to large: 0x%lx \n",size); 		return; 	}		tbl = get_tce_table(hwdev); 	if ( tbl ) {		tce_free(tbl, dma_handle, order, nPages);		free_pages( (unsigned long)vaddr, order );	}}/* Creates TCEs for a user provided buffer.  The user buffer must be  * contiguous real kernel storage (not vmalloc).  The address of the buffer * passed here is the kernel (virtual) address of the buffer.  The buffer * need not be page aligned, the dma_addr_t returned will point to the same * byte within the page as vaddr. */dma_addr_t pci_map_single(struct pci_dev *hwdev, void *vaddr, 			  size_t size, int direction ){	struct TceTable * tbl;	dma_addr_t dma_handle = NO_TCE;	unsigned long uaddr;	unsigned order, nPages;	PPCDBG(PPCDBG_TCE, "pci_map_single:\n");	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, size = 0x%16.16lx, direction = 0x%16.16lx, vaddr = 0x%16.16lx\n", hwdev, size, direction, vaddr);		if ( direction == PCI_DMA_NONE )		BUG();		uaddr = (unsigned long)vaddr;	nPages = PAGE_ALIGN( uaddr + size ) - ( uaddr & PAGE_MASK );	order = get_order( nPages & PAGE_MASK );	nPages >>= PAGE_SHIFT;	 	/* Client asked for way to much space.  This is checked later anyway */	/* It is easier to debug here for the drivers than in the tce tables.*/ 	if(order >= NUM_TCE_LEVELS) { 		printk("PCI_DMA: pci_map_single size to large: 0x%lx \n",size); 		return NO_TCE; 	}	tbl = get_tce_table(hwdev); 	if ( tbl ) {		dma_handle = get_tces( tbl, order, vaddr, nPages, direction );		dma_handle |= ( uaddr & ~PAGE_MASK );	}	return dma_handle;}void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction ){	struct TceTable * tbl;	unsigned order, nPages;		PPCDBG(PPCDBG_TCE, "pci_unmap_single:\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -