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>