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

📄 pci.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1997, Stefan Esser <se@freebsd.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice unmodified, this list of conditions, and the following *    disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: pci.c,v 1.93 1999/01/19 23:29:18 se Exp $ * */#include "pci.h"#if NPCI > 0#include "opt_devfs.h"#include "opt_simos.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/fcntl.h>#include <sys/conf.h>#include <sys/kernel.h>#include <sys/queue.h>#include <sys/types.h>#include <sys/buf.h>#ifdef DEVFS#include <sys/devfsext.h>#endif /* DEVFS */#include <vm/vm.h>#include <vm/pmap.h>#include <vm/vm_extern.h>#include <pci/pcireg.h>#include <pci/pcivar.h>#include <pci/pci_ioctl.h>#ifdef APIC_IO#include <machine/smp.h>#endif /* APIC_IO */STAILQ_HEAD(devlist, pci_devinfo) pci_devq;u_int32_t pci_numdevs = 0;u_int32_t pci_generation = 0;/* return highest PCI bus number known to be used, or -1 if none */static intpci_bushigh(void){	if (pci_cfgopen() == 0)		return (-1);	return (0);}/* return base address of memory or port map */static intpci_mapbase(unsigned mapreg){	int mask = 0x03;	if ((mapreg & 0x01) == 0)		mask = 0x0f;	return (mapreg & ~mask);}/* return map type of memory or port map */static intpci_maptype(unsigned mapreg){	static u_int8_t maptype[0x10] = {		PCI_MAPMEM,		PCI_MAPPORT,		PCI_MAPMEM,		0,		PCI_MAPMEM,		PCI_MAPPORT,		0,			0,		PCI_MAPMEM|PCI_MAPMEMP,	PCI_MAPPORT,		PCI_MAPMEM|PCI_MAPMEMP, 0,		PCI_MAPMEM|PCI_MAPMEMP,	PCI_MAPPORT,		0,			0,	};	return maptype[mapreg & 0x0f];}/* return log2 of map size decoded for memory or port map */static intpci_mapsize(unsigned testval){	int ln2size;	testval = pci_mapbase(testval);	ln2size = 0;	if (testval != 0) {		while ((testval & 1) == 0)		{			ln2size++;			testval >>= 1;		}	}	return (ln2size);}/* return log2 of address range supported by map register */static intpci_maprange(unsigned mapreg){	int ln2range = 0;	switch (mapreg & 0x07) {	case 0x00:	case 0x01:	case 0x05:		ln2range = 32;		break;	case 0x02:		ln2range = 20;		break;	case 0x04:		ln2range = 64;		break;	}	return (ln2range);}/* extract map parameters into newly allocated array of pcimap structures */static pcimap *pci_readmaps(pcicfgregs *cfg, int maxmaps){	int i, j = 0;	pcimap *map;	int map64 = 0;	int reg = PCIR_MAPS;	for (i = 0; i < maxmaps; i++) {		int reg = PCIR_MAPS + i*4;		u_int32_t base;		u_int32_t ln2range;		base = pci_cfgread(cfg, reg, 4);		ln2range = pci_maprange(base);		if (base == 0 || ln2range == 0 || base == 0xffffffff)			continue; /* skip invalid entry */		else {			j++;			if (ln2range > 32) {				i++;				j++;			}		}	}	map = malloc(j * sizeof (pcimap), M_DEVBUF, M_WAITOK);	if (map != NULL) {		bzero(map, sizeof(pcimap) * j);		cfg->nummaps = j;		for (i = 0, j = 0; i < maxmaps; i++, reg += 4) {			u_int32_t base;			u_int32_t testval;			base = pci_cfgread(cfg, reg, 4);			if (map64 == 0) {				if (base == 0 || base == 0xffffffff)					continue; /* skip invalid entry */				pci_cfgwrite(cfg, reg, 0xffffffff, 4);				testval = pci_cfgread(cfg, reg, 4);				pci_cfgwrite(cfg, reg, base, 4);				map[j].reg	= reg;				map[j].base     = pci_mapbase(base);				map[j].type     = pci_maptype(base);				map[j].ln2size  = pci_mapsize(testval);				map[j].ln2range = pci_maprange(testval);				map64 = map[j].ln2range == 64;			} else {				/* only fill in base, other fields are 0 */				map[j].base     = base;				map64 = 0;			}			j++;		}	}	return (map);}/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */static voidpci_fixancient(pcicfgregs *cfg){	if (cfg->hdrtype != 0)		return;	/* PCI to PCI bridges use header type 1 */	if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI)		cfg->hdrtype = 1;}/* read config data specific to header type 1 device (PCI to PCI bridge) */static void *pci_readppb(pcicfgregs *cfg){	pcih1cfgregs *p;	p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK);	if (p == NULL)		return (NULL);	bzero(p, sizeof *p);	p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2);	p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2);	p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1);	p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2),				   pci_cfgread(cfg, PCIR_IOBASEL_1, 1));	p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2),				     pci_cfgread(cfg, PCIR_IOLIMITL_1, 1));	p->membase = PCI_PPBMEMBASE (0,				     pci_cfgread(cfg, PCIR_MEMBASE_1, 2));	p->memlimit = PCI_PPBMEMLIMIT (0,				       pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2));	p->pmembase = PCI_PPBMEMBASE (		(pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4),		pci_cfgread(cfg, PCIR_PMBASEL_1, 2));	p->pmemlimit = PCI_PPBMEMLIMIT (		(pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4),		pci_cfgread(cfg, PCIR_PMLIMITL_1, 2));	return (p);}/* read config data specific to header type 2 device (PCI to CardBus bridge) */static void *pci_readpcb(pcicfgregs *cfg){	pcih2cfgregs *p;	p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK);	if (p == NULL)		return (NULL);	bzero(p, sizeof *p);	p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2);	p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2);		p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1);	p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4);	p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4);	p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4);	p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4);	p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4);	p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4);	p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4);	p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4);	p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4);	return p;}/* extract header type specific config data */static voidpci_hdrtypedata(pcicfgregs *cfg){	switch (cfg->hdrtype) {	case 0:		cfg->subvendor      = pci_cfgread(cfg, PCIR_SUBVEND_0, 2);		cfg->subdevice      = pci_cfgread(cfg, PCIR_SUBDEV_0, 2);		cfg->map            = pci_readmaps(cfg, PCI_MAXMAPS_0);		break;	case 1:		cfg->subvendor      = pci_cfgread(cfg, PCIR_SUBVEND_1, 2);		cfg->subdevice      = pci_cfgread(cfg, PCIR_SUBDEV_1, 2);		cfg->secondarybus   = pci_cfgread(cfg, PCIR_SECBUS_1, 1);		cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1);		cfg->map            = pci_readmaps(cfg, PCI_MAXMAPS_1);		cfg->hdrspec        = pci_readppb(cfg);		break;	case 2:		cfg->subvendor      = pci_cfgread(cfg, PCIR_SUBVEND_2, 2);		cfg->subdevice      = pci_cfgread(cfg, PCIR_SUBDEV_2, 2);		cfg->secondarybus   = pci_cfgread(cfg, PCIR_SECBUS_2, 1);		cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1);		cfg->map            = pci_readmaps(cfg, PCI_MAXMAPS_2);		cfg->hdrspec        = pci_readpcb(cfg);		break;	}}/* read configuration header into pcicfgrect structure */static struct pci_devinfo *pci_readcfg(pcicfgregs *probe){	pcicfgregs *cfg = NULL;	struct pci_devinfo *devlist_entry;	struct devlist *devlist_head;	devlist_head = &pci_devq;	devlist_entry = NULL;	if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) {		devlist_entry = malloc(sizeof(struct pci_devinfo),				       M_DEVBUF, M_WAITOK);		if (devlist_entry == NULL)			return (NULL);		cfg = &devlist_entry->cfg;		bzero(cfg, sizeof *cfg);		cfg->bus		= probe->bus;		cfg->slot		= probe->slot;		cfg->func		= probe->func;		cfg->vendor		= pci_cfgread(cfg, PCIR_VENDOR, 2);		cfg->device		= pci_cfgread(cfg, PCIR_DEVICE, 2);		cfg->cmdreg		= pci_cfgread(cfg, PCIR_COMMAND, 2);		cfg->statreg		= pci_cfgread(cfg, PCIR_STATUS, 2);		cfg->baseclass		= pci_cfgread(cfg, PCIR_CLASS, 1);		cfg->subclass		= pci_cfgread(cfg, PCIR_SUBCLASS, 1);		cfg->progif		= pci_cfgread(cfg, PCIR_PROGIF, 1);		cfg->revid		= pci_cfgread(cfg, PCIR_REVID, 1);		cfg->hdrtype		= pci_cfgread(cfg, PCIR_HEADERTYPE, 1);		cfg->cachelnsz		= pci_cfgread(cfg, PCIR_CACHELNSZ, 1);		cfg->lattimer		= pci_cfgread(cfg, PCIR_LATTIMER, 1);		cfg->intpin		= pci_cfgread(cfg, PCIR_INTPIN, 1);		cfg->intline		= pci_cfgread(cfg, PCIR_INTLINE, 1);#ifdef __alpha__		alpha_platform_assign_pciintr(cfg);#endif#ifdef APIC_IO		if (cfg->intpin != 0) {			int airq;			airq = pci_apic_irq(cfg->bus, cfg->slot, cfg->intpin);			if (airq >= 0) {				/* PCI specific entry found in MP table */				if (airq != cfg->intline) {					undirect_pci_irq(cfg->intline);					cfg->intline = airq;				}			} else {				/* 				 * PCI interrupts might be redirected to the				 * ISA bus according to some MP tables. Use the				 * same methods as used by the ISA devices				 * devices to find the proper IOAPIC int pin.				 */				airq = isa_apic_irq(cfg->intline);				if ((airq >= 0) && (airq != cfg->intline)) {					/* XXX: undirect_pci_irq() ? */					undirect_isa_irq(cfg->intline);					cfg->intline = airq;				}			}		}#endif /* APIC_IO */		cfg->mingnt		= pci_cfgread(cfg, PCIR_MINGNT, 1);		cfg->maxlat		= pci_cfgread(cfg, PCIR_MAXLAT, 1);		cfg->mfdev		= (cfg->hdrtype & PCIM_MFDEV) != 0;		cfg->hdrtype		&= ~PCIM_MFDEV;		pci_fixancient(cfg);		pci_hdrtypedata(cfg);		STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links);		devlist_entry->conf.pc_sel.pc_bus = cfg->bus;		devlist_entry->conf.pc_sel.pc_dev = cfg->slot;		devlist_entry->conf.pc_sel.pc_func = cfg->func;		devlist_entry->conf.pc_hdr = cfg->hdrtype;		devlist_entry->conf.pc_subvendor = cfg->subvendor;		devlist_entry->conf.pc_subdevice = cfg->subdevice;		devlist_entry->conf.pc_vendor = cfg->vendor;		devlist_entry->conf.pc_device = cfg->device;		devlist_entry->conf.pc_class = cfg->baseclass;		devlist_entry->conf.pc_subclass = cfg->subclass;		devlist_entry->conf.pc_progif = cfg->progif;		devlist_entry->conf.pc_revid = cfg->revid;		pci_numdevs++;		pci_generation++;	}	return (devlist_entry);}#if 0/* free pcicfgregs structure and all depending data structures */static intpci_freecfg(struct pci_devinfo *dinfo){	struct devlist *devlist_head;	devlist_head = &pci_devq;	if (dinfo->cfg.hdrspec != NULL)		free(dinfo->cfg.hdrspec, M_DEVBUF);	if (dinfo->cfg.map != NULL)		free(dinfo->cfg.map, M_DEVBUF);	/* XXX this hasn't been tested */	STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links);	free(dinfo, M_DEVBUF);	/* increment the generation count */	pci_generation++;	/* we're losing one device */	pci_numdevs--;	return (0);}#endifstatic voidpci_addcfg(struct pci_devinfo *dinfo){	if (bootverbose) {		int i;		pcicfgregs *cfg = &dinfo->cfg;		printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", 		       cfg->vendor, cfg->device, cfg->revid);		printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n",		       cfg->baseclass, cfg->subclass, cfg->progif,		       cfg->hdrtype, cfg->mfdev);		printf("\tsubordinatebus=%x \tsecondarybus=%x\n",		       cfg->subordinatebus, cfg->secondarybus);#ifdef PCI_DEBUG		printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", 		       cfg->cmdreg, cfg->statreg, cfg->cachelnsz);		printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n",		       cfg->lattimer, cfg->lattimer * 30, 		       cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250);#endif /* PCI_DEBUG */		if (cfg->intpin > 0)			printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline);

⌨️ 快捷键说明

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