From 784b0949d6e2aa7e6a0c069ff892d2c3aeb4bf31 Mon Sep 17 00:00:00 2001 From: se Date: Tue, 21 Jan 1997 23:23:40 +0000 Subject: Add PCI LKM support. --- sys/pci/pci.c | 679 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 389 insertions(+), 290 deletions(-) (limited to 'sys/pci/pci.c') diff --git a/sys/pci/pci.c b/sys/pci/pci.c index c332094..08ad7d9 100644 --- a/sys/pci/pci.c +++ b/sys/pci/pci.c @@ -86,11 +86,8 @@ struct pcicb { struct pcicb *pcicb_down; 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; u_int pcicb_mamount; @@ -108,19 +105,30 @@ struct pcicb { u_long pcicb_p_memlimit; }; +struct pci_lkm { + struct pci_device *dvp; + struct pci_lkm *next; +}; + static void not_supported (pcici_t tag, u_long type); static void 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); static int 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); /*======================================================== ** @@ -140,8 +148,6 @@ unsigned pciroots = 0; /* XXX pcisupport.c increments this * for the Orion host to PCI bridge * UGLY hack ... :( Will be changed :) */ -static struct pcibus* pcibus; - /*-------------------------------------------------------- ** ** Local variables. @@ -149,10 +155,18 @@ static struct pcibus* pcibus; **-------------------------------------------------------- */ +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; /*----------------------------------------------------------------- ** @@ -374,6 +388,264 @@ pci_bridge_config (void) /*======================================================== ** +** 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;regpcicb_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() ** ** Autoconfiguration of one pci bus. @@ -429,10 +701,6 @@ pci_bus_config (void) u_char reg; pcici_t tag, mtag; pcidi_t type; - u_long data; - int unit; - u_char pciint; - int irq; struct pci_device *dvp; @@ -454,9 +722,6 @@ pci_bus_config (void) struct pci_device **dvpp; 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); type = pci_conf_read (tag, PCI_ID_REG); @@ -522,7 +787,7 @@ pci_bus_config (void) maxfunc = 7; } - pci_remember(bus_no, device, func); + pci_remember(bus_no, device, func, dvp); if (dvp==NULL) { #ifndef PCI_QUIET @@ -540,268 +805,8 @@ pci_bus_config (void) 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;regpcicb_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); } } } @@ -832,9 +837,6 @@ pci_bus_config (void) ** ** 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. ** @@ -896,6 +898,81 @@ void pci_configure() pci_conf_count++; } +/*======================================================== +** +** 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) +{ + struct pci_lkm *lkm; + + 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; +} + /*----------------------------------------------------------------------- ** ** Map device into port space. @@ -923,12 +1000,6 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa) return (0); }; - /*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 ** @@ -1709,12 +1780,10 @@ void not_supported (pcici_t tag, u_long type) /* * 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; pcici_t tag; @@ -1746,6 +1815,8 @@ pci_remember(int bus, int dev, int func) p->pc_hdr = (pci_conf_read (tag, PCI_HEADER_MISC) >> 16) & 0xff; tag = pcibus->pb_tag (bus, dev, func); p->pc_devid = pci_conf_read(tag, PCI_ID_REG); + p->pc_dvp = dvp; + p->pc_cb = pcicb; if ((p->pc_hdr & 0x7f) == 1) { p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG1); } else { @@ -1828,6 +1899,34 @@ pci_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) } 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: + case 1: + default: + error = ENODEV; + break; + } + break; + default: error = ENOTTY; break; -- cgit v1.1