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

📄 pcibr_slot.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
#endif        error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);#ifdef PCI_LATER        /* Release the bus lock */        mrunlock(pcibr_soft->bs_bus_lock);#endif        if (error) {            return(error);        }        ++respp;        size -= sizeof(*respp);    }    return(error);}#define PROBE_LOCK 0	/* FIXME: we're attempting to lock around accesses			 * to b_int_enable.   This hangs pcibr_probe_slot()			 *//* * pcibr_slot_info_init *	Probe for this slot and see if it is populated. *	If it is populated initialize the generic PCI infrastructural * 	information associated with this particular PCI device. */intpcibr_slot_info_init(vertex_hdl_t 	pcibr_vhdl,		     pciio_slot_t 	slot){    pcibr_soft_t	    pcibr_soft;    pcibr_info_h	    pcibr_infoh;    pcibr_info_t	    pcibr_info;    bridge_t		   *bridge;    cfg_p                   cfgw;    unsigned                idword;    unsigned                pfail;    unsigned                idwords[8];    pciio_vendor_id_t       vendor;    pciio_device_id_t       device;    unsigned                htype;    unsigned                lt_time;    int                     nbars;    cfg_p                   wptr;    cfg_p                   pcix_cap;    int                     win;    pciio_space_t           space;    int			    nfunc;    pciio_function_t	    rfunc;    int			    func;    vertex_hdl_t	    conn_vhdl;    pcibr_soft_slot_t	    slotp;        /* Get the basic software information required to proceed */    pcibr_soft = pcibr_soft_get(pcibr_vhdl);    if (!pcibr_soft)	return(EINVAL);    bridge = pcibr_soft->bs_base;    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))	return(EINVAL);    /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization     * is done by the host slot then we are done.     */    if (pcibr_soft->bs_slot[slot].has_host) {	return(0);        }    /* Try to read the device-id/vendor-id from the config space */    cfgw = pcibr_slot_config_addr(bridge, slot, 0);#if PROBE_LOCK    s = pcibr_lock(pcibr_soft);#endif    if (pcibr_probe_slot(bridge, cfgw, &idword)) 	return(ENODEV);#if PROBE_LOCK    pcibr_unlock(pcibr_soft, s);#endif    slotp = &pcibr_soft->bs_slot[slot];    slotp->slot_status |= SLOT_POWER_UP;    vendor = 0xFFFF & idword;    device = 0xFFFF & (idword >> 16);    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl,		"pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n",		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device));    /* If the vendor id is not valid then the slot is not populated     * and we are done.     */    if (vendor == 0xFFFF) 	return(ENODEV);			        htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);    nfunc = 1;    rfunc = PCIIO_FUNC_NONE;    pfail = 0;    /* NOTE: if a card claims to be multifunction     * but only responds to config space 0, treat     * it as a unifunction card.     */    if (htype & 0x80) {		/* MULTIFUNCTION */	for (func = 1; func < 8; ++func) {	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);#if PROBE_LOCK            s = pcibr_lock(pcibr_soft);#endif	    if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) {		pfail |= 1 << func;		continue;	    }#if PROBE_LOCK            pcibr_unlock(pcibr_soft, s);#endif	    vendor = 0xFFFF & idwords[func];	    if (vendor == 0xFFFF) {		pfail |= 1 << func;		continue;	    }	    nfunc = func + 1;	    rfunc = 0;	}        cfgw = pcibr_slot_config_addr(bridge, slot, 0);    }    NEWA(pcibr_infoh, nfunc);        pcibr_soft->bs_slot[slot].bss_ninfo = nfunc;    pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh;    for (func = 0; func < nfunc; ++func) {	unsigned                cmd_reg;		if (func) {	    if (pfail & (1 << func))		continue;	    	    idword = idwords[func];	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);	    	    device = 0xFFFF & (idword >> 16);	    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);	    rfunc = func;	}	htype &= 0x7f;	if (htype != 0x00) {	    printk(KERN_WARNING 		"%s pcibr: pci slot %d func %d has strange header type 0x%x\n",		    pcibr_soft->bs_name, slot, func, htype);	    nbars = 2;	} else {	    nbars = PCI_CFG_BASE_ADDRS;	}	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,                "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%x\n",		PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw));#ifdef PIC_LATER        /*         * Check for a Quad ATM PCI "card" and return all the PCI bus         * memory and I/O space.  This will work-around an apparent         * hardware problem with the Quad ATM XIO card handling large         * PIO addresses.  Releasing all the space for use by the card         * will lower the PIO addresses with the PCI bus address space.         * This is OK since the PROM did not assign any BAR addresses.          *         * Only release all the PCI bus addresses once.         *         */        if ((vendor == LINC_VENDOR_ID_NUM) && (device == LINC_DEVICE_ID_NUM)) {            iopaddr_t               prom_base_addr = pcibr_soft->bs_xid << 24;            int                     prom_base_size = 0x1000000;            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_MEM_FREED)) {		pciio_device_win_populate(&pcibr_soft->bs_mem_win_map,					  prom_base_addr, prom_base_size);                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_MEM_FREED;            }            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_IO_FREED)) {		pciio_device_win_populate(&pcibr_soft->bs_io_win_map,					  prom_base_addr, prom_base_size);                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_IO_FREED;            }        }#endif	/* PIC_LATER */	/* 	 * If the latency timer has already been set, by prom or by the	 * card itself, use that value.  Otherwise look at the device's	 * 'min_gnt' and attempt to calculate a latency time. 	 *	 * NOTE: For now if the device is on the 'real time' arbitration	 * ring we don't set the latency timer.  	 *	 * WAR: SGI's IOC3 and RAD devices target abort if you write a 	 * single byte into their config space.  So don't set the Latency	 * Timer for these devices	 */	lt_time = do_pcibr_config_get(cfgw, PCI_CFG_LATENCY_TIMER, 1);	if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) &&				       (device == 0x5 /* RAD_DEV */)) {	     unsigned	min_gnt;	     unsigned	min_gnt_mult;	    	    /* 'min_gnt' indicates how long of a burst period a device	     * needs in increments of 250ns.  But latency timer is in	     * PCI clock cycles, so a conversion is needed.	     */	    min_gnt = do_pcibr_config_get(cfgw, PCI_MIN_GNT, 1);	    if (IS_133MHZ(pcibr_soft))		min_gnt_mult = 32;	/* 250ns @ 133MHz in clocks */	    else if (IS_100MHZ(pcibr_soft))		min_gnt_mult = 24;	/* 250ns @ 100MHz in clocks */	    else if (IS_66MHZ(pcibr_soft))		min_gnt_mult = 16;	/* 250ns @ 66MHz, in clocks */	    else		min_gnt_mult = 8;	/* 250ns @ 33MHz, in clocks */	    if ((min_gnt != 0) && ((min_gnt * min_gnt_mult) < 256))		lt_time = (min_gnt * min_gnt_mult);	    else		lt_time = 4 * min_gnt_mult;	  /* 1 micro second */	    do_pcibr_config_set(cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time);	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,                    "pcibr_slot_info_init: set Latency Timer for slot=%d, "		    "func=%d, to 0x%x\n", 		    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time));	}	/* In our architecture the setting of the cacheline size isn't 	 * beneficial for cards in PCI mode, but in PCI-X mode devices	 * can optionally use the cacheline size value for internal 	 * device optimizations    (See 7.1.5 of the PCI-X v1.0 spec).	 * NOTE: cachline size is in doubleword increments	 */	if (IS_PCIX(pcibr_soft)) {	    if (!do_pcibr_config_get(cfgw, PCI_CFG_CACHE_LINE, 1)) {		do_pcibr_config_set(cfgw, PCI_CFG_CACHE_LINE, 1, 0x20);		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,			"pcibr_slot_info_init: set CacheLine for slot=%d, "			"func=%d, to 0x20\n",			PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func));	    }	    /* Get the PCI-X capability if running in PCI-X mode.  If the func	     * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE	     * pcibr_info struct so the device driver for that function is not	     * called.	     */	    if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) {		printk(KERN_WARNING#if defined(SUPPORT_PRINTING_V_FORMAT)		        "%v: Bus running in PCI-X mode, But card in slot %d, "		        "func %d not PCI-X capable\n", pcibr_vhdl, slot, func);#else		        "0x%lx: Bus running in PCI-X mode, But card in slot %d, "		        "func %d not PCI-X capable\n", (unsigned long)pcibr_vhdl, slot, func);#endif		pcibr_device_info_new(pcibr_soft, slot, PCIIO_FUNC_NONE,		               PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE);		continue;	    }	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,                    "pcibr_slot_info_init: PCI-X capability at 0x%x for "		    "slot=%d, func=%d\n", 		    pcix_cap, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func));	} else {	    pcix_cap = NULL;	}	pcibr_info = pcibr_device_info_new	    (pcibr_soft, slot, rfunc, vendor, device);	/* Keep a running total of the number of PIC-X functions on the bus         * and the number of max outstanding split trasnactions that they	 * have requested.  NOTE: "pcix_cap != NULL" implies IS_PCIX()	 */	pcibr_info->f_pcix_cap = (cap_pcix_type0_t *)pcix_cap;	if (pcibr_info->f_pcix_cap) {	    int max_out;      /* max outstanding splittrans from status reg */	    pcibr_soft->bs_pcix_num_funcs++;	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;	    pcibr_soft->bs_pcix_split_tot += max_splittrans_to_numbuf[max_out];	}	conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);	if (func == 0)	    slotp->slot_conn = conn_vhdl;	cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4);		wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;	for (win = 0; win < nbars; ++win) {	    iopaddr_t               base, mask, code;	    size_t                  size;	    /*	     * GET THE BASE & SIZE OF THIS WINDOW:	     *	     * The low two or four bits of the BASE register	     * determines which address space we are in; the	     * rest is a base address. BASE registers	     * determine windows that are power-of-two sized	     * and naturally aligned, so we can get the size	     * of a window by writing all-ones to the	     * register, reading it back, and seeing which	     * bits are used for decode; the least	     * significant nonzero bit is also the size of	     * the window.	     *	     * WARNING: someone may already have allocated	     * some PCI space to this window, and in fact	     * PIO may be in process at this very moment	     * from another processor (or even from this	     * one, if we get interrupted)! So, if the BASE	     * already has a nonzero address, be generous	     * and use the LSBit of that address as the	     * size; this could overstate the window size.	     * Usually, when one card is set up, all are set	     * up; so, since we don't bitch about	     * overlapping windows, we are ok.	     *	     * UNFORTUNATELY, some cards do not clear their	     * BASE registers on reset. I have two heuristics	     * that can detect such cards: first, if the	     * decode enable is turned off for the space	     * that the window uses, we can disregard the	     * initial value. second, if the address is	     * outside the range that we use, we can disregard	     * it as well.	     *	     * This is looking very PCI generic. Except for	     * knowing how many slots and where their config	     * spaces are, this window loop and the next one	     * could probably be shared with other PCI host	     * adapters. It would be interesting to see if	     * this could be pushed up into pciio, when we	     * start supporting more PCI providers.	     */	    base = do_pcibr_config_get(wptr, (win * 4), 4);	    if (base & PCI_BA_IO_SPACE) {		/* BASE is in I/O space. */		space = PCIIO_SPACE_IO;		mask = -4;		code = base & 3;		base = base & mask;		if (base == 0) {		    ;		/* not assigned */		} else if (!(cmd_reg & PCI_CMD_IO_SPACE)) {		    base = 0;	/* decode not enabled */		}	    } else {		/* BASE is in MEM space. */		space = PCIIO_SPACE_MEM;		mask = -16;		code = base & PCI_BA_MEM_LOCATION;	/* extract BAR type */		base = base & mask;		if (base == 0) {		    ;		/* not assigned */		} else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) {		    base = 0;	/* decode not enabled */		} else if (base & 0xC0000000) {		    base = 0;	/* outside permissable range */		} else if ((code == PCI_BA_MEM_64BIT) &&			   (do_pcibr_config_get(wptr, ((win + 1)*4), 4) != 0)) {		    base = 0;	/* outside permissable range */		}	    }	    if (base != 0) {	/* estimate size */		size = base & -base;	    } else {		/* calculate size */		do_pcibr_config_set(wptr, (win * 4), 4, ~0);    /* write 1's */		size = do_pcibr_config_get(wptr, (win * 4), 4); /* read back */		size &= mask;	/* keep addr */		size &= -size;	/* keep lsbit */		if (size == 0)		    continue;	    }		    pcibr_info->f_window[win].w_space = space;	    pcibr_info->f_window[win].w_base = base;	    pcibr_info->f_window[win].w_size = size;	    if (code == PCI_BA_MEM_64BIT) {		win++;		/* skip upper half */		do_pcibr_config_set(wptr, (win * 4), 4, 0);  /* must be zero */	    }	}				/* next win */    }				/* next func */    return(0);}					/* * pcibr_find_capability *	Walk the list of capabilities (if it exists) looking for *	the requested capability.  Return a cfg_p pointer to the *	capability if found, else return NULL */cfg_ppcibr_find_capability(cfg_p	cfgw,		      unsigned	capability){    unsigned		cap_nxt;    unsigned		cap_id;    int			defend_against_circular_linkedlist = 0;    /* Check to see if there is a capabilities pointer in the cfg header */    if (!(do_pcibr_config_get(cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) {	return (NULL);    }    /*     * Read up the capabilities head pointer from the configuration header.     * Capabilities are stored as a linked list in the lower 48 dwords of     * config space and are dword aligned. (Note: spec states the least two     * significant bits of the next pointer must be ignored,  so we mask     * with 0xfc).     */    cap_nxt = (do_pcibr_config_get(cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc);    while (cap_nxt && (defend_against_circular_linkedlist <= 48)) {	cap_id = do_pcibr_config_get(cfgw, cap_nxt, 1);	if (cap_id == capability) {	    return ((cfg_p)((char *)cfgw + cap_nxt));	}	cap_nxt = (do_pcibr_config_get(cfgw, cap_nxt+1, 1) & 0xfc);	defend_against_circular_linkedlist++;    }    return (NULL);}/* * pcibr_slot_info_free *	Remove all the PCI infrastructural information associated * 	with a particular PCI device. */intpcibr_slot_info_free(vertex_hdl_t pcibr_vhdl,                     pciio_slot_t slot){    pcibr_soft_t	pcibr_soft;    pcibr_info_h	pcibr_infoh;    int			nfunc;    pcibr_soft = pcibr_soft_get(pcibr_vhdl);    if (!pcibr_soft)	return(EINVAL);    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))	return(EINVAL);    nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;    pcibr_device_info_free(pcibr_vhdl, slot);    pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;    DELA(pcibr_infoh,nfunc);    pcibr_soft->bs_slot[slot].bss_ninfo = 0;    return(0);}

⌨️ 快捷键说明

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