Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Add an option (defopt) PCI_NETBSD_CONFIGURE that...



details:   https://anonhg.NetBSD.org/src/rev/defafd12da2a
branches:  trunk
changeset: 503580:defafd12da2a
user:      briggs <briggs%NetBSD.org@localhost>
date:      Fri Feb 09 14:33:15 2001 +0000

description:
Add an option (defopt) PCI_NETBSD_CONFIGURE that provides PCI bus
configuration (assignment of bus numbers, BARs, timer values,
interrupt lines, etc.).
The interface must be called from m.d. code prior to probing the bus.
It is meant to be called once for each primary (bus == 0) PCI bus in
the system.  It will configure any busses behind PCI-PCI bridges.
Section 9 man page for pci_configure_bus() will come soon.
In the meantime, sample usage is in arch/sandpoint/sandpoint/mainbus.c.
[ Reviewed by thorpej ]

diffstat:

 sys/dev/pci/files.pci |    5 +-
 sys/dev/pci/pciconf.c |  917 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/pci/pciconf.h |   49 ++
 sys/dev/pci/pcireg.h  |   67 +++-
 4 files changed, 1035 insertions(+), 3 deletions(-)

diffs (truncated from 1098 to 300 lines):

diff -r 1656321cd6ac -r defafd12da2a sys/dev/pci/files.pci
--- a/sys/dev/pci/files.pci     Fri Feb 09 14:27:06 2001 +0000
+++ b/sys/dev/pci/files.pci     Fri Feb 09 14:33:15 2001 +0000
@@ -1,10 +1,10 @@
-#      $NetBSD: files.pci,v 1.120 2001/02/07 14:41:12 tacha Exp $
+#      $NetBSD: files.pci,v 1.121 2001/02/09 14:33:15 briggs Exp $
 #
 # Config file and device description for machine-independent PCI code.
 # Included by ports that need it.  Requires that the SCSI files be
 # defined first.
 
-defopt opt_pci.h       PCIVERBOSE PCI_CONFIG_DUMP
+defopt opt_pci.h       PCIVERBOSE PCI_CONFIG_DUMP PCI_NETBSD_CONFIGURE
 
 defopt opt_bktr.h      BKTR_OVERRIDE_CARD BKTR_OVERRIDE_TUNER BKTR_OVERRIDE_DBX
                        BKTR_OVERRIDE_MSP BKTR_SYSTEM_DEFAULT
@@ -20,6 +20,7 @@
 file   dev/pci/pci_map.c               pci
 file   dev/pci/pci_quirks.c            pci
 file   dev/pci/pci_subr.c              pci
+file   dev/pci/pciconf.c               pci_netbsd_configure
 
 # Cypress 82c693 hyperCache(tm) Stand-Alone PCI Peripheral Controller
 # with USB.  This is a combo chip:
