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

📄 io.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: io.c,v 1.1.1.1 2004/02/04 12:55:32 laputa Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Colin Ngam */#include <linux/types.h>#include <linux/config.h>#include <linux/slab.h>#include <asm/sn/types.h>#include <asm/sn/sgi.h>#include <asm/sn/iobus.h>#include <asm/sn/iograph.h>#include <asm/param.h>#include <asm/sn/pio.h>#include <asm/sn/xtalk/xwidget.h>#include <asm/sn/sn_private.h>#include <asm/sn/addrs.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/hcl_util.h>#include <asm/sn/agent.h>#include <asm/sn/intr.h>#include <asm/sn/xtalk/xtalkaddrs.h>#include <asm/sn/klconfig.h>#include <asm/sn/io.h>#include <asm/sn/sn_cpuid.h>extern xtalk_provider_t hub_provider;/* * Perform any initializations needed to support hub-based I/O. * Called once during startup. */voidhubio_init(void){#ifdef	LATER	/* This isn't needed unless we port the entire sio driver ... */        extern void early_brl1_port_init( void );	early_brl1_port_init();#endif}/*  * Implementation of hub iobus operations. * * Hub provides a crosstalk "iobus" on IP27 systems.  These routines * provide a platform-specific implementation of xtalk used by all xtalk  * cards on IP27 systems. * * Called from corresponding xtalk_* routines. *//* PIO MANAGEMENT *//* For mapping system virtual address space to xtalk space on a specified widget *//* * Setup pio structures needed for a particular hub. */static voidhub_pio_init(devfs_handle_t hubv){	xwidgetnum_t widget;	hubinfo_t hubinfo;	nasid_t nasid;	int bigwin;	hub_piomap_t hub_piomap;	hubinfo_get(hubv, &hubinfo);	nasid = hubinfo->h_nasid;	/* Initialize small window piomaps for this hub */	for (widget=0; widget <= HUB_WIDGET_ID_MAX; widget++) {		hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);		hub_piomap->hpio_xtalk_info.xp_target = widget;		hub_piomap->hpio_xtalk_info.xp_xtalk_addr = 0;		hub_piomap->hpio_xtalk_info.xp_mapsz = SWIN_SIZE;		hub_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_SWIN_BASE(nasid, widget);		hub_piomap->hpio_hub = hubv;		hub_piomap->hpio_flags = HUB_PIOMAP_IS_VALID;	}	/* Initialize big window piomaps for this hub */	for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {		hub_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin);		hub_piomap->hpio_xtalk_info.xp_mapsz = BWIN_SIZE;		hub_piomap->hpio_hub = hubv;		hub_piomap->hpio_holdcnt = 0;		hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW;		IIO_ITTE_DISABLE(nasid, bigwin);	}	hub_set_piomode(nasid, HUB_PIO_CONVEYOR);	mutex_spinlock_init(&hubinfo->h_bwlock);/* * If this lock can be acquired from interrupts or bh's, add SV_INTS or SV_BHS, * respectively, to the flags here. */	sv_init(&hubinfo->h_bwwait, &hubinfo->h_bwlock, SV_ORDER_FIFO | SV_MON_SPIN); }/*  * Create a caddr_t-to-xtalk_addr mapping. * * Use a small window if possible (that's the usual case), but * manage big windows if needed.  Big window mappings can be * either FIXED or UNFIXED -- we keep at least 1 big window available * for UNFIXED mappings. * * Returns an opaque pointer-sized type which can be passed to * other hub_pio_* routines on success, or NULL if the request * cannot be satisfied. *//* ARGSUSED */hub_piomap_thub_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */		device_desc_t dev_desc,	/* device descriptor */		iopaddr_t xtalk_addr,	/* map for this xtalk_addr range */		size_t byte_count,		size_t byte_count_max, 	/* maximum size of a mapping */		unsigned flags)		/* defined in sys/pio.h */{	xwidget_info_t widget_info = xwidget_info_get(dev);	xwidgetnum_t widget = xwidget_info_id_get(widget_info);	devfs_handle_t hubv = xwidget_info_master_get(widget_info);	hubinfo_t hubinfo;	hub_piomap_t bw_piomap;	int bigwin, free_bw_index;	nasid_t nasid;	volatile hubreg_t junk;	unsigned long s;	/* sanity check */	if (byte_count_max > byte_count)		return(NULL);	hubinfo_get(hubv, &hubinfo);	/* If xtalk_addr range is mapped by a small window, we don't have 	 * to do much 	 */	if (xtalk_addr + byte_count <= SWIN_SIZE)		return(hubinfo_swin_piomap_get(hubinfo, (int)widget));	/* We need to use a big window mapping.  */	/*	 * TBD: Allow requests that would consume multiple big windows --	 * split the request up and use multiple mapping entries.	 * For now, reject requests that span big windows.	 */	if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE)		return(NULL);	/* Round xtalk address down for big window alignement */	xtalk_addr = xtalk_addr & ~(BWIN_SIZE-1);	/*	 * Check to see if an existing big window mapping will suffice.	 */tryagain:	free_bw_index = -1;	s = mutex_spinlock(&hubinfo->h_bwlock);	for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {		bw_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin);		/* If mapping is not valid, skip it */		if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)) {			free_bw_index = bigwin;			continue;		}		/* 		 * If mapping is UNFIXED, skip it.  We don't allow sharing		 * of UNFIXED mappings, because this would allow starvation.		 */		if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED))			continue;		if ( xtalk_addr == bw_piomap->hpio_xtalk_info.xp_xtalk_addr &&		     widget == bw_piomap->hpio_xtalk_info.xp_target) {			bw_piomap->hpio_holdcnt++;			mutex_spinunlock(&hubinfo->h_bwlock, s);			return(bw_piomap);		}	}	/*	 * None of the existing big window mappings will work for us --	 * we need to establish a new mapping.	 */	/* Insure that we don't consume all big windows with FIXED mappings */	if (flags & PIOMAP_FIXED) {		if (hubinfo->h_num_big_window_fixed < HUB_NUM_BIG_WINDOW-1) {			ASSERT(free_bw_index >= 0);			hubinfo->h_num_big_window_fixed++;		} else {			bw_piomap = NULL;			goto done;		}	} else /* PIOMAP_UNFIXED */ {		if (free_bw_index < 0) {			if (flags & PIOMAP_NOSLEEP) {				bw_piomap = NULL;				goto done;			}			sv_wait(&hubinfo->h_bwwait, 0, 0);			goto tryagain;		}	}	/* OK!  Allocate big window free_bw_index for this mapping. */ 	/* 	 * The code below does a PIO write to setup an ITTE entry.	 * We need to prevent other CPUs from seeing our updated memory 	 * shadow of the ITTE (in the piomap) until the ITTE entry is 	 * actually set up; otherwise, another CPU might attempt a PIO 	 * prematurely.  	 *	 * Also, the only way we can know that an entry has been received 	 * by the hub and can be used by future PIO reads/writes is by 	 * reading back the ITTE entry after writing it.	 *	 * For these two reasons, we PIO read back the ITTE entry after	 * we write it.	 */	nasid = hubinfo->h_nasid;	IIO_ITTE_PUT(nasid, free_bw_index, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);		junk = HUB_L(IIO_ITTE_GET(nasid, free_bw_index));	bw_piomap = hubinfo_bwin_piomap_get(hubinfo, free_bw_index);	bw_piomap->hpio_xtalk_info.xp_dev = dev;	bw_piomap->hpio_xtalk_info.xp_target = widget;	bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr;	bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);	bw_piomap->hpio_holdcnt++;	bw_piomap->hpio_bigwin_num = free_bw_index;	if (flags & PIOMAP_FIXED)		bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED;	else		bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID;done:	mutex_spinunlock(&hubinfo->h_bwlock, s);	return(bw_piomap);}/* * hub_piomap_free destroys a caddr_t-to-xtalk pio mapping and frees * any associated mapping resources.   * * If this * piomap was handled with a small window, or if it was handled * in a big window that's still in use by someone else, then there's  * nothing to do.  On the other hand, if this mapping was handled  * with a big window, AND if we were the final user of that mapping,  * then destroy the mapping. */voidhub_piomap_free(hub_piomap_t hub_piomap){	devfs_handle_t hubv;	hubinfo_t hubinfo;	nasid_t nasid;	unsigned long s;	/* 	 * Small windows are permanently mapped to corresponding widgets,	 * so there're no resources to free.	 */	if (!(hub_piomap->hpio_flags & HUB_PIOMAP_IS_BIGWINDOW))		return;	ASSERT(hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID);	ASSERT(hub_piomap->hpio_holdcnt > 0);	hubv = hub_piomap->hpio_hub;	hubinfo_get(hubv, &hubinfo);	nasid = hubinfo->h_nasid;	s = mutex_spinlock(&hubinfo->h_bwlock);	/*	 * If this is the last hold on this mapping, free it.	 */	if (--hub_piomap->hpio_holdcnt == 0) {		IIO_ITTE_DISABLE(nasid, hub_piomap->hpio_bigwin_num );		if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED) {			hub_piomap->hpio_flags &= ~(HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED);			hubinfo->h_num_big_window_fixed--;			ASSERT(hubinfo->h_num_big_window_fixed >= 0);		} else			hub_piomap->hpio_flags &= ~HUB_PIOMAP_IS_VALID;		(void)sv_signal(&hubinfo->h_bwwait);	}	mutex_spinunlock(&hubinfo->h_bwlock, s);}/* * Establish a mapping to a given xtalk address range using the resources * allocated earlier. */caddr_thub_piomap_addr(hub_piomap_t hub_piomap,	/* mapping resources */		iopaddr_t xtalk_addr,		/* map for this xtalk address */		size_t byte_count)		/* map this many bytes */{	/* Verify that range can be mapped using the specified piomap */	if (xtalk_addr < hub_piomap->hpio_xtalk_info.xp_xtalk_addr)		return(0);	if (xtalk_addr + byte_count > 		( hub_piomap->hpio_xtalk_info.xp_xtalk_addr + 			hub_piomap->hpio_xtalk_info.xp_mapsz))		return(0);	if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)		return(hub_piomap->hpio_xtalk_info.xp_kvaddr + 			(xtalk_addr % hub_piomap->hpio_xtalk_info.xp_mapsz));	else		return(0);}/* * Driver indicates that it's done with PIO's from an earlier piomap_addr. *//* ARGSUSED */voidhub_piomap_done(hub_piomap_t hub_piomap)	/* done with these mapping resources */{	/* Nothing to do */}/* * For translations that require no mapping resources, supply a kernel virtual * address that maps to the specified xtalk address range. *//* ARGSUSED */caddr_thub_piotrans_addr(	devfs_handle_t dev,	/* translate to this device */			device_desc_t dev_desc,	/* device descriptor */			iopaddr_t xtalk_addr,	/* Crosstalk address */			size_t byte_count,	/* map this many bytes */			unsigned flags)		/* (currently unused) */{	xwidget_info_t widget_info = xwidget_info_get(dev);	xwidgetnum_t widget = xwidget_info_id_get(widget_info);	devfs_handle_t hubv = xwidget_info_master_get(widget_info);	hub_piomap_t hub_piomap;	hubinfo_t hubinfo;	hubinfo_get(hubv, &hubinfo);	if (xtalk_addr + byte_count <= SWIN_SIZE) {		hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);		return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count));	} else		return(0);}/* DMA MANAGEMENT *//* Mapping from crosstalk space to system physical space *//*  * There's not really very much to do here, since crosstalk maps * directly to system physical space.  It's quite possible that this * DMA layer will be bypassed in performance kernels. *//* ARGSUSED */static voidhub_dma_init(devfs_handle_t hubv){}/* * Allocate resources needed to set up DMA mappings up to a specified size * on a specified adapter. *  * We don't actually use the adapter ID for anything.  It's just the adapter * that the lower level driver plans to use for DMA. *//* ARGSUSED */hub_dmamap_thub_dmamap_alloc(	devfs_handle_t dev,	/* set up mappings for this device */			device_desc_t dev_desc,	/* device descriptor */			size_t byte_count_max, 	/* max size of a mapping */			unsigned flags)		/* defined in dma.h */{	hub_dmamap_t dmamap;	xwidget_info_t widget_info = xwidget_info_get(dev);	xwidgetnum_t widget = xwidget_info_id_get(widget_info);	devfs_handle_t hubv = xwidget_info_master_get(widget_info);	dmamap = kern_malloc(sizeof(struct hub_dmamap_s));	dmamap->hdma_xtalk_info.xd_dev = dev;	dmamap->hdma_xtalk_info.xd_target = widget;	dmamap->hdma_hub = hubv;	dmamap->hdma_flags = HUB_DMAMAP_IS_VALID; 	if (flags & XTALK_FIXED)		dmamap->hdma_flags |= HUB_DMAMAP_IS_FIXED;	return(dmamap);}/* * Destroy a DMA mapping from crosstalk space to system address space. * There is no actual mapping hardware to destroy, but we at least mark * the dmamap INVALID and free the space that it took. */voidhub_dmamap_free(hub_dmamap_t hub_dmamap){	hub_dmamap->hdma_flags &= ~HUB_DMAMAP_IS_VALID;	kern_free(hub_dmamap);}/* * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc. * Return an appropriate crosstalk address range that maps to the specified physical 

⌨️ 快捷键说明

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