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

📄 tioca_provider.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (node_upper > 64) {		printk(KERN_ERR "%s:  coretalk addr 0x%p node id out "		       "of range\n", __FUNCTION__, (void *)ct_addr);		return 0;	}	agp_dma_extn = __sn_readq_relaxed(&ca_base->ca_agp_dma_addr_extn);	if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) {		printk(KERN_ERR "%s:  coretalk upper node (%u) "		       "mismatch with ca_agp_dma_addr_extn (%lu)\n",		       __FUNCTION__,		       node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT));		return 0;	}	return bus_addr;}/** * tioca_dma_mapped - create a DMA mapping using a CA GART  * @pdev: linux pci_dev representing the function * @paddr: host physical address to map * @req_size: len (bytes) to map * * Map @paddr into CA address space using the GART mechanism.  The mapped * dma_addr_t is guaranteed to be contiguous in CA bus space. */static dma_addr_ttioca_dma_mapped(struct pci_dev *pdev, u64 paddr, size_t req_size){	int i, ps, ps_shift, entry, entries, mapsize, last_entry;	u64 xio_addr, end_xio_addr;	struct tioca_common *tioca_common;	struct tioca_kernel *tioca_kern;	dma_addr_t bus_addr = 0;	struct tioca_dmamap *ca_dmamap;	void *map;	unsigned long flags;	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);	tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;	tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private;	xio_addr = PHYS_TO_TIODMA(paddr);	if (!xio_addr)		return 0;	spin_lock_irqsave(&tioca_kern->ca_lock, flags);	/*	 * allocate a map struct	 */	ca_dmamap = kzalloc(sizeof(struct tioca_dmamap), GFP_ATOMIC);	if (!ca_dmamap)		goto map_return;	/*	 * Locate free entries that can hold req_size.  Account for	 * unaligned start/length when allocating.	 */	ps = tioca_kern->ca_ap_pagesize;	/* will be power of 2 */	ps_shift = ffs(ps) - 1;	end_xio_addr = xio_addr + req_size - 1;	entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1;	map = tioca_kern->ca_pcigart_pagemap;	mapsize = tioca_kern->ca_pcigart_entries;	entry = find_first_zero_bit(map, mapsize);	while (entry < mapsize) {		last_entry = find_next_bit(map, mapsize, entry);		if (last_entry - entry >= entries)			break;		entry = find_next_zero_bit(map, mapsize, last_entry);	}	if (entry > mapsize)		goto map_return;	for (i = 0; i < entries; i++)		set_bit(entry + i, map);	bus_addr = tioca_kern->ca_pciap_base + (entry * ps);	ca_dmamap->cad_dma_addr = bus_addr;	ca_dmamap->cad_gart_size = entries;	ca_dmamap->cad_gart_entry = entry;	list_add(&ca_dmamap->cad_list, &tioca_kern->ca_dmamaps);	if (xio_addr % ps) {		tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr);		bus_addr += xio_addr & (ps - 1);		xio_addr &= ~(ps - 1);		xio_addr += ps;		entry++;	}	while (xio_addr < end_xio_addr) {		tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr);		xio_addr += ps;		entry++;	}	tioca_tlbflush(tioca_kern);map_return:	spin_unlock_irqrestore(&tioca_kern->ca_lock, flags);	return bus_addr;}/** * tioca_dma_unmap - release CA mapping resources * @pdev: linux pci_dev representing the function * @bus_addr: bus address returned by an earlier tioca_dma_map * @dir: mapping direction (unused) * * Locate mapping resources associated with @bus_addr and release them. * For mappings created using the direct modes (64 or 48) there are no * resources to release. */static voidtioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir){	int i, entry;	struct tioca_common *tioca_common;	struct tioca_kernel *tioca_kern;	struct tioca_dmamap *map;	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev);	unsigned long flags;	tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info;	tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private;	/* return straight away if this isn't be a mapped address */	if (bus_addr < tioca_kern->ca_pciap_base ||	    bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size))		return;	spin_lock_irqsave(&tioca_kern->ca_lock, flags);	list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list)	    if (map->cad_dma_addr == bus_addr)		break;	BUG_ON(map == NULL);	entry = map->cad_gart_entry;	for (i = 0; i < map->cad_gart_size; i++, entry++) {		clear_bit(entry, tioca_kern->ca_pcigart_pagemap);		tioca_kern->ca_pcigart[entry] = 0;	}	tioca_tlbflush(tioca_kern);	list_del(&map->cad_list);	spin_unlock_irqrestore(&tioca_kern->ca_lock, flags);	kfree(map);}/** * tioca_dma_map - map pages for PCI DMA * @pdev: linux pci_dev representing the function * @paddr: host physical address to map * @byte_count: bytes to map * * This is the main wrapper for mapping host physical pages to CA PCI space. * The mapping mode used is based on the devices dma_mask.  As a last resort * use the GART mapped mode. */static u64tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags){	u64 mapaddr;	/*	 * Not supported for now ...	 */	if (dma_flags & SN_DMA_MSI)		return 0;	/*	 * If card is 64 or 48 bit addressable, use a direct mapping.  32	 * bit direct is so restrictive w.r.t. where the memory resides that	 * we don't use it even though CA has some support.	 */	if (pdev->dma_mask == ~0UL)		mapaddr = tioca_dma_d64(paddr);	else if (pdev->dma_mask == 0xffffffffffffUL)		mapaddr = tioca_dma_d48(pdev, paddr);	else		mapaddr = 0;	/* Last resort ... use PCI portion of CA GART */	if (mapaddr == 0)		mapaddr = tioca_dma_mapped(pdev, paddr, byte_count);	return mapaddr;}/** * tioca_error_intr_handler - SGI TIO CA error interrupt handler * @irq: unused * @arg: pointer to tioca_common struct for the given CA * * Handle a CA error interrupt.  Simply a wrapper around a SAL call which * defers processing to the SGI prom. */static irqreturn_ttioca_error_intr_handler(int irq, void *arg){	struct tioca_common *soft = arg;	struct ia64_sal_retval ret_stuff;	u64 segment;	u64 busnum;	ret_stuff.status = 0;	ret_stuff.v0 = 0;	segment = soft->ca_common.bs_persist_segment;	busnum = soft->ca_common.bs_persist_busnum;	SAL_CALL_NOLOCK(ret_stuff,			(u64) SN_SAL_IOIF_ERROR_INTERRUPT,			segment, busnum, 0, 0, 0, 0, 0);	return IRQ_HANDLED;}/** * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus * @prom_bussoft: Common prom/kernel struct representing the bus * * Replicates the tioca_common pointed to by @prom_bussoft in kernel * space.  Allocates and initializes a kernel-only area for a given CA, * and sets up an irq for handling CA error interrupts. * * On successful setup, returns the kernel version of tioca_common back to * the caller. */static void *tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller){	struct tioca_common *tioca_common;	struct tioca_kernel *tioca_kern;	struct pci_bus *bus;	/* sanity check prom rev */	if (is_shub1() && sn_sal_rev() < 0x0406) {		printk		    (KERN_ERR "%s:  SGI prom rev 4.06 or greater required "		     "for tioca support\n", __FUNCTION__);		return NULL;	}	/*	 * Allocate kernel bus soft and copy from prom.	 */	tioca_common = kzalloc(sizeof(struct tioca_common), GFP_KERNEL);	if (!tioca_common)		return NULL;	memcpy(tioca_common, prom_bussoft, sizeof(struct tioca_common));	tioca_common->ca_common.bs_base = (unsigned long)		ioremap(REGION_OFFSET(tioca_common->ca_common.bs_base),			sizeof(struct tioca_common));	/* init kernel-private area */	tioca_kern = kzalloc(sizeof(struct tioca_kernel), GFP_KERNEL);	if (!tioca_kern) {		kfree(tioca_common);		return NULL;	}	tioca_kern->ca_common = tioca_common;	spin_lock_init(&tioca_kern->ca_lock);	INIT_LIST_HEAD(&tioca_kern->ca_dmamaps);	tioca_kern->ca_closest_node =	    nasid_to_cnodeid(tioca_common->ca_closest_nasid);	tioca_common->ca_kernel_private = (u64) tioca_kern;	bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment,		tioca_common->ca_common.bs_persist_busnum);	BUG_ON(!bus);	tioca_kern->ca_devices = &bus->devices;	/* init GART */	if (tioca_gart_init(tioca_kern) < 0) {		kfree(tioca_kern);		kfree(tioca_common);		return NULL;	}	tioca_gart_found++;	list_add(&tioca_kern->ca_list, &tioca_list);	if (request_irq(SGI_TIOCA_ERROR,			tioca_error_intr_handler,			IRQF_SHARED, "TIOCA error", (void *)tioca_common))		printk(KERN_WARNING		       "%s:  Unable to get irq %d.  "		       "Error interrupts won't be routed for TIOCA bus %d\n",		       __FUNCTION__, SGI_TIOCA_ERROR,		       (int)tioca_common->ca_common.bs_persist_busnum);	sn_set_err_irq_affinity(SGI_TIOCA_ERROR);	/* Setup locality information */	controller->node = tioca_kern->ca_closest_node;	return tioca_common;}static struct sn_pcibus_provider tioca_pci_interfaces = {	.dma_map = tioca_dma_map,	.dma_map_consistent = tioca_dma_map,	.dma_unmap = tioca_dma_unmap,	.bus_fixup = tioca_bus_fixup,	.force_interrupt = NULL,	.target_interrupt = NULL};/** * tioca_init_provider - init SN PCI provider ops for TIO CA */inttioca_init_provider(void){	sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces;	return 0;}

⌨️ 快捷键说明

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