1994-09-01 01:45:19 +00:00
|
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
1995-03-02 21:51:53 +00:00
|
|
|
|
** $Id: pci.c,v 1.17 1995/02/27 17:17:13 se Exp $
|
1994-09-01 01:45:19 +00:00
|
|
|
|
**
|
|
|
|
|
** General subroutines for the PCI bus on 80*86 systems.
|
|
|
|
|
** pci_configure ()
|
|
|
|
|
**
|
|
|
|
|
** 386bsd / 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.
|
|
|
|
|
**
|
1994-10-12 02:33:23 +00:00
|
|
|
|
***************************************************************************
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1995-02-27 17:17:14 +00:00
|
|
|
|
#define PCI_PATCHLEVEL "pl5 95/02/27"
|
1995-02-22 14:17:15 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
#include <pci.h>
|
|
|
|
|
#if NPCI > 0
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
#ifndef __FreeBSD2__
|
|
|
|
|
#if __FreeBSD__ >= 2
|
|
|
|
|
#define __FreeBSD2__
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
/*========================================================
|
|
|
|
|
**
|
|
|
|
|
** #includes and declarations
|
|
|
|
|
**
|
|
|
|
|
**========================================================
|
|
|
|
|
*/
|
|
|
|
|
|
1994-09-14 01:34:51 +00:00
|
|
|
|
#include <sys/param.h>
|
|
|
|
|
#include <sys/systm.h>
|
1994-10-12 02:33:23 +00:00
|
|
|
|
#include <sys/malloc.h>
|
1994-09-14 01:34:51 +00:00
|
|
|
|
#include <sys/errno.h>
|
1995-02-02 13:12:18 +00:00
|
|
|
|
#include <sys/kernel.h>
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
#include <vm/vm.h>
|
|
|
|
|
#include <vm/vm_param.h>
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
#include <pci/pcivar.h>
|
1995-02-02 12:36:19 +00:00
|
|
|
|
#include <pci/pcireg.h>
|
1995-02-02 13:12:18 +00:00
|
|
|
|
#include <pci/pcibus.h>
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1995-02-14 06:19:23 +00:00
|
|
|
|
#include <machine/pmap.h>
|
1994-11-02 23:47:14 +00:00
|
|
|
|
#ifdef __FreeBSD2__
|
|
|
|
|
#include <sys/devconf.h>
|
1995-02-02 13:12:18 +00:00
|
|
|
|
|
1994-11-02 23:47:14 +00:00
|
|
|
|
struct pci_devconf {
|
|
|
|
|
struct kern_devconf pdc_kdc;
|
|
|
|
|
struct pci_info pdc_pi;
|
|
|
|
|
};
|
1995-02-02 13:12:18 +00:00
|
|
|
|
|
|
|
|
|
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__ */
|
1994-11-02 23:47:14 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** Function prototypes missing in system headers
|
|
|
|
|
*/
|
|
|
|
|
|
1994-09-16 00:33:29 +00:00
|
|
|
|
extern pmap_t pmap_kernel(void);
|
|
|
|
|
static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize);
|
1995-02-02 13:12:18 +00:00
|
|
|
|
#endif /* __FreeBSD2__ */
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*========================================================
|
|
|
|
|
**
|
|
|
|
|
** Autoconfiguration of pci devices.
|
|
|
|
|
**
|
|
|
|
|
** This is reverse to the isa configuration.
|
|
|
|
|
** (1) find a pci device.
|
|
|
|
|
** (2) look for a driver.
|
|
|
|
|
**
|
|
|
|
|
**========================================================
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-27 17:17:14 +00:00
|
|
|
|
/*--------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** Limit for pci bus numbers.
|
|
|
|
|
**
|
|
|
|
|
**--------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef PCI_MAX_BUS
|
|
|
|
|
#define PCI_MAX_BUS (256)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static u_long pci_bus_max = 1;
|
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*--------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** The pci devices can be mapped to any address.
|
1995-02-22 14:17:15 +00:00
|
|
|
|
** This is a list of possible starting addresses.
|
|
|
|
|
** It can be prepended by a config option.
|
1994-09-01 01:45:19 +00:00
|
|
|
|
**
|
|
|
|
|
**--------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
static u_long pci_stable[] = {
|
|
|
|
|
#ifdef PCI_PMEM_START
|
|
|
|
|
(PCI_PMEM_START),
|
1994-09-01 01:45:19 +00:00
|
|
|
|
#endif
|
1995-02-22 14:17:15 +00:00
|
|
|
|
0xf1000000,
|
|
|
|
|
0x53900000,
|
|
|
|
|
0xc0000000,
|
|
|
|
|
0x81000000,
|
|
|
|
|
0x0f000000,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static vm_offset_t pci_paddr = 0;
|
|
|
|
|
static vm_offset_t pci_pold = 0;
|
|
|
|
|
static vm_offset_t pci_pidx = 0;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
/*--------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** The pci ports can be mapped to any address.
|
|
|
|
|
** As default we start at 0x400
|
|
|
|
|
**
|
|
|
|
|
**--------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef PCI_PORT_START
|
1995-02-14 23:33:38 +00:00
|
|
|
|
#define PCI_PORT_START 0xbc00
|
1995-02-02 13:12:18 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static u_short pci_ioaddr = PCI_PORT_START;
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
/*--------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** The pci device interrupt lines should have been
|
|
|
|
|
** assigned by the bios. But if the bios failed to
|
|
|
|
|
** to it, we set it.
|
|
|
|
|
**
|
|
|
|
|
**--------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef PCI_IRQ
|
|
|
|
|
#define PCI_IRQ 0
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static u_long pci_irq = PCI_IRQ;
|
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*---------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** pci_configure ()
|
|
|
|
|
**
|
1994-10-12 02:33:23 +00:00
|
|
|
|
** 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.)
|
1995-02-25 17:26:22 +00:00
|
|
|
|
** Has to take care of mirrored devices, which are
|
|
|
|
|
** entailed by incomplete decoding of pci address lines.
|
1994-10-12 02:33:23 +00:00
|
|
|
|
**
|
1994-09-01 01:45:19 +00:00
|
|
|
|
**---------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void not_supported (pcici_t tag, u_long type);
|
|
|
|
|
|
1995-02-27 17:17:14 +00:00
|
|
|
|
static unsigned long pci_seen[PCI_MAX_BUS];
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
|
|
|
|
static int pci_conf_count;
|
1995-02-27 17:17:14 +00:00
|
|
|
|
static int pci_info_done;
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
void pci_configure()
|
|
|
|
|
{
|
1995-02-27 17:17:14 +00:00
|
|
|
|
u_char device,max_device;
|
1994-10-12 02:33:23 +00:00
|
|
|
|
u_short bus;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
pcici_t tag;
|
1995-02-27 17:17:14 +00:00
|
|
|
|
pcidi_t type, type8, type16;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
u_long data;
|
|
|
|
|
int unit;
|
1994-10-12 02:33:23 +00:00
|
|
|
|
int pci_mechanism;
|
|
|
|
|
int pciint;
|
|
|
|
|
int irq;
|
|
|
|
|
char* name=0;
|
1995-02-02 13:12:18 +00:00
|
|
|
|
u_short old_ioaddr=pci_ioaddr;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
int dvi;
|
|
|
|
|
struct pci_device *dvp=0;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-11-02 23:47:14 +00:00
|
|
|
|
#ifdef __FreeBSD2__
|
|
|
|
|
struct pci_devconf *pdcp;
|
|
|
|
|
#endif
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
/*
|
|
|
|
|
** first check pci bus driver available
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (pcibus_set.ls_length <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
#define pcibus (*((struct pcibus*) pcibus_set.ls_items[0]))
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** check pci bus present
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
pci_mechanism = pcibus.pb_mode ();
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (!pci_mechanism) return;
|
1995-02-27 17:17:14 +00:00
|
|
|
|
max_device = pci_mechanism==1 ? 32 : 16;
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** hello world ..
|
|
|
|
|
*/
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
pci_pold=pci_paddr;
|
1995-02-27 17:17:14 +00:00
|
|
|
|
for (bus=0; bus<pci_bus_max; bus++) {
|
1994-09-01 01:45:19 +00:00
|
|
|
|
#ifndef PCI_QUIET
|
1995-02-27 17:17:14 +00:00
|
|
|
|
printf ("Probing for devices on the %s%d bus:\n",
|
|
|
|
|
pcibus.pb_name, bus);
|
|
|
|
|
if (!pci_info_done) {
|
|
|
|
|
pci_info_done=1;
|
|
|
|
|
printf ("\tconfiguration mode %d allows %d devices.\n",
|
|
|
|
|
pci_mechanism, max_device);
|
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
#endif
|
1995-02-27 17:17:14 +00:00
|
|
|
|
for (device=0; device<max_device; device ++) {
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
|
|
|
|
if (pci_seen[bus] & (1ul << device))
|
|
|
|
|
continue;
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
tag = pcibus.pb_tag (bus, device, 0);
|
|
|
|
|
type = pcibus.pb_read (tag, PCI_ID_REG);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
if ((!type) || (type==0xfffffffful)) continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** lookup device in ioconfiguration:
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
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)))
|
1994-10-12 02:33:23 +00:00
|
|
|
|
break;
|
1995-02-02 13:12:18 +00:00
|
|
|
|
dvp = NULL;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
};
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1995-02-25 17:26:22 +00:00
|
|
|
|
/*
|
|
|
|
|
** check for mirrored devices.
|
|
|
|
|
*/
|
1995-02-27 17:17:14 +00:00
|
|
|
|
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)) {
|
1995-02-25 17:26:22 +00:00
|
|
|
|
#ifndef PCI_QUIET
|
1995-02-27 17:17:14 +00:00
|
|
|
|
if (dvp==NULL) continue;
|
|
|
|
|
printf ("%s? <%s> mirrored on pci%d:%d\n",
|
|
|
|
|
dvp->pd_name, name, bus, device);
|
1995-02-25 17:26:22 +00:00
|
|
|
|
#endif
|
1995-02-27 17:17:14 +00:00
|
|
|
|
continue;
|
1995-02-25 17:26:22 +00:00
|
|
|
|
};
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
if (dvp==NULL) {
|
1994-09-01 01:45:19 +00:00
|
|
|
|
#ifndef PCI_QUIET
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (pci_conf_count)
|
|
|
|
|
continue;
|
1995-02-02 13:12:18 +00:00
|
|
|
|
printf("%s%d:%d: ", pcibus.pb_name, bus, device);
|
1994-09-16 00:33:29 +00:00
|
|
|
|
not_supported (tag, type);
|
1994-09-14 01:34:51 +00:00
|
|
|
|
#endif
|
1994-09-01 01:45:19 +00:00
|
|
|
|
continue;
|
1994-10-12 02:33:23 +00:00
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
pci_seen[bus] |= (1ul << device);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
1994-10-12 02:33:23 +00:00
|
|
|
|
** Get and increment the unit.
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
unit = (*dvp->pd_count)++;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
/*
|
|
|
|
|
** ignore device ?
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (!*name) continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Announce this device
|
|
|
|
|
*/
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf ("%s%d <%s>", dvp->pd_name, unit, name);
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
1994-10-12 02:33:23 +00:00
|
|
|
|
** Get the int pin number (pci interrupt number a-d)
|
|
|
|
|
** from the pci configuration space.
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
data = pcibus.pb_read (tag, PCI_INTERRUPT_REG);
|
1994-10-12 02:33:23 +00:00
|
|
|
|
pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (pciint) {
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf (" int %c", 0x60+pciint);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
/*
|
1994-10-12 02:33:23 +00:00
|
|
|
|
** If the interrupt line register is not set,
|
|
|
|
|
** set it now from PCI_IRQ.
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) {
|
|
|
|
|
|
|
|
|
|
irq = pci_irq & 0x0f;
|
|
|
|
|
pci_irq >>= 4;
|
|
|
|
|
|
|
|
|
|
data = PCI_INTERRUPT_LINE_INSERT(data, irq);
|
|
|
|
|
printf (" (config)");
|
1995-02-02 13:12:18 +00:00
|
|
|
|
pcibus.pb_write (tag, PCI_INTERRUPT_REG, data);
|
1994-10-12 02:33:23 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
irq = PCI_INTERRUPT_LINE_EXTRACT(data);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
/*
|
1994-10-12 02:33:23 +00:00
|
|
|
|
** If it's zero, the isa irq number is unknown,
|
|
|
|
|
** and we cannot bind the pci interrupt to isa.
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (irq)
|
|
|
|
|
printf (" irq %d", irq);
|
|
|
|
|
else
|
|
|
|
|
printf (" not bound");
|
1994-09-16 00:33:29 +00:00
|
|
|
|
};
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** enable memory access
|
|
|
|
|
*/
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
data = (pcibus.pb_read (tag, PCI_COMMAND_STATUS_REG)
|
1994-10-12 02:33:23 +00:00
|
|
|
|
& 0xffff) | PCI_COMMAND_MEM_ENABLE;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
pcibus.pb_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
|
1994-09-14 01:34:51 +00:00
|
|
|
|
|
1994-11-02 23:47:14 +00:00
|
|
|
|
/*
|
|
|
|
|
** show pci slot.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
printf (" on pci%d:%d\n", bus, device);
|
|
|
|
|
|
|
|
|
|
#ifdef __FreeBSD2__
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Allocate a devconf structure
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
pdcp = (struct pci_devconf *)
|
1995-02-02 13:12:18 +00:00
|
|
|
|
malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
|
1994-11-02 23:47:14 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Fill in.
|
|
|
|
|
**
|
|
|
|
|
** Sorry, this is not yet complete.
|
|
|
|
|
** 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 -> pdc_pi.pi_device = device;
|
|
|
|
|
|
|
|
|
|
pdcp -> pdc_kdc.kdc_name = dvp->pd_name;
|
|
|
|
|
pdcp -> pdc_kdc.kdc_unit = unit;
|
|
|
|
|
|
|
|
|
|
pdcp -> pdc_kdc.kdc_md.mddc_devtype = MDDT_PCI;
|
|
|
|
|
|
|
|
|
|
pdcp -> pdc_kdc.kdc_externalize = pci_externalize;
|
|
|
|
|
pdcp -> pdc_kdc.kdc_internalize = pci_internalize;
|
|
|
|
|
|
|
|
|
|
pdcp -> pdc_kdc.kdc_datalen = PCI_EXTERNAL_LEN;
|
|
|
|
|
pdcp -> pdc_kdc.kdc_parentdata = &pdcp->pdc_pi;
|
|
|
|
|
pdcp -> pdc_kdc.kdc_state = DC_UNKNOWN;
|
|
|
|
|
pdcp -> pdc_kdc.kdc_description = name;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** And register this device
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
dev_attach (&pdcp->pdc_kdc);
|
|
|
|
|
|
|
|
|
|
#endif /* __FreeBSD2__ */
|
|
|
|
|
|
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** attach device
|
|
|
|
|
** may produce additional log messages,
|
|
|
|
|
** i.e. when installing subdevices.
|
|
|
|
|
*/
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
(*dvp->pd_attach) (tag, unit);
|
1994-10-12 02:33:23 +00:00
|
|
|
|
};
|
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-09-14 01:34:51 +00:00
|
|
|
|
#ifndef PCI_QUIET
|
1995-02-22 14:17:15 +00:00
|
|
|
|
if (pci_paddr != pci_pold)
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf ("pci uses physical addresses from 0x%lx to 0x%lx\n",
|
1995-02-22 14:17:15 +00:00
|
|
|
|
(u_long)pci_pold, (u_long)pci_paddr);
|
1995-02-02 13:12:18 +00:00
|
|
|
|
if (pci_ioaddr != old_ioaddr)
|
|
|
|
|
printf ("pci devices use ioports from 0x%x to 0x%x\n",
|
|
|
|
|
(unsigned)PCI_PORT_START, (unsigned)pci_ioaddr);
|
1994-09-14 01:34:51 +00:00
|
|
|
|
#endif
|
1994-10-12 02:33:23 +00:00
|
|
|
|
pci_conf_count++;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
/*-----------------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** 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);
|
|
|
|
|
}
|
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** Map device into port space.
|
|
|
|
|
**
|
|
|
|
|
** PCI-Specification: 6.2.5.1: address maps
|
|
|
|
|
**
|
|
|
|
|
**-----------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
|
|
|
|
|
{
|
1995-02-22 14:17:15 +00:00
|
|
|
|
u_long data,oldmap;
|
|
|
|
|
u_short size, ioaddr;
|
1995-02-02 13:12:18 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
1995-02-02 13:12:18 +00:00
|
|
|
|
** sanity check
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
1995-02-02 13:12:18 +00:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** 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.
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
#ifdef PCI_REMAP
|
|
|
|
|
oldmap = 0;
|
|
|
|
|
#else
|
|
|
|
|
oldmap = pcibus.pb_read (tag, reg) & 0xfffffffc;
|
|
|
|
|
if (oldmap==0xfffffffc) oldmap=0;
|
|
|
|
|
#endif
|
1995-02-02 13:12:18 +00:00
|
|
|
|
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);
|
|
|
|
|
return (0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** get the size
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
size = -(data & PCI_MAP_IO_ADDRESS_MASK);
|
|
|
|
|
|
|
|
|
|
if (!size) return (0);
|
|
|
|
|
|
|
|
|
|
/*
|
1995-02-22 14:17:15 +00:00
|
|
|
|
** align physical address to virtual size,
|
|
|
|
|
** set ioaddr,
|
|
|
|
|
** and don't forget to increment pci_ioaddr
|
1995-02-02 13:12:18 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
if (oldmap) {
|
|
|
|
|
ioaddr = oldmap;
|
|
|
|
|
} else {
|
|
|
|
|
if ((data = pci_ioaddr % size))
|
|
|
|
|
pci_ioaddr += size - data;
|
|
|
|
|
ioaddr = pci_ioaddr;
|
|
|
|
|
pci_ioaddr += size;
|
|
|
|
|
};
|
1995-02-02 13:12:18 +00:00
|
|
|
|
|
|
|
|
|
#ifndef PCI_QUIET
|
|
|
|
|
/*
|
|
|
|
|
** display values.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
printf ("\treg%d: ioaddr=0x%x size=0x%x\n",
|
1995-02-22 14:17:15 +00:00
|
|
|
|
(unsigned) reg, (unsigned) ioaddr, (unsigned) size);
|
1995-02-02 13:12:18 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
1995-02-14 23:33:38 +00:00
|
|
|
|
/*
|
|
|
|
|
** set device address
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
pcibus.pb_write (tag, reg, (u_long) ioaddr);
|
1995-02-14 23:33:38 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
/*
|
|
|
|
|
** return them to the driver
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
*pa = pci_ioaddr;
|
|
|
|
|
|
|
|
|
|
return (1);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** Map device into virtual and physical space
|
|
|
|
|
**
|
|
|
|
|
** 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)
|
|
|
|
|
{
|
1995-02-22 14:17:15 +00:00
|
|
|
|
u_long data,oldmap,paddr;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
vm_size_t vsize;
|
|
|
|
|
vm_offset_t vaddr;
|
1995-02-09 20:20:33 +00:00
|
|
|
|
int i;
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** sanity check
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
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);
|
1994-10-12 02:33:23 +00:00
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
/*
|
1995-02-22 14:17:15 +00:00
|
|
|
|
** save old mapping, get size and type of memory
|
1994-09-01 01:45:19 +00:00
|
|
|
|
**
|
|
|
|
|
** type is in the lowest four bits.
|
|
|
|
|
** If device requires 2^n bytes, the next
|
|
|
|
|
** n-4 bits are read as 0.
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
#ifdef PCI_REMAP
|
|
|
|
|
oldmap = 0;
|
|
|
|
|
#else
|
|
|
|
|
oldmap = pcibus.pb_read (tag, reg) & 0xfffffff0;
|
|
|
|
|
if (oldmap==0xfffffff0) oldmap = 0;
|
|
|
|
|
#endif
|
1995-02-02 13:12:18 +00:00
|
|
|
|
pcibus.pb_write (tag, reg, 0xfffffffful);
|
|
|
|
|
data = pcibus.pb_read (tag, reg);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
switch (data & 0x0f) {
|
|
|
|
|
|
|
|
|
|
case PCI_MAP_MEMORY_TYPE_32BIT: /* 32 bit non cachable */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* unknown */
|
1995-02-02 13:12:18 +00:00
|
|
|
|
printf ("pci_map_mem failed: bad memory type=0x%x\n",
|
|
|
|
|
(unsigned) data);
|
|
|
|
|
return (0);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
};
|
1995-02-22 14:17:15 +00:00
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** mask out the type,
|
|
|
|
|
** and round up to a page size
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK));
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (!vsize) return (0);
|
1995-02-22 14:17:15 +00:00
|
|
|
|
|
|
|
|
|
if (oldmap) {
|
|
|
|
|
paddr = oldmap;
|
|
|
|
|
goto domap;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
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);
|
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** align physical address to virtual size
|
|
|
|
|
*/
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if ((data = pci_paddr % vsize))
|
1994-09-01 01:45:19 +00:00
|
|
|
|
pci_paddr += vsize - data;
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
if (!pci_pold)
|
|
|
|
|
pci_pold = pci_paddr;
|
1994-09-14 01:34:51 +00:00
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
/*
|
|
|
|
|
** set physical mapping address,
|
|
|
|
|
** and reserve physical address range
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
paddr = pci_paddr;
|
|
|
|
|
pci_paddr += vsize;
|
|
|
|
|
|
|
|
|
|
domap:
|
|
|
|
|
vaddr = (vm_offset_t) pmap_mapdev (paddr, vsize);
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
if (!vaddr) return (0);
|
|
|
|
|
|
1994-09-16 00:33:29 +00:00
|
|
|
|
#ifndef PCI_QUIET
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
|
|
|
|
** display values.
|
|
|
|
|
*/
|
|
|
|
|
|
1994-09-16 00:33:29 +00:00
|
|
|
|
printf ("\treg%d: virtual=0x%lx physical=0x%lx\n",
|
1995-02-22 14:17:15 +00:00
|
|
|
|
(unsigned) reg, (u_long)vaddr, (u_long)paddr);
|
1994-09-14 01:34:51 +00:00
|
|
|
|
#endif
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1995-02-09 20:20:33 +00:00
|
|
|
|
/*
|
|
|
|
|
** probe for already mapped device.
|
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
if (!oldmap) for (i=0; i<vsize; i+=4) {
|
1995-02-09 20:20:33 +00:00
|
|
|
|
u_long* addr = (u_long*) (vaddr+i);
|
|
|
|
|
data = *addr;
|
|
|
|
|
if (data != 0xffffffff) {
|
1995-02-22 14:17:15 +00:00
|
|
|
|
printf ("\t(possible address conflict: "
|
|
|
|
|
"at 0x%x read: 0x%x)\n",
|
|
|
|
|
(unsigned) paddr+i, (unsigned) data);
|
|
|
|
|
pci_paddr = 0;
|
|
|
|
|
goto next_try;
|
1995-02-09 20:20:33 +00:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
1994-09-01 01:45:19 +00:00
|
|
|
|
/*
|
1995-02-22 14:17:15 +00:00
|
|
|
|
** Set device address
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
pcibus.pb_write (tag, reg, paddr);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
/*
|
1995-02-22 14:17:15 +00:00
|
|
|
|
** 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.
|
1994-09-01 01:45:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1995-03-02 21:51:53 +00:00
|
|
|
|
if (!oldmap) {
|
|
|
|
|
for (i=0; i<vsize; i+=4) {
|
|
|
|
|
u_long* addr = (u_long*) (vaddr+i);
|
|
|
|
|
data = *addr;
|
|
|
|
|
if (data != 0xffffffff)
|
|
|
|
|
break;
|
|
|
|
|
};
|
1995-02-22 14:17:15 +00:00
|
|
|
|
|
1995-03-02 21:51:53 +00:00
|
|
|
|
if (data==0xffffffff) {
|
|
|
|
|
printf ("\t(possible mapping problem: "
|
|
|
|
|
"at 0x%x read 0xffffffff)\n",
|
|
|
|
|
(unsigned) paddr);
|
|
|
|
|
pci_paddr = 0;
|
|
|
|
|
goto next_try;
|
|
|
|
|
};
|
1995-02-22 14:17:15 +00:00
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-09-16 00:33:29 +00:00
|
|
|
|
/*
|
1995-02-22 14:17:15 +00:00
|
|
|
|
** Return addresses to the driver
|
1994-09-16 00:33:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1995-02-22 14:17:15 +00:00
|
|
|
|
*va = vaddr;
|
|
|
|
|
*pa = paddr;
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
return (1);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-02-27 17:17:14 +00:00
|
|
|
|
/*-----------------------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** 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);
|
|
|
|
|
}
|
|
|
|
|
|
1994-11-02 23:47:14 +00:00
|
|
|
|
/*------------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** Interface functions for the devconf module.
|
|
|
|
|
**
|
|
|
|
|
**------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l)
|
|
|
|
|
{
|
|
|
|
|
struct pci_externalize_buffer buffer;
|
|
|
|
|
struct pci_info * pip = kdcp->kdc_parentdata;
|
1995-02-02 13:12:18 +00:00
|
|
|
|
pcici_t tag;
|
1994-11-02 23:47:14 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (l < sizeof buffer) {
|
1995-02-02 13:12:18 +00:00
|
|
|
|
return ENOMEM;
|
1994-11-02 23:47:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
tag = pcibus.pb_tag (pip->pi_bus, pip->pi_device, 0);
|
1994-11-02 23:47:14 +00:00
|
|
|
|
|
|
|
|
|
buffer.peb_pci_info = *pip;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<PCI_EXT_CONF_LEN; i++) {
|
1995-02-02 13:12:18 +00:00
|
|
|
|
buffer.peb_config[i] = pcibus.pb_read (tag, i*4);
|
1994-11-02 23:47:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
return copyout(&buffer, u, sizeof buffer);
|
1994-11-02 23:47:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s)
|
|
|
|
|
{
|
1995-02-02 13:12:18 +00:00
|
|
|
|
return EOPNOTSUPP;
|
1994-11-02 23:47:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
/*-----------------------------------------------------------------------
|
1994-09-16 00:33:29 +00:00
|
|
|
|
**
|
1994-10-12 02:33:23 +00:00
|
|
|
|
** Map pci interrupts to isa interrupts.
|
1994-09-16 00:33:29 +00:00
|
|
|
|
**
|
1994-10-12 02:33:23 +00:00
|
|
|
|
**-----------------------------------------------------------------------
|
1994-09-16 00:33:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr)
|
1994-09-16 00:33:29 +00:00
|
|
|
|
{
|
1995-02-02 13:12:18 +00:00
|
|
|
|
int irq, result;
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
irq = PCI_INTERRUPT_LINE_EXTRACT(
|
1995-02-02 13:12:18 +00:00
|
|
|
|
pcibus.pb_read (tag, PCI_INTERRUPT_REG));
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
1994-10-12 02:33:23 +00:00
|
|
|
|
if (irq >= 16 || irq <= 0) {
|
|
|
|
|
printf ("pci_map_int failed: no int line set.\n");
|
1994-09-16 00:33:29 +00:00
|
|
|
|
return (0);
|
1994-10-12 02:33:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
result = pcibus.pb_regint (tag, func, arg, maskptr);
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
if (!result) {
|
|
|
|
|
printf ("pci_map_int failed.\n");
|
|
|
|
|
return (0);
|
1994-09-16 00:33:29 +00:00
|
|
|
|
};
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
1994-09-16 00:33:29 +00:00
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------
|
|
|
|
|
**
|
|
|
|
|
** Display of unknown devices.
|
|
|
|
|
**
|
|
|
|
|
**-----------------------------------------------------------
|
|
|
|
|
*/
|
1994-09-01 01:45:19 +00:00
|
|
|
|
struct vt {
|
|
|
|
|
u_short ident;
|
|
|
|
|
char* name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct vt VendorTable[] = {
|
|
|
|
|
{0x1002, "ATI TECHNOLOGIES INC"},
|
1994-10-12 02:33:23 +00:00
|
|
|
|
{0x1011, "DIGITAL EQUIPMENT CORPORATION"},
|
1994-09-01 01:45:19 +00:00
|
|
|
|
{0x101A, "NCR"},
|
|
|
|
|
{0x102B, "MATROX"},
|
|
|
|
|
{0x1045, "OPTI"},
|
|
|
|
|
{0x5333, "S3 INC."},
|
|
|
|
|
{0x8086, "INTEL CORPORATION"},
|
|
|
|
|
{0,0}
|
|
|
|
|
};
|
|
|
|
|
|
1994-09-14 01:34:51 +00:00
|
|
|
|
static const char *const majclasses[] = {
|
1994-09-16 00:33:29 +00:00
|
|
|
|
"old", "storage", "network", "display",
|
|
|
|
|
"multimedia", "memory", "bridge"
|
1994-09-14 01:34:51 +00:00
|
|
|
|
};
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
void not_supported (pcici_t tag, u_long type)
|
|
|
|
|
{
|
|
|
|
|
u_char reg;
|
|
|
|
|
u_long data;
|
|
|
|
|
struct vt * vp;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** lookup the names.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (vp=VendorTable; vp->ident; vp++)
|
|
|
|
|
if (vp->ident == (type & 0xffff))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** and display them.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (vp->ident) printf (vp->name);
|
1994-09-16 00:33:29 +00:00
|
|
|
|
else printf ("vendor=0x%lx", type & 0xffff);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
1994-09-16 00:33:29 +00:00
|
|
|
|
printf (", device=0x%lx", type >> 16);
|
1994-09-14 01:34:51 +00:00
|
|
|
|
|
1995-02-02 13:12:18 +00:00
|
|
|
|
data = (pcibus.pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
|
1994-09-16 00:33:29 +00:00
|
|
|
|
if (data < sizeof(majclasses) / sizeof(majclasses[0]))
|
|
|
|
|
printf(", class=%s", majclasses[data]);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
|
|
|
|
|
printf (" [not supported]\n");
|
|
|
|
|
|
|
|
|
|
for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
|
1995-02-02 13:12:18 +00:00
|
|
|
|
data = pcibus.pb_read (tag, reg);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
if (!data) continue;
|
|
|
|
|
switch (data&7) {
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
case 5:
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf (" map(%x): io(%lx)\n",
|
|
|
|
|
reg, data & ~3);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
break;
|
|
|
|
|
case 0:
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf (" map(%x): mem32(%lx)\n",
|
|
|
|
|
reg, data & ~7);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
break;
|
|
|
|
|
case 2:
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf (" map(%x): mem20(%lx)\n",
|
|
|
|
|
reg, data & ~7);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
break;
|
|
|
|
|
case 4:
|
1994-10-12 02:33:23 +00:00
|
|
|
|
printf (" map(%x): mem64(%lx)\n",
|
|
|
|
|
reg, data & ~7);
|
1994-09-01 01:45:19 +00:00
|
|
|
|
break;
|
1994-09-14 01:34:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1994-09-01 01:45:19 +00:00
|
|
|
|
}
|
1994-10-12 02:33:23 +00:00
|
|
|
|
|
|
|
|
|
#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 */
|