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

📄 pcibr_ate.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
字号:
/* * * 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) 2001-2002 Silicon Graphics, Inc. All rights reserved. */#include <linux/types.h>#include <linux/slab.h>#include <linux/module.h>#include <asm/sn/sgi.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/addrs.h>#include <asm/sn/arch.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>#include <asm/sn/xtalk/xwidget.h>#include <asm/sn/pci/bridge.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/pci/pcibr_private.h>#include <asm/sn/pci/pci_defs.h>#include <asm/sn/prio.h>#include <asm/sn/xtalk/xbow.h>#include <asm/sn/ioc3.h>#include <asm/sn/eeprom.h>#include <asm/sn/io.h>#include <asm/sn/sn_private.h>#ifdef __ia64uint64_t atealloc(struct map *mp, size_t size);void atefree(struct map *mp, size_t size, uint64_t a);void atemapfree(struct map *mp);struct map *atemapalloc(uint64_t mapsiz);#define rmallocmap atemapalloc#define rmfreemap atemapfree#define rmfree atefree#define rmalloc atealloc#endif#ifndef LOCAL#define LOCAL           static#endif/* * functions */int               pcibr_init_ext_ate_ram(bridge_t *);int               pcibr_ate_alloc(pcibr_soft_t, int);void              pcibr_ate_free(pcibr_soft_t, int, int);bridge_ate_t      pcibr_flags_to_ate(unsigned);bridge_ate_p      pcibr_ate_addr(pcibr_soft_t, int);unsigned 	  ate_freeze(pcibr_dmamap_t pcibr_dmamap,#if PCIBR_FREEZE_TIME	   			unsigned *freeze_time_ptr,#endif	   			unsigned *cmd_regs);void 	  ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);void ate_thaw(pcibr_dmamap_t pcibr_dmamap,	 			int ate_index,#if PCIBR_FREEZE_TIME	 			bridge_ate_t ate,	 			int ate_total,	 			unsigned freeze_time_start,#endif	 			unsigned *cmd_regs,	 			unsigned s);/* Convert from ssram_bits in control register to number of SSRAM entries */#define ATE_NUM_ENTRIES(n) _ate_info[n]/* Possible choices for number of ATE entries in Bridge's SSRAM */LOCAL int               _ate_info[] ={    0,					/* 0 entries */    8 * 1024,				/* 8K entries */    16 * 1024,				/* 16K entries */    64 * 1024				/* 64K entries */};#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int))#define ATE_PROBE_VALUE 0x0123456789abcdefULL/* * Determine the size of this bridge's external mapping SSRAM, and set * the control register appropriately to reflect this size, and initialize * the external SSRAM. */intpcibr_init_ext_ate_ram(bridge_t *bridge){    int                     largest_working_size = 0;    int                     num_entries, entry;    int                     i, j;    bridgereg_t             old_enable, new_enable;    int                     s;    int			    this_is_pic = is_pic(bridge);    /* Probe SSRAM to determine its size. */    if ( this_is_pic ) {	old_enable = bridge->b_int_enable;	new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;	bridge->b_int_enable = new_enable;    }    else {	if (io_get_sh_swapper(NASID_GET(bridge))) {		old_enable = BRIDGE_REG_GET32((&bridge->b_int_enable));		new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;		BRIDGE_REG_SET32((&bridge->b_int_enable)) = new_enable;	}	else {		old_enable = bridge->b_int_enable;		new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;		bridge->b_int_enable = new_enable;	}    }    for (i = 1; i < ATE_NUM_SIZES; i++) {	/* Try writing a value */	if ( this_is_pic ) {		bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;	}	else {		if (io_get_sh_swapper(NASID_GET(bridge)))			bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = __swab64(ATE_PROBE_VALUE);		else			bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;	}	/* Guard against wrap */	for (j = 1; j < i; j++)	    bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0;	/* See if value was written */	if ( this_is_pic ) {		if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)				largest_working_size = i;	}	else {		if (io_get_sh_swapper(NASID_GET(bridge))) {			if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == __swab64(ATE_PROBE_VALUE))					largest_working_size = i;			else {				if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)					largest_working_size = i;			}		}	}    }    if ( this_is_pic ) {	bridge->b_int_enable = old_enable;	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */    }    else {	if (io_get_sh_swapper(NASID_GET(bridge))) {		BRIDGE_REG_SET32((&bridge->b_int_enable)) = old_enable;		BRIDGE_REG_GET32((&bridge->b_wid_tflush));   /* wait until Bridge PIO complete */	}	else {		bridge->b_int_enable = old_enable;		bridge->b_wid_tflush;               /* wait until Bridge PIO complete */	}    }    /*     * ensure that we write and read without any interruption.     * The read following the write is required for the Bridge war     */    s = splhi();    if ( this_is_pic ) {	bridge->b_wid_control = (bridge->b_wid_control			& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)			| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);	bridge->b_wid_control;		/* inval addr bug war */    }    else {	if (io_get_sh_swapper(NASID_GET(bridge))) {		BRIDGE_REG_SET32((&(bridge->b_wid_control))) = 				__swab32((BRIDGE_REG_GET32((&bridge->b_wid_control))					& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)					| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size));		BRIDGE_REG_GET32((&bridge->b_wid_control));/* inval addr bug war */	}	else {		bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK)				| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);		bridge->b_wid_control;              /* inval addr bug war */	}    }    splx(s);    num_entries = ATE_NUM_ENTRIES(largest_working_size);    if (pcibr_debug_mask & PCIBR_DEBUG_ATE) {	if (num_entries) {	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,			"bridge at 0x%x: clearing %d external ATEs\n",			bridge, num_entries));	} else {	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,			"bridge at 0x%x: no external ATE RAM found\n",			bridge));	}    }    /* Initialize external mapping entries */    for (entry = 0; entry < num_entries; entry++)	bridge->b_ext_ate_ram[entry] = 0;    return (num_entries);}/* * Allocate "count" contiguous Bridge Address Translation Entries * on the specified bridge to be used for PCI to XTALK mappings. * Indices in rm map range from 1..num_entries.  Indicies returned * to caller range from 0..num_entries-1. * * Return the start index on success, -1 on failure. */intpcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count){    int                     index = 0;    index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count);    if (!index && pcibr_soft->bs_ext_ate_map)	index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count);    /* rmalloc manages resources in the 1..n     * range, with 0 being failure.     * pcibr_ate_alloc manages resources     * in the 0..n-1 range, with -1 being failure.     */    return index - 1;}voidpcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count)/* Who says there's no such thing as a free meal? :-) */{    /* note the "+1" since rmalloc handles 1..n but     * we start counting ATEs at zero.     */    rmfree((index < pcibr_soft->bs_int_ate_size)	   ? pcibr_soft->bs_int_ate_map	   : pcibr_soft->bs_ext_ate_map,	   count, index + 1);}/* * Convert PCI-generic software flags and Bridge-specific software flags * into Bridge-specific Address Translation Entry attribute bits. */bridge_ate_tpcibr_flags_to_ate(unsigned flags){    bridge_ate_t            attributes;    /* default if nothing specified:     * NOBARRIER     * NOPREFETCH     * NOPRECISE     * COHERENT     * Plus the valid bit     */    attributes = ATE_CO | ATE_V;    /* Generic macro flags     */    if (flags & PCIIO_DMA_DATA) {	/* standard data channel */	attributes &= ~ATE_BAR;		/* no barrier */	attributes |= ATE_PREF;		/* prefetch on */    }    if (flags & PCIIO_DMA_CMD) {	/* standard command channel */	attributes |= ATE_BAR;		/* barrier bit on */	attributes &= ~ATE_PREF;	/* disable prefetch */    }    /* Generic detail flags     */    if (flags & PCIIO_PREFETCH)	attributes |= ATE_PREF;    if (flags & PCIIO_NOPREFETCH)	attributes &= ~ATE_PREF;    /* Provider-specific flags     */    if (flags & PCIBR_BARRIER)	attributes |= ATE_BAR;    if (flags & PCIBR_NOBARRIER)	attributes &= ~ATE_BAR;    if (flags & PCIBR_PREFETCH)	attributes |= ATE_PREF;    if (flags & PCIBR_NOPREFETCH)	attributes &= ~ATE_PREF;    if (flags & PCIBR_PRECISE)	attributes |= ATE_PREC;    if (flags & PCIBR_NOPRECISE)	attributes &= ~ATE_PREC;    return (attributes);}/* * Setup an Address Translation Entry as specified.  Use either the Bridge * internal maps or the external map RAM, as appropriate. */bridge_ate_ppcibr_ate_addr(pcibr_soft_t pcibr_soft,	       int ate_index){    bridge_t *bridge = pcibr_soft->bs_base;    return (ate_index < pcibr_soft->bs_int_ate_size)	? &(bridge->b_int_ate_ram[ate_index].wr)	: &(bridge->b_ext_ate_ram[ate_index]);}/* We are starting to get more complexity * surrounding writing ATEs, so pull * the writing code into this new function. */#if PCIBR_FREEZE_TIME#define	ATE_FREEZE()	s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs)#else#define	ATE_FREEZE()	s = ate_freeze(pcibr_dmamap, cmd_regs)#endifunsignedate_freeze(pcibr_dmamap_t pcibr_dmamap,#if PCIBR_FREEZE_TIME	   unsigned *freeze_time_ptr,#endif	   unsigned *cmd_regs){    pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;#ifdef LATER    int                     dma_slot = pcibr_dmamap->bd_slot;#endif    int                     ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM;    int                     slot;    unsigned long           s;    unsigned                cmd_reg;    volatile unsigned      *cmd_lwa;    unsigned                cmd_lwd;    if (!ext_ates)	return 0;    /* Bridge Hardware Bug WAR #484930:     * Bridge can't handle updating External ATEs     * while DMA is occuring that uses External ATEs,     * even if the particular ATEs involved are disjoint.     */    /* need to prevent anyone else from     * unfreezing the grant while we     * are working; also need to prevent     * this thread from being interrupted     * to keep PCI grant freeze time     * at an absolute minimum.     */    s = pcibr_lock(pcibr_soft);#ifdef LATER    /* just in case pcibr_dmamap_done was not called */    if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) {	pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY;	if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM)	    atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));	xtalk_dmamap_done(pcibr_dmamap->bd_xtalk);    }#endif	/* LATER */#if PCIBR_FREEZE_TIME    *freeze_time_ptr = get_timestamp();#endif    cmd_lwa = 0;    for (slot = pcibr_soft->bs_min_slot; 		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)	if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {	    cmd_reg = pcibr_soft->		bs_slot[slot].		bss_cmd_shadow;	    if (cmd_reg & PCI_CMD_BUS_MASTER) {		cmd_lwa = pcibr_soft->		    bs_slot[slot].		    bss_cmd_pointer;		cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER;		cmd_lwa[0] = cmd_lwd;	    }	    cmd_regs[slot] = cmd_reg;	} else	    cmd_regs[slot] = 0;    if (cmd_lwa) {	    bridge_t	*bridge = pcibr_soft->bs_base;	    /* Read the last master bit that has been cleared. This PIO read	     * on the PCI bus is to ensure the completion of any DMAs that	     * are due to bus requests issued by PCI devices before the	     * clearing of master bits.	     */	    cmd_lwa[0];	    /* Flush all the write buffers in the bridge */	    for (slot = pcibr_soft->bs_min_slot; 				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {		    if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {			    /* Flush the write buffer associated with this			     * PCI device which might be using dma map RAM.			     */			if ( is_pic(bridge) ) {				bridge->b_wr_req_buf[slot].reg;			}			else {				if (io_get_sh_swapper(NASID_GET(bridge)) ) {					BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg));				}				else					bridge->b_wr_req_buf[slot].reg;			}		    }	    }    }    return s;}voidate_write(pcibr_soft_t pcibr_soft,	  bridge_ate_p ate_ptr,	  int ate_count,	  bridge_ate_t ate){	if (IS_PIC_SOFT(pcibr_soft) ) {    		while (ate_count-- > 0) {			*ate_ptr++ = ate;			ate += IOPGSIZE;		}	}	else {		if (io_get_sh_swapper(NASID_GET(ate_ptr))) {    			while (ate_count-- > 0) {				*ate_ptr++ = __swab64(ate);				ate += IOPGSIZE;			}		}		else {    			while (ate_count-- > 0) {				*ate_ptr++ = ate;				ate += IOPGSIZE;			}		}	}}#if PCIBR_FREEZE_TIME#define	ATE_THAW()	ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s)#else#define	ATE_THAW()	ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s)#endifvoidate_thaw(pcibr_dmamap_t pcibr_dmamap,	 int ate_index,#if PCIBR_FREEZE_TIME	 bridge_ate_t ate,	 int ate_total,	 unsigned freeze_time_start,#endif	 unsigned *cmd_regs,	 unsigned s){    pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;    int                     dma_slot = pcibr_dmamap->bd_slot;    int                     slot;    bridge_t               *bridge = pcibr_soft->bs_base;    int                     ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM;    unsigned                cmd_reg;#if PCIBR_FREEZE_TIME    unsigned                freeze_time;    static unsigned         max_freeze_time = 0;    static unsigned         max_ate_total;#endif    if (!ext_ates)	return;    /* restore cmd regs */    for (slot = pcibr_soft->bs_min_slot; 		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {	if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) {		if ( IS_PIC_SOFT(pcibr_soft) ) {			pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);		}		else {			if (io_get_sh_swapper(NASID_GET(bridge))) {				bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = __swab32(cmd_reg);			}			else {//				BUG(); /* Does this really work if called when io_get_sh_swapper = 0? *///				bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg;				pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);			}		}	}    }    pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY;    atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));#if PCIBR_FREEZE_TIME    freeze_time = get_timestamp() - freeze_time_start;    if ((max_freeze_time < freeze_time) ||	(max_ate_total < ate_total)) {	if (max_freeze_time < freeze_time)	    max_freeze_time = freeze_time;	if (max_ate_total < ate_total)	    max_ate_total = ate_total;	pcibr_unlock(pcibr_soft, s);	printk( "%s: pci freeze time %d usec for %d ATEs\n"		"\tfirst ate: %R\n",		pcibr_soft->bs_name,		freeze_time * 1000 / 1250,		ate_total,		ate, ate_bits);    } else#endif	pcibr_unlock(pcibr_soft, s);}

⌨️ 快捷键说明

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