Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 6 Mar 1998 00:47:05 +0100
From:      Stefan Esser <se@FreeBSD.ORG>
To:        freebsd-stable@FreeBSD.ORG
Cc:        Stefan Esser <se@FreeBSD.ORG>
Subject:   PCI LKM support: Need test results under 2.2.5 [se@FreeBSD.ORG: Re: PCI LKM's?]
Message-ID:  <19980306004705.56636@mi.uni-koeln.de>

next in thread | raw e-mail | index | archive | help
***********************************************************

I'd ***really*** love to see PCI LKM support make it
into 2.2.6, but there is a problem, and I need help
from users of FreeBSD-2.2.x.

If you are intererested in this feature, then please
build a patched kernel, and let me know what you find!

***********************************************************

I had sent the message below to Danil O'Conner a few weeks
ago, and he reported a problem with the *first* PCI device
not being attached by a kernel compiled with this patch.

The LKM code itself worked at a time (nearly one year ago),
but there might be some unexpected side effect of the diffs.

Since I do not have a 2.2.5 system to test this on myself
(and since I'm short fo spare time), I'd appreciate more 
feedback about this set of patches. I did not touch the
interrupt registration code, at least not knowingly :)

Please let me know, whether a kernel compiled with this
patch attaches all PCI devices. It will either work, or
fail when probing for devices (best if you try booting
with -s and just check for diagnostics at the start of
the PCI probes).

--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=mutthy1553

On 1998-02-17 10:50 +1030, Daniel O'Connor <doconnor@gsoft.com.au> wrote:
> > I added PCI LKM support to the PCI code more than one year 
> > ago, but never put it into the "official" 2.2.x repository.
> > If you want patches, I can provide you with them, but if 
> > there is sufficient interest, I can also commit that code
> > to -stable.
> I would like that very much :)

Ok, since you offered to test the code, I've appended 
the diffs to /sys/pci/{pci.c,pcibus.h,pci_ioctl.h} and
to /usr/src/usr.sbin/pciconf/pciconf.{c,8} as separate
attachments. Please apply and test them ...

(As I explained before, I don't have any 2.2.x system
to test them on. I compiled pci.c with those patches,
and found that one chunk had gone to the wrong lines,
causing a syntax error. This is fixed in the patches
I'm sending, but I'm a little worried, that it might
have happened in other less obvious places as well ...)

> > The interface is very simple:
> > 
> >   int pci_register_lkm (struct pci_device *dvp, int if_revision)
> What about unloading LKM's? Perhaps pci_unregister_lkm, which unlinks it from 
> the list and removes the lkm..?

Well, unloading LKMs should be possible, and I could 
add support for that, but I didn't at the time, since
I felt that the rest of the kernel wasn't yet up to it.
AFAIK, there is no locking in place currently, which 
would prevent unloading a busy driver.

If you have support for a shutdown function in your
driver, then I could call that, and thereafter remove
the driver from the list of known PCI devices in order
to prepare the unload.

> > I added a support function to pciconf (or rather the underlying
> > ioctl()), which reported whether a driver had been attached to
> > a device. This allowed the loading of PCI LKMs from a script
> > called from /etc/rc, controlled by the PCI vendor and device
> > IDs.
> Thats neat, and IMHO is a good idea for making the system more flexible (ie 
> requiring less reboots :)

Only, if unloading of PCI LKMs is supported, I'm afraid.
If you need it, I can see what I can do within a few days,
though I'm very busy and can't promise anything, currently.

Regards, STefan

--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="PCICONF-LKM.patch"

Index: pciconf.c
===================================================================
RCS file: /usr/cvs/src/usr.sbin/pciconf/pciconf.c,v
retrieving revision 1.1.1.1.2.3
diff -u -2 -r1.1.1.1.2.3 pciconf.c
--- pciconf.c	1997/10/08 07:36:44	1.1.1.1.2.3
+++ pciconf.c	1998/02/17 21:22:55
@@ -50,13 +50,16 @@
 static void readit(const char *, const char *, int);
 static void writeit(const char *, const char *, const char *, int);
+static void chkattached(const char *, int);
 
+static exitstatus = 0;
 
 static void
 usage()
 {
-	fprintf(stderr, "%s\n%s\n%s\n",
-	"usage: pciconf -l",
-	"       pciconf -r [-b | -h] sel addr",
-	"       pciconf -w [-b | -h] sel addr [value]");
+	fprintf(stderr, "%s\n%s\n%s\n%s\n",
+		"usage: pciconf -l",
+		"       pciconf -a sel",
+		"       pciconf -r [-b | -h] sel addr",
+		"       pciconf -w [-b | -h] sel addr [value]");
 	exit (1);
 }