diff -r 1656321cd6ac -r defafd12da2a sys/dev/pci/pciconf.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/pci/pciconf.c     Fri Feb 09 14:33:15 2001 +0000
@@ -0,0 +1,917 @@
+/*     $NetBSD: pciconf.c,v 1.1 2001/02/09 14:33:15 briggs Exp $       */
+
+/*
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Allen Briggs for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed for the NetBSD Project by
+ *      Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+/*
+ * Derived in part from code from PMON/2000 (http://pmon.groupbsd.org/).
+ */
+
+#include "opt_pci.h"
+
+#include <sys/param.h>
+#include <sys/extent.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pciconf.h>
+#include <dev/pci/pcidevs.h>
+
+#ifdef PCI_CONFIGURATION_DEBUG
+int pci_conf_debug = 0;
+#endif
+
+#if !defined(MIN)
+#define        MIN(a,b) (((a)<(b))?(a):(b))
+#define        MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+/* per-bus constants. */
+#define MAX_CONF_DEV   8                       /* Arbitrary */
+#define MAX_CONF_MEM   (3 * MAX_CONF_DEV)      /* Avg. 3 per device -- Arb. */
+#define MAX_CONF_IO    (1 * MAX_CONF_DEV)      /* Avg. 1 per device -- Arb. */
+
+#define PCI_BUSNO_SPACING      (1 << 5)
+
+struct _s_pciconf_bus_t;                       /* Forward declaration */
+
+typedef struct _s_pciconf_dev_t {
+       int             ipin;
+       int             iline;
+       int             min_gnt;
+       int             max_lat;
+       pcitag_t        tag;
+       pci_chipset_tag_t       pc;
+       struct _s_pciconf_bus_t *ppb;           /* I am really a bridge */
+} pciconf_dev_t;
+
+typedef struct _s_pciconf_win_t {
+       pciconf_dev_t   *dev;
+       int             reg;                    /* 0 for busses */
+       int             align;
+       int             prefetch;
+       u_int64_t       size;
+       u_int64_t       address;
+} pciconf_win_t;
+
+typedef struct _s_pciconf_bus_t {
+       int             busno;
+       int             next_busno;
+       int             last_busno;
+       int             busno_spacing;
+       int             max_mingnt;
+       int             min_maxlat;
+       int             prefetch;
+       int             fast_b2b;
+       int             freq_66;
+       int             def_ltim;
+       int             max_ltim;
+       int             bandwidth_used;
+       int             swiz;
+
+       int             ndevs;
+       pciconf_dev_t   device[MAX_CONF_DEV];
+
+       /* These should be sorted in order of decreasing size */
+       int             nmemwin;
+       pciconf_win_t   pcimemwin[MAX_CONF_MEM];
+       int             niowin;
+       pciconf_win_t   pciiowin[MAX_CONF_IO];
+
+       bus_size_t      io_total;
+       bus_size_t      mem_total;
+       bus_size_t      pmem_total;
+
+       struct extent   *ioext;
+       struct extent   *memext;
+       struct extent   *pmemext;
+
+       pci_chipset_tag_t       pc;
+       struct _s_pciconf_bus_t *parent_bus;
+} pciconf_bus_t;
+
+static int     probe_bus(pciconf_bus_t *);
+static void    alloc_busno(pciconf_bus_t *, pciconf_bus_t *);
+static int     pci_do_device_query(pciconf_bus_t *, pcitag_t, int, int);
+static int     setup_iowins(pciconf_bus_t *);
+static int     setup_memwins(pciconf_bus_t *);
+static int     configure_bridge(pciconf_dev_t *);
+static int     configure_bus(pciconf_bus_t *);
+static u_int64_t       pci_allocate_range(struct extent *, u_int64_t, int);
+static pciconf_win_t   *get_io_desc(pciconf_bus_t *, bus_size_t);
+static pciconf_win_t   *get_mem_desc(pciconf_bus_t *, bus_size_t);
+static pciconf_bus_t   *query_bus(pciconf_bus_t *, pciconf_dev_t *, int);
+
+#ifdef PCI_CONFIGURATION_DEBUG
+static void    print_tag(pci_chipset_tag_t, pcitag_t);
+
+static void
+print_tag(pci_chipset_tag_t pc, pcitag_t tag)
+{
+       int     bus, dev, func;
+
+       pci_decompose_tag(pc, tag, &bus, &dev, &func);
+       printf("PCI: bus %d, device %d, function %d: ", bus, dev, func);
+}
+#endif
+
+/************************************************************************/
+/************************************************************************/
+/***********************   Bus probing routines   ***********************/
+/************************************************************************/
+/************************************************************************/
+static pciconf_win_t *
+get_io_desc(pciconf_bus_t *pb, bus_size_t size)
+{
+       int     i, n;
+
+       n = pb->niowin;
+       for (i=n; i > 0 && size > pb->pciiowin[i-1].size; i--)
+               pb->pciiowin[i] = pb->pciiowin[i-1]; /* struct copy */
+       return &pb->pciiowin[i];
+}
+
+static pciconf_win_t *
+get_mem_desc(pciconf_bus_t *pb, bus_size_t size)
+{
+       int     i, n;
+
+       n = pb->nmemwin;
+       for (i=n; i > 0 && size > pb->pcimemwin[i-1].size; i--)
+               pb->pcimemwin[i] = pb->pcimemwin[i-1]; /* struct copy */
+       return &pb->pcimemwin[i];
+}
+
+/*
+ * Set up bus common stuff, then loop over devices & functions.
+ * If we find something, call pci_do_device_query()).
+ */
+static int
+probe_bus(pciconf_bus_t *pb)
+{
+       int device, maxdevs;
+
+       maxdevs = pci_bus_maxdevs(pb->pc, pb->busno);
+       pb->ndevs = 0;
+       pb->niowin = 0;
+       pb->nmemwin = 0;
+       pb->freq_66 = 1;
+       pb->fast_b2b = 1;
+       pb->prefetch = 1;
+       pb->max_mingnt = 0;     /* we are looking for the maximum */
+       pb->min_maxlat = 0x100; /* we are looking for the minimum */
+       pb->bandwidth_used = 0;
+       for (device=0; device < maxdevs; device++) {
+               pcitag_t tag;
+               pcireg_t id, bhlcr;
+               int function, nfunction;
+
+               tag = pci_make_tag(pb->pc, pb->busno, device, 0);
+#ifdef PCI_CONFIGURATION_DEBUG
+               if (pci_conf_debug) {
+                       print_tag(pb->pc, tag);
+                       printf("probing.\n");
+               }
+#endif
+               id = pci_conf_read(pb->pc, tag, PCI_ID_REG);
+
+               /* Invalid vendor ID value? */
+               if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+                       continue;
+
+               bhlcr = pci_conf_read(pb->pc, tag, PCI_BHLC_REG);
+               nfunction = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1;
+               for (function = 0 ; function < nfunction ; function++) {
+                       tag = pci_make_tag(pb->pc, pb->busno, device, function);
+                       id = pci_conf_read(pb->pc, tag, PCI_ID_REG);
+                       if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
+                               continue;
+                       if (pb->ndevs+1 < MAX_CONF_DEV) {
+#ifdef PCI_CONFIGURATION_DEBUG
+                               if (pci_conf_debug) {
+                                       print_tag(pb->pc, tag);
+                                       printf("Found dev--really probing.\n");
+                               }
+#endif
+                               if (pci_do_device_query(pb, tag, device,
+                                   function))
+                                       return -1;
+                               pb->ndevs++;
+                       }
+               }
+       }
+       return 0;
+}
+
+static void
+alloc_busno(pciconf_bus_t *parent, pciconf_bus_t *pb)
+{
+       pb->busno = parent->next_busno;
+       if (parent->next_busno + parent->busno_spacing > parent->last_busno)
+               panic("Too many PCI busses on bus %d", parent->busno);
+       parent->next_busno = parent->next_busno + parent->busno_spacing;
+       pb->next_busno = pb->busno+1;
+       pb->busno_spacing = parent->busno_spacing >> 1;
+       if (!pb->busno_spacing)
+               panic("PCI busses nested too deep.");
+       pb->last_busno = parent->next_busno - 1;
+}
+
+static pciconf_bus_t *
+query_bus(pciconf_bus_t *parent, pciconf_dev_t *pd, int dev)
+{
+       pciconf_bus_t   *pb;
+       pcireg_t        busreg;
+       pciconf_win_t   *pi, *pm;
+
+       pb = malloc (sizeof (pciconf_bus_t), M_DEVBUF, M_NOWAIT);
+       if (!pb)
+               panic("Unable to allocate memory for PCI configuration.");
+
+       pb->parent_bus = parent;
+       alloc_busno(parent, pb);
+#ifdef PCI_CONFIGURATION_DEBUG
+       if (pci_conf_debug)
+               printf("PCI bus bridge covers busses %d-%d\n",
+                       pb->busno, pb->last_busno);
+#endif
+
+       busreg  =  parent->busno << PCI_BRIDGE_BUS_PRIMARY_SHIFT;



Home | Main Index | Thread Index | Old Index