summaryrefslogtreecommitdiffstats
path: root/sys/pci/pci.c
diff options
context:
space:
mode:
authorse <se@FreeBSD.org>1997-05-26 15:08:43 +0000
committerse <se@FreeBSD.org>1997-05-26 15:08:43 +0000
commitcfea77580682c68592b48cba9da572bc10e93b61 (patch)
tree23db6fa5f0b52728e0fa65fe609484e3e52cbab3 /sys/pci/pci.c
parenteba9732c9776c3bb526db98340a2a84ab9172e13 (diff)
downloadFreeBSD-src-cfea77580682c68592b48cba9da572bc10e93b61.zip
FreeBSD-src-cfea77580682c68592b48cba9da572bc10e93b61.tar.gz
Completely replace the PCI bus driver code to make it better reflect
reality. There will be a new call interface, but for now the file pci_compat.c (which is to be deleted, after all drivers are converted) provides an emulation of the old PCI bus driver functions. The only change that might be visible to drivers is, that the type pcici_t (which had been meant to be just a handle, whose exact definition should not be relied on), has been converted into a pcicfgregs* . The Tekram AMD SCSI driver bogusly relied on the definition of pcici_t and has been converted to just call the PCI drivers functions to access configuration space register, instead of inventing its own ... This code is by no means complete, but assumed to be fully operational, and brings the official code base more in line with my development code. A new generic device descriptor data type has to be agreed on. The PCI code will then use that data type to provide new functionality: 1) userconfig support 2) "wired" PCI devices 3) conflicts checking against ISA/EISA 4) maps will depend on the command register enable bits 5) PCI to Anything bridges can be defined as devices, and are probed like any "standard" PCI device. The following features are currently missing, but will be added back, soon: 1) unknown device probe message 2) suppression of "mirrored" devices caused by ancient, broken chip-sets This code relies on generic shared interrupt support just commited to kern_intr.c (plus the modifications of isa.c and isa_device.h).
Diffstat (limited to 'sys/pci/pci.c')
-rw-r--r--sys/pci/pci.c2181
1 files changed, 365 insertions, 1816 deletions
diff --git a/sys/pci/pci.c b/sys/pci/pci.c
index 4456fe6..b6f056e 100644
--- a/sys/pci/pci.c
+++ b/sys/pci/pci.c
@@ -1,1893 +1,459 @@
-/**************************************************************************
-**
-** $Id: pci.c,v 1.70 1997/04/26 11:46:18 peter Exp $
-**
-** General subroutines for the PCI bus.
-** pci_configure ()
-**
-** FreeBSD
-**
-**-------------------------------------------------------------------------
-**
-** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions
-** are met:
-** 1. Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** 2. Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in the
-** documentation and/or other materials provided with the distribution.
-** 3. The name of the author may not be used to endorse or promote products
-** derived from this software without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**
-***************************************************************************
-*/
+/*
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ *
+ */
#include "pci.h"
#if NPCI > 0
-/*========================================================
-**
-** #includes and declarations
-**
-**========================================================
-*/
-
-#include "opt_smp.h"
+#include <stddef.h>
+#include <sys/types.h>
#include <sys/param.h>
+#include <sys/time.h>
#include <sys/systm.h>
#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/fcntl.h>
#include <sys/conf.h>
+#include <sys/kernel.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /* DEVFS */
-#include <sys/fcntl.h>
#include <vm/vm.h>
-#include <vm/vm_param.h>
#include <vm/pmap.h>
-
-#include <i386/isa/isa_device.h> /* XXX inthand2_t */
-
-#include <pci/pcivar.h>
#include <pci/pcireg.h>
-#include <pci/pcibus.h>
+#include <pci/pcivar.h>
#include <pci/pci_ioctl.h>
-/*========================================================
-**
-** Structs and Functions
-**
-**========================================================
-*/
-
-struct pcicb {
- struct pcicb *pcicb_next;
- struct pcicb *pcicb_up;
- struct pcicb *pcicb_down;
- pcici_t pcicb_bridge;
-
- u_char pcicb_bus;
- u_char pcicb_subordinate;
- 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;
-};
-
-struct pci_lkm {
- struct pci_device *dvp;
- struct pci_lkm *next;
-};
-
-static void
-not_supported (pcici_t tag, u_long type);
-
-static void
-pci_bus_config (void);
-
-static void
-pci_rescan (void);
-
-static void pci_attach (int bus, int dev, int func,
- struct pci_device *dvp, const char *name);
-
-static int
-pci_bridge_config (void);
+/* return highest PCI bus number known to be used, or -1 if none */
static int
-pci_mfdev (int bus, int device);
-
-static void pci_remember (int bus, int dev, int func, struct pci_device *dvp);
-
-/*========================================================
-**
-** Variables
-**
-**========================================================
-*/
-
-/*
-** log2 of safe burst len (in words)
-*/
-
-unsigned pci_max_burst_len = 3; /* 2=16Byte, 3=32Byte, 4=64Byte, ... */
-unsigned pci_mechanism = 0;
-unsigned pci_maxdevice = 0;
-unsigned pciroots = 0; /* XXX pcisupport.c increments this
- * for the Orion host to PCI bridge
- * UGLY hack ... :( Will be changed :)
- */
-/*--------------------------------------------------------
-**
-** Local variables.
-**
-**--------------------------------------------------------
-*/
-
-static struct pcibus *pcibus;
-
-static int pci_conf_count;
-static int pci_info_done;
-static int pcibusmax;
-static struct pcicb *pcicb;
-
-static struct pci_conf *pci_dev_list;
-static unsigned pci_dev_list_count;
-static unsigned pci_dev_list_size;
-
-static struct pci_lkm *pci_lkm_head;
-
-/*-----------------------------------------------------------------
-**
-** The following functions are provided for the device driver
-** to read/write the configuration space.
-**
-** pci_conf_read():
-** Read a long word from the pci configuration space.
-** Requires a tag (from pcitag) and the register
-** number (should be a long word alligned one).
-**
-** pci_conf_write():
-** Writes a long word to the pci configuration space.
-** Requires a tag (from pcitag), the register number
-** (should be a long word alligned one), and a value.
-**
-**-----------------------------------------------------------------
-*/
-
-u_long
-pci_conf_read (pcici_t tag, u_long 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);
-}
-
-/*========================================================
-**
-** Subroutines for configuration.
-**
-**========================================================
-*/
-
-static void
-pci_register_io (struct pcicb * cb, u_int base, u_int limit)
+pci_bushigh(void)
{
-#ifdef PCI_BRIDGE_DEBUG
- if (bootverbose)
- printf ("register_io: bus=%d base=%x limit=%x\n",
- cb->pcicb_bus, base, limit);
-#endif
-
- if (!cb->pcicb_pfrom || base < cb->pcicb_pfrom)
- cb->pcicb_pfrom = base;
- if (limit > cb->pcicb_pupto)
- cb->pcicb_pupto = limit;
-
- /*
- ** XXX should set bridge io mapping here
- ** but it can be mapped in 4k blocks only,
- ** leading to conflicts with isa/eisa ..
- */
+ if (pci_cfgopen() == 0)
+ return (-1);
+ return (0);
}
-static void
-pci_register_memory (struct pcicb * cb, u_int base, u_int limit)
-{
-#ifdef PCI_BRIDGE_DEBUG
- if (bootverbose)
- printf ("register_mem: bus=%d base=%x limit=%x\n",
- cb->pcicb_bus, base, limit);
-#endif
+/* return base address of memory or port map */
- 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));
- if (bootverbose)
- 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 u_int
-pci_memalloc (struct pcicb * cb, u_int addr, u_int size)
+static int
+pci_mapbase(unsigned mapreg)
{
- u_int result = 0, limit=0, newbase=0;
-#ifdef PCI_BRIDGE_DEBUG
- if (bootverbose)
- printf ("memalloc: bus=%d addr=%x size=%x ..\n",
- cb->pcicb_bus, addr, size);
-#endif
-
- if (!cb) goto done;
-
- if (!cb->pcicb_membase) {
- printf ("memalloc: bus%d: membase not set.\n",
- cb->pcicb_bus);
- goto done;
- }
-
- /*
- ** get upper allocation limit
- */
- limit = cb->pcicb_memlimit;
- if (cb->pcicb_mfrom && cb->pcicb_mfrom <= limit)
- limit = cb->pcicb_mfrom-1;
-
- /*
- ** address fixed, and impossible to allocate ?
- */
- if (addr && addr+size-1 > limit)
- goto done;
-
- /*
- ** get possible address
- */
-
- result = addr;
- if (!result) result = ((limit + 1) / size - 1) * size;
-
- /*
- ** if not local available, request from parent.
- */
-
- 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);
+ int mask = 0x03;
+ if ((mapreg & 0x01) == 0)
+ mask = 0x0f;
+ return (mapreg & ~mask);
}
-/*========================================================
-**
-** pci_bridge_config()
-**
-** Configuration of a pci bridge.
-**
-**========================================================
-*/
+/* return map type of memory or port map */
static int
-pci_bridge_config (void)
-{
- pcici_t tag;
- struct pcicb* parent;
-
- tag = pcicb->pcicb_bridge;
- if (tag.tag) {
-
- if (!pcicb->pcicb_bus) {
- u_int data;
- /*
- ** Get the lowest available bus number.
- */
- pcicb->pcicb_bus = ++pcibusmax;
-
- /*
- ** 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;
- }
- }
- return pcicb->pcicb_bus;
-}
-
-/*========================================================
-**
-** pci_attach()
-**
-** Attach one device
-**
-**========================================================
-*/
-
-static void pci_attach (int bus, int dev, int func,
- struct pci_device *dvp, const char *name)
-{
- u_long data;
- int unit;
- u_char reg;
- u_char pciint;
- int irq;
-#if defined(APIC_IO)
- u_char airq = 0xff;
- u_char rirq = 0xff;
-#endif /* APIC_IO */
- pcici_t tag = pcibus->pb_tag (bus, dev, func);
-
- /*
- ** Get and increment the unit.
- */
-
- unit = (*dvp->pd_count)++;
-
- /*
- ** Announce this device
- */
-
- 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 = pci_conf_read (tag, PCI_INTERRUPT_REG);
- pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
-
- if (pciint) {
-
- 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.
- */
-
-#if defined(APIC_IO)
- if (irq && (irq != 0xff)) {
- airq = get_pci_apic_irq (bus, dev, pciint);
- if (airq != 0xff) { /* APIC IRQ exists */
- rirq = irq; /* 're-directed' IRQ */
- irq = airq; /* use APIC IRQ */
- }
- printf ("%d", irq);
- }
-#else
- if (irq && (irq != 0xff))
- printf ("%d", irq);
-#endif /* APIC_IO */
- else
- printf ("??");
+pci_maptype(unsigned mapreg)
+{
+ static u_int8_t maptype[0x10] = {
+ PCI_MAPMEM, PCI_MAPPORT,
+ PCI_MAPMEM, 0,
+ PCI_MAPMEM, PCI_MAPPORT,
+ 0, 0,
+ PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT,
+ PCI_MAPMEM|PCI_MAPMEMP, 0,
+ PCI_MAPMEM|PCI_MAPMEMP, PCI_MAPPORT,
+ 0, 0,
};
- printf (" on pci%d:%d:%d\n", bus, dev, func);
-
-#if defined(APIC_IO)
- if (airq != 0xff) { /* APIC IRQ exists */
- data = PCI_INTERRUPT_LINE_INSERT(data, airq);
- pci_conf_write (tag, PCI_INTERRUPT_REG, data);
- undirect_pci_irq (rirq); /* free for ISA card */
- }
-#endif /* APIC_IO */
-
- /*
- ** Read the current mapping,
- ** and update the pcicb fields.
- */
-
- data = pci_conf_read(tag, PCI_CLASS_REG);
- data &= (PCI_CLASS_MASK|PCI_SUBCLASS_MASK);
- switch (data) {
- case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
- break;
- case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_CARDBUS: {
- u_int map, addr, size;
- map = pci_conf_read(tag, PCI_CARDBUS_SOCKET_REG);
- pci_conf_write (tag, PCI_CARDBUS_SOCKET_REG, 0xffffffff);
- size = pci_conf_read(tag, PCI_CARDBUS_SOCKET_REG);
- size = (~size) + 1;
- addr = pci_memalloc (pcicb, map, size);
- pci_conf_write (tag, PCI_CARDBUS_SOCKET_REG, addr);
- pcicb->pcicb_mamount += size;
- break;
- }
- default:
- for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) {
- u_int map, addr, size;
-
-
- map = pci_conf_read (tag, reg);
- if (!(map & PCI_MAP_MEMORY_ADDRESS_MASK))
- continue;
-
- pci_conf_write (tag, reg, 0xffffffff);
- data = pci_conf_read (tag, reg);
- pci_conf_write (tag, reg, map);
-
- switch (data & 7) {
-
- default:
- continue;
- case 1:
- case 5:
- addr = map & PCI_MAP_IO_ADDRESS_MASK;
- size = -(data & PCI_MAP_IO_ADDRESS_MASK);
- size &= ~(addr ^ -addr);
-
- 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;
- };
- break;
- }
- if (bootverbose)
- printf ("\tmapreg[%02x] type=%d addr=%08x size=%04x.\n",
- reg, map&7, addr, size);
- }
- }
-
- /*
- ** attach device
- ** may produce additional log messages,
- ** i.e. when installing subdevices.
- */
-
- (*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 (bootverbose) {
- printf ("\tbridge from pci%d to pci%d through %d.\n",
- primary, secondary, subordinate);
- printf ("\tmapping regs: io:%08lx mem:%08lx pmem:%08lx\n",
- pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG),
- pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG),
- pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG));
- }
-#endif
- /*
- ** check for uninitialized bridge.
- */
- if (!(primary < secondary
- && secondary <= subordinate
- && bus == primary)) {
-
- printf ("\tINCORRECTLY or NEVER CONFIGURED.\n");
- /*
- ** disable this bridge
- */
- pci_conf_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)->pcicb_bus < secondary)
- 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_next = *link;
- 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.
- */
- unsigned reg;
-
- reg = pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG);
- this->pcicb_iobase = PCI_PPB_IOBASE_EXTRACT (reg);
- this->pcicb_iolimit = PCI_PPB_IOLIMIT_EXTRACT(reg);
-
- /*
- ** 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.
- */
- unsigned reg;
-
- /*
- ** non prefetchable memory
- */
- reg = pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG);
- this->pcicb_membase = PCI_PPB_MEMBASE_EXTRACT (reg);
- this->pcicb_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg);
-
- /*
- ** 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);
- this->pcicb_p_membase = PCI_PPB_MEMBASE_EXTRACT (reg);
- this->pcicb_p_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg);
-
- /*
- ** 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;
- }
+ return maptype[mapreg & 0x0f];
}
-/*========================================================
-**
-** pci_bus_config()
-**
-** Autoconfiguration of one pci bus.
-**
-**========================================================
-*/
+/* return log2 of map size decoded for memory or port map */
static int
-pci_mfdev (int bus, int device)
+pci_mapsize(unsigned testval)
{
- pcici_t tag0,tag1;
- unsigned pci_id0, pci_id1;
-
- /*
- ** Detect a multi-function device that complies to the PCI 2.0 spec
- */
- tag0 = pcibus->pb_tag (bus, device, 0);
- if (pci_conf_read (tag0, PCI_HEADER_MISC) & PCI_HEADER_MULTIFUNCTION)
- return 1;
-
- /*
- ** Well, as always: Theory and implementation of PCI ...
- **
- ** If there is a valid device ID returned for function 1 AND
- ** the device ID of function 0 and 1 is different OR
- ** the first mapping register of 0 and 1 differs,
- ** then assume a multi-function device anyway ...
- **
- ** Example of such a broken device: ISA and IDE chip i83371FB (Triton)
- */
- tag1 = pcibus->pb_tag (bus, device, 1);
- pci_id1 = pci_conf_read (tag1, PCI_ID_REG);
-
- if (pci_id1 != 0xffffffff) {
-
- pci_id0 = pci_conf_read (tag0, PCI_ID_REG);
-
- if (pci_id0 != pci_id1)
- return 1;
-
- if (pci_conf_read (tag0, PCI_MAP_REG_START)
- != pci_conf_read (tag1, PCI_MAP_REG_START))
- return 1;
- }
- return 0;
-}
+ int ln2size;
-static void
-pci_bus_config (void)
-{
- int bus_no;
- u_char device;
- u_char reg;
- pcici_t tag, mtag;
- pcidi_t type;
-
- struct pci_device *dvp;
-
- /*
- ** first initialize the bridge (bus controller chip)
- */
- bus_no = pci_bridge_config ();
-
- printf ("Probing for devices on PCI bus %d:\n", bus_no);
-#ifndef PCI_QUIET
- if (bootverbose && !pci_info_done) {
- pci_info_done=1;
- printf ("\tconfiguration mode %d allows %d devices.\n",
- pci_mechanism, pci_maxdevice);
- };
-#endif
- for (device=0; device<pci_maxdevice; device ++) {
- char *name = NULL;
- struct pci_device **dvpp;
- int func, maxfunc = 0;
-
- for (func=0; func <= maxfunc; func++) {
- tag = pcibus->pb_tag (bus_no, device, func);
- type = pci_conf_read (tag, PCI_ID_REG);
-
- if ((!type) || (type==0xfffffffful)) continue;
-
- /*
- ** lookup device in ioconfiguration:
- */
-
- dvpp = (struct pci_device **)pcidevice_set.ls_items;
-
- while (dvp = *dvpp++) {
- if (dvp->pd_probe) {
- if (name=(*dvp->pd_probe)(tag, type))
- break;
- }
- };
- /*
- ** check for mirrored devices.
- */
- if (func != 0) {
- goto real_device;
- }
- if (device & 0x10) {
- mtag=pcibus->pb_tag (bus_no,
- (u_char)(device & ~0x10), 0);
- } else if (device & 0x08) {
- mtag=pcibus->pb_tag (bus_no,
- (u_char)(device & ~0x08), 0);
- } else goto real_device;
-
- if (type!=pci_conf_read (mtag, PCI_ID_REG))
- goto real_device;
-
- for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4)
- if (pci_conf_read(tag,reg)!=pci_conf_read(mtag,reg))
- goto real_device;
-
-#ifndef PCI_QUIET
- if (dvp==NULL) continue;
- if (bootverbose)
- printf ("%s? <%s> mirrored on pci%d:%d\n",
- dvp->pd_name, name, bus_no, device);
-#endif
- continue;
-
- real_device:
-
-#ifndef PCI_QUIET
-#ifdef PCI_BRIDGE_DEBUG
- if (bootverbose) {
- printf ("\tconfig header: 0x%08x 0x%08x 0x%08x 0x%08x\n",
- pci_conf_read (tag, 0),
- pci_conf_read (tag, 4),
- pci_conf_read (tag, 8),
- pci_conf_read (tag, 12));
- }
-#endif
-#endif
-
- if (func == 0 && pci_mfdev (bus_no, device)) {
- maxfunc = 7;
- }
-
- pci_remember(bus_no, device, func, dvp);
-
- if (dvp==NULL) {
-#ifndef PCI_QUIET
- if (pci_conf_count)
- continue;
-
- if (maxfunc == 0)
- printf("%s%d:%d: ",
- pcibus->pb_name, bus_no, device);
- else
- printf("%s%d:%d:%d: ",
- pcibus->pb_name, bus_no, device, func);
- not_supported (tag, type);
-#endif
- continue;
- };
-
- if (*name) {
- pci_attach (bus_no, device, func, dvp, name);
- }
- }
- }
-
-#ifndef PCI_QUIET
- if (bootverbose) {
- if (pcicb->pcicb_mamount)
- printf ("%s%d: uses %ud bytes of memory from %x upto %x.\n",
- pcibus->pb_name, bus_no,
- pcicb->pcicb_mamount,
- pcicb->pcicb_mfrom, pcicb->pcicb_mupto);
- if (pcicb->pcicb_pamount)
- printf ("%s%d: uses %ud bytes of I/O space from %x upto %x.\n",
- pcibus->pb_name, bus_no,
- 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, bus_no,
- pcicb->pcicb_bfrom, pcicb->pcicb_bupto);
+ testval = pci_mapbase(testval);
+ ln2size = 32;
+ while ((testval & 0x80000000) != 0)
+ {
+ ln2size--;
+ testval <<= 1;
}
-#endif
+ return (ln2size);
}
-/*========================================================
-**
-** pci_configure ()
-**
-** Autoconfiguration of pci devices.
-**
-** Has to take care of mirrored devices, which are
-** entailed by incomplete decoding of pci address lines.
-**
-**========================================================
-*/
-
-void pci_configure()
-{
- struct pcibus **pbp = (struct pcibus**) pcibus_set.ls_items;
-
- /*
- ** check pci bus present
- */
+/* return log2 of address range supported by map register */
- while (!pci_maxdevice && (pcibus = *pbp++)) {
- (*pcibus->pb_setup)();
- }
-
- if (!pci_maxdevice) return;
-
- /*
- ** hello world ..
- */
-
- pciroots = 1;
- while (pciroots--) {
-
- pcicb = malloc (sizeof (struct pcicb), M_DEVBUF, M_WAITOK);
- if (pcicb == NULL) {
- return;
- }
- bzero (pcicb, sizeof (struct pcicb));
- pcicb->pcicb_bus = pcibusmax;
- pcicb->pcicb_iolimit = 0xffff;
- pcicb->pcicb_membase = 0x02000000;
- pcicb->pcicb_p_membase = 0x02000000;
- pcicb->pcicb_memlimit = 0xffffffff;
- pcicb->pcicb_p_memlimit = 0xffffffff;
-
- while (pcicb != NULL) {
- pci_bus_config ();
-
- if (pcibusmax < pcicb->pcicb_bus)
- (pcibusmax = pcicb->pcicb_bus);
-
- if (pcicb->pcicb_down) {
- pcicb = pcicb->pcicb_down;
- continue;
- };
-
- while (pcicb && !pcicb->pcicb_next)
- pcicb = pcicb->pcicb_up;
-
- if (pcicb)
- pcicb = pcicb->pcicb_next;
- }
- pcibusmax++;
+static int
+pci_maprange(unsigned mapreg)
+{
+ int ln2range = 0;
+ switch (mapreg & 0x07) {
+ case 0x00:
+ case 0x01:
+ case 0x05:
+ ln2range = 32;
+ break;
+ case 0x02:
+ ln2range = 20;
+ break;
+ case 0x04:
+ ln2range = 64;
+ break;
}
- pci_conf_count++;
+ return (ln2range);
}
-/*========================================================
-**
-** pci_rescan ()
-**
-** try to find lkm driver for device
-**
-** May be called more than once.
-** Any device is attached only once.
-**
-**========================================================
-*/
-
-static void pci_rescan()
+/* extract map parameters into newly allocated array of pcimap structures */
+
+static pcimap *
+pci_readmaps(pcicfgregs *cfg, int maxmaps)
{
int i;
- for (i = 0; i < pci_dev_list_count; i++)
- {
- struct pci_lkm *lkm;
- pcici_t tag;
- struct pci_device *dvp;
- pcidi_t type = pci_dev_list[i].pc_devid;
- char *name = NULL;
- int bus, dev, func;
-
- if (pci_dev_list[i].pc_dvp)
- continue;
-
- bus = pci_dev_list[i].pc_sel.pc_bus;
- dev = pci_dev_list[i].pc_sel.pc_dev;
- func = pci_dev_list[i].pc_sel.pc_func;
-
- tag = pcibus->pb_tag (bus, dev, func);
-
- for (lkm = pci_lkm_head; lkm; lkm = lkm->next) {
- dvp = lkm->dvp;
- if (name=(*dvp->pd_probe)(tag, type))
- break;
- }
- if (name && *name) {
- pcicb = pci_dev_list[i].pc_cb;
- pci_attach (bus, dev, func, dvp, name);
- pci_dev_list[i].pc_dvp = dvp;
+ pcimap *map;
+ int map64 = 0;
+
+ while (maxmaps > 0
+ && pci_cfgread(cfg, PCIR_MAPS + (maxmaps -1) *4, 4) == 0)
+ maxmaps--;
+
+ map = malloc(maxmaps * sizeof (pcimap), M_DEVBUF, M_WAITOK);
+ if (map != NULL) {
+ bzero(map, sizeof(pcimap) * maxmaps);
+
+ for (i = 0; i < maxmaps; i++) {
+ int reg = PCIR_MAPS + i*4;
+ u_int32_t base;
+ u_int32_t testval;
+
+ base = pci_cfgread(cfg, reg, 4);
+
+ if (map64 == 0) {
+ pci_cfgwrite(cfg, reg, 0xffffffff, 4);
+ testval = pci_cfgread(cfg, reg, 4);
+ pci_cfgwrite(cfg, reg, base, 4);
+
+ map[i].base = pci_mapbase(base);
+ map[i].type = pci_maptype(base);
+ map[i].ln2size = pci_mapsize(testval);
+ map[i].ln2range = pci_maprange(testval);
+ map64 = map[i].ln2range == 64;
+ } else {
+ /* only fill in base, other fields are 0 */
+ map[i].base = base;
+ map64 = 0;
+ }
+ if (map[i].type == 0) {
+ /*
+ * This indicates, that some config space register
+ * was mistaken to contain a map, while it in fact
+ * contains unrelated information!
+ * Ignore this map and all that might have been
+ * expected to follow ...
+ */
+ maxmaps = i;
+ }
}
+ cfg->nummaps = maxmaps;
}
+ return (map);
}
-/*========================================================
-**
-** pci_register_lkm ()
-**
-** Add LKM PCI driver's struct pci_device to pci_lkm chain
-**
-**========================================================
-*/
+/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */
-int pci_register_lkm (struct pci_device *dvp, int if_revision)
+static void
+pci_fixancient(pcicfgregs *cfg)
{
- struct pci_lkm *lkm;
-
- if (if_revision != 0) {
- return -1;
- }
-
- if (!dvp || !dvp->pd_probe || !dvp->pd_attach) {
- return -1;
- }
-
- lkm = malloc (sizeof (*lkm), M_DEVBUF, M_WAITOK);
- if (!lkm) {
- return -1;
- }
+ if (cfg->hdrtype != 0)
+ return;
- lkm->dvp = dvp;
- lkm->next = pci_lkm_head;
- pci_lkm_head = lkm;
- pci_rescan();
- return 0;
+ /* PCI to PCI bridges use header type 1 */
+ if (cfg->class == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI)
+ cfg->hdrtype = 1;
}
-/*-----------------------------------------------------------------------
-**
-** 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
-**
-**-----------------------------------------------------------------------
-*/
-
-int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
+/* read config data specific to header type 1 device (PCI to PCI bridge) */
+
+static void *
+pci_readppb(pcicfgregs *cfg)
{
- unsigned data, ioaddr, iosize;
- struct pcicb *link = pcicb;
+ pcih1cfgregs *p;
- /*
- ** sanity check
- */
+ p = malloc(sizeof (pcih1cfgregs), M_DEVBUF, M_WAITOK);
+ if (p == NULL)
+ return (NULL);
- 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);
- return (0);
- };
+ bzero(p, sizeof *p);
- /*
- ** get size and type of port
- **
- ** type is in the lowest two bits.
- ** If device requires 2^n bytes, the next
- ** n-2 bits are hardwired as 0.
- */
-
- ioaddr = pci_conf_read (tag, reg) & PCI_MAP_IO_ADDRESS_MASK;
- if (!ioaddr) {
- printf ("pci_map_port failed: not configured by bios.\n");
- return (0);
- };
+ p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_1, 2);
+ p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_1, 2);
- pci_conf_write (tag, reg, 0xfffffffful);
- data = pci_conf_read (tag, reg);
- pci_conf_write (tag, reg, ioaddr);
+ p->seclat = pci_cfgread(cfg, PCIR_SECLAT_1, 1);
- 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);
- iosize &= ~(ioaddr ^ -ioaddr);
- if (ioaddr < pcicb->pcicb_iobase
- || ioaddr + iosize -1 > 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);
- }
+ p->iobase = PCI_PPBIOBASE (pci_cfgread(cfg, PCIR_IOBASEH_1, 2),
+ pci_cfgread(cfg, PCIR_IOBASEL_1, 1));
+ p->iolimit = PCI_PPBIOLIMIT (pci_cfgread(cfg, PCIR_IOLIMITH_1, 2),
+ pci_cfgread(cfg, PCIR_IOLIMITL_1, 1));
-#ifndef PCI_QUIET
- if (bootverbose)
- printf ("\treg%d: ioaddr=0x%x size=0x%x\n",
- (unsigned) reg, (unsigned) ioaddr, (unsigned) iosize);
-#endif
- /*
- ** 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.
- */
-
- for (;;) {
- data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
- data |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
- (void) pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data);
- if ((link = link->pcicb_up) == NULL)
- break;
- tag = link->pcicb_bridge;
- }
+ p->membase = PCI_PPBMEMBASE (0,
+ pci_cfgread(cfg, PCIR_MEMBASE_1, 2));
+ p->memlimit = PCI_PPBMEMLIMIT (0,
+ pci_cfgread(cfg, PCIR_MEMLIMIT_1, 2));
- *pa = ioaddr;
+ p->pmembase = PCI_PPBMEMBASE (
+ (pci_addr_t)pci_cfgread(cfg, PCIR_PMBASEH_1, 4),
+ pci_cfgread(cfg, PCIR_PMBASEL_1, 2));
- return (1);
+ p->pmemlimit = PCI_PPBMEMLIMIT (
+ (pci_addr_t)pci_cfgread(cfg, PCIR_PMLIMITH_1, 4),
+ pci_cfgread(cfg, PCIR_PMLIMITL_1, 2));
+ return (p);
}
-/*-----------------------------------------------------------------------
-**
-** Map device into virtual and physical 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
-**
-**-----------------------------------------------------------------------
-*/
-
-int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
-{
- struct pcicb *link = pcicb;
- unsigned data ,paddr;
- vm_size_t psize, poffs;
- vm_offset_t vaddr;
-
- /*
- ** sanity check
- */
-
- 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);
- return (0);
- };
-
- /*
- ** save old mapping, get size and type of memory
- **
- ** type is in the lowest four bits.
- ** If device requires 2^n bytes, the next
- ** n-4 bits are read as 0.
- */
-
- paddr = pci_conf_read (tag, reg) & PCI_MAP_MEMORY_ADDRESS_MASK;
- pci_conf_write (tag, reg, 0xfffffffful);
- data = pci_conf_read (tag, reg);
- pci_conf_write (tag, reg, paddr);
-
- /*
- ** check the type
- */
-
- if (!((data & PCI_MAP_MEMORY_TYPE_MASK) == PCI_MAP_MEMORY_TYPE_32BIT_1M
- && (paddr & ~0xfffff) == 0)
- && (data & PCI_MAP_MEMORY_TYPE_MASK) != PCI_MAP_MEMORY_TYPE_32BIT){
- printf ("pci_map_mem failed: bad memory type=0x%x\n",
- (unsigned) data);
- return (0);
- };
-
- /*
- ** get the size.
- */
-
- psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
-
- 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_register_memory (pcicb, paddr, paddr+psize-1);
- };
+/* read config data specific to header type 2 device (PCI to CardBus bridge) */
- 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);*/
-/* ACHTUNG: Ist der Code richtig, wenn eine PCI-PCI-Bridge fuer
- * die PCI-Slots verwendet wird, aber die Onboard-Devices direkt
- * an der CPU-PCI-Bridge haengen (Siehe Compaq Prolinea Problem) ???
- */
- }
- pci_conf_write (tag, reg, paddr);
-
- /*
- ** Truncate paddr to page boundary.
- ** (Or does pmap_mapdev the job?)
- */
+static void *
+pci_readpcb(pcicfgregs *cfg)
+{
+ pcih2cfgregs *p;
- poffs = paddr - trunc_page (paddr);
- vaddr = (vm_offset_t) pmap_mapdev (paddr-poffs, psize+poffs);
+ p = malloc(sizeof (pcih2cfgregs), M_DEVBUF, M_WAITOK);
+ if (p == NULL)
+ return (NULL);
- if (!vaddr) return (0);
+ bzero(p, sizeof *p);
- vaddr += poffs;
+ p->secstat = pci_cfgread(cfg, PCIR_SECSTAT_2, 2);
+ p->bridgectl = pci_cfgread(cfg, PCIR_BRIDGECTL_2, 2);
+
+ p->seclat = pci_cfgread(cfg, PCIR_SECLAT_2, 1);
-#ifndef PCI_QUIET
- /*
- ** display values.
- */
+ p->membase0 = pci_cfgread(cfg, PCIR_MEMBASE0_2, 4);
+ p->memlimit0 = pci_cfgread(cfg, PCIR_MEMLIMIT0_2, 4);
+ p->membase1 = pci_cfgread(cfg, PCIR_MEMBASE1_2, 4);
+ p->memlimit1 = pci_cfgread(cfg, PCIR_MEMLIMIT1_2, 4);
- if (bootverbose)
- 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
- /*
- ** 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.
- */
-
- for (;;) {
- data = pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
- data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
- (void) pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data);
- if ((link = link->pcicb_up) == NULL)
- break;
- tag = link->pcicb_bridge;
- }
+ p->iobase0 = pci_cfgread(cfg, PCIR_IOBASE0_2, 4);
+ p->iolimit0 = pci_cfgread(cfg, PCIR_IOLIMIT0_2, 4);
+ p->iobase1 = pci_cfgread(cfg, PCIR_IOBASE1_2, 4);
+ p->iolimit1 = pci_cfgread(cfg, PCIR_IOLIMIT1_2, 4);
- *va = vaddr;
- *pa = paddr;
-
- return (1);
+ p->pccardif = pci_cfgread(cfg, PCIR_PCCARDIF_2, 4);
+ return p;
}
-/*-----------------------------------------------------------------------
-**
-** 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 :-) :-) :-)
-**
-**-----------------------------------------------------------------------
-*/
-
-static 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;
-}
+/* extract header type specific config data */
static void
-pci_int (int irq)
+pci_hdrtypedata(pcicfgregs *cfg)
{
- struct pci_int_desc * p;
- int s;
-
- if (irq<0 || irq >= PCI_MAX_IRQ) {
- printf ("pci_int: irq %d out of range, ignored\n", irq);
- return;
- };
- for (p = pci_int_desc[irq]; p!=NULL; p=p->pcid_next) {
- s = splq (*p->pcid_maskptr);
- (*p->pcid_handler) (p->pcid_argument);
- p-> pcid_tally++;
- splx (s);
-#if 0
- if (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
- };
-}
-#endif
-
-/*-----------------------------------------------------------------------
-**
-** Auxiliary function for interrupt (un)mapping.
-**
-**-----------------------------------------------------------------------
-*/
-
-static u_int
-getirq (pcici_t tag)
-{
- u_int irq;
-
- irq = PCI_INTERRUPT_LINE_EXTRACT(
- pci_conf_read (tag, PCI_INTERRUPT_REG));
-
- if (irq == 0 || irq == 0xff) {
- printf ("\tint line register not set by bios\n");
- return (0xff);
+ switch (cfg->hdrtype) {
+ case 0:
+ cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_0, 2);
+ cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_0, 2);
+ cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_0);
+ break;
+ case 1:
+ cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_1, 2);
+ cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_1, 2);
+ cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_1, 1);
+ cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_1, 1);
+ cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_1);
+ cfg->hdrspec = pci_readppb(cfg);
+ break;
+ case 2:
+ cfg->subvendor = pci_cfgread(cfg, PCIR_SUBVEND_2, 2);
+ cfg->subdevice = pci_cfgread(cfg, PCIR_SUBDEV_2, 2);
+ cfg->secondarybus = pci_cfgread(cfg, PCIR_SECBUS_2, 1);
+ cfg->subordinatebus = pci_cfgread(cfg, PCIR_SUBBUS_2, 1);
+ cfg->map = pci_readmaps(cfg, PCI_MAXMAPS_2);
+ cfg->hdrspec = pci_readpcb(cfg);
+ break;
}
+}
- if (irq >= PCI_MAX_IRQ) {
- printf ("\tirq %d out of bounds (must be < %d).\n",
- irq, PCI_MAX_IRQ);
- return (0xff);
+/* read configuration header into pcicfgrect structure */
+
+static pcicfgregs *
+pci_readcfg(pcicfgregs *probe)
+{
+ pcicfgregs *cfg = NULL;
+
+ if (pci_cfgread(probe, PCIR_DEVVENDOR, 4) != -1) {
+ cfg = malloc(sizeof (pcicfgregs), M_DEVBUF, M_WAITOK);
+ if (cfg == NULL)
+ return (cfg);
+
+ bzero(cfg, sizeof *cfg);
+
+ cfg->bus = probe->bus;
+ cfg->slot = probe->slot;
+ cfg->func = probe->func;
+ cfg->parent = probe->parent;
+
+ cfg->vendor = pci_cfgread(cfg, PCIR_VENDOR, 2);
+ cfg->device = pci_cfgread(cfg, PCIR_DEVICE, 2);
+ cfg->cmdreg = pci_cfgread(cfg, PCIR_COMMAND, 2);
+ cfg->statreg = pci_cfgread(cfg, PCIR_STATUS, 2);
+ cfg->class = pci_cfgread(cfg, PCIR_CLASS, 1);
+ cfg->subclass = pci_cfgread(cfg, PCIR_SUBCLASS, 1);
+ cfg->progif = pci_cfgread(cfg, PCIR_PROGIF, 1);
+ cfg->revid = pci_cfgread(cfg, PCIR_REVID, 1);
+ cfg->hdrtype = pci_cfgread(cfg, PCIR_HEADERTYPE, 1);
+ cfg->cachelnsz = pci_cfgread(cfg, PCIR_CACHELNSZ, 1);
+ cfg->lattimer = pci_cfgread(cfg, PCIR_LATTIMER, 1);
+ cfg->intpin = pci_cfgread(cfg, PCIR_INTPIN, 1);
+ cfg->intline = pci_cfgread(cfg, PCIR_INTLINE, 1);
+ cfg->mingnt = pci_cfgread(cfg, PCIR_MINGNT, 1);
+ cfg->maxlat = pci_cfgread(cfg, PCIR_MAXLAT, 1);
+
+ cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0;
+ cfg->hdrtype &= ~PCIM_MFDEV;
+
+ pci_fixancient(cfg);
+ pci_hdrtypedata(cfg);
}
-
- return (irq);
+ return (cfg);
}
-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);
+/* free pcicfgregs structure and all depending data structures */
- return (pp);
-}
-
-static struct pci_int_desc *
-getintdescbymptr (u_int irq, unsigned * mptr)
+static int
+pci_freecfg(pcicfgregs *cfg)
{
- struct pci_int_desc *p;
-
- for (p=pci_int_desc[irq];p;p=p->pcid_next)
- if (p->pcid_maskptr == mptr) break;
- return (p);
+ if (cfg->hdrspec != NULL)
+ free(cfg->hdrspec, M_DEVBUF);
+ if (cfg->map != NULL)
+ free(cfg->map, M_DEVBUF);
+ free(cfg, M_DEVBUF);
+ return (0);
}
-/*-----------------------------------------------------------------------
-**
-** Map pci interrupt.
-**
-**-----------------------------------------------------------------------
-*/
-
-static unsigned pci_mask0 = 0;
-
-int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg, unsigned *maskptr)
+static void
+pci_addcfg(pcicfgregs *cfg)
{
- u_int irq;
- int result, oldspl;
- unsigned mask;
- struct pci_int_desc *tail, *mdp=NULL, *new=NULL;
-
- /*
- ** Get irq line from configuration space,
- ** and check for consistency.
- */
-
- irq = getirq (tag);
- if (irq == 0xff) {
- 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
- /*
- * XXX if we get here, then `func' must be pci_int
- * so the bogus casts are almost OK since they just
- * undo the bogus casts that were needed to pass
- * pci_int and its arg to pci_map_int().
- */
- (irq, (inthand2_t *) 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.
- */
-
- if (bootverbose)
- printf ("\tusing shared irq %d.\n", irq);
-
- /*
- ** replace old handler by shared-int-handler.
- */
-
- result = pcibus->pb_idetach (irq,
- (inthand2_t *) 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;
- };
+#ifdef PCI_DEBUG
+ if (bootverbose) {
+ int i;
+ printf("new pci: vendor=0x%04x, dev=0x%04x, revid=0x%02x\n",
+ cfg->vendor, cfg->device, cfg->revid);
+ printf("\t cmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n",
+ cfg->cmdreg, cfg->statreg, cfg->cachelnsz);
+ printf("\t class=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n",
+ cfg->class, cfg->subclass, cfg->progif, cfg->hdrtype, cfg->mfdev);
+ printf("\t lattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n",
+ cfg->lattimer, cfg->lattimer * 30,
+ cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250);
+
+ if (cfg->intpin > 0)
+ printf("\t intpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline);
+
+ for (i = 0; i < cfg->nummaps; i++) {
+ pcimap *m = &cfg->map[i];
+ printf("\t map[%d]: type %x, range %2d, base %08x, size %2d\n",
+ i, m->type, m->ln2range, m->base, m->ln2size);
+ }
}
-#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 (new) free(new, M_DEVBUF);
- if (!mdp) (void) pcibus->pb_imaskexc (irq, maskptr);
- splx (oldspl);
- return (0);
+#endif /* PCI_DEBUG */
+ pci_drvattach(cfg); /* XXX currently defined in pci_compat.c */
}
-/*-----------------------------------------------------------------------
-**
-** Unmap pci interrupt.
-**
-**-----------------------------------------------------------------------
-*/
+/* return pointer to device that is a bridge to this bus */
-int pci_unmap_int (pcici_t tag)
+static pcicfgregs *
+pci_bridgeto(int bus)
{
- 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 == 0xff) {
- return (0);
- };
-
- /*
- ** Search and unlink interrupt descriptor.
- */
-
- 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,
- (inthand2_t *) 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,
- (inthand2_t *) 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);
+ return (NULL); /* XXX not yet implemented */
}
-/*-----------------------------------------------------------
-**
-** Display of unknown devices.
-**
-**-----------------------------------------------------------
-*/
-struct vt {
- u_short ident;
- char* name;
-};
-
-static struct vt VendorTable[] = {
- {0x0e11, "Compaq"},
- {0x1000, "NCR/Symbios"},
- {0x1002, "ATI Technologies Inc."},
- {0x1004, "VLSI"},
- {0x100B, "National Semiconductor"},
- {0x100E, "Weitek"},
- {0x1011, "Digital Equipment Corporation"},
- {0x1013, "Cirrus Logic"},
- {0x101A, "NCR"},
- {0x1022, "AMD"},
- {0x102B, "Matrox"},
- {0x102C, "Chips & Technologies"},
- {0x1039, "Silicon Integrated Systems"},
- {0x1042, "SMC"},
- {0x1044, "DPT"},
- {0x1045, "OPTI"},
- {0x104B, "Bus Logic"},
- {0x104C, "TI"},
- {0x1060, "UMC"},
- {0x1080, "Contaq"},
- {0x1095, "CMD"},
- {0x10b9, "ACER Labs"},
- {0x10c8, "NeoMagic"},
- {0x1106, "VIA Technologies"},
- {0x5333, "S3 Inc."},
- {0x8086, "Intel Corporation"},
- {0x9004, "Adaptec"},
- {0,0}
-};
-
-typedef struct {
- const int subclass;
- const char *name;
-} subclass_name;
-
-/* 0x00 prehistoric subclasses */
-static const subclass_name old_subclasses[] =
-{
- { 0x00, "misc" },
- { 0x01, "vga" },
- { 0x00, NULL }
-};
-
-/* 0x01 mass storage subclasses */
-static const subclass_name storage_subclasses[] =
-{
- { 0x00, "scsi" },
- { 0x01, "ide" },
- { 0x02, "floppy"},
- { 0x03, "ipi" },
- { 0x80, "misc" },
- { 0x00, NULL }
-};
-
-/* 0x02 network subclasses */
-static const subclass_name network_subclasses[] =
-{
- { 0x00, "ethernet" },
- { 0x01, "tokenring" },
- { 0x02, "fddi" },
- { 0x80, "misc" },
- { 0x00, NULL }
-};
-
-/* 0x03 display subclasses */
-static const subclass_name display_subclasses[] =
-{
- { 0x00, "vga" },
- { 0x01, "xga" },
- { 0x80, "misc" },
- { 0x00, NULL }
-};
-
-/* 0x04 multimedia subclasses */
-static const subclass_name multimedia_subclasses[] =
-{
- { 0x00, "video" },
- { 0x01, "audio" },
- { 0x80, "misc" },
- { 0x00, NULL }
-};
-
-/* 0x05 memory subclasses */
-static const subclass_name memory_subclasses[] =
-{
- { 0x00, "ram" },
- { 0x01, "flash" },
- { 0x80, "misc" },
- { 0x00, NULL }
-};
-
-/* 0x06 bridge subclasses */
-static const subclass_name bridge_subclasses[] =
-{
- { 0x00, "host" },
- { 0x01, "isa" },
- { 0x02, "eisa" },
- { 0x03, "mc" },
- { 0x04, "pci" },
- { 0x05, "pcmcia"},
- { 0x07, "cardbus"},
- { 0x80, "misc" },
- { 0x00, NULL }
-};
-
-static const subclass_name *const subclasses[] = {
- old_subclasses,
- storage_subclasses,
- network_subclasses,
- display_subclasses,
- multimedia_subclasses,
- memory_subclasses,
- bridge_subclasses,
-};
-
-static const char *const majclasses[] = {
- "old",
- "storage",
- "network",
- "display",
- "multimedia",
- "memory",
- "bridge",
- "comms",
- "system",
- "input",
- "docking",
- "processor",
- "serial"
-};
-
-
-void not_supported (pcici_t tag, u_long type)
-{
- u_long reg;
- u_long data;
- u_char class;
- u_char subclass;
- struct vt * vp;
- int pciint;
- int irq;
-
- /*
- ** lookup the names.
- */
-
- for (vp=VendorTable; vp->ident; vp++)
- if (vp->ident == (type & 0xffff))
- break;
+/* scan one PCI bus for devices */
- /*
- ** and display them.
- */
-
- if (vp->ident) printf (vp->name);
- else printf ("vendor=0x%04lx", type & 0xffff);
-
- printf (", device=0x%04lx", type >> 16);
-
- data = pci_conf_read(tag, PCI_CLASS_REG);
- class = (data >> 24) & 0xff;
- subclass = (data >> 16) & 0xff;
-
- if (class < sizeof(majclasses) / sizeof(majclasses[0])) {
- printf(", class=%s", majclasses[class]);
- } else {
- printf(", class=0x%02x", class);
- }
-
- if (class < sizeof(subclasses) / sizeof(subclasses[0])) {
- const subclass_name *p = subclasses[class];
- while (p->name && (p->subclass != subclass))
- p++;
- if (p->name) {
- printf(" (%s)", p->name);
- } else {
- printf(" (unknown subclass 0x%02lx)", subclass);
+static int
+pci_probebus(int bus)
+{
+ pcicfgregs probe;
+ int bushigh = bus;
+
+ bzero(&probe, sizeof probe);
+ probe.parent = pci_bridgeto(bus);
+ probe.bus = bus;
+ for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
+ int pcifunchigh = 0;
+ for (probe.func = 0; probe.func <= pcifunchigh; probe.func++) {
+ pcicfgregs *cfg = pci_readcfg(&probe);
+ if (cfg != NULL) {
+ if (cfg->mfdev)
+ pcifunchigh = 7;
+
+ if (bushigh < cfg->subordinatebus)
+ bushigh = cfg->subordinatebus;
+
+ pci_addcfg(cfg);
+ cfg = NULL; /* we don't own this anymore ... */
+ }
}
- } else {
- printf(", subclass=0x%02x", subclass);
}
+ return (bushigh);
+}
- data = pci_conf_read (tag, PCI_INTERRUPT_REG);
- pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
-
- if (pciint) {
-
- 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.
- */
+/* scan a PCI bus tree reached through one PCI attachment point */
- if (irq && (irq != 0xff))
- printf ("%d", irq);
- else
- printf ("??");
- };
+int
+pci_probe(pciattach *parent)
+{
+ int bushigh;
+ int bus = 0;
- if (class != (PCI_CLASS_BRIDGE >> 24))
- printf (" [no driver assigned]");
- printf ("\n");
+ bushigh = pci_bushigh();
+ while (bus <= bushigh) {
+ int newbushigh;
- if (bootverbose) {
- if (class == (PCI_CLASS_BRIDGE >> 24)) {
- printf ("configuration space registers:");
- for (reg = 0; reg < 0x100; reg+=4) {
- if ((reg & 0x0f) == 0) printf ("\n%02x:\t", reg);
- printf ("%08x ", pci_conf_read (tag, reg));
- }
- printf ("\n");
- } else {
- for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
- data = pci_conf_read (tag, reg);
- if ((data&~7)==0) continue;
- switch (data&7) {
+ printf("Probing for devices on PCI bus %d:\n", bus);
+ newbushigh = pci_probebus(bus);
- case 1:
- case 5:
- printf ("\tmap(%x): io(%04lx)\n",
- reg, data & ~3);
- break;
- case 0:
- printf ("\tmap(%x): mem32(%08lx)\n",
- reg, data & ~7);
- break;
- case 2:
- printf ("\tmap(%x): mem20(%05lx)\n",
- reg, data & ~7);
- break;
- case 4:
- printf ("\tmap(%x): mem64(%08x%08lx)\n",
- reg, pci_conf_read (tag, reg +4), data & ~7);
- reg += 4;
- break;
- }
- }
- }
+ if (bushigh < newbushigh)
+ bushigh = newbushigh;
+ bus++;
}
+ return (bushigh);
}
/*
- * This is the user interface to the PCI configuration space.
+ * This is the user interface to PCI configuration space.
*/
-
-
-static void
-pci_remember(int bus, int dev, int func, struct pci_device *dvp)
-{
- struct pci_conf *p;
- pcici_t tag;
-
- if (++pci_dev_list_count > pci_dev_list_size) {
- struct pci_conf *new;
-
- pci_dev_list_size += 8;
- MALLOC(new, struct pci_conf *, pci_dev_list_size * sizeof *new,
- M_DEVL, M_NOWAIT);
- if (!new) {
- pci_dev_list_size -= 8;
- pci_dev_list_count--;
- return;
- }
-
- if (pci_dev_list) {
- bcopy(pci_dev_list, new, ((pci_dev_list_size - 8) *
- sizeof *new));
- FREE(pci_dev_list, M_DEVL);
- }
- pci_dev_list = new;
- }
-
- p = &pci_dev_list[pci_dev_list_count - 1];
- p->pc_sel.pc_bus = bus;
- p->pc_sel.pc_dev = dev;
- p->pc_sel.pc_func = func;
- p->pc_dvp = dvp;
- p->pc_cb = pcicb;
-
- tag = pcibus->pb_tag (bus, dev, func);
- p->pc_hdr = (pci_conf_read (tag, PCI_HEADER_MISC) >> 16) & 0xff;
- p->pc_devid = pci_conf_read(tag, PCI_ID_REG);
- p->pc_class = pci_conf_read(tag, PCI_CLASS_REG);
- switch (p->pc_hdr & 0x7f) {
- case 0:
- p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG0);
- break;
- case 1:
- p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG1);
- break;
- case 2:
- p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG2);
- break;
- default:
- p->pc_subid = 0;
- }
-}
-
+
static int
pci_open(dev_t dev, int oflags, int devtype, struct proc *p)
{
if ((oflags & FWRITE) && securelevel > 0) {
return EPERM;
}
-
return 0;
}
@@ -1904,79 +470,62 @@ pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
struct pci_io *io;
size_t iolen;
int error;
- pcici_t tag;
if (cmd != PCIOCGETCONF && !(flag & FWRITE))
return EPERM;
switch(cmd) {
case PCIOCGETCONF:
+#ifdef NOTYET
+static struct pci_conf *pci_dev_list;
+static unsigned pci_dev_list_count;
+static unsigned pci_dev_list_size;
+
cio = (struct pci_conf_io *)data;
iolen = min(cio->pci_len,
pci_dev_list_count * sizeof(struct pci_conf));
cio->pci_len = pci_dev_list_count * sizeof(struct pci_conf);
error = copyout(pci_dev_list, cio->pci_buf, iolen);
+#else
+ error = ENODEV;
+#endif
break;
case PCIOCREAD:
io = (struct pci_io *)data;
switch(io->pi_width) {
+ pcicfgregs probe;
case 4:
- tag = pcibus->pb_tag (io->pi_sel.pc_bus,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func);
- io->pi_data = pci_conf_read(tag, io->pi_reg);
- error = 0;
- break;
case 2:
case 1:
- default:
- error = ENODEV;
- break;
- }
- break;
-
- case PCIOCWRITE:
- io = (struct pci_io *)data;
- switch(io->pi_width) {
- case 4:
- tag = pcibus->pb_tag (io->pi_sel.pc_bus,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func);
- pci_conf_write(tag, io->pi_reg, io->pi_data);
+ probe.bus = io->pi_sel.pc_bus;
+ probe.slot = io->pi_sel.pc_dev;
+ probe.func = io->pi_sel.pc_func;
+ io->pi_data = pci_cfgread(&probe,
+ io->pi_reg, io->pi_width);
error = 0;
break;
- case 2:
- case 1:
default:
error = ENODEV;
break;
}
break;
- case PCIOCATTACHED:
+ case PCIOCWRITE:
io = (struct pci_io *)data;
switch(io->pi_width) {
+ pcicfgregs probe;
case 4:
- {
- int i = pci_dev_list_count;
- struct pci_conf *p = pci_dev_list;
- error = ENODEV;
- while (i--) {
- if (io->pi_sel.pc_bus == p->pc_sel.pc_bus &&
- io->pi_sel.pc_dev == p->pc_sel.pc_dev &&
- io->pi_sel.pc_func == p->pc_sel.pc_func) {
- io->pi_data = (u_int32_t)p->pc_dvp;
- error = 0;
- break;
- }
- p++;
- }
- }
- break;
case 2:
case 1:
+ probe.bus = io->pi_sel.pc_bus;
+ probe.slot = io->pi_sel.pc_dev;
+ probe.func = io->pi_sel.pc_func;
+ pci_cfgwrite(&probe,
+ io->pi_reg, io->pi_data, io->pi_width);
+ error = 0;
+ break;
default:
error = ENODEV;
break;
@@ -2017,4 +566,4 @@ pci_cdevinit(void *dummy)
SYSINIT(pcidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+PCI_CDEV, pci_cdevinit, NULL);
-#endif /* NPCI */
+#endif /* NPCI > 0 */
OpenPOWER on IntegriCloud