📄 pciconf.c
字号:
/* $Id: pciconf.c,v 1.2 2004/05/17 10:39:22 wlin Exp $ *//* * Copyright (c) 2000 Opsycon AB (www.opsycon.se) * Copyright (c) 2000 Rtmx, Inc (www.rtmx.com) * Copyright (c) 2001 IP Unplugged AB (www.ipunplugged.com) * * 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, 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for Rtmx, Inc by * Opsycon Open System Consulting AB, Sweden. * This product includes software developed for IP Inplugged AB, by * Patrik Lindergren. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 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. * *//* * This work is derivate work created from code written at Algorithmics UK. * It was part of PMON which is not copyrighted. After modifications and * extensions it is now released under standard BSD copyright. *//* * pciconf.c: generic PCI bus configuration */#include <sys/param.h>#include <stdarg.h>#include <progress.h>#include <sys/device.h>#include <sys/malloc.h>#include <machine/bus.h>#include <include/pmon_target.h>#include "pcivar.h"#include "pcireg.h"#define PCIVERBOSE 5#ifdef PCIVERBOSE#include "pcidevs.h"#endif#undef PCI_ALLOC_UPWARDS#include <sys/systm.h>#include <pmon.h>extern char *getenv __P((const char *));extern long atol __P((const char *));extern void *pmalloc __P((size_t ));extern void pfree __P((void * ));static int _pci_roundup(int , int );static int _pci_getIntRouting(struct pci_device *);static int _pci_setupIntRouting(struct pci_device *);static void _pci_scan_dev(struct pci_device *dev, int bus, int device, int initialise);static void _insertsort_window(struct pci_win **, struct pci_win *);static void _pci_device_insert(struct pci_device *parent, struct pci_device *device);static pcireg_t _pci_allocate_mem __P((struct pci_device *, vm_size_t));static pcireg_t _pci_allocate_io __P((struct pci_device *, vm_size_t));static void _setup_pcibuses(int );static void _pci_bus_insert(struct pci_bus *);#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif#ifndef MAX#define MAX(a,b) ((a) > (b) ? (a) : (b))#endif#define PRINTF printf#define VPRINTF vprintf#ifndef PCIVERBOSE#define _PCIVERBOSE 0#else#define _PCIVERBOSE PCIVERBOSE#endifpcitag_t have_vga = 0; /* Have tag if VGA board found */int monarch_mode = 1; /* Default as master on the bus! */int pci_roots; /* How many pci roots to init */int _pciverbose = _PCIVERBOSE;static int _pci_nbus = 8; /* Allow for eight roots */struct tgt_bus_space def_bus_iot; /* Default bus tags */struct tgt_bus_space def_bus_memt; /* Default bus tags */struct pci_device *_pci_head;struct pci_bus *_pci_bushead;struct pci_intline_routing *_pci_inthead;struct pci_device *vga_dev = NULL;static voidprint_bdf (int bus, int device, int function){ PRINTF ("PCI"); PRINTF (" bus %d", bus); if (device >= 0) PRINTF (" slot %d", device); if (function >= 0) PRINTF ("/%d", function); PRINTF (": ");}void_pci_bdfprintf (int bus, int device, int function, const char *fmt, ...){ va_list arg; print_bdf (bus, device, function); va_start(arg, fmt); VPRINTF (fmt, arg); va_end(arg);}void_pci_tagprintf (pcitag_t tag, const char *fmt, ...){ va_list arg; int bus, device, function; _pci_break_tag (tag, &bus, &device, &function); print_bdf (bus, device, function); va_start(arg, fmt); VPRINTF (fmt, arg); va_end(arg);}/* * Scan each PCI device on the system and record its configuration * requirements. */static void_pci_query_dev_func (struct pci_device *dev, pcitag_t tag, int initialise){ pcireg_t id, class; pcireg_t old, mask; pcireg_t stat; pcireg_t bparam; int reg; struct pci_bus *pb; struct pci_device *pd; unsigned int x; int bus, device, function; class = _pci_conf_read(tag, PCI_CLASS_REG); id = _pci_conf_read(tag, PCI_ID_REG); if (_pciverbose) { int supported; char devinfo[256]; _pci_devinfo(id, class, &supported, devinfo); _pci_tagprintf (tag, "%s\n", devinfo); } pd = pmalloc(sizeof(struct pci_device)); if(pd == NULL) { PRINTF ("pci: can't alloc memory for device\n"); return; } _pci_break_tag (tag, &bus, &device, &function); pd->pa.pa_bus = bus; pd->pa.pa_device = device; pd->pa.pa_function = function; pd->pa.pa_tag = tag; pd->pa.pa_id = id; pd->pa.pa_class = class; pd->pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED; pd->pa.pa_iot = dev->pa.pa_iot; pd->pa.pa_memt = dev->pa.pa_memt; pd->pa.pa_dmat = dev->pa.pa_dmat; pd->parent = dev; pd->pcibus = dev->bridge.secbus; pb = pd->pcibus; _pci_device_insert(dev, pd); /* * Calculated Interrupt routing */ _pci_setupIntRouting(pd); /* * Shut off device if we initialize from non reset. */ stat = _pci_conf_read(tag, PCI_COMMAND_STATUS_REG); stat &= ~(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); _pci_conf_write(tag, PCI_COMMAND_STATUS_REG, stat); pd->stat = stat; /* do all devices support fast back-to-back */ if ((stat & PCI_STATUS_BACKTOBACK_SUPPORT) == 0) { pb->fast_b2b = 0; /* no, sorry */ } /* do all devices run at 66 MHz */ if ((stat & PCI_STATUS_66MHZ_SUPPORT) == 0) { pb->freq66 = 0; /* no, sorry */ } /* find slowest devsel */ x = stat & PCI_STATUS_DEVSEL_MASK; if (x > pb->devsel) { pb->devsel = x; } /* Funny looking code which deals with any 32bit read only cfg... */ bparam = _pci_conf_read(tag, (PCI_MINGNT & ~0x3)); pd->min_gnt = 0xff & (bparam >> ((PCI_MINGNT & 3) * 8)); bparam = _pci_conf_read(tag, (PCI_MAXLAT & ~0x3)); pd->max_lat = 0xff & (bparam >> ((PCI_MAXLAT & 3) * 8)); if (pd->min_gnt != 0 || pd->max_lat != 0) { /* find largest minimum grant time of all devices */ if (pd->min_gnt != 0 && pd->min_gnt > pb->min_gnt) { pb->min_gnt = pd->min_gnt; } /* find smallest maximum latency time of all devices */ if (pd->max_lat != 0 && pd->max_lat < pb->max_lat) { pb->max_lat = pd->max_lat; } /* subtract our min on-bus time per second from bus bandwidth */ if (initialise) { pb->bandwidth -= pd->min_gnt * 4000000 / (pd->min_gnt + pd->max_lat); } } /* Map interrupt to interrupt line (software function only) */ bparam = _pci_conf_read(tag, PCI_INTERRUPT_REG); bparam &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); bparam |= ((_pci_getIntRouting(pd) & 0xff) << PCI_INTERRUPT_LINE_SHIFT); _pci_conf_write(tag, PCI_INTERRUPT_REG, bparam); /* * Check to see if device is a PCI Bridge */ if (PCI_ISCLASS(class, PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI)) { struct pci_device *pcidev; struct pci_win *pm_mem = NULL; struct pci_win *pm_io = NULL; struct pci_win *pm; pcireg_t tmp; pd->bridge.pribus_num = bus; pd->bridge.secbus_num = ++_pci_nbus; /* Set it temperary to same as secondary bus number */ pd->bridge.subbus_num = pd->bridge.secbus_num; tmp = _pci_conf_read(tag, PCI_PRIBUS_1); tmp &= 0xff000000; tmp |= pd->bridge.pribus_num; tmp |= pd->bridge.secbus_num << 8; tmp |= pd->bridge.subbus_num << 16; _pci_conf_write(tag, PCI_PRIBUS_1, tmp); /* Update sub bus number */ for(pcidev = dev; pcidev != NULL; pcidev = pcidev->parent) { pcidev->bridge.subbus_num = pd->bridge.secbus_num; tmp = _pci_conf_read(pcidev->pa.pa_tag, PCI_PRIBUS_1); tmp &= 0xff00ffff; tmp |= pd->bridge.secbus_num << 16; _pci_conf_write(pcidev->pa.pa_tag, PCI_PRIBUS_1, tmp); } pd->bridge.secbus = pmalloc(sizeof(struct pci_bus)); if(pd->bridge.secbus == NULL) { PRINTF ("pci: can't alloc memory for new pci bus\n"); return; } pd->bridge.secbus->max_lat = 255; pd->bridge.secbus->fast_b2b = 1; pd->bridge.secbus->prefetch = 1; pd->bridge.secbus->freq66 = 1; pd->bridge.secbus->bandwidth = 4000000; pd->bridge.secbus->ndev = 1; pd->bridge.secbus->bus = pd->bridge.secbus_num; _pci_bus_insert(pd->bridge.secbus); /* Scan secondary bus of the bridge */ _pci_scan_dev(pd, pd->bridge.secbus_num, 0, initialise); /* * Sum up the address space needed by secondary side of bridge */ /* Sum up I/O Space needed */ for(pm = pd->bridge.iospace; pm != NULL; pm = pm->next) { if(pm_io == NULL) { pm_io = pmalloc(sizeof(struct pci_win)); if(pm_io == NULL) { PRINTF ("pci: can't alloc memory for pci memory window\n"); return; } pm_io->device = pd; pm_io->reg = PCI_IOBASEL_1; pm_io->flags = PCI_MAPREG_TYPE_IO; } pm_io->size += pm->size; } /* Sum up Memory Space needed */ for(pm = pd->bridge.memspace; pm != NULL; pm = pm->next) { if(pm_mem == NULL) { pm_mem = pmalloc(sizeof(struct pci_win)); if(pm_mem == NULL) { PRINTF ("pci: can't alloc memory for pci memory window\n"); return; } pm_mem->device = pd; pm_mem->reg = PCI_MEMBASE_1; pm_mem->flags = PCI_MAPREG_MEM_TYPE_32BIT; } pm_mem->size += pm->size; } /* Round to minimum granularity requierd for a bridge */ pm_io->size = _pci_roundup(pm_io->size, 0x1000); pm_mem->size = _pci_roundup(pm_mem->size, 0x100000); if(pm_io) { _insertsort_window(&pd->parent->bridge.iospace, pm_io); } if(pm_mem) { _insertsort_window(&pd->parent->bridge.memspace,pm_mem); } } else if (PCI_ISCLASS(class, PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE) && dev->bridge.secbus->minpciioaddr == 0) { /* * There is no need to setup memory regions for IDE storage devices * but only if PCI/ISA I/O space is accessables */ return; } else { int skipnext = 0; for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) { struct pci_win *pm; if (skipnext) { skipnext = 0; continue; } old = _pci_conf_read(tag, reg); _pci_conf_write(tag, reg, 0xfffffffe); mask = _pci_conf_read(tag, reg); _pci_conf_write(tag, reg, old); if (mask == 0 || mask == 0xffffffff) { break; } if (_pciverbose >= 3) { _pci_tagprintf (tag, "reg 0x%x = 0x%x\n", reg, mask); } if (PCI_MAPREG_TYPE(mask) == PCI_MAPREG_TYPE_IO) { mask |= 0xffff0000; /* must be ones */ pm = pmalloc(sizeof(struct pci_win)); if(pm == NULL) { PRINTF ("pci: can't alloc memory for pci memory window\n"); return; } pm->device = pd; pm->reg = reg; pm->flags = PCI_MAPREG_TYPE_IO; pm->size = -(PCI_MAPREG_IO_ADDR(mask)); _insertsort_window(&pd->parent->bridge.iospace, pm); } else { switch (PCI_MAPREG_MEM_TYPE(mask)) { case PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_MEM_TYPE_32BIT_1M: break; case PCI_MAPREG_MEM_TYPE_64BIT: _pci_conf_write(tag, reg + 4, 0x0); skipnext = 1; break; default: _pci_tagprintf (tag, "reserved mapping type 0x%x\n", PCI_MAPREG_MEM_TYPE(mask)); continue; } if (!PCI_MAPREG_MEM_PREFETCHABLE(mask)) { pb->prefetch = 0; } pm = pmalloc(sizeof(struct pci_win)); if(pm == NULL) { PRINTF ("pci: can't alloc memory for pci memory window\n"); return; } pm->device = pd; pm->reg = reg; pm->flags = PCI_MAPREG_MEM_TYPE_32BIT; pm->size = -(PCI_MAPREG_MEM_ADDR(mask)); _insertsort_window(&pd->parent->bridge.memspace, pm); } } /* Finally check for Expansion ROM */ reg = PCI_MAPREG_ROM; old = _pci_conf_read(tag, reg); _pci_conf_write(tag, reg, 0xfffffffe); mask = _pci_conf_read(tag, reg); _pci_conf_write(tag, reg, old); if (mask != 0 && mask != 0xffffffff) { struct pci_win *pm; if (_pciverbose >= 3) { _pci_tagprintf (tag, "reg 0x%x = 0x%x\n", reg, mask); } pm = pmalloc(sizeof(struct pci_win)); if(pm == NULL) { PRINTF ("pci: can't alloc memory for pci memory window\n"); return; } pm->device = pd; pm->reg = reg; pm->size = -(PCI_MAPREG_ROM_ADDR(mask)); _insertsort_window(&pd->parent->bridge.memspace, pm); } }}static int_pci_roundup(value, round) int value; int round;{ int result = (value / round) * round; if(value % round) result += round; return(result);}static void_pci_bus_insert(bus) struct pci_bus *bus;{ struct pci_bus *pb; for(pb = _pci_bushead; pb->next != NULL; pb = pb->next) ;; pb->next = bus;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -