summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/pci.c1537
-rw-r--r--sys/dev/pci/pcireg.h31
-rw-r--r--sys/dev/pci/pcivar.h114
-rw-r--r--sys/pci/pci.c1537
-rw-r--r--sys/pci/pcibus.h57
-rw-r--r--sys/pci/pcireg.h31
-rw-r--r--sys/pci/pcisupport.c169
-rw-r--r--sys/pci/pcivar.h114
8 files changed, 2329 insertions, 1261 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index aa51596..32428c6 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1,11 +1,11 @@
/**************************************************************************
**
-** $Id: pci.c,v 1.18 1995/03/02 21:51:53 se Exp $
+** $Id: pci.c,v 1.19 1995/03/17 04:27:19 davidg Exp $
**
-** General subroutines for the PCI bus on 80*86 systems.
+** General subroutines for the PCI bus.
** pci_configure ()
**
-** 386bsd / FreeBSD
+** FreeBSD
**
**-------------------------------------------------------------------------
**
@@ -36,17 +36,11 @@
***************************************************************************
*/
-#define PCI_PATCHLEVEL "pl5 95/02/27"
+#define __PCI_C__ "pl13 95/03/21"
#include <pci.h>
#if NPCI > 0
-#ifndef __FreeBSD2__
-#if __FreeBSD__ >= 2
-#define __FreeBSD2__
-#endif
-#endif
-
/*========================================================
**
** #includes and declarations
@@ -59,199 +53,334 @@
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/kernel.h>
+#include <sys/proc.h> /* declaration of wakeup(), used by vm.h */
+#include <sys/devconf.h>
+
+#include <machine/cpu.h> /* bootverbose */
#include <vm/vm.h>
#include <vm/vm_param.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/pcibus.h>
+
#include <machine/pmap.h>
-#ifdef __FreeBSD2__
#include <sys/devconf.h>
+#define PCI_MAX_IRQ (16)
+
+
+/*========================================================
+**
+** Structs and Functions
+**
+**========================================================
+*/
+
struct pci_devconf {
struct kern_devconf pdc_kdc;
struct pci_info pdc_pi;
};
+struct pcicb {
+ struct pcicb *pcicb_next;
+ struct pcicb *pcicb_up;
+ struct pcicb *pcicb_down;
+ pcici_t pcicb_bridge;
+
+ u_long pcicb_seen;
+ u_char pcicb_bus;
+ u_char pcicb_subordinate;
+ u_char pcicb_flags;
+#define PCICB_ISAMEM 0x01
+ u_int pcicb_mfrom;
+ u_int pcicb_mupto;
+ u_int pcicb_mamount;
+ u_short pcicb_pfrom;
+ u_short pcicb_pupto;
+ u_short pcicb_pamount;
+ u_char pcicb_bfrom;
+ u_char pcicb_bupto;
+
+ u_long pcicb_iobase;
+ u_long pcicb_iolimit;
+ u_long pcicb_membase;
+ u_long pcicb_memlimit;
+ u_long pcicb_p_membase;
+ u_long pcicb_p_memlimit;
+};
+
static int
pci_externalize (struct proc *, struct kern_devconf *, void *, size_t);
static int
pci_internalize (struct proc *, struct kern_devconf *, void *, size_t);
-#else /* __FreeBSD2__ */
-
-/*
-** Function prototypes missing in system headers
-*/
-extern pmap_t pmap_kernel(void);
-static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize);
-#endif /* __FreeBSD2__ */
+static void
+not_supported (pcici_t tag, u_long type);
-#include <pci/pcivar.h>
-#include <pci/pcireg.h>
-#include <pci/pcibus.h>
+static void
+pci_bus_config (void);
+static void
+pci_bridge_config (void);
-
/*========================================================
**
-** Autoconfiguration of pci devices.
-**
-** This is reverse to the isa configuration.
-** (1) find a pci device.
-** (2) look for a driver.
+** Variables
**
**========================================================
*/
+/*
+** log2 of safe burst len (in words)
+*/
+
+unsigned pci_max_burst_len = 2;
+unsigned pci_mechanism = 0;
+unsigned pci_maxdevice = 0;
+struct pcibus* pcibus;
+
/*--------------------------------------------------------
**
-** Limit for pci bus numbers.
+** Local variables.
**
**--------------------------------------------------------
*/
-#ifndef PCI_MAX_BUS
-#define PCI_MAX_BUS (256)
-#endif
-
-static u_long pci_bus_max = 1;
+static int pci_conf_count;
+static int pci_info_done;
+static struct pcicb pcibus0 = {
+ NULL, NULL, NULL,
+ { 0 },
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* real allocation */
+ 0, 0xFFFF, /* iobase/limit */
+ 0x4000000, 0xFFFFFFFFu, /* nonprefetch membase/limit */
+ 0x4000000, 0xFFFFFFFFu /* prefetch membase/limit */
+};
+static struct pcicb *pcicb;
-/*--------------------------------------------------------
+/*========================================================
**
-** The pci devices can be mapped to any address.
-** This is a list of possible starting addresses.
-** It can be prepended by a config option.
+** pci_configure ()
**
-**--------------------------------------------------------
+** Autoconfiguration of pci devices.
+**
+** May be called more than once.
+** Any device is attached only once.
+**
+** Has to take care of mirrored devices, which are
+** entailed by incomplete decoding of pci address lines.
+**
+**========================================================
*/
-static u_long pci_stable[] = {
-#ifdef PCI_PMEM_START
- (PCI_PMEM_START),
-#endif
- 0xf1000000,
- 0x53900000,
- 0xc0000000,
- 0x81000000,
- 0x0f000000,
-};
+void pci_configure()
+{
+ int i;
-static vm_offset_t pci_paddr = 0;
-static vm_offset_t pci_pold = 0;
-static vm_offset_t pci_pidx = 0;
+ /*
+ ** check pci bus present
+ */
+ for (i=0; i<pcibus_set.ls_length; i++) {
+ if (pci_maxdevice) break;
+ pcibus = (struct pcibus*) pcibus_set.ls_items[i];
+ pcibus->pb_setup ();
+ }
+ if (!pci_maxdevice) return;
-/*--------------------------------------------------------
+ /*
+ ** hello world ..
+ */
+
+ for (pcicb = &pcibus0; pcicb != NULL;) {
+ pci_bus_config ();
+
+ if (pcicb->pcicb_down) {
+ pcicb = pcicb->pcicb_down;
+ continue;
+ };
+
+ while (pcicb && !pcicb->pcicb_next)
+ pcicb = pcicb->pcicb_up;
+
+ if (pcicb)
+ pcicb = pcicb->pcicb_next;
+ }
+ pci_conf_count++;
+}
+
+/*========================================================
**
-** The pci ports can be mapped to any address.
-** As default we start at 0x400
+** Subroutines for configuration.
**
-**--------------------------------------------------------
+**========================================================
*/
-#ifndef PCI_PORT_START
-#define PCI_PORT_START 0xbc00
+static void
+pci_register_io (struct pcicb * cb, u_int base, u_int limit)
+{
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("register_io: bus=%d base=%x limit=%x\n",
+ cb->pcicb_bus, base, limit);
#endif
-static u_short pci_ioaddr = PCI_PORT_START;
+ if (!cb->pcicb_pfrom || base < cb->pcicb_pfrom)
+ cb->pcicb_pfrom = base;
+ if (limit > cb->pcicb_pupto)
+ cb->pcicb_pupto = limit;
-/*--------------------------------------------------------
-**
-** The pci device interrupt lines should have been
-** assigned by the bios. But if the bios failed to
-** to it, we set it.
-**
-**--------------------------------------------------------
-*/
+ /*
+ ** XXX should set bridge io mapping here
+ ** but it can be mapped in 4k blocks only,
+ ** leading to conflicts with isa/eisa ..
+ */
+}
-#ifndef PCI_IRQ
-#define PCI_IRQ 0
+static void
+pci_register_memory (struct pcicb * cb, u_int base, u_int limit)
+{
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("register_mem: bus=%d base=%x limit=%x\n",
+ cb->pcicb_bus, base, limit);
#endif
-static u_long pci_irq = PCI_IRQ;
-
-/*---------------------------------------------------------
-**
-** pci_configure ()
-**
-** Probe all devices on pci bus and attach them.
-**
-** May be called more than once.
-** Any device is attached only once.
-** (Attached devices are remembered in pci_seen.)
-** Has to take care of mirrored devices, which are
-** entailed by incomplete decoding of pci address lines.
-**
-**---------------------------------------------------------
+ if (!cb->pcicb_mfrom || base < cb->pcicb_mfrom)
+ cb->pcicb_mfrom = base;
+ if (limit > cb->pcicb_mupto)
+ cb->pcicb_mupto = limit;
+ /*
+ ** set the bridges mapping
+ **
+ ** XXX should handle the 1Mb granularity.
+ */
+ if (cb->pcicb_bridge.tag) {
+ pci_conf_write(cb->pcicb_bridge,
+ PCI_PCI_BRIDGE_MEM_REG,
+ (cb->pcicb_memlimit & 0xffff0000) |
+ (cb->pcicb_membase >> 16));
+ printf ("\t[pci%d uses memory from %x to %x]\n",
+ cb->pcicb_bus,
+ (unsigned) cb->pcicb_membase,
+ (unsigned) cb->pcicb_memlimit);
+ }
+}
+
+/*
+** XXX This function is neither complete nor tested.
+** It's only used if the bios hasn't done it's job
+** of mapping the pci devices in the physical memory.
*/
-static void not_supported (pcici_t tag, u_long type);
+static u_int
+pci_memalloc (struct pcicb * cb, u_int addr, u_int size)
+{
+ u_int result = 0, limit=0, newbase=0;
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("memalloc: bus=%d addr=%x size=%x ..\n",
+ cb->pcicb_bus, addr, size);
+#endif
-static unsigned long pci_seen[PCI_MAX_BUS];
+ if (!cb) goto done;
-static int pci_conf_count;
-static int pci_info_done;
+ if (!cb->pcicb_membase) {
+ printf ("memalloc: bus%d: membase not set.\n",
+ cb->pcicb_bus);
+ goto done;
+ }
-void pci_configure()
-{
- u_char device,max_device;
- u_short bus;
- pcici_t tag;
- pcidi_t type, type8, type16;
- u_long data;
- int unit;
- int pci_mechanism;
- int pciint;
- int irq;
- char* name=0;
- u_short old_ioaddr=pci_ioaddr;
-
- int dvi;
- struct pci_device *dvp=0;
+ /*
+ ** get upper allocation limit
+ */
+ limit = cb->pcicb_memlimit;
+ if (cb->pcicb_mfrom && cb->pcicb_mfrom <= limit)
+ limit = cb->pcicb_mfrom-1;
-#ifdef __FreeBSD2__
- struct pci_devconf *pdcp;
-#endif
+ /*
+ ** address fixed, and impossible to allocate ?
+ */
+ if (addr && addr+size-1 > limit)
+ goto done;
/*
- ** first check pci bus driver available
+ ** get possible address
*/
- if (pcibus_set.ls_length <= 0)
- return;
+ result = addr;
+ if (!result) result = ((limit + 1) / size - 1) * size;
-#define pcibus (*((struct pcibus*) pcibus_set.ls_items[0]))
/*
- ** check pci bus present
+ ** if not local available, request from parent.
*/
- pci_mechanism = pcibus.pb_mode ();
- if (!pci_mechanism) return;
- max_device = pci_mechanism==1 ? 32 : 16;
+ if (result < cb->pcicb_membase) {
+ newbase = pci_memalloc (cb->pcicb_up, result, size);
+ if (newbase) cb->pcicb_membase = result;
+ else result=0;
+ }
+done:
+ if (result)
+ pci_register_memory (cb, result, result+size-1);
+
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("memalloc: bus=%d addr=%x size=%x --> %x (limit=%x).\n",
+ cb->pcicb_bus, addr, size, result, limit);
+#endif
+
+ return (result);
+}
+
+/*========================================================
+**
+** pci_bus_config()
+**
+** Autoconfiguration of one pci bus.
+**
+**========================================================
+*/
+
+static void
+pci_bus_config (void)
+{
+ u_char device;
+ u_char reg;
+ pcici_t tag, mtag;
+ pcidi_t type;
+ u_long data;
+ int unit;
+ int pciint;
+ int irq;
+ char* name=0;
+
+ int dvi;
+ struct pci_device *dvp=0;
+
+ struct pci_devconf *pdcp;
/*
- ** hello world ..
+ ** first initialize the bridge (bus controller chip)
*/
-
- pci_pold=pci_paddr;
- for (bus=0; bus<pci_bus_max; bus++) {
+ pci_bridge_config ();
+
#ifndef PCI_QUIET
- printf ("Probing for devices on the %s%d bus:\n",
- pcibus.pb_name, bus);
- if (!pci_info_done) {
+ printf ("Probing for devices on the %s%d bus:\n",
+ pcibus->pb_name, pcicb->pcicb_bus);
+ if (!pci_info_done) {
pci_info_done=1;
printf ("\tconfiguration mode %d allows %d devices.\n",
- pci_mechanism, max_device);
- };
+ pci_mechanism, pci_maxdevice);
+ };
#endif
- for (device=0; device<max_device; device ++) {
+ for (device=0; device<pci_maxdevice; device ++) {
- if (pci_seen[bus] & (1ul << device))
+ if ((pcicb->pcicb_seen >> device) & 1)
continue;
- tag = pcibus.pb_tag (bus, device, 0);
- type = pcibus.pb_read (tag, PCI_ID_REG);
+ tag = pcibus->pb_tag (pcicb->pcicb_bus, device, 0);
+ type = pcibus->pb_read (tag, PCI_ID_REG);
if ((!type) || (type==0xfffffffful)) continue;
@@ -259,7 +388,7 @@ void pci_configure()
** lookup device in ioconfiguration:
*/
- for (dvi=0; dvi<pcidevice_set.ls_length; dvi++) {
+ for (dvi=0; dvi<pcidevice_set.ls_length; dvi++) {
dvp = (struct pci_device*) pcidevice_set.ls_items[dvi];
if ((name=(*dvp->pd_probe)(tag, type)))
break;
@@ -269,36 +398,42 @@ void pci_configure()
/*
** check for mirrored devices.
*/
- if (device & 0x08) {
- pcici_t mtag;
- mtag = pcibus.pb_tag (bus, device & ~0x08, 0);
- type8 = pcibus.pb_read (mtag, PCI_ID_REG);
- } else type8 = 0;
if (device & 0x10) {
- pcici_t mtag;
- mtag = pcibus.pb_tag (bus, device & ~0x10, 0);
- type16 = pcibus.pb_read (mtag, PCI_ID_REG);
- } else type16 = 0;
- if ((type==type8) || (type==type16)) {
+ mtag=pcibus->pb_tag (pcicb->pcicb_bus,
+ (u_char)(device & ~0x10), 0);
+ } else if (device & 0x08) {
+ mtag=pcibus->pb_tag (pcicb->pcicb_bus,
+ (u_char)(device & ~0x08), 0);
+ } else goto real_device;
+
+ if (type!=pcibus->pb_read (mtag, PCI_ID_REG))
+ goto real_device;
+
+ for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4)
+ if (pcibus->pb_read(tag,reg)!=pcibus->pb_read(mtag,reg))
+ goto real_device;
+
#ifndef PCI_QUIET
- if (dvp==NULL) continue;
- printf ("%s? <%s> mirrored on pci%d:%d\n",
- dvp->pd_name, name, bus, device);
+ if (dvp==NULL) continue;
+ printf ("%s? <%s> mirrored on pci%d:%d\n",
+ dvp->pd_name, name, pcicb->pcicb_bus, device);
#endif
- continue;
- };
+ continue;
+
+ real_device:
if (dvp==NULL) {
#ifndef PCI_QUIET
if (pci_conf_count)
continue;
- printf("%s%d:%d: ", pcibus.pb_name, bus, device);
+ printf("%s%d:%d: ", pcibus->pb_name,
+ pcicb->pcicb_bus, device);
not_supported (tag, type);
#endif
continue;
};
-
- pci_seen[bus] |= (1ul << device);
+
+ pcicb->pcicb_seen |= (1ul << device);
/*
** Get and increment the unit.
*/
@@ -315,85 +450,102 @@ void pci_configure()
** Announce this device
*/
- printf ("%s%d <%s>", dvp->pd_name, unit, name);
-
+ printf ("%s%d <%s> rev %d", dvp->pd_name, unit, name,
+ (unsigned) pci_conf_read (tag, PCI_CLASS_REG) & 0xff);
+
/*
** Get the int pin number (pci interrupt number a-d)
** from the pci configuration space.
*/
- data = pcibus.pb_read (tag, PCI_INTERRUPT_REG);
+ data = pcibus->pb_read (tag, PCI_INTERRUPT_REG);
pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
if (pciint) {
- printf (" int %c", 0x60+pciint);
-
- /*
- ** If the interrupt line register is not set,
- ** set it now from PCI_IRQ.
- */
-
- if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) {
-
- irq = pci_irq & 0x0f;
- pci_irq >>= 4;
-
- data = PCI_INTERRUPT_LINE_INSERT(data, irq);
- printf (" (config)");
- pcibus.pb_write (tag, PCI_INTERRUPT_REG, data);
- };
+ printf (" int %c irq ", 0x60+pciint);
irq = PCI_INTERRUPT_LINE_EXTRACT(data);
/*
** If it's zero, the isa irq number is unknown,
- ** and we cannot bind the pci interrupt to isa.
+ ** and we cannot bind the pci interrupt.
*/
if (irq)
- printf (" irq %d", irq);
+ printf ("%d", irq);
else
- printf (" not bound");
+ printf ("??");
};
+ printf (" on pci%d:%d\n", pcicb->pcicb_bus, device);
+
/*
- ** enable memory access
+ ** Read the current mapping,
+ ** and update the pcicb fields.
*/
- data = (pcibus.pb_read (tag, PCI_COMMAND_STATUS_REG)
- & 0xffff) | PCI_COMMAND_MEM_ENABLE;
+ for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) {
+ u_int map, addr, size;
- pcibus.pb_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
+ data = pci_conf_read(tag, PCI_CLASS_REG);
+ switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+ case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+ continue;
+ };
- /*
- ** show pci slot.
- */
+ map = pcibus->pb_read (tag, reg);
+ if (!(map & PCI_MAP_MEMORY_ADDRESS_MASK))
+ continue;
- printf (" on pci%d:%d\n", bus, device);
+ pcibus->pb_write (tag, reg, 0xffffffff);
+ data = pcibus->pb_read (tag, reg);
+ pcibus->pb_write (tag, reg, map);
-#ifdef __FreeBSD2__
+ switch (data & 7) {
- /*
- ** Allocate a devconf structure
- */
+ default:
+ continue;
+ case 1:
+ case 5:
+ size = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ addr = map & PCI_MAP_IO_ADDRESS_MASK;
- pdcp = (struct pci_devconf *)
- malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
+ pci_register_io (pcicb, addr, addr+size-1);
+ pcicb->pcicb_pamount += size;
+ break;
+
+ case 0:
+ case 2:
+ case 4:
+ size = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
+ addr = map & PCI_MAP_MEMORY_ADDRESS_MASK;
+ if (addr >= 0x100000) {
+ pci_register_memory
+ (pcicb, addr, addr+size-1);
+ pcicb->pcicb_mamount += size;
+ } else {
+ pcicb->pcicb_flags |= PCICB_ISAMEM;
+ };
+ break;
+ };
+ if (!bootverbose)
+ continue;
+ printf ("\tmapreg[%02x] type=%d addr=%08x size=%04x.\n",
+ reg, map&7, addr, size);
+ };
/*
- ** Fill in.
- **
- ** Sorry, this is not yet complete.
+ ** Allocate a devconf structure
** We should, and eventually will, set the
** parent pointer to a pci bus devconf structure,
** and arrange to set the state field dynamically.
- **
- ** But I'll go to vacation today, and after all,
- ** wasn't there a new feature freeze on Oct 1.?
*/
- pdcp -> pdc_pi.pi_bus = bus;
+ pdcp = (struct pci_devconf *)
+ malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
+
+ pdcp -> pdc_pi.pi_bus = pcicb->pcicb_bus;
pdcp -> pdc_pi.pi_device = device;
pdcp -> pdc_kdc.kdc_name = dvp->pd_name;
@@ -408,7 +560,6 @@ void pci_configure()
pdcp -> pdc_kdc.kdc_parentdata = &pdcp->pdc_pi;
pdcp -> pdc_kdc.kdc_state = DC_UNKNOWN;
pdcp -> pdc_kdc.kdc_description = name;
- pdcp -> pdc_kdc.kdc_shutdown = dvp->pd_shutdown;
/*
** And register this device
@@ -416,9 +567,6 @@ void pci_configure()
dev_attach (&pdcp->pdc_kdc);
-#endif /* __FreeBSD2__ */
-
-
/*
** attach device
** may produce additional log messages,
@@ -426,20 +574,255 @@ void pci_configure()
*/
(*dvp->pd_attach) (tag, unit);
- };
- };
+ /*
+ ** Special processing of certain classes
+ */
+
+ data = pci_conf_read(tag, PCI_CLASS_REG);
+
+ switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+ struct pcicb *this, **link;
+ unsigned char primary, secondary, subordinate;
+ u_int command;
+
+ case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+
+ /*
+ ** get current configuration of the bridge.
+ */
+ data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG);
+ primary = PCI_PRIMARY_BUS_EXTRACT (data);
+ secondary = PCI_SECONDARY_BUS_EXTRACT(data);
+ subordinate = PCI_SUBORDINATE_BUS_EXTRACT(data);
#ifndef PCI_QUIET
- if (pci_paddr != pci_pold)
- printf ("pci uses physical addresses from 0x%lx to 0x%lx\n",
- (u_long)pci_pold, (u_long)pci_paddr);
- if (pci_ioaddr != old_ioaddr)
- printf ("pci devices use ioports from 0x%x to 0x%x\n",
- (unsigned)PCI_PORT_START, (unsigned)pci_ioaddr);
+ printf ("\tbridge from pci%d to pci%d through %d.\n",
+ primary, secondary, subordinate);
#endif
- pci_conf_count++;
+ /*
+ ** check for uninitialized bridge.
+ */
+ if (secondary == 0 || secondary < primary ||
+ pcicb->pcicb_bus != primary)
+ {
+ printf ("\tINCORRECTLY or NEVER CONFIGURED.\n");
+ /*
+ ** disable this bridge
+ */
+ pcibus->pb_write (tag, PCI_COMMAND_STATUS_REG,
+ 0xffff0000);
+ secondary = 0;
+ subordinate = 0;
+ };
+
+ /*
+ ** allocate bus descriptor for bus behind the bridge
+ */
+ link = &pcicb->pcicb_down;
+ while (*link) link = &(*link)->pcicb_next;
+
+ this = malloc (sizeof (*this), M_DEVBUF, M_WAITOK);
+
+ /*
+ ** Initialize this descriptor so far.
+ ** (the initialization is completed just before
+ ** scanning the bus behind the bridge.
+ */
+ bzero (this, sizeof(*this));
+ this->pcicb_up = pcicb;
+ this->pcicb_bridge = tag;
+ this->pcicb_bus = secondary;
+ this->pcicb_subordinate = subordinate;
+
+ command = pci_conf_read(tag,PCI_COMMAND_STATUS_REG);
+
+ if (command & PCI_COMMAND_IO_ENABLE){
+ /*
+ ** Bridge was configured by the bios.
+ ** Read out the mapped io region.
+ */
+ u_int reg, data, mask;
+
+ reg = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_IO_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_IO_REG, 0xFFFF);
+ data = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_IO_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_IO_REG, reg & 0xffff);
+
+ mask = (0xFF00 ^ (data & 0xFF00)) | 0xFF;
+
+ this->pcicb_iobase =
+ PCI_PPB_IOBASE_EXTRACT (reg);
+ this->pcicb_iolimit =
+ PCI_PPB_IOLIMIT_EXTRACT(reg) | mask;
+
+ /*
+ ** Note the used io space.
+ */
+ pci_register_io (pcicb, this->pcicb_iobase,
+ this->pcicb_iolimit);
+
+ };
+
+ if (command & PCI_COMMAND_MEM_ENABLE) {
+ /*
+ ** Bridge was configured by the bios.
+ ** Read out the mapped memory regions.
+ */
+ u_int reg, data, mask;
+
+ /*
+ ** non prefetchable memory
+ */
+ reg = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_MEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_MEM_REG, 0xFFFFFFFF);
+ data = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_MEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_MEM_REG, reg);
+ mask = (0xFFFF0000 ^ (data & 0xFFFF0000))
+ | 0xFFFF;
+
+ this->pcicb_membase =
+ PCI_PPB_MEMBASE_EXTRACT (reg);
+ this->pcicb_memlimit =
+ PCI_PPB_MEMLIMIT_EXTRACT(reg) | mask;
+
+ /*
+ ** Register used memory space.
+ */
+ pci_register_memory (pcicb,
+ this->pcicb_membase,
+ this->pcicb_memlimit);
+
+ /*
+ ** prefetchable memory
+ */
+ reg = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_PMEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_PMEM_REG, 0xFFFFFFFF);
+ data = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_PMEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_PMEM_REG, reg);
+
+ mask = (0xFFFF0000 ^ (data & 0xFFFF0000))
+ | 0xFFFF;
+ this->pcicb_p_membase=
+ PCI_PPB_MEMBASE_EXTRACT (reg);
+ this->pcicb_p_memlimit=
+ PCI_PPB_MEMLIMIT_EXTRACT(reg) | mask;
+
+ /*
+ ** Register used memory space.
+ */
+ pci_register_memory (pcicb,
+ this->pcicb_p_membase,
+ this->pcicb_p_memlimit);
+ }
+
+ /*
+ ** Link it in chain.
+ */
+ *link=this;
+
+ /*
+ ** Update mapping info of parent bus.
+ */
+ if (!pcicb->pcicb_bfrom||secondary< pcicb->pcicb_bfrom)
+ pcicb->pcicb_bfrom = secondary;
+ if (subordinate > pcicb->pcicb_bupto)
+ pcicb->pcicb_bupto = subordinate;
+
+ break;
+ }
+ }
+
+#ifndef PCI_QUIET
+ if (pcicb->pcicb_mamount)
+ printf ("%s%d: uses %d bytes of memory from %x upto %x.\n",
+ pcibus->pb_name, pcicb->pcicb_bus,
+ pcicb->pcicb_mamount,
+ pcicb->pcicb_mfrom, pcicb->pcicb_mupto);
+ if (pcicb->pcicb_pamount)
+ printf ("%s%d: uses %d bytes of I/O space from %x upto %x.\n",
+ pcibus->pb_name, pcicb->pcicb_bus,
+ pcicb->pcicb_pamount,
+ pcicb->pcicb_pfrom, pcicb->pcicb_pupto);
+ if (pcicb->pcicb_bfrom)
+ printf ("%s%d: subordinate busses from %x upto %x.\n",
+ pcibus->pb_name, pcicb->pcicb_bus,
+ pcicb->pcicb_bfrom, pcicb->pcicb_bupto);
+#endif
+}
+
+/*========================================================
+**
+** pci_bridge_config()
+**
+** Configuration of a pci bridge.
+**
+**========================================================
+*/
+
+static void
+pci_bridge_config (void)
+{
+ pcici_t tag;
+ struct pcicb* parent;
+
+ tag = pcicb->pcicb_bridge;
+ if (!tag.tag) return;
+
+ if (!pcicb->pcicb_bus) {
+ u_int data;
+ /*
+ ** Get the lowest available bus number.
+ */
+ pcicb->pcicb_bus = ++pcibus0.pcicb_subordinate;
+
+ /*
+ ** and configure the bridge
+ */
+ data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG);
+ data = PCI_PRIMARY_BUS_INSERT(data, pcicb->pcicb_up->pcicb_bus);
+ data = PCI_SECONDARY_BUS_INSERT(data, pcicb->pcicb_bus);
+ data = PCI_SUBORDINATE_BUS_INSERT(data, pcicb->pcicb_bus);
+ pci_conf_write (tag, PCI_PCI_BRIDGE_BUS_REG, data);
+
+ /*
+ ** Propagate the new upper bus number limit.
+ */
+ for (parent = pcicb->pcicb_up; parent != NULL;
+ parent = parent->pcicb_up)
+ {
+ if (parent->pcicb_subordinate >= pcicb->pcicb_bus)
+ continue;
+ parent->pcicb_subordinate = pcicb->pcicb_bus;
+ if (!parent->pcicb_bridge.tag)
+ continue;
+ data = pci_conf_read
+ (parent->pcicb_bridge, PCI_PCI_BRIDGE_BUS_REG);
+ data = PCI_SUBORDINATE_BUS_INSERT
+ (data, pcicb->pcicb_bus);
+ pci_conf_write (parent->pcicb_bridge,
+ PCI_PCI_BRIDGE_BUS_REG, data);
+ }
+ }
+
+ if (!pcicb->pcicb_membase) {
+ u_int size = 0x100000;
+ pcicb->pcicb_membase = pci_memalloc (pcicb->pcicb_up, 0, size);
+ if (pcicb->pcicb_membase)
+ pcicb->pcicb_memlimit = pcicb->pcicb_membase+size-1;
+ }
}
-
/*-----------------------------------------------------------------
**
** The following functions are provided for the device driver
@@ -461,19 +844,22 @@ void pci_configure()
u_long
pci_conf_read (pcici_t tag, u_long reg)
{
- return (pcibus.pb_read (tag, reg));
+ return (pcibus->pb_read (tag, reg));
}
void
pci_conf_write (pcici_t tag, u_long reg, u_long data)
{
- pcibus.pb_write (tag, reg, data);
+ pcibus->pb_write (tag, reg, data);
}
-
+
/*-----------------------------------------------------------------------
**
** Map device into port space.
**
+** Actually the device should have been mapped by the bios.
+** This function only reads and verifies the value.
+**
** PCI-Specification: 6.2.5.1: address maps
**
**-----------------------------------------------------------------------
@@ -481,8 +867,8 @@ pci_conf_write (pcici_t tag, u_long reg, u_long data)
int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
{
- u_long data,oldmap;
- u_short size, ioaddr;
+ unsigned data, ioaddr, iosize;
+ struct pcicb *link = pcicb;
/*
** sanity check
@@ -490,10 +876,16 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
printf ("pci_map_port failed: bad register=0x%x\n",
- (unsigned)reg);
+ (unsigned)reg);
return (0);
};
+ /*if (pcicb->pcicb_flags & PCICB_NOIOSET) {
+ printf ("pci_map_port failed: pci%d has not been configured for I/O access\n",
+ pcicb->pcicb_bus);
+ return (0);
+ }*/
+
/*
** get size and type of port
**
@@ -502,88 +894,75 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
** n-2 bits are hardwired as 0.
*/
-#ifdef PCI_REMAP
- oldmap = 0;
-#else
- oldmap = pcibus.pb_read (tag, reg) & 0xfffffffc;
- if (oldmap==0xfffffffc) oldmap=0;
-#endif
- pcibus.pb_write (tag, reg, 0xfffffffful);
- data = pcibus.pb_read (tag, reg);
-
- switch (data & 0x03) {
-
- case PCI_MAP_IO:
- break;
-
- default: /* unknown */
- printf ("pci_map_port failed: bad port type=0x%x\n",
- (unsigned) data);
+ ioaddr = pcibus->pb_read (tag, reg) & PCI_MAP_IO_ADDRESS_MASK;
+ if (!ioaddr || ioaddr > 0xfffful) {
+ printf ("pci_map_port failed: not configured by bios.\n");
return (0);
};
- /*
- ** get the size
- */
-
- size = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ pcibus->pb_write (tag, reg, 0xfffffffful);
+ data = pcibus->pb_read (tag, reg);
+ pcibus->pb_write (tag, reg, ioaddr);
- if (!size) return (0);
-
- /*
- ** align physical address to virtual size,
- ** set ioaddr,
- ** and don't forget to increment pci_ioaddr
- */
-
- if (oldmap) {
- ioaddr = oldmap;
- } else {
- if ((data = pci_ioaddr % size))
- pci_ioaddr += size - data;
- ioaddr = pci_ioaddr;
- pci_ioaddr += size;
+ if ((data & 0x03) != PCI_MAP_IO) {
+ printf ("pci_map_port failed: bad port type=0x%x\n",
+ (unsigned) data);
+ return (0);
};
+ iosize = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ if (ioaddr < pcicb->pcicb_iobase
+ || ioaddr + iosize > pcicb->pcicb_iolimit) {
+ printf ("pci_map_port failed: device's iorange 0x%x-0x%x "
+ "is incompatible with its bridge's range 0x%x-0x%x\n",
+ (unsigned) ioaddr, (unsigned) ioaddr + iosize - 1,
+ (unsigned) pcicb->pcicb_iobase,
+ (unsigned) pcicb->pcicb_iolimit);
+ return (0);
+ }
#ifndef PCI_QUIET
- /*
- ** display values.
- */
-
printf ("\treg%d: ioaddr=0x%x size=0x%x\n",
- (unsigned) reg, (unsigned) ioaddr, (unsigned) size);
+ (unsigned) reg, (unsigned) ioaddr, (unsigned) iosize);
#endif
-
/*
- ** set device address
+ ** set the configuration register of and
+ ** return the address to the driver.
+ ** Make sure to enable each upstream bridge
+ ** so I/O and DMA can go all the way.
*/
- pcibus.pb_write (tag, reg, (u_long) ioaddr);
-
- /*
- ** return them to the driver
- */
+ for (;;) {
+ data = pcibus->pb_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
+ data |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ (void) pcibus->pb_write(tag, PCI_COMMAND_STATUS_REG, data);
+ if ((link = link->pcicb_up) == NULL)
+ break;
+ tag = link->pcicb_bridge;
+ }
- *pa = pci_ioaddr;
+ *pa = ioaddr;
return (1);
}
-
+
/*-----------------------------------------------------------------------
**
** Map device into virtual and physical space
**
-** PCI-Specification: 6.2.5.1: address maps
+** Actually the device should have been mapped by the bios.
+** This function only reads and verifies the value.
+**
+** PCI-Specification: 6.2.5.1: address maps
**
**-----------------------------------------------------------------------
*/
int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
{
- u_long data,oldmap,paddr;
- vm_size_t vsize;
+ struct pcicb *link = pcicb;
+ unsigned data ,paddr;
+ vm_size_t psize, poffs;
vm_offset_t vaddr;
- int i;
/*
** sanity check
@@ -591,7 +970,7 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
printf ("pci_map_mem failed: bad register=0x%x\n",
- (unsigned)reg);
+ (unsigned)reg);
return (0);
};
@@ -603,179 +982,90 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
** n-4 bits are read as 0.
*/
-#ifdef PCI_REMAP
- oldmap = 0;
-#else
- oldmap = pcibus.pb_read (tag, reg) & 0xfffffff0;
- if (oldmap==0xfffffff0) oldmap = 0;
-#endif
- pcibus.pb_write (tag, reg, 0xfffffffful);
- data = pcibus.pb_read (tag, reg);
+ paddr = pcibus->pb_read (tag, reg) & PCI_MAP_MEMORY_ADDRESS_MASK;
+ pcibus->pb_write (tag, reg, 0xfffffffful);
+ data = pcibus->pb_read (tag, reg);
+ pcibus->pb_write (tag, reg, paddr);
- switch (data & 0x0f) {
-
- case PCI_MAP_MEMORY_TYPE_32BIT: /* 32 bit non cachable */
- break;
+ /*
+ ** check the type
+ */
- default: /* unknown */
+ if ((data & PCI_MAP_MEMORY_TYPE_MASK) != PCI_MAP_MEMORY_TYPE_32BIT) {
printf ("pci_map_mem failed: bad memory type=0x%x\n",
- (unsigned) data);
+ (unsigned) data);
return (0);
};
-
+
/*
- ** mask out the type,
- ** and round up to a page size
+ ** get the size.
*/
- vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK));
-
- if (!vsize) return (0);
-
- if (oldmap) {
- paddr = oldmap;
- goto domap;
- };
+ psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
-next_try:
- if (!pci_paddr) {
- /*
- ** Get a starting address.
- */
- if (pci_pidx >= sizeof(pci_stable)/sizeof(u_long)) {
- printf ("pci_map_mem: out of start addresses.\n");
+ if (!paddr || paddr == PCI_MAP_MEMORY_ADDRESS_MASK) {
+ paddr = pci_memalloc (pcicb, 0, psize);
+ if (!paddr) {
+ printf ("pci_map_mem: not configured by bios.\n");
return (0);
};
-
- pci_paddr = pci_stable[pci_pidx++];
- pci_pold = 0;
-
- if (pci_pidx>1)
- printf ("\t(retry at 0x%x)\n",
- (unsigned) pci_paddr);
+ pci_register_memory (pcicb, paddr, paddr+psize-1);
};
- /*
- ** align physical address to virtual size
- */
-
- if ((data = pci_paddr % vsize))
- pci_paddr += vsize - data;
- if (!pci_pold)
- pci_pold = pci_paddr;
+ if (paddr < pcicb->pcicb_membase ||
+ paddr + psize - 1 > pcicb->pcicb_memlimit) {
+ printf ("pci_map_mem failed: device's memrange 0x%x-0x%x is "
+ "incompatible with its bridge's memrange 0x%x-0x%x\n",
+ (unsigned) paddr,
+ (unsigned) (paddr + psize - 1),
+ (unsigned) pcicb->pcicb_membase,
+ (unsigned) pcicb->pcicb_memlimit);
+ return (0);
+ }
+ pcibus->pb_write (tag, reg, paddr);
/*
- ** set physical mapping address,
- ** and reserve physical address range
+ ** Truncate paddr to page boundary.
+ ** (Or does pmap_mapdev the job?)
*/
- paddr = pci_paddr;
- pci_paddr += vsize;
-
-domap:
- vaddr = (vm_offset_t) pmap_mapdev (paddr, vsize);
+ poffs = paddr - trunc_page (paddr);
+ vaddr = (vm_offset_t) pmap_mapdev (paddr-poffs, psize+poffs);
if (!vaddr) return (0);
-
+
+ vaddr += poffs;
+
#ifndef PCI_QUIET
/*
** display values.
*/
- printf ("\treg%d: virtual=0x%lx physical=0x%lx\n",
- (unsigned) reg, (u_long)vaddr, (u_long)paddr);
+ printf ("\treg%d: virtual=0x%lx physical=0x%lx size=0x%lx\n",
+ (unsigned) reg, (u_long)vaddr, (u_long)paddr, (u_long)psize);
#endif
-
/*
- ** probe for already mapped device.
- */
-
- if (!oldmap) for (i=0; i<vsize; i+=4) {
- u_long* addr = (u_long*) (vaddr+i);
- data = *addr;
- if (data != 0xffffffff) {
- printf ("\t(possible address conflict: "
- "at 0x%x read: 0x%x)\n",
- (unsigned) paddr+i, (unsigned) data);
- pci_paddr = 0;
- goto next_try;
- };
- };
-
- /*
- ** Set device address
- */
-
- pcibus.pb_write (tag, reg, paddr);
-
- /*
- ** Check if correctly mapped.
- **
- ** W A R N I N G
- **
- ** This code assumes that the device will NOT return
- ** only ones (0xffffffff) from all offsets.
+ ** set the configuration register and
+ ** return the address to the driver
+ ** Make sure to enable each upstream bridge
+ ** so memory and DMA can go all the way.
*/
- if (!oldmap) {
- for (i=0; i<vsize; i+=4) {
- u_long* addr = (u_long*) (vaddr+i);
- data = *addr;
- if (data != 0xffffffff)
- break;
- };
-
- if (data==0xffffffff) {
- printf ("\t(possible mapping problem: "
- "at 0x%x read 0xffffffff)\n",
- (unsigned) paddr);
- pci_paddr = 0;
- goto next_try;
- };
- };
-
- /*
- ** Return addresses to the driver
- */
+ for (;;) {
+ data = pcibus->pb_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
+ data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ (void) pcibus->pb_write(tag, PCI_COMMAND_STATUS_REG, data);
+ if ((link = link->pcicb_up) == NULL)
+ break;
+ tag = link->pcicb_bridge;
+ }
*va = vaddr;
*pa = paddr;
return (1);
}
-
-/*-----------------------------------------------------------------------
-**
-** Map new pci bus. (XXX under construction)
-**
-** PCI-Specification: ____________?
-**
-**-----------------------------------------------------------------------
-*/
-int pci_map_bus (pcici_t tag, u_long bus)
-{
- if (bus >= PCI_MAX_BUS) {
- printf ("pci_map_bus failed: bus number %d too big.\n",
- (int) bus);
- return (0);
- };
-
- if (bus >= pci_bus_max)
- pci_bus_max = bus + 1;
-
-#ifndef PCI_QUIET
- /*
- ** display values.
- */
-
- printf ("\tmapped pci bus %d.\n",
- (int) bus);
-#endif
-
- return (1);
-}
-
/*------------------------------------------------------------
**
** Interface functions for the devconf module.
@@ -795,12 +1085,12 @@ pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l)
return ENOMEM;
};
- tag = pcibus.pb_tag (pip->pi_bus, pip->pi_device, 0);
+ tag = pcibus->pb_tag (pip->pi_bus, pip->pi_device, 0);
buffer.peb_pci_info = *pip;
for (i=0; i<PCI_EXT_CONF_LEN; i++) {
- buffer.peb_config[i] = pcibus.pb_read (tag, i*4);
+ buffer.peb_config[i] = pcibus->pb_read (tag, i*4);
};
return copyout(&buffer, u, sizeof buffer);
@@ -812,36 +1102,354 @@ pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s)
{
return EOPNOTSUPP;
}
-
+
+/*-----------------------------------------------------------------------
+**
+** Pci meta interrupt handler
+**
+** This handler assumes level triggered interrupts.
+** It's possible to build a kernel which handles shared
+** edge triggered interrupts by the options "PCI_EDGE_INT".
+** But there is a performance penalty.
+**
+** (Of course you can delete the #ifdef PCI_EDGE_INT bracketed
+** code at all :-) :-) :-)
+**
+**-----------------------------------------------------------------------
+*/
+
+struct pci_int_desc*
+ pci_int_desc [PCI_MAX_IRQ];
+
+#ifndef NO_SHARED_IRQ
+
+static inline unsigned
+splq (unsigned mask)
+{
+ unsigned temp=cpl;
+ cpl |= mask;
+ return temp;
+}
+
+static void
+pci_int (int irq)
+{
+ struct pci_int_desc * p;
+ int c, s;
+#ifdef PCI_EDGE_INT
+ int i, n;
+#endif
+ if (irq<0 || irq >= PCI_MAX_IRQ) {
+ printf ("pci_int(%d)\n", irq);
+ return;
+ };
+
+#ifdef PCI_EDGE_INT
+ for (i=0; i<1000; i++) {
+ n = 0;
+#endif
+ for (p = pci_int_desc[irq]; p!=NULL; p=p->pcid_next) {
+ s = splq (*p->pcid_maskptr);
+ c= (*p->pcid_handler) (p->pcid_argument);
+ p-> pcid_tally += c;
+ splx (s);
+#ifdef PCI_EDGE_INT
+ n += c;
+#endif
+#if 0
+ if (c && p->pcid_tally<20)
+ printf ("PCI_INT: irq=%d h=%p cpl o=%x n=%x val=%d\n",
+ irq, p->pcid_handler, s, cpl, c);
+#endif
+ };
+#ifdef PCI_EDGE_INT
+ if (!n) return;
+ };
+ printf ("pci_int(%d): permanent interrupt request.\n", irq);
+#endif
+}
+#endif
+
/*-----------------------------------------------------------------------
**
-** Map pci interrupts to isa interrupts.
+** Auxiliary function for interrupt (un)mapping.
**
**-----------------------------------------------------------------------
*/
+static u_int
+getirq (pcici_t tag)
+{
+ u_int irq;
+
+ irq = PCI_INTERRUPT_LINE_EXTRACT(
+ pcibus->pb_read (tag, PCI_INTERRUPT_REG));
+
+ if (irq <= 0) {
+ printf ("\tint line register not set by bios\n");
+ return (0);
+ }
+
+ if (irq >= pcibus->pb_maxirq || irq >= PCI_MAX_IRQ) {
+ printf ("\tirq %d invalid.\n", irq);
+ return (0);
+ }
+
+ return (irq);
+}
+
+static struct pci_int_desc **
+getintdescbytag (u_int irq, pcici_t tag)
+{
+ struct pci_int_desc *p, **pp;
+
+ pp=&pci_int_desc[irq];
+ while (((p=*pp)) && !sametag(p->pcid_tag,tag))
+ pp=&p->pcid_next;
+
+ if (!p) return (NULL);
+
+ return (pp);
+}
+
+static struct pci_int_desc *
+getintdescbymptr (u_int irq, unsigned * mptr)
+{
+ struct pci_int_desc *p;
+
+ for (p=pci_int_desc[irq];p;p=p->pcid_next)
+ if (p->pcid_maskptr == mptr) break;
+ return (p);
+}
+
+/*-----------------------------------------------------------------------
+**
+** Map pci interrupt.
+**
+**-----------------------------------------------------------------------
+*/
+
+static unsigned pci_mask0 = 0;
+
int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr)
{
- int irq, result;
+ u_int irq;
+ int result, oldspl;
+ unsigned mask;
+ struct pci_int_desc *tail, *mdp=NULL, *new=NULL;
- irq = PCI_INTERRUPT_LINE_EXTRACT(
- pcibus.pb_read (tag, PCI_INTERRUPT_REG));
+ /*
+ ** Get irq line from configuration space,
+ ** and check for consistency.
+ */
- if (irq >= 16 || irq <= 0) {
- printf ("pci_map_int failed: no int line set.\n");
+ irq = getirq (tag);
+ if (irq >= PCI_MAX_IRQ) {
+ printf ("\tillegal irq %d.\n", irq);
return (0);
- }
+ };
+ mask= 1ul << irq;
+
+ /*
+ ** disable this interrupt.
+ */
+
+ oldspl = splq (mask);
+
+ /*
+ ** If handler for this tag already installed,
+ ** remove it first.
+ */
+
+ if (getintdescbytag (irq, tag) != NULL)
+ pci_unmap_int (tag);
+
+ /*
+ ** If this irq not yet included in the mask, include it.
+ */
+
+ mdp = getintdescbymptr (irq, maskptr);
+ if (!mdp) {
+ result = pcibus->pb_imaskinc (irq, maskptr);
+ if (result)
+ goto conflict;
+ };
+
+ /*
+ ** Allocate descriptor and initialize it.
+ */
+
+ tail = pci_int_desc[irq];
+
+ new = malloc (sizeof (*new), M_DEVBUF, M_WAITOK);
+ bzero (new, sizeof (*new));
+
+ new->pcid_next = tail;
+ new->pcid_tag = tag;
+ new->pcid_handler = func;
+ new->pcid_argument = arg;
+ new->pcid_maskptr = maskptr;
+ new->pcid_tally = 0;
+ new->pcid_mask = mask;
+
+ /*
+ ** If first handler: install it.
+ ** If second handler: install shared-int-handler.
+ */
+
+ if (!tail) {
+ /*
+ ** first handler for this irq.
+ */
+
+ result = pcibus->pb_iattach
+ (irq, (void(*)()) func, (int) arg, maskptr);
+ if (result) goto conflict;
+
+#ifdef NO_SHARED_IRQ
+ } else goto conflict;
+#else
+ } else if (!tail->pcid_next) {
+ /*
+ ** Second handler for this irq.
+ */
+
+ printf ("\tusing shared irq %d.\n", irq);
+
+ /*
+ ** replace old handler by shared-int-handler.
+ */
+
+ result = pcibus->pb_idetach (irq,(void(*)())tail->pcid_handler);
+ if (result)
+ printf ("\tCANNOT DETACH INT HANDLER.\n");
+
+ result = pcibus->pb_iattach (irq, pci_int, irq, &pci_mask0);
+ if (result) {
+ printf ("\tCANNOT ATTACH SHARED INT HANDLER.\n");
+ goto fail;
+ };
+ }
+#endif
+ /*
+ ** Link new descriptor, reenable ints and done.
+ */
+
+ pci_int_desc[irq] = new;
+ splx (oldspl);
+ return (1);
+
+ /*
+ ** Handle some problems.
+ */
+
+conflict:
+ printf ("\tirq %d already in use.\n", irq);
+fail:
+ /*
+ ** If descriptor allocated, free it.
+ ** If included in mask, remove it.
+ */
+
+ if (free) free (new, M_DEVBUF);
+ if (!mdp) (void) pcibus->pb_imaskexc (irq, maskptr);
+ splx (oldspl);
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+**
+** Unmap pci interrupt.
+**
+**-----------------------------------------------------------------------
+*/
+
+int pci_unmap_int (pcici_t tag)
+{
+ int result, oldspl;
+ struct pci_int_desc *this, **hook, *tail;
+ unsigned irq;
+
+ /*
+ ** Get irq line from configuration space,
+ ** and check for consistency.
+ */
+
+ irq = getirq (tag);
+ if (irq >= PCI_MAX_IRQ) {
+ printf ("\tillegal irq %d.\n", irq);
+ return (0);
+ };
- result = pcibus.pb_regint (tag, func, arg, maskptr);
+ /*
+ ** Search and unlink interrupt descriptor.
+ */
- if (!result) {
- printf ("pci_map_int failed.\n");
+ hook = getintdescbytag (irq, tag);
+ if (hook == NULL) {
+ printf ("\tno irq %d handler for pci %x\n",
+ irq, tag.tag);
return (0);
};
+ this = *hook;
+ *hook= this->pcid_next;
+
+ /*
+ ** Message
+ */
+
+ printf ("\tirq %d handler %p(%p) unmapped for pci %x after %d ints.\n",
+ irq, this->pcid_handler, this->pcid_argument,
+ this->pcid_tag.tag, this->pcid_tally);
+
+ /*
+ ** If this irq no longer included in the mask, remove it.
+ */
+
+ if (!getintdescbymptr (irq, this->pcid_maskptr))
+ (void) pcibus->pb_imaskexc (irq, this->pcid_maskptr);
+
+ tail = pci_int_desc[irq];
+
+ if (tail == NULL) {
+
+ /*
+ ** Remove the old handler.
+ */
+
+ result = pcibus->pb_idetach (irq,(void(*)())this->pcid_handler);
+ if (result)
+ printf ("\tirq %d: cannot remove handler.\n", irq);
+
+ } else if (tail->pcid_next == NULL) {
+
+ /*
+ ** Remove the shared int handler.
+ ** Install the last remaining handler.
+ */
+
+ oldspl = splq (1ul << irq);
+
+ result = pcibus->pb_idetach (irq, pci_int);
+ if (result)
+ printf ("\tirq %d: cannot remove handler.\n", irq);
+
+ result = pcibus->pb_iattach (irq,
+ (void(*)()) tail->pcid_handler,
+ (int) tail->pcid_argument,
+ tail->pcid_maskptr);
+
+ if (result)
+ printf ("\tirq %d: cannot install handler.\n", irq);
+
+ splx (oldspl);
+ };
+
+ free (this, M_DEVBUF);
return (1);
}
-
+
/*-----------------------------------------------------------
**
** Display of unknown devices.
@@ -868,7 +1476,7 @@ static const char *const majclasses[] = {
"old", "storage", "network", "display",
"multimedia", "memory", "bridge"
};
-
+
void not_supported (pcici_t tag, u_long type)
{
u_char reg;
@@ -892,15 +1500,15 @@ void not_supported (pcici_t tag, u_long type)
printf (", device=0x%lx", type >> 16);
- data = (pcibus.pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
+ data = (pcibus->pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
if (data < sizeof(majclasses) / sizeof(majclasses[0]))
printf(", class=%s", majclasses[data]);
printf (" [not supported]\n");
for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
- data = pcibus.pb_read (tag, reg);
- if (!data) continue;
+ data = pcibus->pb_read (tag, reg);
+ if ((data&~7)==0) continue;
switch (data&7) {
case 1:
@@ -923,89 +1531,4 @@ void not_supported (pcici_t tag, u_long type)
}
}
}
-
-#ifndef __FreeBSD2__
-/*-----------------------------------------------------------
-**
-** Mapping of physical to virtual memory
-**
-**-----------------------------------------------------------
-*/
-
-extern vm_map_t kernel_map;
-
-static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize)
-{
- vm_offset_t vaddr,value;
- u_long result;
-
- vaddr = vm_map_min (kernel_map);
-
- result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
- &vaddr, vsize, TRUE);
-
- if (result != KERN_SUCCESS) {
- printf (" vm_map_find failed(%d)\n", result);
- return (0);
- };
-
- /*
- ** map physical
- */
-
- value = vaddr;
- while (vsize >= NBPG) {
- pmap_enter (pmap_kernel(), vaddr, paddr,
- VM_PROT_READ|VM_PROT_WRITE, TRUE);
- vaddr += NBPG;
- paddr += NBPG;
- vsize -= NBPG;
- };
- return (value);
-}
-
-/*------------------------------------------------------------
-**
-** Emulate the register_intr() function of FreeBSD 2.0
-**
-** requires a patch:
-** FreeBSD 2.0: "/sys/i386/isa/vector.s"
-** 386bsd0.1: "/sys/i386/isa/icu.s"
-** 386bsd1.0: Please ask Jesus Monroy Jr.
-**
-**------------------------------------------------------------
-*/
-
-#include <machine/segments.h>
-
-int pci_int_unit [16];
-inthand2_t* (pci_int_hdlr [16]);
-unsigned int * pci_int_mptr [16];
-unsigned int pci_int_count[16];
-
-extern void
- Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(),
- Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15();
-
-static inthand_t* pci_int_glue[16] = {
- 0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8,
- Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 };
-
-static int
-register_intr __P((int intr, int device_id, unsigned int flags,
- inthand2_t *handler, unsigned int* mptr, int unit))
-{
- if (intr >= 16 || intr <= 2)
- return (EINVAL);
- if (pci_int_hdlr [intr])
- return (EBUSY);
-
- pci_int_hdlr [intr] = handler;
- pci_int_unit [intr] = unit;
- pci_int_mptr [intr] = mptr;
-
- setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL);
- return (0);
-}
-#endif /* __FreeBSD2__ */
#endif /* NPCI */
diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h
index 1f687f1..a1fbcdf 100644
--- a/sys/dev/pci/pcireg.h
+++ b/sys/dev/pci/pcireg.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** $Id: pcireg.h,v 1.3 1995/02/02 13:12:18 davidg Exp $
+** $Id: pcireg.h,v 1.4 1995/02/02 22:01:40 se Exp $
**
** Names for PCI configuration space registers.
**
@@ -33,8 +33,7 @@
*/
#ifndef __PCI_REG_H__
-#define __PCI_REG_H__
-
+#define __PCI_REG_H__ "pl2 95/03/21"
/*
** Device identification register; contains a vendor ID and a device ID.
@@ -146,6 +145,32 @@
#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0
#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc
+/*
+** PCI-PCI bridge mapping registers
+*/
+#define PCI_PCI_BRIDGE_BUS_REG 0x18
+#define PCI_PCI_BRIDGE_IO_REG 0x1c
+#define PCI_PCI_BRIDGE_MEM_REG 0x20
+#define PCI_PCI_BRIDGE_PMEM_REG 0x24
+
+
+#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000
+#define PCI_SECONDARY_BUS_MASK 0x0000ff00
+#define PCI_PRIMARY_BUS_MASK 0x000000ff
+
+#define PCI_SUBORDINATE_BUS_EXTRACT(x) (((x) > 16) & 0xff)
+#define PCI_SECONDARY_BUS_EXTRACT(x) (((x) > 8) & 0xff)
+#define PCI_PRIMARY_BUS_EXTRACT(x) (((x) ) & 0xff)
+
+#define PCI_PRIMARY_BUS_INSERT(x, y) (((x) & ~PCI_PRIMARY_BUS_MASK) | ((y) << 0))
+#define PCI_SECONDARY_BUS_INSERT(x, y) (((x) & ~PCI_SECONDARY_BUS_MASK) | ((y) << 8))
+#define PCI_SUBORDINATE_BUS_INSERT(x, y) (((x) & ~PCI_SUBORDINATE_BUS_MASK) | ((y) << 16))
+
+#define PCI_PPB_IOBASE_EXTRACT(x) (((x) << 8) & 0xFF00)
+#define PCI_PPB_IOLIMIT_EXTRACT(x) (((x) << 0) & 0xFF00)
+
+#define PCI_PPB_MEMBASE_EXTRACT(x) (((x) << 16) & 0xFFFF0000)
+#define PCI_PPB_MEMLIMIT_EXTRACT(x) (((x) << 0) & 0xFFFF0000)
/*
** Interrupt configuration register
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 4e62dbf..23bc8ae 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -1,10 +1,10 @@
/**************************************************************************
**
-** $Id: pcivar.h,v 1.2 1995/02/27 17:17:14 se Exp $
+** $Id: pcivar.h,v 1.3 1995/03/17 04:27:21 davidg Exp $
**
** Declarations for pci device drivers.
**
-** 386bsd / FreeBSD
+** FreeBSD
**
**-------------------------------------------------------------------------
**
@@ -36,10 +36,8 @@
*/
#ifndef __PCI_VAR_H__
-#define __PCI_VAR_H__
+#define __PCI_VAR_H__ "pl2 95/03/21"
-#define PCIVAR_H_PATCHLEVEL "pl1 95/02/27"
-
/*-----------------------------------------------------------------
**
** main pci initialization function.
@@ -60,13 +58,16 @@ void pci_configure (void);
typedef union {
u_long cfg1;
- struct {
+ struct {
u_char enable;
u_char forward;
u_short port;
} cfg2;
+ unsigned tag;
} pcici_t;
+#define sametag(x,y) ((x).tag == (y).tag)
+
/*-----------------------------------------------------------------
**
** Each pci device has an unique device id.
@@ -98,7 +99,7 @@ typedef u_long pcidi_t;
u_long pci_conf_read (pcici_t tag, u_long reg );
void pci_conf_write (pcici_t tag, u_long reg, u_long data);
-
+
/*-----------------------------------------------------------------
**
** The pci driver structure.
@@ -141,7 +142,11 @@ struct pci_device {
*/
extern struct linker_set pcidevice_set;
-
+
+extern unsigned pci_max_burst_len; /* log2 of safe burst transfer length */
+extern unsigned pci_mechanism;
+extern unsigned pci_maxdevice;
+
/*-----------------------------------------------------------------
**
** The pci-devconf interface.
@@ -150,8 +155,8 @@ extern struct linker_set pcidevice_set;
*/
struct pci_info {
- u_short pi_bus;
- u_short pi_device;
+ u_short pi_bus;
+ u_short pi_device;
};
#define PCI_EXT_CONF_LEN (16)
@@ -162,31 +167,18 @@ struct pci_externalize_buffer {
u_long peb_config[PCI_EXT_CONF_LEN];
};
-
-/*-----------------------------------------------------------------
-**
-** Register an additional pci bus for probing.
-** Called by pci-pci bridge handlers.
-**
-**-----------------------------------------------------------------
-*/
-
-int pci_map_bus (pcici_t tag, u_long bus);
-
/*-----------------------------------------------------------------
**
** Map a pci device to physical and virtual memory.
**
-** The va and pa addresses are "in/out" parameters.
-** If they are 0 on entry, the function assigns an address.
-**
-** Entry selects the register in the pci configuration
+** Entry selects the register in the pci configuration
** space, which supplies the size of the region, and
** receives the physical address.
**
-** If there is any error, a message is written, and
-** the function returns with zero.
-** Else it returns with a value different to zero.
+** In case of success the function sets the addresses
+** in *va and *pa, and returns 1.
+** In case of errors a message is written,
+** and the function returns 0.
**
**-----------------------------------------------------------------
*/
@@ -197,59 +189,65 @@ int pci_map_mem (pcici_t tag, u_long entry, u_long * va, u_long * pa);
**
** Map a pci device to an io port area.
**
-** *pa is an "in/out" parameter.
-** If it's 0 on entry, the function assigns an port number..
-**
** Entry selects the register in the pci configuration
** space, which supplies the size of the region, and
** receives the port number.
**
-** If there is any error, a message is written, and
-** the function returns with zero.
-** Else it returns with a value different to zero.
+** In case of success the function sets the port number in pa,
+** and returns 1.
+** In case of errors a message is written,
+** and the function returns 0.
**
**-----------------------------------------------------------------
*/
-int pci_map_port(pcici_t tag, u_long entry, u_short * pa);
-
+int pci_map_port (pcici_t tag, u_long entry, u_short * pa);
+
/*-----------------------------------------------------------------
**
-** Map a pci interrupt to an isa irq line,
-** and enable the interrupt.
+** Map a pci interrupt to an isa irq line, and enable the interrupt.
**
-** func is the interrupt handler, arg is the argument
-** to this function.
+** -----------------
**
-** The maskptr argument should be &bio_imask,
-** &net_imask etc. or NULL.
+** func is the interrupt handler, arg is the argument
+** to the handler (usually a pointer to a softc).
**
-** If there is any error, a message is written, and
-** the function returns with zero.
-** Else it returns with a value different to zero.
+** The maskptr argument should be &bio_imask,
+** &net_imask etc. or NULL.
**
-** A word of caution for FreeBSD 2.0:
+** If there is any error, a message is written, and
+** the function returns with zero.
+** Else it returns with a value different to zero.
**
-** We use the register_intr() function.
+** -----------------
**
-** The interrupt line of the selected device is included
-** into the supplied mask: after the corresponding splXXX
-** this drivers interrupts are blocked.
+** The irq number is read from the configuration space.
+** (Should have been set by the bios).
**
-** But in the interrupt handlers startup code ONLY
-** the interrupt of the driver is blocked, and NOT
-** all interrupts of the spl group.
+** Supports multiple handlers per irq (shared interrupts).
**
-** It may be required to additional block the group
-** interrupts by splXXX() inside the interrupt handler.
+** -----------------
**
-** In pre 2.0 kernels we emulate the register_intr
-** function. The emulating function blocks all interrupts
-** of the group in the interrupt handler prefix code.
+** There is code to support shared edge triggered ints.
+** This relies on the cooperation of the interrupt handlers:
+** they have to return a value <>0 if and only if something
+** was done. Beware of the performance penalty.
**
**-----------------------------------------------------------------
*/
+struct pci_int_desc {
+ struct pci_int_desc * pcid_next;
+ pcici_t pcid_tag;
+ int (*pcid_handler)();
+ void* pcid_argument;
+ unsigned * pcid_maskptr;
+ unsigned pcid_tally;
+ unsigned pcid_mask;
+};
+
int pci_map_int (pcici_t tag, int (*func)(), void* arg, unsigned * maskptr);
+int pci_unmap_int (pcici_t tag);
+
#endif
diff --git a/sys/pci/pci.c b/sys/pci/pci.c
index aa51596..32428c6 100644
--- a/sys/pci/pci.c
+++ b/sys/pci/pci.c
@@ -1,11 +1,11 @@
/**************************************************************************
**
-** $Id: pci.c,v 1.18 1995/03/02 21:51:53 se Exp $
+** $Id: pci.c,v 1.19 1995/03/17 04:27:19 davidg Exp $
**
-** General subroutines for the PCI bus on 80*86 systems.
+** General subroutines for the PCI bus.
** pci_configure ()
**
-** 386bsd / FreeBSD
+** FreeBSD
**
**-------------------------------------------------------------------------
**
@@ -36,17 +36,11 @@
***************************************************************************
*/
-#define PCI_PATCHLEVEL "pl5 95/02/27"
+#define __PCI_C__ "pl13 95/03/21"
#include <pci.h>
#if NPCI > 0
-#ifndef __FreeBSD2__
-#if __FreeBSD__ >= 2
-#define __FreeBSD2__
-#endif
-#endif
-
/*========================================================
**
** #includes and declarations
@@ -59,199 +53,334 @@
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/kernel.h>
+#include <sys/proc.h> /* declaration of wakeup(), used by vm.h */
+#include <sys/devconf.h>
+
+#include <machine/cpu.h> /* bootverbose */
#include <vm/vm.h>
#include <vm/vm_param.h>
+#include <pci/pcivar.h>
+#include <pci/pcireg.h>
+#include <pci/pcibus.h>
+
#include <machine/pmap.h>
-#ifdef __FreeBSD2__
#include <sys/devconf.h>
+#define PCI_MAX_IRQ (16)
+
+
+/*========================================================
+**
+** Structs and Functions
+**
+**========================================================
+*/
+
struct pci_devconf {
struct kern_devconf pdc_kdc;
struct pci_info pdc_pi;
};
+struct pcicb {
+ struct pcicb *pcicb_next;
+ struct pcicb *pcicb_up;
+ struct pcicb *pcicb_down;
+ pcici_t pcicb_bridge;
+
+ u_long pcicb_seen;
+ u_char pcicb_bus;
+ u_char pcicb_subordinate;
+ u_char pcicb_flags;
+#define PCICB_ISAMEM 0x01
+ u_int pcicb_mfrom;
+ u_int pcicb_mupto;
+ u_int pcicb_mamount;
+ u_short pcicb_pfrom;
+ u_short pcicb_pupto;
+ u_short pcicb_pamount;
+ u_char pcicb_bfrom;
+ u_char pcicb_bupto;
+
+ u_long pcicb_iobase;
+ u_long pcicb_iolimit;
+ u_long pcicb_membase;
+ u_long pcicb_memlimit;
+ u_long pcicb_p_membase;
+ u_long pcicb_p_memlimit;
+};
+
static int
pci_externalize (struct proc *, struct kern_devconf *, void *, size_t);
static int
pci_internalize (struct proc *, struct kern_devconf *, void *, size_t);
-#else /* __FreeBSD2__ */
-
-/*
-** Function prototypes missing in system headers
-*/
-extern pmap_t pmap_kernel(void);
-static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize);
-#endif /* __FreeBSD2__ */
+static void
+not_supported (pcici_t tag, u_long type);
-#include <pci/pcivar.h>
-#include <pci/pcireg.h>
-#include <pci/pcibus.h>
+static void
+pci_bus_config (void);
+static void
+pci_bridge_config (void);
-
/*========================================================
**
-** Autoconfiguration of pci devices.
-**
-** This is reverse to the isa configuration.
-** (1) find a pci device.
-** (2) look for a driver.
+** Variables
**
**========================================================
*/
+/*
+** log2 of safe burst len (in words)
+*/
+
+unsigned pci_max_burst_len = 2;
+unsigned pci_mechanism = 0;
+unsigned pci_maxdevice = 0;
+struct pcibus* pcibus;
+
/*--------------------------------------------------------
**
-** Limit for pci bus numbers.
+** Local variables.
**
**--------------------------------------------------------
*/
-#ifndef PCI_MAX_BUS
-#define PCI_MAX_BUS (256)
-#endif
-
-static u_long pci_bus_max = 1;
+static int pci_conf_count;
+static int pci_info_done;
+static struct pcicb pcibus0 = {
+ NULL, NULL, NULL,
+ { 0 },
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* real allocation */
+ 0, 0xFFFF, /* iobase/limit */
+ 0x4000000, 0xFFFFFFFFu, /* nonprefetch membase/limit */
+ 0x4000000, 0xFFFFFFFFu /* prefetch membase/limit */
+};
+static struct pcicb *pcicb;
-/*--------------------------------------------------------
+/*========================================================
**
-** The pci devices can be mapped to any address.
-** This is a list of possible starting addresses.
-** It can be prepended by a config option.
+** pci_configure ()
**
-**--------------------------------------------------------
+** Autoconfiguration of pci devices.
+**
+** May be called more than once.
+** Any device is attached only once.
+**
+** Has to take care of mirrored devices, which are
+** entailed by incomplete decoding of pci address lines.
+**
+**========================================================
*/
-static u_long pci_stable[] = {
-#ifdef PCI_PMEM_START
- (PCI_PMEM_START),
-#endif
- 0xf1000000,
- 0x53900000,
- 0xc0000000,
- 0x81000000,
- 0x0f000000,
-};
+void pci_configure()
+{
+ int i;
-static vm_offset_t pci_paddr = 0;
-static vm_offset_t pci_pold = 0;
-static vm_offset_t pci_pidx = 0;
+ /*
+ ** check pci bus present
+ */
+ for (i=0; i<pcibus_set.ls_length; i++) {
+ if (pci_maxdevice) break;
+ pcibus = (struct pcibus*) pcibus_set.ls_items[i];
+ pcibus->pb_setup ();
+ }
+ if (!pci_maxdevice) return;
-/*--------------------------------------------------------
+ /*
+ ** hello world ..
+ */
+
+ for (pcicb = &pcibus0; pcicb != NULL;) {
+ pci_bus_config ();
+
+ if (pcicb->pcicb_down) {
+ pcicb = pcicb->pcicb_down;
+ continue;
+ };
+
+ while (pcicb && !pcicb->pcicb_next)
+ pcicb = pcicb->pcicb_up;
+
+ if (pcicb)
+ pcicb = pcicb->pcicb_next;
+ }
+ pci_conf_count++;
+}
+
+/*========================================================
**
-** The pci ports can be mapped to any address.
-** As default we start at 0x400
+** Subroutines for configuration.
**
-**--------------------------------------------------------
+**========================================================
*/
-#ifndef PCI_PORT_START
-#define PCI_PORT_START 0xbc00
+static void
+pci_register_io (struct pcicb * cb, u_int base, u_int limit)
+{
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("register_io: bus=%d base=%x limit=%x\n",
+ cb->pcicb_bus, base, limit);
#endif
-static u_short pci_ioaddr = PCI_PORT_START;
+ if (!cb->pcicb_pfrom || base < cb->pcicb_pfrom)
+ cb->pcicb_pfrom = base;
+ if (limit > cb->pcicb_pupto)
+ cb->pcicb_pupto = limit;
-/*--------------------------------------------------------
-**
-** The pci device interrupt lines should have been
-** assigned by the bios. But if the bios failed to
-** to it, we set it.
-**
-**--------------------------------------------------------
-*/
+ /*
+ ** XXX should set bridge io mapping here
+ ** but it can be mapped in 4k blocks only,
+ ** leading to conflicts with isa/eisa ..
+ */
+}
-#ifndef PCI_IRQ
-#define PCI_IRQ 0
+static void
+pci_register_memory (struct pcicb * cb, u_int base, u_int limit)
+{
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("register_mem: bus=%d base=%x limit=%x\n",
+ cb->pcicb_bus, base, limit);
#endif
-static u_long pci_irq = PCI_IRQ;
-
-/*---------------------------------------------------------
-**
-** pci_configure ()
-**
-** Probe all devices on pci bus and attach them.
-**
-** May be called more than once.
-** Any device is attached only once.
-** (Attached devices are remembered in pci_seen.)
-** Has to take care of mirrored devices, which are
-** entailed by incomplete decoding of pci address lines.
-**
-**---------------------------------------------------------
+ if (!cb->pcicb_mfrom || base < cb->pcicb_mfrom)
+ cb->pcicb_mfrom = base;
+ if (limit > cb->pcicb_mupto)
+ cb->pcicb_mupto = limit;
+ /*
+ ** set the bridges mapping
+ **
+ ** XXX should handle the 1Mb granularity.
+ */
+ if (cb->pcicb_bridge.tag) {
+ pci_conf_write(cb->pcicb_bridge,
+ PCI_PCI_BRIDGE_MEM_REG,
+ (cb->pcicb_memlimit & 0xffff0000) |
+ (cb->pcicb_membase >> 16));
+ printf ("\t[pci%d uses memory from %x to %x]\n",
+ cb->pcicb_bus,
+ (unsigned) cb->pcicb_membase,
+ (unsigned) cb->pcicb_memlimit);
+ }
+}
+
+/*
+** XXX This function is neither complete nor tested.
+** It's only used if the bios hasn't done it's job
+** of mapping the pci devices in the physical memory.
*/
-static void not_supported (pcici_t tag, u_long type);
+static u_int
+pci_memalloc (struct pcicb * cb, u_int addr, u_int size)
+{
+ u_int result = 0, limit=0, newbase=0;
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("memalloc: bus=%d addr=%x size=%x ..\n",
+ cb->pcicb_bus, addr, size);
+#endif
-static unsigned long pci_seen[PCI_MAX_BUS];
+ if (!cb) goto done;
-static int pci_conf_count;
-static int pci_info_done;
+ if (!cb->pcicb_membase) {
+ printf ("memalloc: bus%d: membase not set.\n",
+ cb->pcicb_bus);
+ goto done;
+ }
-void pci_configure()
-{
- u_char device,max_device;
- u_short bus;
- pcici_t tag;
- pcidi_t type, type8, type16;
- u_long data;
- int unit;
- int pci_mechanism;
- int pciint;
- int irq;
- char* name=0;
- u_short old_ioaddr=pci_ioaddr;
-
- int dvi;
- struct pci_device *dvp=0;
+ /*
+ ** get upper allocation limit
+ */
+ limit = cb->pcicb_memlimit;
+ if (cb->pcicb_mfrom && cb->pcicb_mfrom <= limit)
+ limit = cb->pcicb_mfrom-1;
-#ifdef __FreeBSD2__
- struct pci_devconf *pdcp;
-#endif
+ /*
+ ** address fixed, and impossible to allocate ?
+ */
+ if (addr && addr+size-1 > limit)
+ goto done;
/*
- ** first check pci bus driver available
+ ** get possible address
*/
- if (pcibus_set.ls_length <= 0)
- return;
+ result = addr;
+ if (!result) result = ((limit + 1) / size - 1) * size;
-#define pcibus (*((struct pcibus*) pcibus_set.ls_items[0]))
/*
- ** check pci bus present
+ ** if not local available, request from parent.
*/
- pci_mechanism = pcibus.pb_mode ();
- if (!pci_mechanism) return;
- max_device = pci_mechanism==1 ? 32 : 16;
+ if (result < cb->pcicb_membase) {
+ newbase = pci_memalloc (cb->pcicb_up, result, size);
+ if (newbase) cb->pcicb_membase = result;
+ else result=0;
+ }
+done:
+ if (result)
+ pci_register_memory (cb, result, result+size-1);
+
+#ifdef PCI_BRIDGE_DEBUG
+ printf ("memalloc: bus=%d addr=%x size=%x --> %x (limit=%x).\n",
+ cb->pcicb_bus, addr, size, result, limit);
+#endif
+
+ return (result);
+}
+
+/*========================================================
+**
+** pci_bus_config()
+**
+** Autoconfiguration of one pci bus.
+**
+**========================================================
+*/
+
+static void
+pci_bus_config (void)
+{
+ u_char device;
+ u_char reg;
+ pcici_t tag, mtag;
+ pcidi_t type;
+ u_long data;
+ int unit;
+ int pciint;
+ int irq;
+ char* name=0;
+
+ int dvi;
+ struct pci_device *dvp=0;
+
+ struct pci_devconf *pdcp;
/*
- ** hello world ..
+ ** first initialize the bridge (bus controller chip)
*/
-
- pci_pold=pci_paddr;
- for (bus=0; bus<pci_bus_max; bus++) {
+ pci_bridge_config ();
+
#ifndef PCI_QUIET
- printf ("Probing for devices on the %s%d bus:\n",
- pcibus.pb_name, bus);
- if (!pci_info_done) {
+ printf ("Probing for devices on the %s%d bus:\n",
+ pcibus->pb_name, pcicb->pcicb_bus);
+ if (!pci_info_done) {
pci_info_done=1;
printf ("\tconfiguration mode %d allows %d devices.\n",
- pci_mechanism, max_device);
- };
+ pci_mechanism, pci_maxdevice);
+ };
#endif
- for (device=0; device<max_device; device ++) {
+ for (device=0; device<pci_maxdevice; device ++) {
- if (pci_seen[bus] & (1ul << device))
+ if ((pcicb->pcicb_seen >> device) & 1)
continue;
- tag = pcibus.pb_tag (bus, device, 0);
- type = pcibus.pb_read (tag, PCI_ID_REG);
+ tag = pcibus->pb_tag (pcicb->pcicb_bus, device, 0);
+ type = pcibus->pb_read (tag, PCI_ID_REG);
if ((!type) || (type==0xfffffffful)) continue;
@@ -259,7 +388,7 @@ void pci_configure()
** lookup device in ioconfiguration:
*/
- for (dvi=0; dvi<pcidevice_set.ls_length; dvi++) {
+ for (dvi=0; dvi<pcidevice_set.ls_length; dvi++) {
dvp = (struct pci_device*) pcidevice_set.ls_items[dvi];
if ((name=(*dvp->pd_probe)(tag, type)))
break;
@@ -269,36 +398,42 @@ void pci_configure()
/*
** check for mirrored devices.
*/
- if (device & 0x08) {
- pcici_t mtag;
- mtag = pcibus.pb_tag (bus, device & ~0x08, 0);
- type8 = pcibus.pb_read (mtag, PCI_ID_REG);
- } else type8 = 0;
if (device & 0x10) {
- pcici_t mtag;
- mtag = pcibus.pb_tag (bus, device & ~0x10, 0);
- type16 = pcibus.pb_read (mtag, PCI_ID_REG);
- } else type16 = 0;
- if ((type==type8) || (type==type16)) {
+ mtag=pcibus->pb_tag (pcicb->pcicb_bus,
+ (u_char)(device & ~0x10), 0);
+ } else if (device & 0x08) {
+ mtag=pcibus->pb_tag (pcicb->pcicb_bus,
+ (u_char)(device & ~0x08), 0);
+ } else goto real_device;
+
+ if (type!=pcibus->pb_read (mtag, PCI_ID_REG))
+ goto real_device;
+
+ for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4)
+ if (pcibus->pb_read(tag,reg)!=pcibus->pb_read(mtag,reg))
+ goto real_device;
+
#ifndef PCI_QUIET
- if (dvp==NULL) continue;
- printf ("%s? <%s> mirrored on pci%d:%d\n",
- dvp->pd_name, name, bus, device);
+ if (dvp==NULL) continue;
+ printf ("%s? <%s> mirrored on pci%d:%d\n",
+ dvp->pd_name, name, pcicb->pcicb_bus, device);
#endif
- continue;
- };
+ continue;
+
+ real_device:
if (dvp==NULL) {
#ifndef PCI_QUIET
if (pci_conf_count)
continue;
- printf("%s%d:%d: ", pcibus.pb_name, bus, device);
+ printf("%s%d:%d: ", pcibus->pb_name,
+ pcicb->pcicb_bus, device);
not_supported (tag, type);
#endif
continue;
};
-
- pci_seen[bus] |= (1ul << device);
+
+ pcicb->pcicb_seen |= (1ul << device);
/*
** Get and increment the unit.
*/
@@ -315,85 +450,102 @@ void pci_configure()
** Announce this device
*/
- printf ("%s%d <%s>", dvp->pd_name, unit, name);
-
+ printf ("%s%d <%s> rev %d", dvp->pd_name, unit, name,
+ (unsigned) pci_conf_read (tag, PCI_CLASS_REG) & 0xff);
+
/*
** Get the int pin number (pci interrupt number a-d)
** from the pci configuration space.
*/
- data = pcibus.pb_read (tag, PCI_INTERRUPT_REG);
+ data = pcibus->pb_read (tag, PCI_INTERRUPT_REG);
pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
if (pciint) {
- printf (" int %c", 0x60+pciint);
-
- /*
- ** If the interrupt line register is not set,
- ** set it now from PCI_IRQ.
- */
-
- if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) {
-
- irq = pci_irq & 0x0f;
- pci_irq >>= 4;
-
- data = PCI_INTERRUPT_LINE_INSERT(data, irq);
- printf (" (config)");
- pcibus.pb_write (tag, PCI_INTERRUPT_REG, data);
- };
+ printf (" int %c irq ", 0x60+pciint);
irq = PCI_INTERRUPT_LINE_EXTRACT(data);
/*
** If it's zero, the isa irq number is unknown,
- ** and we cannot bind the pci interrupt to isa.
+ ** and we cannot bind the pci interrupt.
*/
if (irq)
- printf (" irq %d", irq);
+ printf ("%d", irq);
else
- printf (" not bound");
+ printf ("??");
};
+ printf (" on pci%d:%d\n", pcicb->pcicb_bus, device);
+
/*
- ** enable memory access
+ ** Read the current mapping,
+ ** and update the pcicb fields.
*/
- data = (pcibus.pb_read (tag, PCI_COMMAND_STATUS_REG)
- & 0xffff) | PCI_COMMAND_MEM_ENABLE;
+ for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) {
+ u_int map, addr, size;
- pcibus.pb_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
+ data = pci_conf_read(tag, PCI_CLASS_REG);
+ switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+ case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+ continue;
+ };
- /*
- ** show pci slot.
- */
+ map = pcibus->pb_read (tag, reg);
+ if (!(map & PCI_MAP_MEMORY_ADDRESS_MASK))
+ continue;
- printf (" on pci%d:%d\n", bus, device);
+ pcibus->pb_write (tag, reg, 0xffffffff);
+ data = pcibus->pb_read (tag, reg);
+ pcibus->pb_write (tag, reg, map);
-#ifdef __FreeBSD2__
+ switch (data & 7) {
- /*
- ** Allocate a devconf structure
- */
+ default:
+ continue;
+ case 1:
+ case 5:
+ size = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ addr = map & PCI_MAP_IO_ADDRESS_MASK;
- pdcp = (struct pci_devconf *)
- malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
+ pci_register_io (pcicb, addr, addr+size-1);
+ pcicb->pcicb_pamount += size;
+ break;
+
+ case 0:
+ case 2:
+ case 4:
+ size = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
+ addr = map & PCI_MAP_MEMORY_ADDRESS_MASK;
+ if (addr >= 0x100000) {
+ pci_register_memory
+ (pcicb, addr, addr+size-1);
+ pcicb->pcicb_mamount += size;
+ } else {
+ pcicb->pcicb_flags |= PCICB_ISAMEM;
+ };
+ break;
+ };
+ if (!bootverbose)
+ continue;
+ printf ("\tmapreg[%02x] type=%d addr=%08x size=%04x.\n",
+ reg, map&7, addr, size);
+ };
/*
- ** Fill in.
- **
- ** Sorry, this is not yet complete.
+ ** Allocate a devconf structure
** We should, and eventually will, set the
** parent pointer to a pci bus devconf structure,
** and arrange to set the state field dynamically.
- **
- ** But I'll go to vacation today, and after all,
- ** wasn't there a new feature freeze on Oct 1.?
*/
- pdcp -> pdc_pi.pi_bus = bus;
+ pdcp = (struct pci_devconf *)
+ malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
+
+ pdcp -> pdc_pi.pi_bus = pcicb->pcicb_bus;
pdcp -> pdc_pi.pi_device = device;
pdcp -> pdc_kdc.kdc_name = dvp->pd_name;
@@ -408,7 +560,6 @@ void pci_configure()
pdcp -> pdc_kdc.kdc_parentdata = &pdcp->pdc_pi;
pdcp -> pdc_kdc.kdc_state = DC_UNKNOWN;
pdcp -> pdc_kdc.kdc_description = name;
- pdcp -> pdc_kdc.kdc_shutdown = dvp->pd_shutdown;
/*
** And register this device
@@ -416,9 +567,6 @@ void pci_configure()
dev_attach (&pdcp->pdc_kdc);
-#endif /* __FreeBSD2__ */
-
-
/*
** attach device
** may produce additional log messages,
@@ -426,20 +574,255 @@ void pci_configure()
*/
(*dvp->pd_attach) (tag, unit);
- };
- };
+ /*
+ ** Special processing of certain classes
+ */
+
+ data = pci_conf_read(tag, PCI_CLASS_REG);
+
+ switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+ struct pcicb *this, **link;
+ unsigned char primary, secondary, subordinate;
+ u_int command;
+
+ case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+
+ /*
+ ** get current configuration of the bridge.
+ */
+ data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG);
+ primary = PCI_PRIMARY_BUS_EXTRACT (data);
+ secondary = PCI_SECONDARY_BUS_EXTRACT(data);
+ subordinate = PCI_SUBORDINATE_BUS_EXTRACT(data);
#ifndef PCI_QUIET
- if (pci_paddr != pci_pold)
- printf ("pci uses physical addresses from 0x%lx to 0x%lx\n",
- (u_long)pci_pold, (u_long)pci_paddr);
- if (pci_ioaddr != old_ioaddr)
- printf ("pci devices use ioports from 0x%x to 0x%x\n",
- (unsigned)PCI_PORT_START, (unsigned)pci_ioaddr);
+ printf ("\tbridge from pci%d to pci%d through %d.\n",
+ primary, secondary, subordinate);
#endif
- pci_conf_count++;
+ /*
+ ** check for uninitialized bridge.
+ */
+ if (secondary == 0 || secondary < primary ||
+ pcicb->pcicb_bus != primary)
+ {
+ printf ("\tINCORRECTLY or NEVER CONFIGURED.\n");
+ /*
+ ** disable this bridge
+ */
+ pcibus->pb_write (tag, PCI_COMMAND_STATUS_REG,
+ 0xffff0000);
+ secondary = 0;
+ subordinate = 0;
+ };
+
+ /*
+ ** allocate bus descriptor for bus behind the bridge
+ */
+ link = &pcicb->pcicb_down;
+ while (*link) link = &(*link)->pcicb_next;
+
+ this = malloc (sizeof (*this), M_DEVBUF, M_WAITOK);
+
+ /*
+ ** Initialize this descriptor so far.
+ ** (the initialization is completed just before
+ ** scanning the bus behind the bridge.
+ */
+ bzero (this, sizeof(*this));
+ this->pcicb_up = pcicb;
+ this->pcicb_bridge = tag;
+ this->pcicb_bus = secondary;
+ this->pcicb_subordinate = subordinate;
+
+ command = pci_conf_read(tag,PCI_COMMAND_STATUS_REG);
+
+ if (command & PCI_COMMAND_IO_ENABLE){
+ /*
+ ** Bridge was configured by the bios.
+ ** Read out the mapped io region.
+ */
+ u_int reg, data, mask;
+
+ reg = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_IO_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_IO_REG, 0xFFFF);
+ data = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_IO_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_IO_REG, reg & 0xffff);
+
+ mask = (0xFF00 ^ (data & 0xFF00)) | 0xFF;
+
+ this->pcicb_iobase =
+ PCI_PPB_IOBASE_EXTRACT (reg);
+ this->pcicb_iolimit =
+ PCI_PPB_IOLIMIT_EXTRACT(reg) | mask;
+
+ /*
+ ** Note the used io space.
+ */
+ pci_register_io (pcicb, this->pcicb_iobase,
+ this->pcicb_iolimit);
+
+ };
+
+ if (command & PCI_COMMAND_MEM_ENABLE) {
+ /*
+ ** Bridge was configured by the bios.
+ ** Read out the mapped memory regions.
+ */
+ u_int reg, data, mask;
+
+ /*
+ ** non prefetchable memory
+ */
+ reg = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_MEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_MEM_REG, 0xFFFFFFFF);
+ data = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_MEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_MEM_REG, reg);
+ mask = (0xFFFF0000 ^ (data & 0xFFFF0000))
+ | 0xFFFF;
+
+ this->pcicb_membase =
+ PCI_PPB_MEMBASE_EXTRACT (reg);
+ this->pcicb_memlimit =
+ PCI_PPB_MEMLIMIT_EXTRACT(reg) | mask;
+
+ /*
+ ** Register used memory space.
+ */
+ pci_register_memory (pcicb,
+ this->pcicb_membase,
+ this->pcicb_memlimit);
+
+ /*
+ ** prefetchable memory
+ */
+ reg = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_PMEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_PMEM_REG, 0xFFFFFFFF);
+ data = pci_conf_read (tag,
+ PCI_PCI_BRIDGE_PMEM_REG);
+ pci_conf_write(tag,
+ PCI_PCI_BRIDGE_PMEM_REG, reg);
+
+ mask = (0xFFFF0000 ^ (data & 0xFFFF0000))
+ | 0xFFFF;
+ this->pcicb_p_membase=
+ PCI_PPB_MEMBASE_EXTRACT (reg);
+ this->pcicb_p_memlimit=
+ PCI_PPB_MEMLIMIT_EXTRACT(reg) | mask;
+
+ /*
+ ** Register used memory space.
+ */
+ pci_register_memory (pcicb,
+ this->pcicb_p_membase,
+ this->pcicb_p_memlimit);
+ }
+
+ /*
+ ** Link it in chain.
+ */
+ *link=this;
+
+ /*
+ ** Update mapping info of parent bus.
+ */
+ if (!pcicb->pcicb_bfrom||secondary< pcicb->pcicb_bfrom)
+ pcicb->pcicb_bfrom = secondary;
+ if (subordinate > pcicb->pcicb_bupto)
+ pcicb->pcicb_bupto = subordinate;
+
+ break;
+ }
+ }
+
+#ifndef PCI_QUIET
+ if (pcicb->pcicb_mamount)
+ printf ("%s%d: uses %d bytes of memory from %x upto %x.\n",
+ pcibus->pb_name, pcicb->pcicb_bus,
+ pcicb->pcicb_mamount,
+ pcicb->pcicb_mfrom, pcicb->pcicb_mupto);
+ if (pcicb->pcicb_pamount)
+ printf ("%s%d: uses %d bytes of I/O space from %x upto %x.\n",
+ pcibus->pb_name, pcicb->pcicb_bus,
+ pcicb->pcicb_pamount,
+ pcicb->pcicb_pfrom, pcicb->pcicb_pupto);
+ if (pcicb->pcicb_bfrom)
+ printf ("%s%d: subordinate busses from %x upto %x.\n",
+ pcibus->pb_name, pcicb->pcicb_bus,
+ pcicb->pcicb_bfrom, pcicb->pcicb_bupto);
+#endif
+}
+
+/*========================================================
+**
+** pci_bridge_config()
+**
+** Configuration of a pci bridge.
+**
+**========================================================
+*/
+
+static void
+pci_bridge_config (void)
+{
+ pcici_t tag;
+ struct pcicb* parent;
+
+ tag = pcicb->pcicb_bridge;
+ if (!tag.tag) return;
+
+ if (!pcicb->pcicb_bus) {
+ u_int data;
+ /*
+ ** Get the lowest available bus number.
+ */
+ pcicb->pcicb_bus = ++pcibus0.pcicb_subordinate;
+
+ /*
+ ** and configure the bridge
+ */
+ data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG);
+ data = PCI_PRIMARY_BUS_INSERT(data, pcicb->pcicb_up->pcicb_bus);
+ data = PCI_SECONDARY_BUS_INSERT(data, pcicb->pcicb_bus);
+ data = PCI_SUBORDINATE_BUS_INSERT(data, pcicb->pcicb_bus);
+ pci_conf_write (tag, PCI_PCI_BRIDGE_BUS_REG, data);
+
+ /*
+ ** Propagate the new upper bus number limit.
+ */
+ for (parent = pcicb->pcicb_up; parent != NULL;
+ parent = parent->pcicb_up)
+ {
+ if (parent->pcicb_subordinate >= pcicb->pcicb_bus)
+ continue;
+ parent->pcicb_subordinate = pcicb->pcicb_bus;
+ if (!parent->pcicb_bridge.tag)
+ continue;
+ data = pci_conf_read
+ (parent->pcicb_bridge, PCI_PCI_BRIDGE_BUS_REG);
+ data = PCI_SUBORDINATE_BUS_INSERT
+ (data, pcicb->pcicb_bus);
+ pci_conf_write (parent->pcicb_bridge,
+ PCI_PCI_BRIDGE_BUS_REG, data);
+ }
+ }
+
+ if (!pcicb->pcicb_membase) {
+ u_int size = 0x100000;
+ pcicb->pcicb_membase = pci_memalloc (pcicb->pcicb_up, 0, size);
+ if (pcicb->pcicb_membase)
+ pcicb->pcicb_memlimit = pcicb->pcicb_membase+size-1;
+ }
}
-
/*-----------------------------------------------------------------
**
** The following functions are provided for the device driver
@@ -461,19 +844,22 @@ void pci_configure()
u_long
pci_conf_read (pcici_t tag, u_long reg)
{
- return (pcibus.pb_read (tag, reg));
+ return (pcibus->pb_read (tag, reg));
}
void
pci_conf_write (pcici_t tag, u_long reg, u_long data)
{
- pcibus.pb_write (tag, reg, data);
+ pcibus->pb_write (tag, reg, data);
}
-
+
/*-----------------------------------------------------------------------
**
** Map device into port space.
**
+** Actually the device should have been mapped by the bios.
+** This function only reads and verifies the value.
+**
** PCI-Specification: 6.2.5.1: address maps
**
**-----------------------------------------------------------------------
@@ -481,8 +867,8 @@ pci_conf_write (pcici_t tag, u_long reg, u_long data)
int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
{
- u_long data,oldmap;
- u_short size, ioaddr;
+ unsigned data, ioaddr, iosize;
+ struct pcicb *link = pcicb;
/*
** sanity check
@@ -490,10 +876,16 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
printf ("pci_map_port failed: bad register=0x%x\n",
- (unsigned)reg);
+ (unsigned)reg);
return (0);
};
+ /*if (pcicb->pcicb_flags & PCICB_NOIOSET) {
+ printf ("pci_map_port failed: pci%d has not been configured for I/O access\n",
+ pcicb->pcicb_bus);
+ return (0);
+ }*/
+
/*
** get size and type of port
**
@@ -502,88 +894,75 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
** n-2 bits are hardwired as 0.
*/
-#ifdef PCI_REMAP
- oldmap = 0;
-#else
- oldmap = pcibus.pb_read (tag, reg) & 0xfffffffc;
- if (oldmap==0xfffffffc) oldmap=0;
-#endif
- pcibus.pb_write (tag, reg, 0xfffffffful);
- data = pcibus.pb_read (tag, reg);
-
- switch (data & 0x03) {
-
- case PCI_MAP_IO:
- break;
-
- default: /* unknown */
- printf ("pci_map_port failed: bad port type=0x%x\n",
- (unsigned) data);
+ ioaddr = pcibus->pb_read (tag, reg) & PCI_MAP_IO_ADDRESS_MASK;
+ if (!ioaddr || ioaddr > 0xfffful) {
+ printf ("pci_map_port failed: not configured by bios.\n");
return (0);
};
- /*
- ** get the size
- */
-
- size = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ pcibus->pb_write (tag, reg, 0xfffffffful);
+ data = pcibus->pb_read (tag, reg);
+ pcibus->pb_write (tag, reg, ioaddr);
- if (!size) return (0);
-
- /*
- ** align physical address to virtual size,
- ** set ioaddr,
- ** and don't forget to increment pci_ioaddr
- */
-
- if (oldmap) {
- ioaddr = oldmap;
- } else {
- if ((data = pci_ioaddr % size))
- pci_ioaddr += size - data;
- ioaddr = pci_ioaddr;
- pci_ioaddr += size;
+ if ((data & 0x03) != PCI_MAP_IO) {
+ printf ("pci_map_port failed: bad port type=0x%x\n",
+ (unsigned) data);
+ return (0);
};
+ iosize = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ if (ioaddr < pcicb->pcicb_iobase
+ || ioaddr + iosize > pcicb->pcicb_iolimit) {
+ printf ("pci_map_port failed: device's iorange 0x%x-0x%x "
+ "is incompatible with its bridge's range 0x%x-0x%x\n",
+ (unsigned) ioaddr, (unsigned) ioaddr + iosize - 1,
+ (unsigned) pcicb->pcicb_iobase,
+ (unsigned) pcicb->pcicb_iolimit);
+ return (0);
+ }
#ifndef PCI_QUIET
- /*
- ** display values.
- */
-
printf ("\treg%d: ioaddr=0x%x size=0x%x\n",
- (unsigned) reg, (unsigned) ioaddr, (unsigned) size);
+ (unsigned) reg, (unsigned) ioaddr, (unsigned) iosize);
#endif
-
/*
- ** set device address
+ ** set the configuration register of and
+ ** return the address to the driver.
+ ** Make sure to enable each upstream bridge
+ ** so I/O and DMA can go all the way.
*/
- pcibus.pb_write (tag, reg, (u_long) ioaddr);
-
- /*
- ** return them to the driver
- */
+ for (;;) {
+ data = pcibus->pb_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
+ data |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ (void) pcibus->pb_write(tag, PCI_COMMAND_STATUS_REG, data);
+ if ((link = link->pcicb_up) == NULL)
+ break;
+ tag = link->pcicb_bridge;
+ }
- *pa = pci_ioaddr;
+ *pa = ioaddr;
return (1);
}
-
+
/*-----------------------------------------------------------------------
**
** Map device into virtual and physical space
**
-** PCI-Specification: 6.2.5.1: address maps
+** Actually the device should have been mapped by the bios.
+** This function only reads and verifies the value.
+**
+** PCI-Specification: 6.2.5.1: address maps
**
**-----------------------------------------------------------------------
*/
int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
{
- u_long data,oldmap,paddr;
- vm_size_t vsize;
+ struct pcicb *link = pcicb;
+ unsigned data ,paddr;
+ vm_size_t psize, poffs;
vm_offset_t vaddr;
- int i;
/*
** sanity check
@@ -591,7 +970,7 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
printf ("pci_map_mem failed: bad register=0x%x\n",
- (unsigned)reg);
+ (unsigned)reg);
return (0);
};
@@ -603,179 +982,90 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
** n-4 bits are read as 0.
*/
-#ifdef PCI_REMAP
- oldmap = 0;
-#else
- oldmap = pcibus.pb_read (tag, reg) & 0xfffffff0;
- if (oldmap==0xfffffff0) oldmap = 0;
-#endif
- pcibus.pb_write (tag, reg, 0xfffffffful);
- data = pcibus.pb_read (tag, reg);
+ paddr = pcibus->pb_read (tag, reg) & PCI_MAP_MEMORY_ADDRESS_MASK;
+ pcibus->pb_write (tag, reg, 0xfffffffful);
+ data = pcibus->pb_read (tag, reg);
+ pcibus->pb_write (tag, reg, paddr);
- switch (data & 0x0f) {
-
- case PCI_MAP_MEMORY_TYPE_32BIT: /* 32 bit non cachable */
- break;
+ /*
+ ** check the type
+ */
- default: /* unknown */
+ if ((data & PCI_MAP_MEMORY_TYPE_MASK) != PCI_MAP_MEMORY_TYPE_32BIT) {
printf ("pci_map_mem failed: bad memory type=0x%x\n",
- (unsigned) data);
+ (unsigned) data);
return (0);
};
-
+
/*
- ** mask out the type,
- ** and round up to a page size
+ ** get the size.
*/
- vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK));
-
- if (!vsize) return (0);
-
- if (oldmap) {
- paddr = oldmap;
- goto domap;
- };
+ psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
-next_try:
- if (!pci_paddr) {
- /*
- ** Get a starting address.
- */
- if (pci_pidx >= sizeof(pci_stable)/sizeof(u_long)) {
- printf ("pci_map_mem: out of start addresses.\n");
+ if (!paddr || paddr == PCI_MAP_MEMORY_ADDRESS_MASK) {
+ paddr = pci_memalloc (pcicb, 0, psize);
+ if (!paddr) {
+ printf ("pci_map_mem: not configured by bios.\n");
return (0);
};
-
- pci_paddr = pci_stable[pci_pidx++];
- pci_pold = 0;
-
- if (pci_pidx>1)
- printf ("\t(retry at 0x%x)\n",
- (unsigned) pci_paddr);
+ pci_register_memory (pcicb, paddr, paddr+psize-1);
};
- /*
- ** align physical address to virtual size
- */
-
- if ((data = pci_paddr % vsize))
- pci_paddr += vsize - data;
- if (!pci_pold)
- pci_pold = pci_paddr;
+ if (paddr < pcicb->pcicb_membase ||
+ paddr + psize - 1 > pcicb->pcicb_memlimit) {
+ printf ("pci_map_mem failed: device's memrange 0x%x-0x%x is "
+ "incompatible with its bridge's memrange 0x%x-0x%x\n",
+ (unsigned) paddr,
+ (unsigned) (paddr + psize - 1),
+ (unsigned) pcicb->pcicb_membase,
+ (unsigned) pcicb->pcicb_memlimit);
+ return (0);
+ }
+ pcibus->pb_write (tag, reg, paddr);
/*
- ** set physical mapping address,
- ** and reserve physical address range
+ ** Truncate paddr to page boundary.
+ ** (Or does pmap_mapdev the job?)
*/
- paddr = pci_paddr;
- pci_paddr += vsize;
-
-domap:
- vaddr = (vm_offset_t) pmap_mapdev (paddr, vsize);
+ poffs = paddr - trunc_page (paddr);
+ vaddr = (vm_offset_t) pmap_mapdev (paddr-poffs, psize+poffs);
if (!vaddr) return (0);
-
+
+ vaddr += poffs;
+
#ifndef PCI_QUIET
/*
** display values.
*/
- printf ("\treg%d: virtual=0x%lx physical=0x%lx\n",
- (unsigned) reg, (u_long)vaddr, (u_long)paddr);
+ printf ("\treg%d: virtual=0x%lx physical=0x%lx size=0x%lx\n",
+ (unsigned) reg, (u_long)vaddr, (u_long)paddr, (u_long)psize);
#endif
-
/*
- ** probe for already mapped device.
- */
-
- if (!oldmap) for (i=0; i<vsize; i+=4) {
- u_long* addr = (u_long*) (vaddr+i);
- data = *addr;
- if (data != 0xffffffff) {
- printf ("\t(possible address conflict: "
- "at 0x%x read: 0x%x)\n",
- (unsigned) paddr+i, (unsigned) data);
- pci_paddr = 0;
- goto next_try;
- };
- };
-
- /*
- ** Set device address
- */
-
- pcibus.pb_write (tag, reg, paddr);
-
- /*
- ** Check if correctly mapped.
- **
- ** W A R N I N G
- **
- ** This code assumes that the device will NOT return
- ** only ones (0xffffffff) from all offsets.
+ ** set the configuration register and
+ ** return the address to the driver
+ ** Make sure to enable each upstream bridge
+ ** so memory and DMA can go all the way.
*/
- if (!oldmap) {
- for (i=0; i<vsize; i+=4) {
- u_long* addr = (u_long*) (vaddr+i);
- data = *addr;
- if (data != 0xffffffff)
- break;
- };
-
- if (data==0xffffffff) {
- printf ("\t(possible mapping problem: "
- "at 0x%x read 0xffffffff)\n",
- (unsigned) paddr);
- pci_paddr = 0;
- goto next_try;
- };
- };
-
- /*
- ** Return addresses to the driver
- */
+ for (;;) {
+ data = pcibus->pb_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
+ data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ (void) pcibus->pb_write(tag, PCI_COMMAND_STATUS_REG, data);
+ if ((link = link->pcicb_up) == NULL)
+ break;
+ tag = link->pcicb_bridge;
+ }
*va = vaddr;
*pa = paddr;
return (1);
}
-
-/*-----------------------------------------------------------------------
-**
-** Map new pci bus. (XXX under construction)
-**
-** PCI-Specification: ____________?
-**
-**-----------------------------------------------------------------------
-*/
-int pci_map_bus (pcici_t tag, u_long bus)
-{
- if (bus >= PCI_MAX_BUS) {
- printf ("pci_map_bus failed: bus number %d too big.\n",
- (int) bus);
- return (0);
- };
-
- if (bus >= pci_bus_max)
- pci_bus_max = bus + 1;
-
-#ifndef PCI_QUIET
- /*
- ** display values.
- */
-
- printf ("\tmapped pci bus %d.\n",
- (int) bus);
-#endif
-
- return (1);
-}
-
/*------------------------------------------------------------
**
** Interface functions for the devconf module.
@@ -795,12 +1085,12 @@ pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l)
return ENOMEM;
};
- tag = pcibus.pb_tag (pip->pi_bus, pip->pi_device, 0);
+ tag = pcibus->pb_tag (pip->pi_bus, pip->pi_device, 0);
buffer.peb_pci_info = *pip;
for (i=0; i<PCI_EXT_CONF_LEN; i++) {
- buffer.peb_config[i] = pcibus.pb_read (tag, i*4);
+ buffer.peb_config[i] = pcibus->pb_read (tag, i*4);
};
return copyout(&buffer, u, sizeof buffer);
@@ -812,36 +1102,354 @@ pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s)
{
return EOPNOTSUPP;
}
-
+
+/*-----------------------------------------------------------------------
+**
+** Pci meta interrupt handler
+**
+** This handler assumes level triggered interrupts.
+** It's possible to build a kernel which handles shared
+** edge triggered interrupts by the options "PCI_EDGE_INT".
+** But there is a performance penalty.
+**
+** (Of course you can delete the #ifdef PCI_EDGE_INT bracketed
+** code at all :-) :-) :-)
+**
+**-----------------------------------------------------------------------
+*/
+
+struct pci_int_desc*
+ pci_int_desc [PCI_MAX_IRQ];
+
+#ifndef NO_SHARED_IRQ
+
+static inline unsigned
+splq (unsigned mask)
+{
+ unsigned temp=cpl;
+ cpl |= mask;
+ return temp;
+}
+
+static void
+pci_int (int irq)
+{
+ struct pci_int_desc * p;
+ int c, s;
+#ifdef PCI_EDGE_INT
+ int i, n;
+#endif
+ if (irq<0 || irq >= PCI_MAX_IRQ) {
+ printf ("pci_int(%d)\n", irq);
+ return;
+ };
+
+#ifdef PCI_EDGE_INT
+ for (i=0; i<1000; i++) {
+ n = 0;
+#endif
+ for (p = pci_int_desc[irq]; p!=NULL; p=p->pcid_next) {
+ s = splq (*p->pcid_maskptr);
+ c= (*p->pcid_handler) (p->pcid_argument);
+ p-> pcid_tally += c;
+ splx (s);
+#ifdef PCI_EDGE_INT
+ n += c;
+#endif
+#if 0
+ if (c && p->pcid_tally<20)
+ printf ("PCI_INT: irq=%d h=%p cpl o=%x n=%x val=%d\n",
+ irq, p->pcid_handler, s, cpl, c);
+#endif
+ };
+#ifdef PCI_EDGE_INT
+ if (!n) return;
+ };
+ printf ("pci_int(%d): permanent interrupt request.\n", irq);
+#endif
+}
+#endif
+
/*-----------------------------------------------------------------------
**
-** Map pci interrupts to isa interrupts.
+** Auxiliary function for interrupt (un)mapping.
**
**-----------------------------------------------------------------------
*/
+static u_int
+getirq (pcici_t tag)
+{
+ u_int irq;
+
+ irq = PCI_INTERRUPT_LINE_EXTRACT(
+ pcibus->pb_read (tag, PCI_INTERRUPT_REG));
+
+ if (irq <= 0) {
+ printf ("\tint line register not set by bios\n");
+ return (0);
+ }
+
+ if (irq >= pcibus->pb_maxirq || irq >= PCI_MAX_IRQ) {
+ printf ("\tirq %d invalid.\n", irq);
+ return (0);
+ }
+
+ return (irq);
+}
+
+static struct pci_int_desc **
+getintdescbytag (u_int irq, pcici_t tag)
+{
+ struct pci_int_desc *p, **pp;
+
+ pp=&pci_int_desc[irq];
+ while (((p=*pp)) && !sametag(p->pcid_tag,tag))
+ pp=&p->pcid_next;
+
+ if (!p) return (NULL);
+
+ return (pp);
+}
+
+static struct pci_int_desc *
+getintdescbymptr (u_int irq, unsigned * mptr)
+{
+ struct pci_int_desc *p;
+
+ for (p=pci_int_desc[irq];p;p=p->pcid_next)
+ if (p->pcid_maskptr == mptr) break;
+ return (p);
+}
+
+/*-----------------------------------------------------------------------
+**
+** Map pci interrupt.
+**
+**-----------------------------------------------------------------------
+*/
+
+static unsigned pci_mask0 = 0;
+
int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr)
{
- int irq, result;
+ u_int irq;
+ int result, oldspl;
+ unsigned mask;
+ struct pci_int_desc *tail, *mdp=NULL, *new=NULL;
- irq = PCI_INTERRUPT_LINE_EXTRACT(
- pcibus.pb_read (tag, PCI_INTERRUPT_REG));
+ /*
+ ** Get irq line from configuration space,
+ ** and check for consistency.
+ */
- if (irq >= 16 || irq <= 0) {
- printf ("pci_map_int failed: no int line set.\n");
+ irq = getirq (tag);
+ if (irq >= PCI_MAX_IRQ) {
+ printf ("\tillegal irq %d.\n", irq);
return (0);
- }
+ };
+ mask= 1ul << irq;
+
+ /*
+ ** disable this interrupt.
+ */
+
+ oldspl = splq (mask);
+
+ /*
+ ** If handler for this tag already installed,
+ ** remove it first.
+ */
+
+ if (getintdescbytag (irq, tag) != NULL)
+ pci_unmap_int (tag);
+
+ /*
+ ** If this irq not yet included in the mask, include it.
+ */
+
+ mdp = getintdescbymptr (irq, maskptr);
+ if (!mdp) {
+ result = pcibus->pb_imaskinc (irq, maskptr);
+ if (result)
+ goto conflict;
+ };
+
+ /*
+ ** Allocate descriptor and initialize it.
+ */
+
+ tail = pci_int_desc[irq];
+
+ new = malloc (sizeof (*new), M_DEVBUF, M_WAITOK);
+ bzero (new, sizeof (*new));
+
+ new->pcid_next = tail;
+ new->pcid_tag = tag;
+ new->pcid_handler = func;
+ new->pcid_argument = arg;
+ new->pcid_maskptr = maskptr;
+ new->pcid_tally = 0;
+ new->pcid_mask = mask;
+
+ /*
+ ** If first handler: install it.
+ ** If second handler: install shared-int-handler.
+ */
+
+ if (!tail) {
+ /*
+ ** first handler for this irq.
+ */
+
+ result = pcibus->pb_iattach
+ (irq, (void(*)()) func, (int) arg, maskptr);
+ if (result) goto conflict;
+
+#ifdef NO_SHARED_IRQ
+ } else goto conflict;
+#else
+ } else if (!tail->pcid_next) {
+ /*
+ ** Second handler for this irq.
+ */
+
+ printf ("\tusing shared irq %d.\n", irq);
+
+ /*
+ ** replace old handler by shared-int-handler.
+ */
+
+ result = pcibus->pb_idetach (irq,(void(*)())tail->pcid_handler);
+ if (result)
+ printf ("\tCANNOT DETACH INT HANDLER.\n");
+
+ result = pcibus->pb_iattach (irq, pci_int, irq, &pci_mask0);
+ if (result) {
+ printf ("\tCANNOT ATTACH SHARED INT HANDLER.\n");
+ goto fail;
+ };
+ }
+#endif
+ /*
+ ** Link new descriptor, reenable ints and done.
+ */
+
+ pci_int_desc[irq] = new;
+ splx (oldspl);
+ return (1);
+
+ /*
+ ** Handle some problems.
+ */
+
+conflict:
+ printf ("\tirq %d already in use.\n", irq);
+fail:
+ /*
+ ** If descriptor allocated, free it.
+ ** If included in mask, remove it.
+ */
+
+ if (free) free (new, M_DEVBUF);
+ if (!mdp) (void) pcibus->pb_imaskexc (irq, maskptr);
+ splx (oldspl);
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+**
+** Unmap pci interrupt.
+**
+**-----------------------------------------------------------------------
+*/
+
+int pci_unmap_int (pcici_t tag)
+{
+ int result, oldspl;
+ struct pci_int_desc *this, **hook, *tail;
+ unsigned irq;
+
+ /*
+ ** Get irq line from configuration space,
+ ** and check for consistency.
+ */
+
+ irq = getirq (tag);
+ if (irq >= PCI_MAX_IRQ) {
+ printf ("\tillegal irq %d.\n", irq);
+ return (0);
+ };
- result = pcibus.pb_regint (tag, func, arg, maskptr);
+ /*
+ ** Search and unlink interrupt descriptor.
+ */
- if (!result) {
- printf ("pci_map_int failed.\n");
+ hook = getintdescbytag (irq, tag);
+ if (hook == NULL) {
+ printf ("\tno irq %d handler for pci %x\n",
+ irq, tag.tag);
return (0);
};
+ this = *hook;
+ *hook= this->pcid_next;
+
+ /*
+ ** Message
+ */
+
+ printf ("\tirq %d handler %p(%p) unmapped for pci %x after %d ints.\n",
+ irq, this->pcid_handler, this->pcid_argument,
+ this->pcid_tag.tag, this->pcid_tally);
+
+ /*
+ ** If this irq no longer included in the mask, remove it.
+ */
+
+ if (!getintdescbymptr (irq, this->pcid_maskptr))
+ (void) pcibus->pb_imaskexc (irq, this->pcid_maskptr);
+
+ tail = pci_int_desc[irq];
+
+ if (tail == NULL) {
+
+ /*
+ ** Remove the old handler.
+ */
+
+ result = pcibus->pb_idetach (irq,(void(*)())this->pcid_handler);
+ if (result)
+ printf ("\tirq %d: cannot remove handler.\n", irq);
+
+ } else if (tail->pcid_next == NULL) {
+
+ /*
+ ** Remove the shared int handler.
+ ** Install the last remaining handler.
+ */
+
+ oldspl = splq (1ul << irq);
+
+ result = pcibus->pb_idetach (irq, pci_int);
+ if (result)
+ printf ("\tirq %d: cannot remove handler.\n", irq);
+
+ result = pcibus->pb_iattach (irq,
+ (void(*)()) tail->pcid_handler,
+ (int) tail->pcid_argument,
+ tail->pcid_maskptr);
+
+ if (result)
+ printf ("\tirq %d: cannot install handler.\n", irq);
+
+ splx (oldspl);
+ };
+
+ free (this, M_DEVBUF);
return (1);
}
-
+
/*-----------------------------------------------------------
**
** Display of unknown devices.
@@ -868,7 +1476,7 @@ static const char *const majclasses[] = {
"old", "storage", "network", "display",
"multimedia", "memory", "bridge"
};
-
+
void not_supported (pcici_t tag, u_long type)
{
u_char reg;
@@ -892,15 +1500,15 @@ void not_supported (pcici_t tag, u_long type)
printf (", device=0x%lx", type >> 16);
- data = (pcibus.pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
+ data = (pcibus->pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
if (data < sizeof(majclasses) / sizeof(majclasses[0]))
printf(", class=%s", majclasses[data]);
printf (" [not supported]\n");
for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
- data = pcibus.pb_read (tag, reg);
- if (!data) continue;
+ data = pcibus->pb_read (tag, reg);
+ if ((data&~7)==0) continue;
switch (data&7) {
case 1:
@@ -923,89 +1531,4 @@ void not_supported (pcici_t tag, u_long type)
}
}
}
-
-#ifndef __FreeBSD2__
-/*-----------------------------------------------------------
-**
-** Mapping of physical to virtual memory
-**
-**-----------------------------------------------------------
-*/
-
-extern vm_map_t kernel_map;
-
-static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize)
-{
- vm_offset_t vaddr,value;
- u_long result;
-
- vaddr = vm_map_min (kernel_map);
-
- result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
- &vaddr, vsize, TRUE);
-
- if (result != KERN_SUCCESS) {
- printf (" vm_map_find failed(%d)\n", result);
- return (0);
- };
-
- /*
- ** map physical
- */
-
- value = vaddr;
- while (vsize >= NBPG) {
- pmap_enter (pmap_kernel(), vaddr, paddr,
- VM_PROT_READ|VM_PROT_WRITE, TRUE);
- vaddr += NBPG;
- paddr += NBPG;
- vsize -= NBPG;
- };
- return (value);
-}
-
-/*------------------------------------------------------------
-**
-** Emulate the register_intr() function of FreeBSD 2.0
-**
-** requires a patch:
-** FreeBSD 2.0: "/sys/i386/isa/vector.s"
-** 386bsd0.1: "/sys/i386/isa/icu.s"
-** 386bsd1.0: Please ask Jesus Monroy Jr.
-**
-**------------------------------------------------------------
-*/
-
-#include <machine/segments.h>
-
-int pci_int_unit [16];
-inthand2_t* (pci_int_hdlr [16]);
-unsigned int * pci_int_mptr [16];
-unsigned int pci_int_count[16];
-
-extern void
- Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(),
- Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15();
-
-static inthand_t* pci_int_glue[16] = {
- 0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8,
- Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 };
-
-static int
-register_intr __P((int intr, int device_id, unsigned int flags,
- inthand2_t *handler, unsigned int* mptr, int unit))
-{
- if (intr >= 16 || intr <= 2)
- return (EINVAL);
- if (pci_int_hdlr [intr])
- return (EBUSY);
-
- pci_int_hdlr [intr] = handler;
- pci_int_unit [intr] = unit;
- pci_int_mptr [intr] = mptr;
-
- setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL);
- return (0);
-}
-#endif /* __FreeBSD2__ */
#endif /* NPCI */
diff --git a/sys/pci/pcibus.h b/sys/pci/pcibus.h
index 1c5671c..842d97c 100644
--- a/sys/pci/pcibus.h
+++ b/sys/pci/pcibus.h
@@ -1,14 +1,14 @@
/**************************************************************************
**
-** $Id: pcibus.h,v 1.2 1994/11/02 23:47:14 se Exp $
+** $Id: pcibus.h,v 1.1 1995/02/01 22:56:47 se Exp $
**
** Declarations for pci bus driver.
**
-** 386bsd / FreeBSD
+** FreeBSD
**
**-------------------------------------------------------------------------
**
-** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved.
+** Copyright (c) 1995 Wolfgang Stanglmeier. All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
@@ -36,51 +36,58 @@
*/
#ifndef __PCI_BUS_H__
-#define __PCI_BUS_H__
-
+#define __PCI_BUS_H__ "pl1 95/03/13"
+
/*-----------------------------------------------------------------
**
** The following functions are provided by the pci bios.
** They are used only by the pci configuration.
**
-** pb_mode():
+** pcibus_setup():
** Probes for a pci system.
-** Returns 1 or 2 for pci configuration mechanism.
-** Returns 0 if no pci system.
+** Sets pci_maxdevice and pci_mechanism.
+**
+** pcibus_tag():
+** Creates a handle for pci configuration space access.
+** This handle is given to the read/write functions.
**
-** pb_tag():
-** Gets a handle for accessing the pci configuration
-** space.
-** This handle is given to the mapping functions (see
-** above) or to the read/write functions.
+** pcibus_ftag():
+** Creates a modified handle.
**
-** pb_read():
+** pcibus_read():
** Read a long word from the pci configuration space.
** Requires a tag (from pcitag) and the register
-** number (should be a long word aligned one).
+** number (should be a long word alligned one).
**
-** pb_write():
+** pcibus_write():
** Writes a long word to the pci configuration space.
** Requires a tag (from pcitag), the register number
-** (should be a long word aligned one), and a value.
+** (should be a long word alligned one), and a value.
**
-** pb_regint():
+** pcibus_regirq():
** Register an interupt handler for a pci device.
-** Requires a tag (from pcitag), the handler function
-** and it's argument, and an interupt mask.
+** Requires a tag (from pcitag), the register number
+** (should be a long word alligned one), and a value.
**
**-----------------------------------------------------------------
*/
struct pcibus {
char *pb_name;
- int (*pb_mode ) (void);
- pcici_t (*pb_tag ) (u_char bus, u_char device, u_char func);
- u_long (*pb_read ) (pcici_t tag, u_long reg);
- void (*pb_write ) (pcici_t tag, u_long reg, u_long data);
- int (*pb_regint) (pcici_t tag, int(*func)(), void*arg, unsigned*mp);
+ void (*pb_setup ) (void);
+ pcici_t (*pb_tag ) (u_char bus, u_char device, u_char func);
+ pcici_t (*pb_ftag ) (pcici_t tag, u_char func);
+ u_long (*pb_read ) (pcici_t tag, u_long reg);
+ void (*pb_write ) (pcici_t tag, u_long reg, u_long data);
+ unsigned pb_maxirq;
+ int (*pb_iattach) (int irq, void(*func)(), int arg, unsigned*maskp);
+ int (*pb_idetach) (int irq, void(*func)());
+ int (*pb_imaskinc)(int irq, unsigned *maskptr);
+ int (*pb_imaskexc)(int irq, unsigned *maskptr);
};
+#define PCI_MAX_IRQ (16)
+
/*
** The following structure should be generated by the driver
*/
diff --git a/sys/pci/pcireg.h b/sys/pci/pcireg.h
index 1f687f1..a1fbcdf 100644
--- a/sys/pci/pcireg.h
+++ b/sys/pci/pcireg.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** $Id: pcireg.h,v 1.3 1995/02/02 13:12:18 davidg Exp $
+** $Id: pcireg.h,v 1.4 1995/02/02 22:01:40 se Exp $
**
** Names for PCI configuration space registers.
**
@@ -33,8 +33,7 @@
*/
#ifndef __PCI_REG_H__
-#define __PCI_REG_H__
-
+#define __PCI_REG_H__ "pl2 95/03/21"
/*
** Device identification register; contains a vendor ID and a device ID.
@@ -146,6 +145,32 @@
#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0
#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc
+/*
+** PCI-PCI bridge mapping registers
+*/
+#define PCI_PCI_BRIDGE_BUS_REG 0x18
+#define PCI_PCI_BRIDGE_IO_REG 0x1c
+#define PCI_PCI_BRIDGE_MEM_REG 0x20
+#define PCI_PCI_BRIDGE_PMEM_REG 0x24
+
+
+#define PCI_SUBORDINATE_BUS_MASK 0x00ff0000
+#define PCI_SECONDARY_BUS_MASK 0x0000ff00
+#define PCI_PRIMARY_BUS_MASK 0x000000ff
+
+#define PCI_SUBORDINATE_BUS_EXTRACT(x) (((x) > 16) & 0xff)
+#define PCI_SECONDARY_BUS_EXTRACT(x) (((x) > 8) & 0xff)
+#define PCI_PRIMARY_BUS_EXTRACT(x) (((x) ) & 0xff)
+
+#define PCI_PRIMARY_BUS_INSERT(x, y) (((x) & ~PCI_PRIMARY_BUS_MASK) | ((y) << 0))
+#define PCI_SECONDARY_BUS_INSERT(x, y) (((x) & ~PCI_SECONDARY_BUS_MASK) | ((y) << 8))
+#define PCI_SUBORDINATE_BUS_INSERT(x, y) (((x) & ~PCI_SUBORDINATE_BUS_MASK) | ((y) << 16))
+
+#define PCI_PPB_IOBASE_EXTRACT(x) (((x) << 8) & 0xFF00)
+#define PCI_PPB_IOLIMIT_EXTRACT(x) (((x) << 0) & 0xFF00)
+
+#define PCI_PPB_MEMBASE_EXTRACT(x) (((x) << 16) & 0xFFFF0000)
+#define PCI_PPB_MEMLIMIT_EXTRACT(x) (((x) << 0) & 0xFFFF0000)
/*
** Interrupt configuration register
diff --git a/sys/pci/pcisupport.c b/sys/pci/pcisupport.c
index eee424a..c88b86a 100644
--- a/sys/pci/pcisupport.c
+++ b/sys/pci/pcisupport.c
@@ -1,20 +1,20 @@
/**************************************************************************
**
-** $Id: pcisupport.c,v 1.11 1995/03/02 23:29:44 se Exp $
+** $Id: pcisupport.c,v 1.12 1995/03/17 04:27:20 davidg Exp $
**
-** Device driver for INTEL PCI chipsets.
+** Device driver for DEC/INTEL PCI chipsets.
**
-** 386bsd / FreeBSD
+** FreeBSD
**
**-------------------------------------------------------------------------
**
-** Written for 386bsd and FreeBSD by
-** wolf@dentaro.gun.de Wolfgang Stanglmeier
+** Written for FreeBSD by
+** wolf@cologne.de Wolfgang Stanglmeier
** se@mi.Uni-Koeln.de Stefan Esser
**
**-------------------------------------------------------------------------
**
-** Copyright (c) 1994 Stefan Esser. All rights reserved.
+** Copyright (c) 1994,1995 Stefan Esser. All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
@@ -41,28 +41,19 @@
***************************************************************************
*/
-#define __PCISUPPORT_C_PATCHLEVEL__ "pl2 95/02/27"
-
-/*==========================================================
-**
-** Include files
-**
-**==========================================================
-*/
+#define __PCISUPPORT_C__ "pl4 95/03/21"
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/devconf.h>
+#include <machine/cpu.h>
+
#include <pci/pcivar.h>
#include <pci/pcireg.h>
-extern void printf();
-
-extern int bootverbose;
-
-
/*---------------------------------------------------------
**
** Intel chipsets for 486 / Pentium processor
@@ -74,7 +65,7 @@ static char* chipset_probe (pcici_t tag, pcidi_t type);
static void chipset_attach(pcici_t tag, int unit);
static u_long chipset_count;
-struct pci_device chipset_device = {
+struct pci_device chipset_device = {
"chip",
chipset_probe,
chipset_attach,
@@ -84,8 +75,6 @@ struct pci_device chipset_device = {
DATA_SET (pcidevice_set, chipset_device);
-static char confread(pcici_t config_id, int port);
-
struct condmsg {
unsigned char port;
unsigned char mask;
@@ -94,12 +83,11 @@ struct condmsg {
char *text;
};
-#define M_EQ 0 /* mask and return true if equal */
-#define M_NE 1 /* mask and return true if not equal */
-#define TRUE 2 /* don't read config, always true */
-
-static char* chipset_probe (pcici_t tag, pcidi_t type)
+static char*
+chipset_probe (pcici_t tag, pcidi_t type)
{
+ u_long data;
+
switch (type) {
case 0x04848086:
return ("Intel 82378IB PCI-ISA bridge");
@@ -109,11 +97,28 @@ static char* chipset_probe (pcici_t tag, pcidi_t type)
return ("Intel 82375EB PCI-EISA bridge");
case 0x04a38086:
return ("Intel 82434LX PCI cache memory controller");
+ case 0x00011011:
+ return ("DEC 21050 PCI-PCI bridge");
+ };
+
+ /*
+ ** check classes
+ */
+
+ data = pci_conf_read(tag, PCI_CLASS_REG);
+ switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+
+ case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+ return ("PCI-PCI bridge");
};
return ((char*)0);
}
-struct condmsg conf82424zx[] =
+#define M_EQ 0 /* mask and return true if equal */
+#define M_NE 1 /* mask and return true if not equal */
+#define TRUE 2 /* don't read config, always true */
+
+static const struct condmsg conf82424zx[] =
{
{ 0x00, 0x00, 0x00, TRUE, "\tCPU: " },
{ 0x50, 0xe0, 0x00, M_EQ, "486DX" },
@@ -177,7 +182,7 @@ struct condmsg conf82424zx[] =
{ 0 }
};
-struct condmsg conf82434lx[] =
+static const struct condmsg conf82434lx[] =
{
{ 0x00, 0x00, 0x00, TRUE, "\tCPU: " },
{ 0x50, 0xe3, 0x82, M_EQ, "Pentium, 60MHz" },
@@ -246,7 +251,8 @@ static char confread (pcici_t config_id, int port)
return (l >> ports);
}
-static void writeconfig(pcici_t config_id, struct condmsg *tbl)
+static void
+writeconfig (pcici_t config_id, const struct condmsg *tbl)
{
while (tbl->text) {
int cond = 0;
@@ -268,10 +274,13 @@ static void writeconfig(pcici_t config_id, struct condmsg *tbl)
}
}
-void chipset_attach(pcici_t config_id, int unit)
+static void
+chipset_attach (pcici_t config_id, int unit)
{
- if (bootverbose) {
- switch (pci_conf_read (config_id, 0)) {
+ if (!bootverbose)
+ return;
+
+ switch (pci_conf_read (config_id, PCI_ID_REG)) {
case 0x04838086:
writeconfig (config_id, conf82424zx);
@@ -287,64 +296,23 @@ void chipset_attach(pcici_t config_id, int unit)
pci_conf_read (config_id, 0x54));
break;
};
- }
-}
-
-/*---------------------------------------------------------
-**
-** Catchall driver for pci-pci bridges.
-**
-**---------------------------------------------------------
-*/
-
-static char* ppb_probe (pcici_t tag, pcidi_t type);
-static void ppb_attach(pcici_t tag, int unit);
-static u_long ppb_count;
-
-struct pci_device ppb_device = {
- "ppb",
- ppb_probe,
- ppb_attach,
- &ppb_count,
- NULL
-};
-
-DATA_SET (pcidevice_set, ppb_device);
-
-static char* ppb_probe (pcici_t tag, pcidi_t type)
-{
- int data = pci_conf_read(tag, PCI_CLASS_REG);
-
- if ((data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) ==
- (PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI))
- return ("PCI-PCI bridge");
- return ((char*)0);
}
-static void ppb_attach(pcici_t tag, int unit)
-{
- /*
- ** XXX should read bus number from device
- */
- (void) pci_map_bus (tag, 1);
-}
-
/*---------------------------------------------------------
**
** Catchall driver for VGA devices
**
-**
** By Garrett Wollman
** <wollman@halloran-eldar.lcs.mit.edu>
**
**---------------------------------------------------------
*/
-static char* vga_probe (pcici_t tag, pcidi_t type);
-static void vga_attach(pcici_t tag, int unit);
+static char* vga_probe (pcici_t tag, pcidi_t type);
+static void vga_attach (pcici_t tag, int unit);
static u_long vga_count;
-struct pci_device vga_device = {
+struct pci_device vga_device = {
"vga",
vga_probe,
vga_attach,
@@ -354,7 +322,7 @@ struct pci_device vga_device = {
DATA_SET (pcidevice_set, vga_device);
-static char* vga_probe (pcici_t tag, pcidi_t type)
+static char* vga_probe (pcici_t tag, pcidi_t type)
{
int data = pci_conf_read(tag, PCI_CLASS_REG);
@@ -375,11 +343,11 @@ static char* vga_probe (pcici_t tag, pcidi_t type)
return ((char*)0);
}
-static void vga_attach(pcici_t tag, int unit)
+static void vga_attach (pcici_t tag, int unit)
{
/*
-** The assigned adresses may not be remapped,
-** because certain values are assumed by the console driver.
+** If the assigned addresses are remapped,
+** the console driver has to be informed about the new address.
*/
#if 0
vm_offset_t va;
@@ -389,7 +357,7 @@ static void vga_attach(pcici_t tag, int unit)
(void) pci_map_mem (tag, reg, &va, &pa);
#endif
}
-
+
/*---------------------------------------------------------
**
** Hook for loadable pci drivers
@@ -397,11 +365,11 @@ static void vga_attach(pcici_t tag, int unit)
**---------------------------------------------------------
*/
-static char* lkm_probe (pcici_t tag, pcidi_t type);
-static void lkm_attach(pcici_t tag, int unit);
+static char* lkm_probe (pcici_t tag, pcidi_t type);
+static void lkm_attach (pcici_t tag, int unit);
static u_long lkm_count;
-struct pci_device lkm_device = {
+struct pci_device lkm_device = {
"lkm",
lkm_probe,
lkm_attach,
@@ -411,19 +379,20 @@ struct pci_device lkm_device = {
DATA_SET (pcidevice_set, lkm_device);
-static char* lkm_probe (pcici_t tag, pcidi_t type)
+static char*
+lkm_probe (pcici_t tag, pcidi_t type)
{
/*
- ** Should try to load a matching driver.
- ** XXX Not yet!
+ ** Not yet!
+ ** (Should try to load a matching driver)
*/
return ((char*)0);
}
-static void lkm_attach(pcici_t tag, int unit)
-{
-}
-
+static void
+lkm_attach (pcici_t tag, int unit)
+{}
+
/*---------------------------------------------------------
**
** Devices to ignore
@@ -431,11 +400,11 @@ static void lkm_attach(pcici_t tag, int unit)
**---------------------------------------------------------
*/
-static char* ign_probe (pcici_t tag, pcidi_t type);
-static void ign_attach(pcici_t tag, int unit);
+static char* ign_probe (pcici_t tag, pcidi_t type);
+static void ign_attach (pcici_t tag, int unit);
static u_long ign_count;
-struct pci_device ign_device = {
+struct pci_device ign_device = {
NULL,
ign_probe,
ign_attach,
@@ -445,17 +414,17 @@ struct pci_device ign_device = {
DATA_SET (pcidevice_set, ign_device);
-static char* ign_probe (pcici_t tag, pcidi_t type)
+static char*
+ign_probe (pcici_t tag, pcidi_t type)
{
switch (type) {
case 0x10001042ul: /* wd */
return ("");
-
};
return ((char*)0);
}
-static void ign_attach(pcici_t tag, int unit)
-{
-}
+static void
+ign_attach (pcici_t tag, int unit)
+{}
diff --git a/sys/pci/pcivar.h b/sys/pci/pcivar.h
index 4e62dbf..23bc8ae 100644
--- a/sys/pci/pcivar.h
+++ b/sys/pci/pcivar.h
@@ -1,10 +1,10 @@
/**************************************************************************
**
-** $Id: pcivar.h,v 1.2 1995/02/27 17:17:14 se Exp $
+** $Id: pcivar.h,v 1.3 1995/03/17 04:27:21 davidg Exp $
**
** Declarations for pci device drivers.
**
-** 386bsd / FreeBSD
+** FreeBSD
**
**-------------------------------------------------------------------------
**
@@ -36,10 +36,8 @@
*/
#ifndef __PCI_VAR_H__
-#define __PCI_VAR_H__
+#define __PCI_VAR_H__ "pl2 95/03/21"
-#define PCIVAR_H_PATCHLEVEL "pl1 95/02/27"
-
/*-----------------------------------------------------------------
**
** main pci initialization function.
@@ -60,13 +58,16 @@ void pci_configure (void);
typedef union {
u_long cfg1;
- struct {
+ struct {
u_char enable;
u_char forward;
u_short port;
} cfg2;
+ unsigned tag;
} pcici_t;
+#define sametag(x,y) ((x).tag == (y).tag)
+
/*-----------------------------------------------------------------
**
** Each pci device has an unique device id.
@@ -98,7 +99,7 @@ typedef u_long pcidi_t;
u_long pci_conf_read (pcici_t tag, u_long reg );
void pci_conf_write (pcici_t tag, u_long reg, u_long data);
-
+
/*-----------------------------------------------------------------
**
** The pci driver structure.
@@ -141,7 +142,11 @@ struct pci_device {
*/
extern struct linker_set pcidevice_set;
-
+
+extern unsigned pci_max_burst_len; /* log2 of safe burst transfer length */
+extern unsigned pci_mechanism;
+extern unsigned pci_maxdevice;
+
/*-----------------------------------------------------------------
**
** The pci-devconf interface.
@@ -150,8 +155,8 @@ extern struct linker_set pcidevice_set;
*/
struct pci_info {
- u_short pi_bus;
- u_short pi_device;
+ u_short pi_bus;
+ u_short pi_device;
};
#define PCI_EXT_CONF_LEN (16)
@@ -162,31 +167,18 @@ struct pci_externalize_buffer {
u_long peb_config[PCI_EXT_CONF_LEN];
};
-
-/*-----------------------------------------------------------------
-**
-** Register an additional pci bus for probing.
-** Called by pci-pci bridge handlers.
-**
-**-----------------------------------------------------------------
-*/
-
-int pci_map_bus (pcici_t tag, u_long bus);
-
/*-----------------------------------------------------------------
**
** Map a pci device to physical and virtual memory.
**
-** The va and pa addresses are "in/out" parameters.
-** If they are 0 on entry, the function assigns an address.
-**
-** Entry selects the register in the pci configuration
+** Entry selects the register in the pci configuration
** space, which supplies the size of the region, and
** receives the physical address.
**
-** If there is any error, a message is written, and
-** the function returns with zero.
-** Else it returns with a value different to zero.
+** In case of success the function sets the addresses
+** in *va and *pa, and returns 1.
+** In case of errors a message is written,
+** and the function returns 0.
**
**-----------------------------------------------------------------
*/
@@ -197,59 +189,65 @@ int pci_map_mem (pcici_t tag, u_long entry, u_long * va, u_long * pa);
**
** Map a pci device to an io port area.
**
-** *pa is an "in/out" parameter.
-** If it's 0 on entry, the function assigns an port number..
-**
** Entry selects the register in the pci configuration
** space, which supplies the size of the region, and
** receives the port number.
**
-** If there is any error, a message is written, and
-** the function returns with zero.
-** Else it returns with a value different to zero.
+** In case of success the function sets the port number in pa,
+** and returns 1.
+** In case of errors a message is written,
+** and the function returns 0.
**
**-----------------------------------------------------------------
*/
-int pci_map_port(pcici_t tag, u_long entry, u_short * pa);
-
+int pci_map_port (pcici_t tag, u_long entry, u_short * pa);
+
/*-----------------------------------------------------------------
**
-** Map a pci interrupt to an isa irq line,
-** and enable the interrupt.
+** Map a pci interrupt to an isa irq line, and enable the interrupt.
**
-** func is the interrupt handler, arg is the argument
-** to this function.
+** -----------------
**
-** The maskptr argument should be &bio_imask,
-** &net_imask etc. or NULL.
+** func is the interrupt handler, arg is the argument
+** to the handler (usually a pointer to a softc).
**
-** If there is any error, a message is written, and
-** the function returns with zero.
-** Else it returns with a value different to zero.
+** The maskptr argument should be &bio_imask,
+** &net_imask etc. or NULL.
**
-** A word of caution for FreeBSD 2.0:
+** If there is any error, a message is written, and
+** the function returns with zero.
+** Else it returns with a value different to zero.
**
-** We use the register_intr() function.
+** -----------------
**
-** The interrupt line of the selected device is included
-** into the supplied mask: after the corresponding splXXX
-** this drivers interrupts are blocked.
+** The irq number is read from the configuration space.
+** (Should have been set by the bios).
**
-** But in the interrupt handlers startup code ONLY
-** the interrupt of the driver is blocked, and NOT
-** all interrupts of the spl group.
+** Supports multiple handlers per irq (shared interrupts).
**
-** It may be required to additional block the group
-** interrupts by splXXX() inside the interrupt handler.
+** -----------------
**
-** In pre 2.0 kernels we emulate the register_intr
-** function. The emulating function blocks all interrupts
-** of the group in the interrupt handler prefix code.
+** There is code to support shared edge triggered ints.
+** This relies on the cooperation of the interrupt handlers:
+** they have to return a value <>0 if and only if something
+** was done. Beware of the performance penalty.
**
**-----------------------------------------------------------------
*/
+struct pci_int_desc {
+ struct pci_int_desc * pcid_next;
+ pcici_t pcid_tag;
+ int (*pcid_handler)();
+ void* pcid_argument;
+ unsigned * pcid_maskptr;
+ unsigned pcid_tally;
+ unsigned pcid_mask;
+};
+
int pci_map_int (pcici_t tag, int (*func)(), void* arg, unsigned * maskptr);
+int pci_unmap_int (pcici_t tag);
+
#endif
OpenPOWER on IntegriCloud