@@ -66,11 +69,15 @@
 {
 	int c;
-	int listmode, readmode, writemode;
+	int listmode, readmode, writemode, attachedmode;
 	int byte, isshort;
 
-	listmode = readmode = writemode = byte = isshort = 0;
+	listmode = readmode = writemode = attachedmode = byte = isshort = 0;
 
-	while ((c = getopt(argc, argv, "lrwbh")) !=  -1) {
+	while ((c = getopt(argc, argv, "alrwbh")) != -1) {
 		switch(c) {
+		case 'a':
+			attachedmode = 1;
+			break;
+
 		case 'l':
 			listmode = 1;
@@ -100,9 +107,13 @@
 	if ((listmode && optind != argc)
 	    || (writemode && optind + 3 != argc)
-	    || (readmode && optind + 2 != argc))
+	    || (readmode && optind + 2 != argc)
+	    || (attachedmode && optind + 1 != argc))
 		usage();
 
 	if (listmode) {
 		list_devs();
+	} else if(attachedmode) {
+		chkattached(argv[optind], 
+		       byte ? 1 : isshort ? 2 : 4);
 	} else if(readmode) {
 		readit(argv[optind], argv[optind + 1], 
@@ -115,5 +126,5 @@
 	}
 
-	return 0;
+	return exitstatus;
 }
 
@@ -208,3 +219,25 @@
 	if (ioctl(fd, PCIOCWRITE, &pi) < 0)
 		err(1, "ioctl(PCIOCWRITE)");
+}
+
+static void
+chkattached (const char *name, int width)
+{
+	int fd;
+	struct pci_io pi;
+
+	pi.pi_sel = getsel(name);
+	pi.pi_reg = 0;
+	pi.pi_width = width;
+	pi.pi_data = 0;
+
+	fd = open(_PATH_DEVPCI, O_RDWR, 0);
+	if (fd < 0)
+		err(1, "%s", _PATH_DEVPCI);
+
+	if (ioctl(fd, PCIOCATTACHED, &pi) < 0)
+		err(1, "ioctl(PCIOCATTACHED)");
+
+	exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */
+	printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached");
 }
Index: pciconf.8
===================================================================
RCS file: /usr/cvs/src/usr.sbin/pciconf/pciconf.8,v
retrieving revision 1.3.2.1
diff -u -2 -r1.3.2.1 pciconf.8
--- pciconf.8	1997/10/08 10:33:10	1.3.2.1
+++ pciconf.8	1998/02/17 21:28:24
@@ -33,4 +33,5 @@
 .Sh SYNOPSIS
 .Nm pciconf Fl l
+.Nm pciconf Fl a Ar selector
 .Nm pciconf Fl r Ar selector 
 .Op Fl b | Fl h
@@ -105,4 +106,14 @@
 .Fl l
 can be used without modification.  All numbers are base 10.
+.Pp
+With the
+.Fl a
+flag,
+.Nm
+determines whether any driver has been assigned to the device
+identified by 
+.Ar selector .
+An exit status of zero indicates that the device has a driver;
+non-zero indicates that it does not.
 .Pp
 The 

--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=loadlkm

#!/bin/sh
#
# Put this script into a new directory /etc/pci under the name "loadlkm" and
# make /etc/rc call it early (may have to load network interface drivers).
#
# Put a file named "lkmtable" consisting of two columns (PCI vendor/device ID
# and LKM name without trailing .o) into the same directory:
#
# 0x0350109E brkt	BrookTree 848
# 0x802910ec if_ed	RealTek 8029 NE2000 compatible Ethernet
#
# Put PCI LKMs into directory "/lkm/pci" for now (or change the script to
# search for LKMs in some other directory).
#
for dev in `pciconf -l |cut -f1`
do
    if pciconf -a $dev | grep -q "not attached"
    then
      DevVendorID=`pciconf -r $dev 0`
      LKM=`grep $DevVendorID /etc/pci/lkmtable | cut -f 2`
      LKMfile=/lkm/pci/$LKM.o
      echo "$dev Loading $LKMfile for DevVendorID $DevVendorID"
      modload $LKMfile
    fi
done

--liOOAslEiF7prFVr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="PCI-LKM.patch"

Index: pci.c
===================================================================
RCS file: /usr/cvs/src/sys/pci/pci.c,v
retrieving revision 1.57.2.5
diff -u -2 -r1.57.2.5 pci.c
--- pci.c	1997/07/11 18:16:18	1.57.2.5
+++ pci.c	1998/02/17 22:23:50
@@ -87,9 +87,6 @@
 	pcici_t 	pcicb_bridge;
 
-	u_long		pcicb_seen;
 	u_char		pcicb_bus;
 	u_char		pcicb_subordinate;
-	u_char		pcicb_flags;
-#define  PCICB_ISAMEM	0x01
 	u_int		pcicb_mfrom;
 	u_int		pcicb_mupto;
@@ -109,4 +106,9 @@
 };
 
+struct pci_lkm {
+	struct pci_device *dvp;
+	struct pci_lkm	*next;
+};
+
 static void
 not_supported (pcici_t tag, u_long type);
@@ -115,4 +117,10 @@
 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);
