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>
