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

📄 pcibr_slot.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
        /* Acquire read access to the bus */        mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);        error = pcibr_slot_info_return(pcibr_soft, slot, respp);        /* Release the bus lock */        mrunlock(pcibr_soft->bs_bus_lock);        return(error);    }    /* Return information for all the slots */    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {        if (size < sizeof(*respp)) {            return(PCI_RESP_AREA_TOO_SMALL);        }        /* Acquire read access to the bus */        mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);        error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);        /* Release the bus lock */        mrunlock(pcibr_soft->bs_bus_lock);        if (error) {            return(error);        }        ++respp;        size -= sizeof(*respp);    }    return(error);}#endif	/* LATER *//* FIXME: there should be a better way to do this. * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE *//*  * PCI_ADDR_SPACE_LIMITS_LOAD *	Gets the current values of  *		pci io base,  *		pci io last, *		pci low memory base, *		pci low memory last, *		pci high memory base, * 		pci high memory last */#define PCI_ADDR_SPACE_LIMITS_LOAD()			\    pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base;	\    pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last;	\    pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base;	\    pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last;	\    pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base;	\    pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last;/* * PCI_ADDR_SPACE_LIMITS_STORE *	Sets the current values of *		pci io base,  *		pci io last, *		pci low memory base, *		pci low memory last, *		pci high memory base, * 		pci high memory last */#define PCI_ADDR_SPACE_LIMITS_STORE()			\    pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;	\    pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;	\    pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;	\    pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;	\    pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;	\    pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;#define PCI_ADDR_SPACE_LIMITS_PRINT()			\    printf("+++++++++++++++++++++++\n"			\	   "IO base 0x%x last 0x%x\n"			\	   "SWIN base 0x%x last 0x%x\n"			\	   "MEM base 0x%x last 0x%x\n"			\	   "+++++++++++++++++++++++\n",			\	   pcibr_soft->bs_spinfo.pci_io_base,		\	   pcibr_soft->bs_spinfo.pci_io_last,		\	   pcibr_soft->bs_spinfo.pci_swin_base,		\	   pcibr_soft->bs_spinfo.pci_swin_last,		\	   pcibr_soft->bs_spinfo.pci_mem_base,		\	   pcibr_soft->bs_spinfo.pci_mem_last);/* * 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(devfs_handle_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;    cfg_p                   wptr;    int                     win;    pciio_space_t           space;    iopaddr_t		    pci_io_fb,	pci_io_fl;    iopaddr_t		    pci_lo_fb,  pci_lo_fl;    iopaddr_t		    pci_hi_fb,  pci_hi_fl;    int			    nfunc;    pciio_function_t	    rfunc;    int			    func;    devfs_handle_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(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);        }    /* Check for a slot with any system critical functions */    if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot))        return(EPERM);    /* Load the current values of allocated PCI address spaces */    PCI_ADDR_SPACE_LIMITS_LOAD();        /* Try to read the device-id/vendor-id from the config space */    cfgw = bridge->b_type0_cfg_dev[slot].l;    if (pcibr_probe_slot(bridge, cfgw, &idword)) 	return(ENODEV);    slotp = &pcibr_soft->bs_slot[slot];    slotp->slot_status |= SLOT_POWER_UP;    vendor = 0xFFFF & idword;    /* If the vendor id is not valid then the slot is not populated     * and we are done.     */    if (vendor == 0xFFFF) 	return(ENODEV);			        device = 0xFFFF & (idword >> 16);    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 = bridge->b_type0_cfg_dev[slot].f[func].l;	    if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) {		pfail |= 1 << func;		continue;	    }	    vendor = 0xFFFF & idwords[func];	    if (vendor == 0xFFFF) {		pfail |= 1 << func;		continue;	    }	    nfunc = func + 1;	    rfunc = 0;	}	cfgw = bridge->b_type0_cfg_dev[slot].l;    }    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 = bridge->b_type0_cfg_dev[slot].f[func].l;	    	    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);	    continue;	}#if DEBUG && ATTACH_DEBUG	printk(KERN_NOTICE   		"%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x",		pcibr_soft->bs_name, slot, func, vendor, device);#endif		pcibr_info = pcibr_device_info_new	    (pcibr_soft, slot, rfunc, vendor, device);	conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);	if (func == 0)	    slotp->slot_conn = conn_vhdl;#ifdef SN1_LITTLE_ENDIAN	cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4];#else	cmd_reg = cfgw[PCI_CFG_COMMAND / 4];#endif		wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++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.	     */#ifdef SN1_LITTLE_ENDIAN	    base = wptr[((win*4)^4)/4];#else	    base = wptr[win];#endif	    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) &&#ifdef SN1_LITTLE_ENDIAN			   (wptr[(((win + 1)*4)^4)/4] != 0)) {#else 			   (wptr[win + 1] != 0)) {#endif /* LITTLE_ENDIAN */		    base = 0;	/* outside permissable range */		}	    }	    if (base != 0) {	/* estimate size */		size = base & -base;	    } else {		/* calculate size */#ifdef SN1_LITTLE_ENDIAN		wptr[((win*4)^4)/4] = ~0;	/* turn on all bits */		size = wptr[((win*4)^4)/4];	/* get stored bits */#else 		wptr[win] = ~0;	/* turn on all bits */		size = wptr[win];	/* get stored bits */#endif /* LITTLE_ENDIAN */		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 this window already has PCI space	     * allocated for it, "subtract" that space from	     * our running freeblocks. Don't worry about	     * overlaps in existing allocated windows; we	     * may be overstating their sizes anyway.	     */	    if (base && size) {		if (space == PCIIO_SPACE_IO) {		    pcibr_freeblock_sub(&pci_io_fb,					&pci_io_fl,					base, size);		} else {		    pcibr_freeblock_sub(&pci_lo_fb,					&pci_lo_fl,					base, size);		    pcibr_freeblock_sub(&pci_hi_fb,					&pci_hi_fl,					base, size);		}		    }#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM)	    /*	     * IOC3 BASE_ADDR* BUG WORKAROUND	     *	     	     * If we write to BASE1 on the IOC3, the	     * data in BASE0 is replaced. The	     * original workaround was to remember	     * the value of BASE0 and restore it	     * when we ran off the end of the BASE	     * registers; however, a later	     * workaround was added (I think it was	     * rev 1.44) to avoid setting up	     * anything but BASE0, with the comment	     * that writing all ones to BASE1 set	     * the enable-parity-error test feature	     * in IOC3's SCR bit 14.	     *	     * So, unless we defer doing any PCI	     * space allocation until drivers	     * attach, and set up a way for drivers	     * (the IOC3 in paricular) to tell us	     * generically to keep our hands off	     * BASE registers, we gotta "know" about	     * the IOC3 here.	     *	     * Too bad the PCI folks didn't reserve the	     * all-zero value for 'no BASE here' (it is a	     * valid code for an uninitialized BASE in	     * 32-bit PCI memory space).	     */	    	    if ((vendor == IOC3_VENDOR_ID_NUM) &&		(device == IOC3_DEVICE_ID_NUM))		break;#endif	    if (code == PCI_BA_MEM_64BIT) {		win++;		/* skip upper half */#ifdef SN1_LITTLE_ENDIAN		wptr[((win*4)^4)/4] = 0;	/* which must be zero */#else 		wptr[win] = 0;	/* which must be zero */#endif /* LITTLE_ENDIAN */	    }	}				/* next win */    }				/* next func */    /* Store back the values for allocated PCI address spaces */    PCI_ADDR_SPACE_LIMITS_STORE();    return(0);}					/* * pcibr_slot_info_free *	Remove all the PCI infrastructural information associated * 	with a particular PCI device. */intpcibr_slot_info_free(devfs_handle_t pcibr_vhdl,

⌨️ 快捷键说明

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