@@ -121,5 +129,5 @@
 pci_mfdev (int bus, int device);
 
-static void pci_remember (int bus, int dev, int func);
+static void pci_remember (int bus, int dev, int func, struct pci_device *dvp);
 
 /*========================================================
@@ -141,6 +149,4 @@
 				 * UGLY hack ... :( Will be changed :)
 				 */
-static struct pcibus* pcibus;
-
 /*--------------------------------------------------------
 **
@@ -150,9 +156,17 @@
 */
 
+static	struct pcibus	*pcibus;
+
 static	int		pci_conf_count;
 static	int		pci_info_done;
 static	int		pcibusmax;
-static	struct pcicb   *pcicb;
+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;
+
 /*-----------------------------------------------------------------
 **
@@ -375,4 +389,262 @@
 /*========================================================
 **
+**	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;
+	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 (irq && (irq != 0xff))
+			printf ("%d", irq);
+		else
+			printf ("??");
+	};
+
+	printf (" on pci%d:%d:%d\n", bus, dev, func);
+
+	/*
+	**	Read the current mapping,
+	**	and update the pcicb fields.
+	*/
+
+	for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) {
+		u_int map, addr, size;
+
+		data = pci_conf_read(tag, PCI_CLASS_REG);
+		switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+		case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+			continue;
+		};
+
+		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;
+	}
+}
+
+/*========================================================
+**
 **	pci_bus_config()
 **
@@ -405,8 +677,4 @@
 	pcici_t tag, mtag;
 	pcidi_t type;
-	u_long  data;
-	int     unit;
-	u_char	pciint;
-	int	irq;
 
 	struct	pci_device *dvp;
@@ -430,7 +698,4 @@
 	    int func, maxfunc = 0;
 
-	    if ((pcicb->pcicb_seen >> device) & 1)
-	    	continue;
-
 	    for (func=0; func <= maxfunc; func++) {
 		tag  = pcibus->pb_tag  (bus_no, device, func);
@@ -498,5 +763,5 @@
 		}
 
-		pci_remember(bus_no, device, func);
+		pci_remember(bus_no, device, func, dvp);
 
 		if (dvp==NULL) {
@@ -515,267 +780,7 @@
 			continue;
 		};
-
-		pcicb->pcicb_seen |= (1ul << device);
-
-		/*
-		**	Get and increment the unit.
-		*/
-
-		unit = (*dvp->pd_count)++;
-
-		/*
-		**	ignore device ?
-		*/
-
-		if (!*name) continue;
-
-		/*
-		**	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 (irq && (irq != 0xff))
-				printf ("%d", irq);
-			else
-				printf ("??");
-		};
-
-		if (maxfunc == 0)
-			printf (" on pci%d:%d\n", bus_no, device);
-		else
-			printf (" on pci%d:%d:%d\n", bus_no, device, func);
-
-		/*
-		**	Read the current mapping,
-		**	and update the pcicb fields.
-		*/
-
-		for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) {
-			u_int map, addr, size;
-
-			data = pci_conf_read(tag, PCI_CLASS_REG);
-			switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
-			case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
-				continue;
-			};
-
-			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;
-				} else {
-					pcicb->pcicb_flags |= PCICB_ISAMEM;
-				};
-				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_no == 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;
-
-			break;
+		if (*name) {
+			pci_attach (bus_no, device, func, dvp, name);
 		}
 	    }
