diff options
author | se <se@FreeBSD.org> | 1995-02-22 14:17:15 +0000 |
---|---|---|
committer | se <se@FreeBSD.org> | 1995-02-22 14:17:15 +0000 |
commit | fc2b47aebc779f9b2ace3a08a54f8aee1e2942b8 (patch) | |
tree | cae0a0d85466e4cf633d7c1910fbbb956a3783a5 /sys/dev/pci | |
parent | f735b85680829ae68d2eef7bd43575c54abb7a22 (diff) | |
download | FreeBSD-src-fc2b47aebc779f9b2ace3a08a54f8aee1e2942b8.zip FreeBSD-src-fc2b47aebc779f9b2ace3a08a54f8aee1e2942b8.tar.gz |
New PCI attach code:
PCI BIOS mappings are retained, except if option PCI_REMAP
is specified in the kernel config file.
There is now a list of attach addresses, and the first
address that seems to make some device registers appear
is chosen.
Reviewed by: se
Submitted by: wolf
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/pci.c | 162 |
1 files changed, 120 insertions, 42 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index fe27418..a3ddeb8 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pci.c,v 1.9 1994/11/02 23:47:13 se Exp $ +** $Id: pci.c,v 1.14 1995/02/14 23:33:38 se Exp $ ** ** General subroutines for the PCI bus on 80*86 systems. ** pci_configure () @@ -36,6 +36,8 @@ *************************************************************************** */ +#define PCI_PATCHLEVEL "pl2 95/02/21" + #include <pci.h> #if NPCI > 0 @@ -104,16 +106,27 @@ static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize); /*-------------------------------------------------------- ** ** The pci devices can be mapped to any address. -** As default we start at the last gigabyte. +** This is a list of possible starting addresses. +** It can be prepended by a config option. ** **-------------------------------------------------------- */ -#ifndef PCI_PMEM_START -#define PCI_PMEM_START 0xc0000000 +static u_long pci_stable[] = { +#ifdef PCI_PMEM_START + (PCI_PMEM_START), #endif + 0xf1000000, + 0x53900000, + 0xc0000000, + 0x81000000, + 0x0f000000, +}; + +static vm_offset_t pci_paddr = 0; +static vm_offset_t pci_pold = 0; +static vm_offset_t pci_pidx = 0; -static vm_offset_t pci_paddr = PCI_PMEM_START; /*-------------------------------------------------------- ** @@ -175,7 +188,6 @@ void pci_configure() int pciint; int irq; char* name=0; - vm_offset_t old_addr=pci_paddr; u_short old_ioaddr=pci_ioaddr; int dvi; @@ -204,8 +216,8 @@ void pci_configure() /* ** hello world .. */ - + pci_pold=pci_paddr; for (bus=0;bus<NPCI;bus++) { #ifndef PCI_QUIET printf ("%s%d: scanning device 0..%d, mechanism=%d.\n", @@ -373,9 +385,9 @@ void pci_configure() }; #ifndef PCI_QUIET - if (pci_paddr != old_addr) + if (pci_paddr != pci_pold) printf ("pci uses physical addresses from 0x%lx to 0x%lx\n", - (u_long)PCI_PMEM_START, (u_long)pci_paddr); + (u_long)pci_pold, (u_long)pci_paddr); if (pci_ioaddr != old_ioaddr) printf ("pci devices use ioports from 0x%x to 0x%x\n", (unsigned)PCI_PORT_START, (unsigned)pci_ioaddr); @@ -424,8 +436,8 @@ pci_conf_write (pcici_t tag, u_long reg, u_long data) int pci_map_port (pcici_t tag, u_long reg, u_short* pa) { - u_long data; - u_short size; + u_long data,oldmap; + u_short size, ioaddr; /* ** sanity check @@ -445,6 +457,12 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa) ** n-2 bits are hardwired as 0. */ +#ifdef PCI_REMAP + oldmap = 0; +#else + oldmap = pcibus.pb_read (tag, reg) & 0xfffffffc; + if (oldmap==0xfffffffc) oldmap=0; +#endif pcibus.pb_write (tag, reg, 0xfffffffful); data = pcibus.pb_read (tag, reg); @@ -468,11 +486,19 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa) if (!size) return (0); /* - ** align physical address to virtual size + ** align physical address to virtual size, + ** set ioaddr, + ** and don't forget to increment pci_ioaddr */ - if ((data = pci_ioaddr % size)) - pci_ioaddr += size - data; + if (oldmap) { + ioaddr = oldmap; + } else { + if ((data = pci_ioaddr % size)) + pci_ioaddr += size - data; + ioaddr = pci_ioaddr; + pci_ioaddr += size; + }; #ifndef PCI_QUIET /* @@ -480,14 +506,14 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa) */ printf ("\treg%d: ioaddr=0x%x size=0x%x\n", - (unsigned) reg, (unsigned) pci_ioaddr, (unsigned) size); + (unsigned) reg, (unsigned) ioaddr, (unsigned) size); #endif /* ** set device address */ - pcibus.pb_write (tag, reg, (u_long) pci_ioaddr); + pcibus.pb_write (tag, reg, (u_long) ioaddr); /* ** return them to the driver @@ -495,12 +521,6 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa) *pa = pci_ioaddr; - /* - ** and don't forget to increment pci_ioaddr - */ - - pci_ioaddr += size; - return (1); } @@ -515,7 +535,7 @@ int pci_map_port (pcici_t tag, u_long reg, u_short* pa) int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) { - u_long data; + u_long data,oldmap,paddr; vm_size_t vsize; vm_offset_t vaddr; int i; @@ -531,13 +551,19 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) }; /* - ** get size and type of memory + ** save old mapping, get size and type of memory ** ** type is in the lowest four bits. ** If device requires 2^n bytes, the next ** n-4 bits are read as 0. */ +#ifdef PCI_REMAP + oldmap = 0; +#else + oldmap = pcibus.pb_read (tag, reg) & 0xfffffff0; + if (oldmap==0xfffffff0) oldmap = 0; +#endif pcibus.pb_write (tag, reg, 0xfffffffful); data = pcibus.pb_read (tag, reg); @@ -551,7 +577,7 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) (unsigned) data); return (0); }; - + /* ** mask out the type, ** and round up to a page size @@ -560,7 +586,29 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK)); if (!vsize) return (0); - + + if (oldmap) { + paddr = oldmap; + goto domap; + }; + +next_try: + if (!pci_paddr) { + /* + ** Get a starting address. + */ + if (pci_pidx >= sizeof(pci_stable)/sizeof(u_long)) { + printf ("pci_map_mem: out of start addresses.\n"); + return (0); + }; + + pci_paddr = pci_stable[pci_pidx++]; + pci_pold = 0; + + if (pci_pidx>1) + printf ("\t(retry at 0x%x)\n", + (unsigned) pci_paddr); + }; /* ** align physical address to virtual size */ @@ -568,53 +616,83 @@ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) if ((data = pci_paddr % vsize)) pci_paddr += vsize - data; - vaddr = (vm_offset_t) pmap_mapdev (pci_paddr, vsize); - + if (!pci_pold) + pci_pold = pci_paddr; - if (!vaddr) return (0); + /* + ** set physical mapping address, + ** and reserve physical address range + */ + + paddr = pci_paddr; + pci_paddr += vsize; + +domap: + vaddr = (vm_offset_t) pmap_mapdev (paddr, vsize); + if (!vaddr) return (0); + #ifndef PCI_QUIET /* ** display values. */ printf ("\treg%d: virtual=0x%lx physical=0x%lx\n", - (unsigned) reg, (u_long)vaddr, (u_long)pci_paddr); + (unsigned) reg, (u_long)vaddr, (u_long)paddr); #endif /* ** probe for already mapped device. */ - for (i=0; i<vsize; i+=4) { + if (!oldmap) for (i=0; i<vsize; i+=4) { u_long* addr = (u_long*) (vaddr+i); data = *addr; if (data != 0xffffffff) { - printf ("WARNING: possible address conflict " - "at 0x%08x (read: 0x%08x).\n", - (unsigned) pci_paddr+i, (unsigned) data); - break; + printf ("\t(possible address conflict: " + "at 0x%x read: 0x%x)\n", + (unsigned) paddr+i, (unsigned) data); + pci_paddr = 0; + goto next_try; }; }; /* - ** return them to the driver + ** Set device address */ - *va = vaddr; - *pa = pci_paddr; + pcibus.pb_write (tag, reg, paddr); /* - ** set device address + ** Check if correctly mapped. + ** + ** W A R N I N G + ** + ** This code assumes that the device will NOT return + ** only ones (0xffffffff) from all offsets. */ - pcibus.pb_write (tag, reg, pci_paddr); + for (i=0; i<vsize; i+=4) { + u_long* addr = (u_long*) (vaddr+i); + data = *addr; + if (data != 0xffffffff) + break; + }; + + if (data==0xffffffff) { + printf ("\t(possible mapping problem: " + "at 0x%x read 0xffffffff)\n", + (unsigned) paddr); + pci_paddr = 0; + goto next_try; + }; /* - ** and don't forget to increment pci_paddr + ** Return addresses to the driver */ - pci_paddr += vsize; + *va = vaddr; + *pa = paddr; return (1); } |