patch-2.3.16 linux/arch/sparc64/kernel/psycho.c
Next file: linux/arch/sparc64/kernel/semaphore.c
Previous file: linux/arch/sparc64/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 2906
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.15/linux/arch/sparc64/kernel/psycho.c
- Orig date:
Fri Aug 6 11:58:00 1999
diff -u --recursive --new-file v2.3.15/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
@@ -1,2905 +0,0 @@
-/* $Id: psycho.c,v 1.89 1999/08/06 10:37:35 davem Exp $
- * psycho.c: Ultra/AX U2P PCI controller support.
- *
- * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
- * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#undef PROM_DEBUG
-#undef FIXUP_REGS_DEBUG
-#undef FIXUP_IRQ_DEBUG
-#undef FIXUP_VMA_DEBUG
-#undef PCI_COOKIE_DEBUG
-
-#ifdef PROM_DEBUG
-#define dprintf prom_printf
-#else
-#define dprintf printk
-#endif
-
-unsigned long pci_dvma_offset = 0x00000000UL;
-unsigned long pci_dvma_mask = 0xffffffffUL;
-
-#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL
-unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
-unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
-
-#ifndef CONFIG_PCI
-
-int pcibios_present(void)
-{
- return 0;
-}
-
-asmlinkage int sys_pciconfig_read(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- return 0;
-}
-
-asmlinkage int sys_pciconfig_write(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- return 0;
-}
-
-#else
-
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/pci.h>
-
-#include <asm/oplib.h>
-#include <asm/pbm.h>
-#include <asm/apb.h>
-#include <asm/uaccess.h>
-
-#define PSYCHO_REORDER_ONBOARDFIRST 1
-
-struct linux_psycho *psycho_root = NULL;
-int linux_num_psycho = 0;
-static struct linux_pbm_info *bus2pbm[256];
-static int psycho_reorder __initdata = 0;
-
-static int pbm_read_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value);
-static int pbm_read_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value);
-static int pbm_read_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value);
-static int pbm_write_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value);
-static int pbm_write_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value);
-static int pbm_write_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value);
-
-/* This is used to make the scan_bus in the generic PCI code be
- * a nop, as we need to control the actual bus probing sequence.
- * After that we leave it on of course.
- */
-static int pci_probe_enable = 0;
-
-static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr)
-{
- unsigned long dvma_addr = pci_dvma_offset + daddr;
- unsigned long vaddr = (unsigned long)__va(paddr);
-
- pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr;
- pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr;
-}
-
-static void __init psycho_iommu_init(struct linux_psycho *psycho, int tsbsize)
-{
- extern int this_is_starfire;
- extern void *starfire_hookup(int);
- struct linux_mlist_p1275 *mlist;
- unsigned long tsbbase;
- unsigned long control, i, n;
- unsigned long *iopte;
- unsigned long order;
-
- /*
- * Invalidate TLB Entries.
- */
- control = psycho->psycho_regs->iommu_control;
- control |= IOMMU_CTRL_DENAB;
- psycho->psycho_regs->iommu_control = control;
- for(i = 0; i < 16; i++) {
- psycho->psycho_regs->iommu_data[i] = 0;
- }
- control &= ~(IOMMU_CTRL_DENAB);
- psycho->psycho_regs->iommu_control = control;
-
- for(order = 0;; order++) {
- if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
- break;
- }
- tsbbase = __get_free_pages(GFP_DMA, order);
- if (!tsbbase) {
- prom_printf("IOMMU: Error, kmalloc(tsb) failed.\n");
- prom_halt();
- }
- iopte = (unsigned long *)tsbbase;
-
- /* Initialize to "none" settings. */
- for(i = 0; i < PCI_DVMA_HASHSZ; i++) {
- pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE;
- pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE;
- }
-
- n = 0;
- mlist = *prom_meminfo()->p1275_totphys;
- while (mlist) {
- unsigned long paddr = mlist->start_adr;
- unsigned long num_bytes = mlist->num_bytes;
-
- if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET))
- goto next;
-
- if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET))
- num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr;
-
- /* Align base and length so we map whole hash table sized chunks
- * at a time (and therefore full 64K IOMMU pages).
- */
- paddr &= ~((1UL << 24UL) - 1);
- num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1);
-
- /* Move up the base for mappings already created. */
- while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] !=
- PCI_DVMA_HASH_NONE) {
- paddr += (1UL << 24UL);
- num_bytes -= (1UL << 24UL);
- if(num_bytes == 0UL)
- goto next;
- }
-
- /* Move down the size for tail mappings already created. */
- while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] !=
- PCI_DVMA_HASH_NONE) {
- num_bytes -= (1UL << 24UL);
- if(num_bytes == 0UL)
- goto next;
- }
-
- /* Now map the rest. */
- for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K |
- IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= paddr;
-
- if (!(n & 0xff))
- set_dvma_hash(paddr, (n << 16));
-
- if (++n > (tsbsize * 1024))
- goto out;
-
- paddr += (1 << 16);
- iopte++;
- }
- next:
- mlist = mlist->theres_more;
- }
-out:
- if (mlist) {
- prom_printf("WARNING: not all physical memory mapped in IOMMU\n");
- prom_printf("Try booting with mem=xxxM or similar\n");
- prom_halt();
- }
-
- psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
-
- control = psycho->psycho_regs->iommu_control;
- control &= ~(IOMMU_CTRL_TSBSZ);
- control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
- switch(tsbsize) {
- case 8:
- pci_dvma_mask = 0x1fffffffUL;
- control |= IOMMU_TSBSZ_8K;
- break;
- case 16:
- pci_dvma_mask = 0x3fffffffUL;
- control |= IOMMU_TSBSZ_16K;
- break;
- case 32:
- pci_dvma_mask = 0x7fffffffUL;
- control |= IOMMU_TSBSZ_32K;
- break;
- default:
- prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
- prom_halt();
- break;
- }
- psycho->psycho_regs->iommu_control = control;
-
- /* If necessary, hook us up for starfire IRQ translations. */
- if(this_is_starfire)
- psycho->starfire_cookie = starfire_hookup(psycho->upa_portid);
- else
- psycho->starfire_cookie = NULL;
-}
-
-extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
-extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm);
-
-/*
- * Poor man's PCI...
- */
-void __init sabre_init(int pnode)
-{
- struct linux_prom64_registers pr_regs[2];
- struct linux_psycho *sabre;
- unsigned long ctrl;
- int tsbsize, node, err;
- u32 busrange[2];
- u32 vdma[2];
- u32 portid;
- int bus;
-
- sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
- if (!sabre) {
- prom_printf("SABRE: Error, kmalloc(sabre) failed.\n");
- prom_halt();
- }
-
- portid = prom_getintdefault(pnode, "upa-portid", 0xff);
-
- memset(sabre, 0, sizeof(*sabre));
-
- sabre->next = psycho_root;
- psycho_root = sabre;
-
- sabre->upa_portid = portid;
- sabre->index = linux_num_psycho++;
-
- /*
- * Map in SABRE register set and report the presence of this SABRE.
- */
- err = prom_getproperty(pnode, "reg",
- (char *)&pr_regs[0], sizeof(pr_regs));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get U2P registers "
- "from PROM.\n");
- prom_halt();
- }
-
- /*
- * First REG in property is base of entire SABRE register space.
- */
- sabre->psycho_regs =
- sparc_alloc_io((pr_regs[0].phys_addr & 0xffffffff),
- NULL, sizeof(struct psycho_regs),
- "SABRE Registers",
- (pr_regs[0].phys_addr >> 32), 0);
- if(sabre->psycho_regs == NULL) {
- prom_printf("SABRE: Error, cannot map SABRE main registers.\n");
- prom_halt();
- }
-
- printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
- sabre->psycho_regs, sabre->psycho_regs->control);
-#ifdef PROM_DEBUG
- dprintf("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
- sabre->psycho_regs, sabre->psycho_regs->control);
-#endif
-
- ctrl = sabre->psycho_regs->pci_a_control;
- ctrl = (1UL << 36) | (1UL << 34) | (1UL << 21) | (1UL << 8) | 0x0fUL;
- sabre->psycho_regs->pci_a_control = ctrl;
-
- /* Now map in PCI config space for entire SABRE. */
- sabre->pci_config_space =
- sparc_alloc_io(((pr_regs[0].phys_addr & 0xffffffff)
- + 0x01000000),
- NULL, 0x01000000,
- "PCI Config Space",
- (pr_regs[0].phys_addr >> 32), 0);
- if(sabre->pci_config_space == NULL) {
- prom_printf("SABRE: Error, cannot map PCI config space.\n");
- prom_halt();
- }
-
- /* Report some more info. */
- printk("SABRE: PCI config space at %p\n", sabre->pci_config_space);
-#ifdef PROM_DEBUG
- dprintf("SABRE: PCI config space at %p\n", sabre->pci_config_space);
-#endif
-
- err = prom_getproperty(pnode, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get virtual-dma property "
- "from PROM.\n");
- prom_halt();
- }
-
- switch(vdma[1]) {
- case 0x20000000:
- tsbsize = 8;
- break;
- case 0x40000000:
- tsbsize = 16;
- break;
- case 0x80000000:
- tsbsize = 32;
- break;
- default:
- prom_printf("SABRE: strange virtual-dma size.\n");
- prom_halt();
- }
-
- pci_dvma_offset = vdma[0];
- psycho_iommu_init(sabre, tsbsize);
-
- printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
-#ifdef PROM_DEBUG
- dprintf("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
-#endif
-
- err = prom_getproperty(pnode, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("SIMBA: Error, cannot get PCI bus-range "
- " from PROM.\n");
- prom_halt();
- }
-
- sabre->pci_first_busno = busrange[0];
- sabre->pci_last_busno = busrange[1];
- sabre->pci_bus = &pci_root;
-
- /*
- * Handle config space reads through any Simba on APB.
- */
- for (bus = sabre->pci_first_busno; bus <= sabre->pci_last_busno; bus++)
- bus2pbm[bus] = &sabre->pbm_A;
-
- /*
- * Look for APB underneath.
- */
- node = prom_getchild(pnode);
- while ((node = prom_searchsiblings(node, "pci"))) {
- struct linux_pbm_info *pbm;
- char namebuf[128];
-
- err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
- if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
- goto next_pci;
-
- err = prom_getproperty(node, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("SIMBA: Error, cannot get PCI bus-range "
- " from PROM.\n");
- prom_halt();
- }
-
- if (busrange[0] == 1)
- pbm = &sabre->pbm_B;
- else
- pbm = &sabre->pbm_A;
-
- pbm->parent = sabre;
- pbm->IO_assignments = NULL;
- pbm->MEM_assignments = NULL;
- pbm->prom_node = node;
-
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
- strcpy(pbm->prom_name, namebuf);
-
- /* Now the ranges. */
- prom_pbm_ranges_init(pnode, pbm);
- prom_pbm_intmap_init(node, pbm);
-
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
- memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
-
- for (bus = pbm->pci_first_busno;
- bus <= pbm->pci_last_busno; bus++)
- bus2pbm[bus] = pbm;
-
- next_pci:
- node = prom_getsibling(node);
- if (!node)
- break;
- }
-}
-
-static __inline__ int
-apb_present(struct linux_psycho *psycho)
-{
- return psycho->pci_bus ? 1 : 0;
-}
-
-void __init pcibios_init(void)
-{
- struct linux_prom64_registers pr_regs[3];
- struct linux_psycho *psycho;
- char namebuf[128];
- u32 portid;
- int node;
-
- printk("PCI: Probing for controllers.\n");
-#ifdef PROM_DEBUG
- dprintf("PCI: Probing for controllers.\n");
-#endif
-
- node = prom_getchild(prom_root_node);
- while((node = prom_searchsiblings(node, "pci")) != 0) {
- struct linux_psycho *search;
- struct linux_pbm_info *pbm = NULL;
- u32 busrange[2];
- int err, is_pbm_a;
-
- err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
- if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
- sabre_init(node);
- goto next_pci;
- }
-
- portid = prom_getintdefault(node, "upa-portid", 0xff);
- for(search = psycho_root; search; search = search->next) {
- if(search->upa_portid == portid) {
- psycho = search;
-
- /* This represents _this_ instance, so it's
- * which ever one does _not_ have the prom node
- * info filled in yet.
- */
- is_pbm_a = (psycho->pbm_A.prom_node == 0);
- goto other_pbm;
- }
- }
-
- psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
- if (!psycho) {
- prom_printf("PSYCHO: Error, kmalloc(psycho) failed.\n");
- prom_halt();
- }
- memset(psycho, 0, sizeof(*psycho));
-
- psycho->next = psycho_root;
- psycho_root = psycho;
-
- psycho->upa_portid = portid;
- psycho->index = linux_num_psycho++;
-
- /*
- * Map in PSYCHO register set and report the presence
- * of this PSYCHO.
- */
- err = prom_getproperty(node, "reg",
- (char *)&pr_regs[0], sizeof(pr_regs));
- if(err == 0 || err == -1) {
- prom_printf("PSYCHO: Error, cannot get U2P registers "
- "from PROM.\n");
- prom_halt();
- }
-
- /*
- * Third REG in property is base of entire PSYCHO
- * register space.
- */
- psycho->psycho_regs =
- sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
- NULL, sizeof(struct psycho_regs),
- "PSYCHO Registers",
- (pr_regs[2].phys_addr >> 32), 0);
- if(psycho->psycho_regs == NULL) {
- prom_printf("PSYCHO: Error, cannot map PSYCHO "
- "main registers.\n");
- prom_halt();
- }
-
- printk("PCI: Found PSYCHO, main regs at %p\n",
- psycho->psycho_regs);
-#ifdef PROM_DEBUG
- dprintf("PCI: Found PSYCHO, main regs at %p\n",
- psycho->psycho_regs);
-#endif
-
- psycho->psycho_regs->irq_retry = 0xff;
-
- /* Now map in PCI config space for entire PSYCHO. */
- psycho->pci_config_space =
- sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)
- + 0x01000000),
- NULL, 0x01000000,
- "PCI Config Space",
- (pr_regs[2].phys_addr >> 32), 0);
- if(psycho->pci_config_space == NULL) {
- prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
- prom_halt();
- }
-
- /* Report some more info. */
- printk("PSYCHO: PCI config space at %p\n",
- psycho->pci_config_space);
-#ifdef PROM_DEBUG
- dprintf("PSYCHO: PCI config space at %p\n",
- psycho->pci_config_space);
-#endif
-
- pci_dvma_offset = 0x80000000UL;
- psycho_iommu_init(psycho, 32);
-
- is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
-
- /* Enable arbitration for all PCI slots. */
- psycho->psycho_regs->pci_a_control |= PSYCHO_PCICTRL_AEN;
- psycho->psycho_regs->pci_b_control |= PSYCHO_PCICTRL_AEN;
-
- /* Disable DMA write / PIO rd synchronization on both
- * PCI bus segments.
- */
- psycho->psycho_regs->pci_a_diag |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho->psycho_regs->pci_b_diag |= PSYCHO_PCIDIAG_DDWSYNC;
-
- other_pbm:
- if(is_pbm_a)
- pbm = &psycho->pbm_A;
- else
- pbm = &psycho->pbm_B;
-
- pbm->parent = psycho;
- pbm->IO_assignments = NULL;
- pbm->MEM_assignments = NULL;
- pbm->prom_node = node;
-
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
- strcpy(pbm->prom_name, namebuf);
-
- /* Now the ranges. */
- prom_pbm_ranges_init(node, pbm);
- prom_pbm_intmap_init(node, pbm);
-
- /* Finally grab the pci bus root array for this pbm after
- * having found the bus range existing under it.
- */
- err = prom_getproperty(node, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
- prom_halt();
- }
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
- memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
-
- next_pci:
- node = prom_getsibling(node);
- if(!node)
- break;
- }
-}
-
-int pcibios_present(void)
-{
- return psycho_root != NULL;
-}
-
-static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm,
- unsigned long start,
- unsigned int offset, int io)
-{
- struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
-
- while (vp) {
- if (offset && (vp->offset != offset))
- goto next;
- if (vp->end >= start)
- break;
- next:
- vp = vp->next;
- }
- return vp;
-}
-
-static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, int io)
-{
- struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
-
- if(!vp) {
- new->next = NULL;
- if(io)
- pbm->IO_assignments = new;
- else
- pbm->MEM_assignments = new;
- } else {
- struct pci_vma *prev = NULL;
-
- while(vp && (vp->end < new->end)) {
- prev = vp;
- vp = vp->next;
- }
- new->next = vp;
- if(!prev) {
- if(io)
- pbm->IO_assignments = new;
- else
- pbm->MEM_assignments = new;
- } else {
- prev->next = new;
- }
-
- /* Check for programming errors. */
- if(vp &&
- ((vp->start >= new->start && vp->start < new->end) ||
- (vp->end >= new->start && vp->end < new->end))) {
- prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n",
- io ? "IO" : "MEM");
- prom_printf("pci_add_vma: vp[%016lx:%016lx] "
- "new[%016lx:%016lx]\n",
- vp->start, vp->end,
- new->start, new->end);
- }
- }
-}
-
-static inline struct pci_vma *pci_vma_alloc(void)
-{
- return kmalloc(sizeof(struct pci_vma), GFP_ATOMIC);
-}
-
-static inline struct pcidev_cookie *pci_devcookie_alloc(void)
-{
- return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
-}
-
-
-static void __init
-pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
-{
- unsigned int devfn, l, class;
- unsigned char hdr_type = 0;
- int is_multi = 0;
-
- for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) != 0 && is_multi == 0) {
- /* not a multi-function device */
- continue;
- }
- pbm_read_config_byte(pbm, bus, devfn,
- PCI_HEADER_TYPE, &hdr_type);
- if (PCI_FUNC(devfn) == 0)
- is_multi = hdr_type & 0x80;
-
- /* Check if there is anything here. */
- pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l);
- if (l == 0xffffffff || l == 0x00000000 ||
- l == 0x0000ffff || l == 0xffff0000) {
- is_multi = 0;
- continue;
- }
-
- /* See if this is a bridge device. */
- pbm_read_config_dword(pbm, bus, devfn,
- PCI_CLASS_REVISION, &class);
-
- if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
- unsigned int buses;
-
- pbm_read_config_dword(pbm, bus, devfn,
- PCI_PRIMARY_BUS, &buses);
-
- /*
- * First reconfigure everything underneath the bridge.
- */
- pbm_reconfigure_bridges(pbm, (buses >> 8) & 0xff);
-
- /*
- * Unconfigure this bridges bus numbers,
- * pci_scan_bus() will fix this up properly.
- */
- buses &= 0xff000000;
- pbm_write_config_dword(pbm, bus, devfn,
- PCI_PRIMARY_BUS, buses);
- }
- }
-}
-
-static void __init pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
-{
- unsigned int nbus;
-
- /*
- * First, reconfigure all bridge devices underneath this pbm.
- */
- pbm_reconfigure_bridges(pbm, pbm->pci_first_busno);
-
- /*
- * Now reconfigure the pbm to it's new bus number and set up
- * our bus2pbm mapping for this pbm.
- */
- nbus = pbm->pci_last_busno - pbm->pci_first_busno;
-
- pbm_write_config_byte(pbm, pbm->pci_first_busno, 0, 0x40, bus);
-
- pbm->pci_first_busno = bus;
- pbm_write_config_byte(pbm, bus, 0, 0x41, 0xff);
-
- do {
- bus2pbm[bus++] = pbm;
- } while (nbus--);
-}
-
-static void __init apb_init(struct linux_psycho *sabre)
-{
- struct pci_dev *pdev;
- unsigned short stmp;
- unsigned int itmp;
-
-#if 0
- for(pdev = pci_devices; pdev; pdev = pdev->next) {
- if(pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- break;
- }
- }
-#endif
- for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
- if (pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
- pci_read_config_word(pdev, PCI_COMMAND, &stmp);
- stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
- PCI_COMMAND_IO;
- pci_write_config_word(pdev, PCI_COMMAND, stmp);
-
- /* Status register bits are "write 1 to clear". */
- pci_write_config_word(pdev, PCI_STATUS, 0xffff);
- pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
-
- pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp);
- stmp = PCI_BRIDGE_CTL_MASTER_ABORT |
- PCI_BRIDGE_CTL_SERR |
- PCI_BRIDGE_CTL_PARITY;
- pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp);
-
- pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp);
- itmp = APB_PCI_CTL_HIGH_SERR |
- APB_PCI_CTL_HIGH_ARBITER_EN;
- pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
-
- /* Systems with SIMBA are usually workstations, so
- * we configure to park to SIMBA not to the previous
- * bus owner.
- */
- pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
- itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
- pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
-#if 0
- /* Don't mess with the retry limit and PIO/DMA latency
- * timer settings. But do set primary and secondary
- * latency timers.
- */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
-#endif
- }
- }
-}
-
-extern struct pci_bus pci_root;
-extern struct pci_dev *pci_devices;
-static struct pci_dev **pci_last_dev_p = &pci_devices;
-extern int pci_reverse;
-
-extern void pci_namedevice(struct pci_dev *);
-
-static void __init sparc64_pci_read_bases(struct pci_dev *dev, unsigned int howmany)
-{
- unsigned int reg;
- u32 l;
-
- for(reg=0; reg < howmany; reg++) {
- struct resource *res = dev->resource + reg;
- unsigned long mask;
- unsigned int newval, size;
-
- res->name = dev->name;
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
- if (l == 0xffffffff)
- continue;
-
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), 0xffffffff);
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &newval);
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), l);
-
- mask = PCI_BASE_ADDRESS_MEM_MASK;
- if (l & PCI_BASE_ADDRESS_SPACE_IO)
- mask = PCI_BASE_ADDRESS_IO_MASK;
-
- newval &= mask;
- if (!newval)
- continue;
-
- res->start = l & mask;
- res->flags = l & ~mask;
-
- size = 1;
- do {
- size <<= 1;
- } while (!(size & newval));
-
- /* 64-bit memory? */
- if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
- unsigned int high;
- reg++;
- pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &high);
- if (high)
- res->start |= ((unsigned long) high) << 32;
- }
- res->end = res->start + size - 1;
- }
-}
-
-static unsigned int __init sparc64_pci_scan_bus(struct pci_bus *bus)
-{
- unsigned int devfn, l, max, class;
- unsigned char cmd, irq, tmp, hdr_type, is_multi = 0;
- struct pci_dev *dev, **bus_last;
- struct pci_bus *child;
-
- bus_last = &bus->devices;
- max = bus->secondary;
- for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) && !is_multi) {
- /* not a multi-function device */
- continue;
- }
- if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type))
- continue;
- if (!PCI_FUNC(devfn))
- is_multi = hdr_type & 0x80;
-
- if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
- /* some broken boards return 0 if a slot is empty: */
- l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
- continue;
-
- dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
- if(dev==NULL)
- {
- printk(KERN_ERR "pci: out of memory.\n");
- continue;
- }
- memset(dev, 0, sizeof(*dev));
- dev->bus = bus;
- dev->devfn = devfn;
- dev->vendor = l & 0xffff;
- dev->device = (l >> 16) & 0xffff;
- pci_namedevice(dev);
-
- /* non-destructively determine if device can be a master: */
- pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd);
- pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
- pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &tmp);
- dev->master = ((tmp & PCI_COMMAND_MASTER) != 0);
- pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd);
-
- pcibios_read_config_dword(bus->number, devfn, PCI_CLASS_REVISION, &class);
- class >>= 8; /* upper 3 bytes */
- dev->class = class;
- class >>= 8;
- dev->hdr_type = hdr_type;
-
- switch (hdr_type & 0x7f) { /* header type */
- case PCI_HEADER_TYPE_NORMAL: /* standard header */
- if (class == PCI_CLASS_BRIDGE_PCI)
- goto bad;
- /*
- * If the card generates interrupts, read IRQ number
- * (some architectures change it during pcibios_fixup())
- */
- pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq);
- if (irq)
- pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
- dev->irq = irq;
- sparc64_pci_read_bases(dev, 6);
- pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
- dev->rom_address = (l == 0xffffffff) ? 0 : l;
- break;
- case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
- if (class != PCI_CLASS_BRIDGE_PCI)
- goto bad;
- sparc64_pci_read_bases(dev, 2);
- pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
- dev->rom_address = (l == 0xffffffff) ? 0 : l;
- break;
- case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
- if (class != PCI_CLASS_BRIDGE_CARDBUS)
- goto bad;
- sparc64_pci_read_bases(dev, 1);
- break;
- default: /* unknown header */
- bad:
- printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
- bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
- continue;
- }
-
- /*
- * Put it into the global PCI device chain. It's used to
- * find devices once everything is set up.
- */
- if (!pci_reverse) {
- *pci_last_dev_p = dev;
- pci_last_dev_p = &dev->next;
- } else {
- dev->next = pci_devices;
- pci_devices = dev;
- }
-
- /*
- * Now insert it into the list of devices held
- * by the parent bus.
- */
- *bus_last = dev;
- bus_last = &dev->sibling;
- }
-
- /*
- * After performing arch-dependent fixup of the bus, look behind
- * all PCI-to-PCI bridges on this bus.
- */
- pcibios_fixup_bus(bus);
- for(dev=bus->devices; dev; dev=dev->sibling)
- /*
- * If it's a bridge, scan the bus behind it.
- */
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- unsigned int buses;
- unsigned int devfn = dev->devfn;
- unsigned short cr;
-
- /*
- * Insert it into the tree of buses.
- */
- child = kmalloc(sizeof(*child), GFP_ATOMIC);
- if(child==NULL)
- {
- printk(KERN_ERR "pci: out of memory for bridge.\n");
- continue;
- }
- memset(child, 0, sizeof(*child));
- child->next = bus->children;
- bus->children = child;
- child->self = dev;
- child->parent = bus;
-
- /*
- * Set up the primary, secondary and subordinate
- * bus numbers.
- */
- child->number = child->secondary = ++max;
- child->primary = bus->secondary;
- child->subordinate = 0xff;
- /*
- * Clear all status bits and turn off memory,
- * I/O and master enables.
- */
- pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
- pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
- pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
- /*
- * Read the existing primary/secondary/subordinate bus
- * number configuration to determine if the PCI bridge
- * has already been configured by the system. If so,
- * do not modify the configuration, merely note it.
- */
- pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
- if ((buses & 0xFFFFFF) != 0)
- {
- unsigned int cmax;
-
- child->primary = buses & 0xFF;
- child->secondary = (buses >> 8) & 0xFF;
- child->subordinate = (buses >> 16) & 0xFF;
- child->number = child->secondary;
- cmax = sparc64_pci_scan_bus(child);
- if (cmax > max) max = cmax;
- }
- else
- {
- /*
- * Configure the bus numbers for this bridge:
- */
- buses &= 0xff000000;
- buses |=
- (((unsigned int)(child->primary) << 0) |
- ((unsigned int)(child->secondary) << 8) |
- ((unsigned int)(child->subordinate) << 16));
- pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
- /*
- * Now we can scan all subordinate buses:
- */
- max = sparc64_pci_scan_bus(child);
- /*
- * Set the subordinate bus number to its real
- * value:
- */
- child->subordinate = max;
- buses = (buses & 0xff00ffff)
- | ((unsigned int)(child->subordinate) << 16);
- pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
- }
- pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
- }
-
- /*
- * We've scanned the bus and so we know all about what's on
- * the other side of any bridges that may be on this bus plus
- * any devices.
- *
- * Return how far we've got finding sub-buses.
- */
- return max;
-}
-
-static void __init sabre_probe(struct linux_psycho *sabre)
-{
- struct pci_bus *pbus = sabre->pci_bus;
- static unsigned char busno = 0;
-
- pbus->number = pbus->secondary = busno;
- pbus->sysdata = sabre;
-
- pbus->subordinate = sparc64_pci_scan_bus(pbus);
- busno = pbus->subordinate + 1;
-
- for(pbus = pbus->children; pbus; pbus = pbus->next) {
- if (pbus->number == sabre->pbm_A.pci_first_busno)
- memcpy(&sabre->pbm_A.pci_bus, pbus, sizeof(*pbus));
- if (pbus->number == sabre->pbm_B.pci_first_busno)
- memcpy(&sabre->pbm_B.pci_bus, pbus, sizeof(*pbus));
- }
-
- apb_init(sabre);
-}
-
-
-static void __init pbm_probe(struct linux_pbm_info *pbm)
-{
- static struct pci_bus *pchain = NULL;
- struct pci_bus *pbus = &pbm->pci_bus;
- static unsigned char busno = 0;
-
- /* PSYCHO PBM's include child PCI bridges in bus-range property,
- * but we don't scan each of those ourselves, Linux generic PCI
- * probing code will find child bridges and link them into this
- * pbm's root PCI device hierarchy.
- */
-
- pbus->number = pbus->secondary = busno;
- pbus->sysdata = pbm;
-
- pbm_fixup_busno(pbm, busno);
-
- pbus->subordinate = sparc64_pci_scan_bus(pbus);
-
- /*
- * Set the maximum subordinate bus of this pbm.
- */
- pbm->pci_last_busno = pbus->subordinate;
- pbm_write_config_byte(pbm, busno, 0, 0x41, pbm->pci_last_busno);
-
- busno = pbus->subordinate + 1;
-
- /*
- * Fixup the chain of primary PCI busses.
- */
- if (pchain) {
- pchain->next = &pbm->pci_bus;
- pchain = pchain->next;
- } else {
- pchain = &pci_root;
- memcpy(pchain, &pbm->pci_bus, sizeof(pci_root));
- }
-}
-
-static int __init pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- int pnode)
-{
- struct linux_prom_pci_registers pregs[PROMREG_MAX];
- int node;
- int err;
-
- node = prom_getchild(pnode);
- while (node) {
-
- err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
- if(err != 0 && err != -1) {
- u32 devfn = (pregs[0].phys_hi >> 8) & 0xff;
-
- if(devfn == pdev->devfn)
- return node; /* Match */
- }
-
- node = prom_getsibling(node);
- }
- return 0;
-}
-
-static void __init pdev_cookie_fillin(struct linux_pbm_info *pbm,
- struct pci_dev *pdev, int pnode)
-{
- struct pcidev_cookie *pcp;
- int node;
-
- node = pdev_to_pnode_sibtraverse(pbm, pdev, pnode);
- if(node == 0)
- node = -1;
- pcp = pci_devcookie_alloc();
- pcp->pbm = pbm;
- pcp->prom_node = node;
- pdev->sysdata = pcp;
-#ifdef PCI_COOKIE_DEBUG
- dprintf("pdev_cookie_fillin: pdev [%02x.%02x]: pbm %p, node %x\n",
- pdev->bus->number, pdev->devfn, pbm, node);
-#endif
-}
-
-static void __init fill_in_pbm_cookies(struct pci_bus *pbus,
- struct linux_pbm_info *pbm,
- int node)
-{
- struct pci_dev *pdev;
-
- pbus->sysdata = pbm;
-
-#ifdef PCI_COOKIE_DEBUG
- dprintf("fill_in_pbm_cookies: pbus [%02x]: pbm %p\n",
- pbus->number, pbm);
-#endif
-
- for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_cookie_fillin(pbm, pdev, node);
-
- for(pbus = pbus->children; pbus; pbus = pbus->next) {
- struct pcidev_cookie *pcp = pbus->self->sysdata;
- fill_in_pbm_cookies(pbus, pbm, pcp->prom_node);
- }
-}
-
-static void __init sabre_cookie_fillin(struct linux_psycho *sabre)
-{
- struct pci_bus *pbus = sabre->pci_bus;
-
- for(pbus = pbus->children; pbus; pbus = pbus->next) {
- if (pbus->number == sabre->pbm_A.pci_first_busno)
- pdev_cookie_fillin(&sabre->pbm_A, pbus->self,
- sabre->pbm_A.prom_node);
- else if (pbus->number == sabre->pbm_B.pci_first_busno)
- pdev_cookie_fillin(&sabre->pbm_B, pbus->self,
- sabre->pbm_B.prom_node);
- }
-}
-
-/* Walk PROM device tree under PBM, looking for 'assigned-address'
- * properties, and recording them in pci_vma's linked in via
- * PBM->assignments.
- */
-static int __init gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
-{
- struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
- int err, iter;
-
- err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng));
- if(err == 0 || err == -1) {
- prom_printf("EBUS: fatal error, no range property.\n");
- prom_halt();
- }
- err = (err / sizeof(struct linux_prom_ebus_ranges));
- for(iter = 0; iter < err; iter++) {
- struct linux_prom_ebus_ranges *ep = &erng[iter];
- struct linux_prom_pci_registers *ap = &aregs[iter];
-
- ap->phys_hi = ep->parent_phys_hi;
- ap->phys_mid = ep->parent_phys_mid;
- ap->phys_lo = ep->parent_phys_lo;
-
- ap->size_hi = 0;
- ap->size_lo = ep->size;
- }
- return err;
-}
-
-static void __init assignment_process(struct linux_pbm_info *pbm, int node)
-{
- struct linux_prom_pci_registers aregs[PROMREG_MAX];
- char pname[256];
- int err, iter, numa;
-
- err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname));
- if (err > 0)
- pname[err] = 0;
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: %s\n", __FUNCTION__, err > 0 ? pname : "???");
-#endif
- if(strcmp(pname, "ebus") == 0) {
- numa = gimme_ebus_assignments(node, &aregs[0]);
- } else {
- err = prom_getproperty(node, "assigned-addresses",
- (char *)&aregs[0], sizeof(aregs));
-
- /* No assignments, nothing to do. */
- if(err == 0 || err == -1)
- return;
-
- numa = (err / sizeof(struct linux_prom_pci_registers));
- }
-
- for(iter = 0; iter < numa; iter++) {
- struct linux_prom_pci_registers *ap = &aregs[iter];
- struct pci_vma *vp;
- int space, breg, io;
-
- space = (ap->phys_hi >> 24) & 3;
- if(space != 1 && space != 2)
- continue;
- io = (space == 1);
-
- breg = (ap->phys_hi & 0xff);
-
- vp = pci_vma_alloc();
-
- /* XXX Means we don't support > 32-bit range of
- * XXX PCI MEM space, PSYCHO/PBM does not support it
- * XXX either due to it's layout so...
- */
- vp->start = ap->phys_lo;
- vp->end = vp->start + ap->size_lo - 1;
- vp->offset = (ap->phys_hi & 0xffffff);
-
- pci_add_vma(pbm, vp, io);
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: BaseReg %02x", pname, breg);
- dprintf(" %s vma [%08x,%08x]\n",
- io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
-#endif
- }
-}
-
-static void __init assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
-{
- while(node) {
- int child = prom_getchild(node);
- if(child)
- assignment_walk_siblings(pbm, child);
-
- assignment_process(pbm, node);
-
- node = prom_getsibling(node);
- }
-}
-
-static inline void record_assignments(struct linux_pbm_info *pbm)
-{
- struct pci_vma *vp;
-
- if (apb_present(pbm->parent)) {
- /*
- * Disallow anything that is not in our IO/MEM map on SIMBA.
- */
- struct pci_bus *pbus = pbm->parent->pci_bus;
- struct pci_dev *pdev;
- unsigned char map;
- int bit;
-
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
- struct pcidev_cookie *pcp = pdev->sysdata;
- if (!pcp)
- continue;
- if (pcp->pbm == pbm)
- break;
- }
-
- if (!pdev) {
- prom_printf("record_assignments: no pdev for PBM\n");
- prom_halt();
- }
-
- pci_read_config_byte(pdev, APB_IO_ADDRESS_MAP, &map);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: IO %02x\n", __FUNCTION__, map);
-#endif
- for (bit = 0; bit < 8; bit++) {
- if (!(map & (1 << bit))) {
- vp = pci_vma_alloc();
- vp->start = (bit << 21);
- vp->end = vp->start + (1 << 21) - 1;
- vp->offset = 0;
- pci_add_vma(pbm, vp, 1);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: IO prealloc vma [%08x,%08x]\n",
- __FUNCTION__, vp->start, vp->end);
-#endif
- }
- }
- pci_read_config_byte(pdev, APB_MEM_ADDRESS_MAP, &map);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: MEM %02x\n", __FUNCTION__, map);
-#endif
- for (bit = 0; bit < 8; bit++) {
- if (!(map & (1 << bit))) {
- vp = pci_vma_alloc();
- vp->start = (bit << 29);
- vp->end = vp->start + (1 << 29) - 1;
- vp->offset = 0;
- pci_add_vma(pbm, vp, 0);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: MEM prealloc vma [%08x,%08x]\n",
- __FUNCTION__, vp->start, vp->end);
-#endif
- }
- }
- }
-
- assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
-
- /*
- * Protect ISA IO space from being used.
- */
- vp = pci_find_vma(pbm, 0, 0, 1);
- if (!vp || 0x400 <= vp->start) {
- vp = pci_vma_alloc();
- vp->start = 0;
- vp->end = vp->start + 0x400 - 1;
- vp->offset = 0;
- pci_add_vma(pbm, vp, 1);
- }
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("PROM IO assignments for PBM %s:\n",
- pbm == &pbm->parent->pbm_A ? "A" : "B");
- vp = pbm->IO_assignments;
- while (vp) {
- dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end,
- vp->offset ? "Register" : "Unmapped");
- vp = vp->next;
- }
- dprintf("PROM MEM assignments for PBM %s:\n",
- pbm == &pbm->parent->pbm_A ? "A" : "B");
- vp = pbm->MEM_assignments;
- while (vp) {
- dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end,
- vp->offset ? "Register" : "Unmapped");
- vp = vp->next;
- }
-#endif
-}
-
-static void __init fixup_regs(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- struct linux_prom_pci_registers *assigned,
- int numaa)
-{
- int preg, rng;
- int IO_seen = 0;
- int MEM_seen = 0;
-
- for(preg = 0; preg < nregs; preg++) {
- struct linux_prom_pci_registers *ap = NULL;
- int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
- int bsreg, brindex;
- unsigned int rtmp;
- u64 pci_addr, pci_size;
-
- if(bustype == 0) {
- /* Config space cookie, nothing to do. */
- if(preg != 0)
- printk("%s %02x.%02x [%04x,%04x]: "
- "strange, config space not 0\n",
- __FUNCTION__,
- pdev->bus->number, pdev->devfn,
- pdev->vendor, pdev->device);
- continue;
- } else if(bustype == 3) {
- /* XXX add support for this... */
- printk("%s %02x.%02x [%04x,%04x]: "
- "Warning, ignoring 64-bit PCI memory space, "
- "tell Eddie C. Dost (ecd@skynet.be).\n",
- __FUNCTION__,
- pdev->bus->number, pdev->devfn,
- pdev->vendor, pdev->device);
- continue;
- }
-
- bsreg = (pregs[preg].phys_hi & 0xff);
-
- /* Sanity */
- if((bsreg < PCI_BASE_ADDRESS_0) ||
- ((bsreg > (PCI_BASE_ADDRESS_5 + 4)) && (bsreg != PCI_ROM_ADDRESS)) ||
- (bsreg & 3)) {
- printk("%s %02x.%02x [%04x:%04x]: "
- "Warning, ignoring bogus basereg [%x]\n",
- __FUNCTION__, pdev->bus->number, pdev->devfn,
- pdev->vendor, pdev->device, bsreg);
- printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n",
- pregs[preg].phys_hi, pregs[preg].phys_mid,
- pregs[preg].phys_lo, pregs[preg].size_hi,
- pregs[preg].size_lo);
- continue;
- }
-
- brindex = (bsreg - PCI_BASE_ADDRESS_0) >> 2;
- if(numaa) {
- int r;
-
- for(r = 0; r < numaa; r++) {
- int abreg;
-
- abreg = (assigned[r].phys_hi & 0xff);
- if(abreg == bsreg) {
- ap = &assigned[r];
- break;
- }
- }
- }
-
- /* Now construct UPA physical address. */
- pci_addr = (((u64)pregs[preg].phys_mid) << 32UL);
- pci_addr |= (((u64)pregs[preg].phys_lo));
- pci_size = (((u64)pregs[preg].size_hi) << 32UL);
- pci_size |= (((u64)pregs[preg].size_lo));
-
- if(ap) {
- pci_addr += ((u64)ap->phys_lo);
- pci_addr += (((u64)ap->phys_mid) << 32UL);
- }
-
- /* Final step, apply PBM range. */
- for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rngp = &pbm->pbm_ranges[rng];
- int space = (rngp->child_phys_hi >> 24) & 3;
-
- if(space == bustype) {
- pci_addr += ((u64)rngp->parent_phys_lo);
- pci_addr += (((u64)rngp->parent_phys_hi) << 32UL);
- break;
- }
- }
- if(rng == pbm->num_pbm_ranges) {
- /* AIEEE */
- prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n");
- }
- if (bsreg == PCI_ROM_ADDRESS) {
- pdev->rom_address = (unsigned long)__va(pci_addr);
- pdev->rom_address &= ~1UL;
-
- /*
- * Disable access to the ROM.
- */
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1);
- } else {
- struct resource *root, *rp;
-
- rp = &pdev->resource[brindex];
-
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + (brindex * 4), &rtmp);
- if (rtmp & 0x1)
- rtmp &= 0x1;
- else
- rtmp &= 0xf;
-
- rp->name = pdev->name;
- rp->start = (unsigned long)__va(pci_addr);
- rp->end = rp->start + pci_size - 1;
-
- /* Keep track of what we've seen so far. */
- if(rtmp & 0x1) {
- IO_seen = 1;
- root = &ioport_resource;
- } else {
- MEM_seen = 1;
- root = &iomem_resource;
- }
- rp->flags = rtmp;
- request_resource(root, rp);
- }
- }
-
- /* Now handle assignments PROM did not take care of. */
- if(nregs) {
- unsigned int rtmp, ridx;
- unsigned int offset, base;
- struct pci_vma *vp;
- u64 pci_addr;
- int breg;
-
- for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
- struct resource *rp;
- int io;
-
- ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
- rp = &pdev->resource[ridx];
- base = (unsigned int)rp->start;
-
- /* Already handled? */
- if(rp->start > PAGE_OFFSET)
- continue;
-
- pci_read_config_dword(pdev, breg, &rtmp);
- io = (rtmp & 0x1);
- offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
- vp = pci_find_vma(pbm, base, offset, io);
- if(!vp || vp->start > base) {
- unsigned int size, new_base;
-
- pci_write_config_dword(pdev, breg, 0xffffffff);
- pci_read_config_dword(pdev, breg, &size);
-
- if(io)
- size &= ~0x1;
- else
- size &= ~0xf;
-
- size = (~(size) + 1);
- if(!size)
- continue;
-
- new_base = 0;
- for(vp = pci_find_vma(pbm, new_base, 0, io); ;
- vp = vp->next) {
- if(!vp || new_base + size <= vp->start)
- break;
- new_base = (vp->end + (size - 1)) & ~(size-1);
- }
- if(vp && (new_base + size > vp->start)) {
- prom_printf("PCI: Impossible full %s space.\n",
- (io ? "IO" : "MEM"));
- prom_halt();
- }
- vp = pci_vma_alloc();
- vp->start = new_base;
- vp->end = vp->start + size - 1;
- vp->offset = offset;
-
- pci_add_vma(pbm, vp, io);
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%02x.%02x.%x: BaseReg %02x",
- pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn),
- breg);
- dprintf(" %s vma [%08x,%08x]\n",
- io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
-#endif
- rtmp = new_base;
- pci_read_config_dword(pdev, breg, &base);
- if(io)
- rtmp |= (base & ~PCI_BASE_ADDRESS_IO_MASK);
- else
- rtmp |= (base & ~PCI_BASE_ADDRESS_MEM_MASK);
- pci_write_config_dword(pdev, breg, rtmp);
-
- /* Apply PBM ranges and update pci_dev. */
- pci_addr = new_base;
- for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rngp;
- int rspace;
-
- rngp = &pbm->pbm_ranges[rng];
- rspace = (rngp->child_phys_hi >> 24) & 3;
- if(io && rspace != 1)
- continue;
- else if(!io && rspace != 2)
- continue;
- pci_addr += ((u64)rngp->parent_phys_lo);
- pci_addr += (((u64)rngp->parent_phys_hi)<<32UL);
- break;
- }
- if(rng == pbm->num_pbm_ranges) {
- /* AIEEE */
- prom_printf("fixup_doit: YIEEE, cannot find "
- "PBM ranges\n");
- }
- rp->name = pdev->name;
- rp->start = (unsigned long) __va(pci_addr);
- rp->end = rp->start + size - 1;
-
- /* Keep track of what we've seen so far. */
- if(io) {
- IO_seen = 1;
- rp->flags = rtmp & 0x1;
- request_resource(&ioport_resource, rp);
- } else {
- MEM_seen = 1;
- rp->flags = rtmp & 0xf;
- request_resource(&iomem_resource, rp);
- }
- }
- }
-
- /*
- * Handle PCI_ROM_ADDRESS.
- */
- breg = PCI_ROM_ADDRESS;
- base = (unsigned int)pdev->rom_address;
-
- if(pdev->rom_address > PAGE_OFFSET)
- goto rom_address_done;
-
- base &= PCI_ROM_ADDRESS_MASK;
- offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
- vp = pci_find_vma(pbm, base, offset, 0);
- if(!vp || vp->start > base) {
- unsigned int size, new_base;
-
- pci_read_config_dword(pdev, breg, &rtmp);
- pci_write_config_dword(pdev, breg, 0xffffffff);
- pci_read_config_dword(pdev, breg, &size);
- size &= ~1;
- size = (~(size) + 1);
- if(!size)
- goto rom_address_done;
-
- new_base = 0;
- for(vp = pci_find_vma(pbm, new_base, 0, 0); ; vp = vp->next) {
- if(!vp || new_base + size <= vp->start)
- break;
- new_base = (vp->end + (size - 1)) & ~(size-1);
- }
- if(vp && (new_base + size > vp->start)) {
- prom_printf("PCI: Impossible full MEM space.\n");
- prom_halt();
- }
- vp = pci_vma_alloc();
- vp->start = new_base;
- vp->end = vp->start + size - 1;
- vp->offset = offset;
-
- pci_add_vma(pbm, vp, 0);
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%02x.%02x.%x: BaseReg %02x",
- pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn),
- breg);
- dprintf(" %s vma [%08x,%08x]\n",
- "ROM", vp->start, vp->end);
-#endif
-
- rtmp = new_base;
- pci_read_config_dword(pdev, breg, &base);
- rtmp &= ~(base & ~PCI_ROM_ADDRESS_MASK);
- pci_write_config_dword(pdev, breg, rtmp);
-
- /* Apply PBM ranges and update pci_dev. */
- pci_addr = new_base;
- for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rngp;
- int rspace;
-
- rngp = &pbm->pbm_ranges[rng];
- rspace = (rngp->child_phys_hi >> 24) & 3;
- if(rspace != 2)
- continue;
- pci_addr += ((u64)rngp->parent_phys_lo);
- pci_addr += (((u64)rngp->parent_phys_hi)<<32UL);
- break;
- }
- if(rng == pbm->num_pbm_ranges) {
- /* AIEEE */
- prom_printf("fixup_doit: YIEEE, cannot find "
- "PBM ranges\n");
- }
- pdev->rom_address = (unsigned long)__va(pci_addr);
- pdev->rom_address &= ~(base & ~PCI_ROM_ADDRESS_MASK);
- MEM_seen = 1;
- }
- rom_address_done:
-
- }
- if(IO_seen || MEM_seen) {
- unsigned int l;
-
- pci_read_config_dword(pdev, PCI_COMMAND, &l);
-#ifdef FIXUP_REGS_DEBUG
- dprintf("[");
-#endif
- if(IO_seen) {
-#ifdef FIXUP_REGS_DEBUG
- dprintf("IO ");
-#endif
- l |= PCI_COMMAND_IO;
- }
- if(MEM_seen) {
-#ifdef FIXUP_REGS_DEBUG
- dprintf("MEM");
-#endif
- l |= PCI_COMMAND_MEMORY;
- }
-#ifdef FIXUP_REGS_DEBUG
- dprintf("]");
-#endif
- pci_write_config_dword(pdev, PCI_COMMAND, l);
- }
-
-#ifdef FIXUP_REGS_DEBUG
- dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device);
- for(preg = 0; preg < 6; preg++) {
- if(pdev->resource[preg].start != 0)
- dprintf("%d[%016lx] ", preg, pdev->resource[preg].start);
- }
- dprintf("\n");
-#endif
-}
-
-#define imap_offset(__member) \
- ((unsigned long)(&(((struct psycho_regs *)0)->__member)))
-
-static unsigned long __init psycho_pcislot_imap_offset(unsigned long ino)
-{
- unsigned int bus, slot;
-
- bus = (ino & 0x10) >> 4;
- slot = (ino & 0x0c) >> 2;
-
- if(bus == 0) {
- switch(slot) {
- case 0:
- return imap_offset(imap_a_slot0);
- case 1:
- return imap_offset(imap_a_slot1);
- case 2:
- return imap_offset(imap_a_slot2);
- case 3:
- default:
- return imap_offset(imap_a_slot3);
- }
- } else {
- switch(slot) {
- case 0:
- return imap_offset(imap_b_slot0);
- case 1:
- return imap_offset(imap_b_slot1);
- case 2:
- return imap_offset(imap_b_slot2);
- case 3:
- default:
- return imap_offset(imap_b_slot3);
- }
- }
-}
-
-/* Exported for EBUS probing layer. */
-unsigned int __init psycho_irq_build(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino)
-{
- unsigned long imap_off;
- int need_dma_sync = 0;
-
- ino &= PSYCHO_IMAP_INO;
-
- /* Compute IMAP register offset, generic IRQ layer figures out
- * the ICLR register address as this is simple given the 32-bit
- * irq number and IMAP register address.
- */
- if((ino & 0x20) == 0)
- imap_off = psycho_pcislot_imap_offset(ino);
- else {
- switch(ino) {
- case 0x20:
- /* Onboard SCSI. */
- imap_off = imap_offset(imap_scsi);
- break;
-
- case 0x21:
- /* Onboard Ethernet (ie. CheerIO/HME) */
- imap_off = imap_offset(imap_eth);
- break;
-
- case 0x22:
- /* Onboard Parallel Port */
- imap_off = imap_offset(imap_bpp);
- break;
-
- case 0x23:
- /* Audio Record */
- imap_off = imap_offset(imap_au_rec);
- break;
-
- case 0x24:
- /* Audio Play */
- imap_off = imap_offset(imap_au_play);
- break;
-
- case 0x25:
- /* Power Fail */
- imap_off = imap_offset(imap_pfail);
- break;
-
- case 0x26:
- /* Onboard KBD/MOUSE/SERIAL */
- imap_off = imap_offset(imap_kms);
- break;
-
- case 0x27:
- /* Floppy (ie. fdthree) */
- imap_off = imap_offset(imap_flpy);
- break;
-
- case 0x28:
- /* Spare HW INT */
- imap_off = imap_offset(imap_shw);
- break;
-
- case 0x29:
- /* Onboard Keyboard (only) */
- imap_off = imap_offset(imap_kbd);
- break;
-
- case 0x2a:
- /* Onboard Mouse (only) */
- imap_off = imap_offset(imap_ms);
- break;
-
- case 0x2b:
- /* Onboard Serial (only) */
- imap_off = imap_offset(imap_ser);
- break;
-
- case 0x2c:
- /* Onboard Timer 0 */
- imap_off = imap_offset(imap_tim0);
- break;
-
- case 0x2d:
- /* Onboard Timer 1 */
- imap_off = imap_offset(imap_tim1);
- break;
-
- case 0x2e:
- /* Psycho UE Interrupt */
- imap_off = imap_offset(imap_ue);
- break;
-
- case 0x2f:
- /* Psycho CE Interrupt */
- imap_off = imap_offset(imap_ce);
- break;
-
- case 0x30:
- /* Psycho PCI A Error Interrupt */
- imap_off = imap_offset(imap_a_err);
- break;
-
- case 0x31:
- /* Psycho PCI B Error Interrupt */
- imap_off = imap_offset(imap_b_err);
- break;
-
- case 0x32:
- /* Power Management */
- imap_off = imap_offset(imap_pmgmt);
- break;
-
- default:
- /* We don't expect anything else.
- */
- prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
- prom_halt();
- };
- }
- imap_off -= imap_offset(imap_a_slot0);
-
- if (apb_present(pbm->parent) && (pdev->bus->number != pbm->pci_first_busno)) {
- need_dma_sync = 1;
- }
-
- return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync);
-}
-
-static int __init pbm_intmap_match(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- struct linux_prom_pci_registers *preg,
- unsigned int *interrupt)
-{
- struct linux_prom_pci_registers ppreg;
- unsigned int hi, mid, lo, irq;
- int i;
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("pbm_intmap_match: ");
-#endif
- if (!pbm->num_pbm_intmap) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No intmap UPA[%x:%c]\n",
- pbm->parent->upa_portid,
- (pbm == &pbm->parent->pbm_A) ? 'A' : 'B');
-#endif
- return 0;
- }
- /*
- * Underneath a bridge, use register of parent bridge.
- */
- if (pdev->bus->number != pbm->pci_first_busno) {
- struct pcidev_cookie *pcp;
- int node, offset;
- char prom_name[64];
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("UnderBridge, ");
-#endif
- pcp = pdev->bus->self->sysdata;
- if (!pcp) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No bus PCP\n");
-#endif
- goto out;
- }
- node = pcp->prom_node;
-
- i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg));
- if(i == 0 || i == -1) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No reg property.\n");
-#endif
- goto out;
- }
- /*
- * Did PROM know better and assign an interrupt different
- * to #INTA to the device? - We test here for presence of
- * FCODE on the card, in this case we assume PROM has set
- * correct 'interrupts' property, unless it is quadhme.
- */
- pcp = pdev->sysdata;
- if (!pcp) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No dev PCP\n");
-#endif
- goto out;
- }
- node = pcp->prom_node;
-
- offset = prom_getint(node, "fcode-rom-offset");
- prom_getstring(node, "name", prom_name, sizeof(prom_name));
- if (offset == -1 ||
- !strcmp(prom_name, "SUNW,qfe") ||
- !strcmp(prom_name, "qfe")) {
- /*
- * No, use low slot number bits of child as IRQ line.
- */
- *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1;
- }
- preg = &ppreg;
- }
-
- hi = preg->phys_hi & pbm->pbm_intmask.phys_hi;
- mid = preg->phys_mid & pbm->pbm_intmask.phys_mid;
- lo = preg->phys_lo & pbm->pbm_intmask.phys_lo;
- irq = *interrupt & pbm->pbm_intmask.interrupt;
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("intmap_match: [%02x.%02x.%x] key: [%08x.%08x.%08x.%08x] ",
- pdev->bus->number, pdev->devfn >> 3, pdev->devfn & 7,
- hi, mid, lo, irq);
-#endif
- for (i = 0; i < pbm->num_pbm_intmap; i++) {
- if ((pbm->pbm_intmap[i].phys_hi == hi) &&
- (pbm->pbm_intmap[i].phys_mid == mid) &&
- (pbm->pbm_intmap[i].phys_lo == lo) &&
- (pbm->pbm_intmap[i].interrupt == irq)) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("irq: [%08x]", pbm->pbm_intmap[i].cinterrupt);
-#endif
- *interrupt = pbm->pbm_intmap[i].cinterrupt;
- return 1;
- }
- }
-
-out:
- prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ",
- pdev->bus->number, pdev->devfn);
- prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
- preg->phys_hi, preg->phys_mid, preg->phys_lo, *interrupt);
- prom_halt();
-}
-
-static void __init fixup_irq(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *preg,
- int node)
-{
- unsigned int prom_irq, portid = pbm->parent->upa_portid;
- int err;
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("fixup_irq[%04x:%04x]: ", pdev->vendor, pdev->device);
-#endif
- err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
- if(err == 0 || err == -1) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No interrupts property.\n");
-#endif
- pdev->irq = 0;
- return;
- }
-
- /* See if fully specified already (ie. for onboard devices like hme) */
- if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
- pdev->irq = psycho_irq_build(pbm, pdev, prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
- /* See if onboard device interrupt (i.e. bit 5 set) */
- } else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) {
- pdev->irq = psycho_irq_build(pbm, pdev,
- (pbm->parent->upa_portid << 6)
- | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("partially specified prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
- /* See if we find a matching interrupt-map entry. */
- } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
- pdev->irq = psycho_irq_build(pbm, pdev,
- (pbm->parent->upa_portid << 6)
- | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
- } else {
- unsigned int bus, slot, line;
-
- bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
-
- /* Use the given interrupt property value as the line if it
- * is non-zero and legal. Legal encodings are INTA=1, INTB=2,
- * INTC=3, INTD=4 as per PCI OBP binding spec version 2.1 -DaveM
- */
- if(prom_irq > 0 && prom_irq < 5) {
- line = ((prom_irq - 1) & 3);
- } else {
- unsigned char pci_irq_line;
-
- /* The generic PCI probing layer will read the
- * interrupt line into pdev->irq if the interrupt
- * pin is non-zero, so we have to explicitly fetch
- * the pin here to be certain (the interrupt line is
- * typically left at zero by OBP).
- */
- pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line);
- line = ((pci_irq_line - 1) & 3);
- }
-
- /* Slot determination is only slightly complex. Handle
- * the easy case first.
- */
- if(pdev->bus->number == pbm->pci_first_busno) {
- if(pbm == &pbm->parent->pbm_A)
- slot = (pdev->devfn >> 3) - 1;
- else
- slot = (pdev->devfn >> 3) - 2;
- } else {
- /* Underneath a bridge, use slot number of parent
- * bridge.
- */
- if(pbm == &pbm->parent->pbm_A)
- slot = (pdev->bus->self->devfn >> 3) - 1;
- else
- slot = (pdev->bus->self->devfn >> 3) - 2;
-
- /* Use low slot number bits of child as IRQ line. */
- line = (pdev->devfn >> 3) & 0x03;
- }
- slot = (slot << 2);
-
- pdev->irq = psycho_irq_build(pbm, pdev,
- (((portid << 6) & PSYCHO_IMAP_IGN)
- | (bus | slot | line)));
-
-#ifdef FIXUP_IRQ_DEBUG
- do {
- unsigned char iline, ipin;
-
- pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &ipin);
- pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &iline);
- dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] "
- "irq[%x] iline[%x] ipin[%x] prom_irq[%x]",
- portid, bus>>4, slot>>2, line, pdev->irq,
- iline, ipin, prom_irq);
- } while(0);
-#endif
- }
-
- /*
- * Write the INO to config space PCI_INTERRUPT_LINE.
- */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- pdev->irq & PCI_IRQ_INO);
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("\n");
-#endif
-}
-
-static void __init fixup_doit(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- int node)
-{
- struct linux_prom_pci_registers assigned[PROMREG_MAX];
- int numaa, err;
-
- /* Get assigned addresses, if any. */
- err = prom_getproperty(node, "assigned-addresses",
- (char *)&assigned[0], sizeof(assigned));
- if(err == 0 || err == -1)
- numaa = 0;
- else
- numaa = (err / sizeof(struct linux_prom_pci_registers));
-
- /* First, scan and fixup base registers. */
- fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa);
-
- /* Next, fixup interrupt numbers. */
- fixup_irq(pdev, pbm, &pregs[0], node);
-}
-
-static void __init fixup_pci_dev(struct pci_dev *pdev,
- struct pci_bus *pbus,
- struct linux_pbm_info *pbm)
-{
- struct linux_prom_pci_registers pregs[PROMREG_MAX];
- struct pcidev_cookie *pcp = pdev->sysdata;
- int node, nregs, err;
-
- /* If this is a PCI bridge, we must program it. */
- if(pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
- unsigned short cmd;
-
- /* First, enable bus mastering. */
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
- /* Now, set cache line size to 64-bytes.
- * NOTE: Cache line size is in 32-bit word units.
- */
- pci_write_config_byte(pdev,
- PCI_CACHE_LINE_SIZE,
- (64 / sizeof(u32)));
- }
-
- /* Ignore if this is one of the PBM's, EBUS, or a
- * sub-bridge underneath the PBM. We only need to fixup
- * true devices.
- */
- if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) ||
- (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) ||
- (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
- (pcp == NULL)) {
- /*
- * Prevent access to PCI_ROM_ADDRESS, in case present
- * as we don't fixup the address.
- */
- if (pdev->rom_address) {
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0);
- pdev->rom_address = 0;
- }
- return;
- }
-
- node = pcp->prom_node;
-
- err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
- if(err == 0 || err == -1) {
- prom_printf("Cannot find REG for pci_dev\n");
- prom_halt();
- }
-
- nregs = (err / sizeof(pregs[0]));
-
- fixup_doit(pdev, pbm, &pregs[0], nregs, node);
-
- /* Enable bus mastering on IDE interfaces. */
- if ((pdev->class >> 8 == PCI_CLASS_STORAGE_IDE)
- && (pdev->class & 0x80)) {
- unsigned short cmd;
-
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- }
-}
-
-static void __init fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
-{
- struct pci_dev *pdev;
-
- for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- fixup_pci_dev(pdev, pbus, pbm);
-
- for(pbus = pbus->children; pbus; pbus = pbus->next)
- fixup_pci_bus(pbus, pbm);
-}
-
-static void __init fixup_addr_irq(struct linux_pbm_info *pbm)
-{
- struct pci_bus *pbus = &pbm->pci_bus;
-
- /* Work through top level devices (not bridges, those and their
- * devices are handled specially in the next loop).
- */
- fixup_pci_bus(pbus, pbm);
-}
-
-/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
- * We use OBP for most of this work.
- */
-static void __init psycho_final_fixup(struct linux_psycho *psycho)
-{
- /* Second, fixup base address registers and IRQ lines... */
- if (psycho->pbm_A.parent)
- fixup_addr_irq(&psycho->pbm_A);
- if (psycho->pbm_B.parent)
- fixup_addr_irq(&psycho->pbm_B);
-}
-
-/* Reorder the pci_dev chain, so that onboard devices come first
- and then come the pluggable cards. */
-void __init psycho_reorder_devs(void)
-{
- struct pci_dev **pci_onboard = &pci_devices;
- struct pci_dev **pci_tail = &pci_devices;
- struct pci_dev *pdev = pci_devices, *pci_other = NULL;
-
- while (pdev) {
- if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) {
- if (pci_other) {
- *pci_onboard = pdev;
- pci_onboard = &pdev->next;
- pdev = pdev->next;
- *pci_onboard = pci_other;
- *pci_tail = pdev;
- continue;
- } else
- pci_onboard = &pdev->next;
- } else if (!pci_other)
- pci_other = pdev;
- pci_tail = &pdev->next;
- pdev = pdev->next;
- }
-}
-
-void __init pcibios_fixup(void)
-{
- struct linux_psycho *psycho;
-
- pci_probe_enable = 1;
-
- /* XXX Really this should be per-PSYCHO, but the config space
- * XXX reads and writes give us no way to know which PSYCHO
- * XXX in which the config space reads should occur.
- * XXX
- * XXX Further thought says that we cannot change this generic
- * XXX interface, else we'd break xfree86 and other parts of the
- * XXX kernel (but whats more important is breaking userland for
- * XXX the ix86/Alpha/etc. people). So we should define our own
- * XXX internal extension initially, we can compile our own user
- * XXX apps that need to get at PCI configuration space.
- */
-
- for (psycho = psycho_root; psycho; psycho = psycho->next) {
- /* Probe bus on builtin PCI. */
- if (apb_present(psycho)) {
- sabre_probe(psycho);
- } else {
- /* Probe busses under PBM B. */
- pbm_probe(&psycho->pbm_B);
-
- /* Probe busses under PBM A. */
- pbm_probe(&psycho->pbm_A);
- }
- }
-
- /* Walk all PCI devices found. For each device, and
- * PCI bridge which is not one of the PSYCHO PBM's, fill in the
- * sysdata with a pointer to the PBM (for pci_bus's) or
- * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
- */
- for (psycho = psycho_root; psycho; psycho = psycho->next) {
- if (apb_present(psycho))
- sabre_cookie_fillin(psycho);
-
- fill_in_pbm_cookies(&psycho->pbm_A.pci_bus,
- &psycho->pbm_A,
- psycho->pbm_A.prom_node);
- fill_in_pbm_cookies(&psycho->pbm_B.pci_bus,
- &psycho->pbm_B,
- psycho->pbm_B.prom_node);
-
- /* See what OBP has taken care of already. */
- record_assignments(&psycho->pbm_A);
- record_assignments(&psycho->pbm_B);
-
- /* Now, fix it all up. */
- psycho_final_fixup(psycho);
- }
-
- if (psycho_reorder & PSYCHO_REORDER_ONBOARDFIRST)
- psycho_reorder_devs();
-
- return ebus_init();
-}
-
-/* "PCI: The emerging standard..." 8-( */
-volatile int pci_poke_in_progress = 0;
-volatile int pci_poke_faulted = 0;
-
-/* XXX Current PCI support code is broken, it assumes one master PCI config
- * XXX space exists, on Ultra we can have many of them, especially with
- * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
- */
-static void *
-pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus,
- unsigned char devfn, unsigned char where)
-{
- unsigned long ret;
-
- if (!pbm)
- return NULL;
-
- ret = (unsigned long) pbm->parent->pci_config_space;
-
- ret |= (1 << 24);
- ret |= (bus << 16);
- ret |= (devfn << 8);
- ret |= where;
-
- return (void *)ret;
-}
-
-static inline int
-out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn)
-{
- return ((pbm->parent == 0) ||
- ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) ||
- ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) ||
- (pci_probe_enable == 0));
-}
-
-static inline int
-sabre_out_of_range(unsigned char devfn)
-{
- return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
- ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
- (PCI_SLOT(devfn) > 1) ||
- (pci_probe_enable == 0));
-}
-
-static int
-sabre_read_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value)
-{
- if (bus)
- return pbm_read_config_byte(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn)) {
- *value = 0xff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- if (where < 8) {
- unsigned short tmp;
-
- pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
- if (where & 1)
- *value = tmp >> 8;
- else
- *value = tmp & 0xff;
- return PCIBIOS_SUCCESSFUL;
- } else
- return pbm_read_config_byte(pbm, bus, devfn, where, value);
-}
-
-static int
-sabre_read_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value)
-{
- if (bus)
- return pbm_read_config_word(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn)) {
- *value = 0xffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- if (where < 8)
- return pbm_read_config_word(pbm, bus, devfn, where, value);
- else {
- unsigned char tmp;
-
- pbm_read_config_byte(pbm, bus, devfn, where, &tmp);
- *value = tmp;
- pbm_read_config_byte(pbm, bus, devfn, where + 1, &tmp);
- *value |= tmp << 8;
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-static int
-sabre_read_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value)
-{
- unsigned short tmp;
-
- if (bus)
- return pbm_read_config_dword(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn)) {
- *value = 0xffffffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- sabre_read_config_word(pbm, bus, devfn, where, &tmp);
- *value = tmp;
- sabre_read_config_word(pbm, bus, devfn, where + 2, &tmp);
- *value |= tmp << 16;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-sabre_write_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- if (bus)
- return pbm_write_config_byte(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where < 8) {
- unsigned short tmp;
-
- pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
- if (where & 1) {
- value &= 0x00ff;
- value |= tmp << 8;
- } else {
- value &= 0xff00;
- value |= tmp;
- }
- return pbm_write_config_word(pbm, bus, devfn, where & ~1, tmp);
- } else
- return pbm_write_config_byte(pbm, bus, devfn, where, value);
-}
-
-static int
-sabre_write_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- if (bus)
- return pbm_write_config_word(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where < 8)
- return pbm_write_config_word(pbm, bus, devfn, where, value);
- else {
- pbm_write_config_byte(pbm, bus, devfn, where, value & 0xff);
- pbm_write_config_byte(pbm, bus, devfn, where + 1, value >> 8);
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-static int
-sabre_write_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- if (bus)
- return pbm_write_config_dword(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- sabre_write_config_word(pbm, bus, devfn, where, value & 0xffff);
- sabre_write_config_word(pbm, bus, devfn, where + 2, value >> 16);
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_read_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value)
-{
- unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where);
- unsigned int trapped;
- unsigned char byte;
-
- *value = 0xff;
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- pci_poke_in_progress = 1;
- pci_poke_faulted = 0;
- __asm__ __volatile__("membar #Sync\n\t"
- "lduba [%1] %2, %0\n\t"
- "membar #Sync"
- : "=r" (byte)
- : "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- trapped = pci_poke_faulted;
- pci_poke_faulted = 0;
- if(!trapped)
- *value = byte;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_read_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value)
-{
- unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where);
- unsigned int trapped;
- unsigned short word;
-
- *value = 0xffff;
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where & 0x01) {
- printk("pcibios_read_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_poke_in_progress = 1;
- pci_poke_faulted = 0;
- __asm__ __volatile__("membar #Sync\n\t"
- "lduha [%1] %2, %0\n\t"
- "membar #Sync"
- : "=r" (word)
- : "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- trapped = pci_poke_faulted;
- pci_poke_faulted = 0;
- if(!trapped)
- *value = word;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_read_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value)
-{
- unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where);
- unsigned int word, trapped;
-
- *value = 0xffffffff;
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where & 0x03) {
- printk("pcibios_read_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_poke_in_progress = 1;
- pci_poke_faulted = 0;
- __asm__ __volatile__("membar #Sync\n\t"
- "lduwa [%1] %2, %0\n\t"
- "membar #Sync"
- : "=r" (word)
- : "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- trapped = pci_poke_faulted;
- pci_poke_faulted = 0;
- if(!trapped)
- *value = word;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_write_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where);
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- pci_poke_in_progress = 1;
-
- /* Endianness doesn't matter but we have to get the memory
- * barriers in there so...
- */
- __asm__ __volatile__("membar #Sync\n\t"
- "stba %0, [%1] %2\n\t"
- "membar #Sync\n\t"
- : /* no outputs */
- : "r" (value), "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_write_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where);
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where & 0x01) {
- printk("pcibios_write_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_poke_in_progress = 1;
- __asm__ __volatile__("membar #Sync\n\t"
- "stha %0, [%1] %2\n\t"
- "membar #Sync\n\t"
- : /* no outputs */
- : "r" (value), "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_write_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where);
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where & 0x03) {
- printk("pcibios_write_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_poke_in_progress = 1;
- __asm__ __volatile__("membar #Sync\n\t"
- "stwa %0, [%1] %2\n\t"
- "membar #Sync"
- : /* no outputs */
- : "r" (value), "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- return PCIBIOS_SUCCESSFUL;
-}
-
-int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_read_config_byte(pbm, bus, devfn, where, value);
- return pbm_read_config_byte(pbm, bus, devfn, where, value);
-}
-
-int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_read_config_word(pbm, bus, devfn, where, value);
- return pbm_read_config_word(pbm, bus, devfn, where, value);
-}
-
-int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_read_config_dword(pbm, bus, devfn, where, value);
- return pbm_read_config_dword(pbm, bus, devfn, where, value);
-}
-
-int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_write_config_byte(pbm, bus, devfn, where, value);
- return pbm_write_config_byte(pbm, bus, devfn, where, value);
-}
-
-int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_write_config_word(pbm, bus, devfn, where, value);
- return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value);
-}
-
-int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_write_config_dword(pbm, bus, devfn, where, value);
- return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value);
-}
-
-asmlinkage int sys_pciconfig_read(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- unsigned char ubyte;
- unsigned short ushort;
- unsigned int uint;
- int err = 0;
-
- if(!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- lock_kernel();
- switch(len) {
- case 1:
- pcibios_read_config_byte(bus, dfn, off, &ubyte);
- put_user(ubyte, (unsigned char *)buf);
- break;
- case 2:
- pcibios_read_config_word(bus, dfn, off, &ushort);
- put_user(ushort, (unsigned short *)buf);
- break;
- case 4:
- pcibios_read_config_dword(bus, dfn, off, &uint);
- put_user(uint, (unsigned int *)buf);
- break;
-
- default:
- err = -EINVAL;
- break;
- };
- unlock_kernel();
-
- return err;
-}
-
-asmlinkage int sys_pciconfig_write(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- unsigned char ubyte;
- unsigned short ushort;
- unsigned int uint;
- int err = 0;
-
- if(!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- lock_kernel();
- switch(len) {
- case 1:
- err = get_user(ubyte, (unsigned char *)buf);
- if(err)
- break;
- pcibios_write_config_byte(bus, dfn, off, ubyte);
- break;
-
- case 2:
- err = get_user(ushort, (unsigned short *)buf);
- if(err)
- break;
- pcibios_write_config_byte(bus, dfn, off, ushort);
- break;
-
- case 4:
- err = get_user(uint, (unsigned int *)buf);
- if(err)
- break;
- pcibios_write_config_byte(bus, dfn, off, uint);
- break;
-
- default:
- err = -EINVAL;
- break;
-
- };
- unlock_kernel();
-
- return err;
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
-
-char * __init pcibios_setup(char *str)
-{
- if (!strcmp(str, "onboardfirst")) {
- psycho_reorder |= PSYCHO_REORDER_ONBOARDFIRST;
- return NULL;
- }
- if (!strcmp(str, "noreorder")) {
- psycho_reorder = 0;
- return NULL;
- }
- return str;
-}
-
-#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)