@@ -785,10 +790,10 @@
 	if (bootverbose) {
 	    if (pcicb->pcicb_mamount)
-		printf ("%s%d: uses %d bytes of memory from %x upto %x.\n",
+		printf ("%s%d: uses %u 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 %d bytes of I/O space from %x upto %x.\n",
+		printf ("%s%d: uses %u bytes of I/O space from %x upto %x.\n",
 			pcibus->pb_name, bus_no,
 			pcicb->pcicb_pamount,
@@ -808,7 +813,4 @@
 **      Autoconfiguration of pci devices.
 **
-**      May be called more than once.
-**      Any device is attached only once.
-**
 **      Has to take care of mirrored devices, which are
 **      entailed by incomplete decoding of pci address lines.
@@ -872,4 +874,83 @@
 }
 
+/*========================================================
+**
+**	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()
+{
+	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;
+		}
+	}
+}
+
+/*========================================================
+**
+**	pci_register_lkm ()
+**
+**      Add LKM PCI driver's struct pci_device to pci_lkm chain
+**
+**========================================================
+*/
+
+int pci_register_lkm (struct pci_device *dvp, int if_revision)
+{
+	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;
+	}
+
+	lkm->dvp = dvp;
+	lkm->next = pci_lkm_head;
+	pci_lkm_head = lkm;
+	pci_rescan();
+	return 0;
+}
+
 /*-----------------------------------------------------------------------
 **
@@ -899,10 +980,4 @@
 	};
 
-	/*if (pcicb->pcicb_flags & PCICB_NOIOSET) {
-		printf ("pci_map_port failed: pci%d has not been configured for I/O access\n",
-			pcicb->pcicb_bus);
-		return (0);
-	}*/
-
 	/*
 	**	get size and type of port
@@ -982,5 +1057,5 @@
 	struct pcicb *link = pcicb;
 	unsigned    data ,paddr;
-	vm_size_t   psize, poffs;
+	vm_size_t   psize, poffs, pend;
 	vm_offset_t vaddr;
 
@@ -1025,4 +1100,5 @@
 
 	psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
+	pend = paddr + psize -1;
 
 	if (!paddr || paddr == PCI_MAP_MEMORY_ADDRESS_MASK) {
@@ -1032,20 +1108,20 @@
 			return (0);
 		};
-		pci_register_memory (pcicb, paddr, paddr+psize-1);
+		pci_register_memory (pcicb, paddr, pend);
 	};
 
-	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",
+	if (!((pcicb->pcicb_membase <= paddr &&
+	       pend <= pcicb->pcicb_memlimit) || 
+	      (pcicb->pcicb_p_membase <= paddr &&
+	       pend <= pcicb->pcicb_p_memlimit))) {
+		printf ("pci_map_mem: device's memrange 0x%x-0x%x is "
+			"incompatible with its bridge's\n"
+			"\tmemrange 0x%x-0x%x and prefetchable memrange 0x%x-0x%x\n",
 			(unsigned) paddr,
 			(unsigned) (paddr + psize - 1),
+			(unsigned) pcicb->pcicb_p_membase,
+			(unsigned) pcicb->pcicb_p_memlimit,
 			(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);
@@ -1463,8 +1539,10 @@
 	{0x1045, "OPTI"},
 	{0x104B, "Bus Logic"},
+	{0x104C, "TI"},
 	{0x1060, "UMC"},
 	{0x1080, "Contaq"},
 	{0x1095, "CMD"},
 	{0x10b9, "ACER Labs"},
+	{0x10c8, "NeoMagic"},
 	{0x1106, "VIA Technologies"},
 	{0x5333, "S3 Inc."},
@@ -1544,4 +1622,5 @@
 	{ 0x04, "pci"	},
 	{ 0x05, "pcmcia"},
+	{ 0x07, "cardbus"},
 	{ 0x80, "misc"	},
 	{ 0x00, NULL	}
@@ -1565,5 +1644,11 @@
 	"multimedia", 
 	"memory", 
-	"bridge"
+	"bridge",
+	"comms",
+	"system",
+	"input",
+	"docking",
+	"processor",
+	"serial"
 };
 
@@ -1613,5 +1698,5 @@
 			printf(" (%s)", p->name);
 		} else {
-			printf(" (unknown subclass 0x%02lx)", subclass);
+			printf(" (unknown subclass 0x%02x)", subclass);
 		}
 	} else {
@@ -1647,6 +1732,6 @@
 		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));
+		    if ((reg & 0x0f) == 0) printf ("\n%02lx:\t", reg);
+		    printf ("%08lx ", pci_conf_read (tag, reg));
 		}
 		printf ("\n");
@@ -1659,17 +1744,17 @@
 		case 1:
 		case 5:
-			printf ("\tmap(%x): io(%04lx)\n",
+			printf ("\tmap(%lx): io(%04lx)\n",
 				reg, data & ~3);
 			break;
 		case 0:
-			printf ("\tmap(%x): mem32(%08lx)\n",
+			printf ("\tmap(%lx): mem32(%08lx)\n",
 				reg, data & ~7);
 			break;
 		case 2:
-			printf ("\tmap(%x): mem20(%05lx)\n",
+			printf ("\tmap(%lx): mem20(%05lx)\n",
 				reg, data & ~7);
 			break;
 		case 4:
-			printf ("\tmap(%x): mem64(%08x%08lx)\n",
+			printf ("\tmap(%lx): mem64(%08lx%08lx)\n",
 				reg, pci_conf_read (tag, reg +4), data & ~7);
 			reg += 4;
@@ -1684,10 +1769,8 @@
  * This is the user interface to the PCI configuration space.
  */
-static struct pci_conf *pci_dev_list;
-static unsigned pci_dev_list_count;
-static unsigned pci_dev_list_size;
 
+
 static void
-pci_remember(int bus, int dev, int func)
+pci_remember(int bus, int dev, int func, struct pci_device *dvp)
 {
 	struct pci_conf *p;
@@ -1723,4 +1806,6 @@
 	p->pc_devid = pci_conf_read(tag, PCI_ID_REG);
 	p->pc_class = pci_conf_read(tag, PCI_CLASS_REG);
+	p->pc_dvp = dvp;
+	p->pc_cb  = pcicb;
 	switch (p->pc_hdr & 0x7f) {
 	case 0:
@@ -1803,4 +1888,32 @@
 			pci_conf_write(tag, io->pi_reg, io->pi_data);
 			error = 0;
+			break;
+		case 2:
+		case 1:
+		default:
+			error = ENODEV;
+			break;
+		}
+		break;
+
+	case PCIOCATTACHED:
+		io = (struct pci_io *)data;
+		switch(io->pi_width) {
+		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:
Index: pcibus.h
===================================================================
RCS file: /usr/cvs/src/sys/pci/Attic/pcibus.h,v
retrieving revision 1.4
diff -u -2 -r1.4 pcibus.h
--- pcibus.h	1996/01/30 22:59:55	1.4
+++ pcibus.h	1998/02/17 22:04:42
@@ -80,5 +80,4 @@
 	u_long	(*pb_read  )  (pcici_t tag, u_long reg);
 	void	(*pb_write )  (pcici_t tag, u_long reg, u_long data);
-	unsigned  pb_maxirq;
 	int	(*pb_iattach) (int irq, inthand2_t *func, int arg,
 			       unsigned *maskptr);
@@ -95,4 +94,6 @@
 
 extern struct linker_set pcibus_set;
+
+int pci_register_lkm (struct pci_device *dvp, int if_revision);
 
 #endif
Index: pci_ioctl.h
===================================================================
RCS file: /usr/cvs/src/sys/pci/pci_ioctl.h,v
retrieving revision 1.1.2.1
diff -u -2 -r1.1.2.1 pci_ioctl.h
--- pci_ioctl.h	1996/11/25 07:19:06	1.1.2.1
+++ pci_ioctl.h	1998/02/17 22:04:42
@@ -16,4 +16,6 @@
     pcidi_t		pc_subid;	/* subvendor ID */
     u_int32_t		pc_class;	/* device class */
+    struct pci_device	*pc_dvp;	/* device driver pointer or NULL */
+    struct pcicb	*pc_cb;		/* pointer to bus parameters */
 };
 
@@ -34,4 +36,5 @@
 #define	PCIOCREAD	_IOWR('p', 2, struct pci_io)
 #define	PCIOCWRITE	_IOWR('p', 3, struct pci_io)
+#define	PCIOCATTACHED	_IOWR('p', 4, struct pci_io)
 
 #endif /* _PCI_IOCTL_H */

--liOOAslEiF7prFVr--
----- End forwarded message -----

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19980306004705.56636>