patch-2.1.115 linux/arch/sparc64/kernel/psycho.c
Next file: linux/arch/sparc64/kernel/ptrace.c
Previous file: linux/arch/sparc64/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 324
- Date:
Tue Aug 4 16:03:35 1998
- Orig file:
v2.1.114/linux/arch/sparc64/kernel/psycho.c
- Orig date:
Tue Jul 21 00:15:30 1998
diff -u --recursive --new-file v2.1.114/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.54 1998/05/01 19:16:32 ecd Exp $
+/* $Id: psycho.c,v 1.63 1998/08/02 05:55:42 ecd Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -14,6 +14,8 @@
#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
@@ -27,8 +29,13 @@
#define dprintf printk
#endif
+
unsigned long pci_dvma_offset = 0x00000000UL;
-unsigned long pci_dvma_mask = 0xffffffffUL;
+unsigned long pci_dvma_mask = 0xffffffffUL;
+
+unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
+unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
+
#ifndef CONFIG_PCI
@@ -97,10 +104,20 @@
*/
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;
+}
+
__initfunc(static void psycho_iommu_init(struct linux_psycho *psycho, int tsbsize))
{
+ struct linux_mlist_p1275 *mlist;
unsigned long tsbbase;
- unsigned long control, i;
+ unsigned long control, i, n;
unsigned long *iopte;
unsigned long order;
@@ -122,12 +139,36 @@
}
tsbbase = __get_free_pages(GFP_DMA, order);
iopte = (unsigned long *)tsbbase;
- for(i = 0; i < (tsbsize * 1024); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K |
- IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= (i << 16);
- iopte++;
+
+ memset(pci_dvma_v2p_hash, 0, sizeof(pci_dvma_v2p_hash));
+ memset(pci_dvma_p2v_hash, 0, sizeof(pci_dvma_p2v_hash));
+
+ n = 0;
+ mlist = *prom_meminfo()->p1275_totphys;
+ while (mlist) {
+ unsigned long paddr = mlist->start_adr;
+
+ for (i = 0; i < (mlist->num_bytes >> 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++;
+ }
+
+ mlist = mlist->theres_more;
}
+out:
+ if (mlist)
+ printk("WARNING: not all physical memory mapped in IOMMU\n");
psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
@@ -136,15 +177,15 @@
control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
switch(tsbsize) {
case 8:
- pci_dvma_mask = 0x1fffffffUL;
+ pci_dvma_mask = 0x1fffffffUL;
control |= IOMMU_TSBSZ_8K;
break;
case 16:
- pci_dvma_mask = 0x3fffffffUL;
+ pci_dvma_mask = 0x3fffffffUL;
control |= IOMMU_TSBSZ_16K;
break;
case 32:
- pci_dvma_mask = 0x7fffffffUL;
+ pci_dvma_mask = 0x7fffffffUL;
control |= IOMMU_TSBSZ_32K;
break;
default:
@@ -258,8 +299,8 @@
prom_halt();
}
- psycho_iommu_init(sabre, tsbsize);
pci_dvma_offset = vdma[0];
+ psycho_iommu_init(sabre, tsbsize);
printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
#ifdef PROM_DEBUG
@@ -448,8 +489,8 @@
psycho->pci_config_space);
#endif
- psycho_iommu_init(psycho, 32);
pci_dvma_offset = 0x80000000UL;
+ psycho_iommu_init(psycho, 32);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
@@ -777,22 +818,15 @@
__initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
struct pci_dev *pdev,
- int node))
+ int pnode))
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ int node;
int err;
- while(node) {
- int child;
+ node = prom_getchild(pnode);
+ while (node) {
- child = prom_getchild(node);
- if(child != 0 && child != -1) {
- int res;
-
- res = pdev_to_pnode_sibtraverse(pbm, pdev, child);
- if(res != 0 && res != -1)
- return res;
- }
err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
if(err != 0 && err != -1) {
u32 devfn = (pregs[0].phys_hi >> 8) & 0xff;
@@ -806,12 +840,13 @@
return 0;
}
-__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev))
+__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev, int pnode))
{
struct pcidev_cookie *pcp;
- int node = prom_getchild(pbm->prom_node);
+ int node;
- node = pdev_to_pnode_sibtraverse(pbm, pdev, node);
+ node = pdev_to_pnode_sibtraverse(pbm, pdev, pnode);
if(node == 0)
node = -1;
pcp = pci_devcookie_alloc();
@@ -825,7 +860,8 @@
}
__initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus,
- struct linux_pbm_info *pbm))
+ struct linux_pbm_info *pbm,
+ int node))
{
struct pci_dev *pdev;
@@ -837,10 +873,12 @@
#endif
for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_cookie_fillin(pbm, pdev);
+ pdev_cookie_fillin(pbm, pdev, node);
- for(pbus = pbus->children; pbus; pbus = pbus->next)
- fill_in_pbm_cookies(pbus, pbm);
+ for(pbus = pbus->children; pbus; pbus = pbus->next) {
+ struct pcidev_cookie *pcp = pbus->self->sysdata;
+ fill_in_pbm_cookies(pbus, pbm, pcp->prom_node);
+ }
}
__initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
@@ -849,9 +887,11 @@
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);
+ 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);
+ pdev_cookie_fillin(&sabre->pbm_B, pbus->self,
+ sabre->pbm_B.prom_node);
}
}
@@ -1431,13 +1471,12 @@
/* Exported for EBUS probing layer. */
__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
struct pci_dev *pdev,
- unsigned int full_ino))
+ unsigned int ino))
{
- unsigned long imap_off, ign, ino;
+ unsigned long imap_off;
int need_dma_sync = 0;
- ign = (full_ino & PSYCHO_IMAP_IGN) >> 6;
- ino = (full_ino & PSYCHO_IMAP_INO);
+ 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
@@ -1513,10 +1552,7 @@
break;
default:
- /* We don't expect anything else. The other possible
- * values are not found in PCI device nodes, and are
- * so hardware specific that they should use DCOOKIE's
- * anyways.
+ /* We don't expect anything else.
*/
prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
prom_halt();
@@ -1528,7 +1564,7 @@
need_dma_sync = 1;
}
- return pci_irq_encode(imap_off, pbm->parent->index, ign, ino, need_dma_sync);
+ return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync);
}
__initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm,
@@ -1559,6 +1595,9 @@
if(i == 0 || i == -1)
goto out;
+ /* Use low slot number bits of child as IRQ line. */
+ *interrupt = ((pdev->devfn >> 3) & 3) + 1;
+
preg = &ppreg;
}
@@ -1566,20 +1605,29 @@
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 *interrupt;
+ return 1;
}
}
out:
- prom_printf("pbm_intmap_match: IRQ [%08x.%08x.%08x.%08x] "
- "not found in interrupt-map\n", preg->phys_hi,
- preg->phys_mid, preg->phys_lo, *interrupt);
+ 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();
}
@@ -1610,8 +1658,8 @@
(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);
+ dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
#endif
/* See if fully specified already (ie. for onboard devices like hme) */
} else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
@@ -1847,9 +1895,11 @@
sabre_cookie_fillin(psycho);
fill_in_pbm_cookies(&psycho->pbm_A.pci_bus,
- &psycho->pbm_A);
+ &psycho->pbm_A,
+ psycho->pbm_A.prom_node);
fill_in_pbm_cookies(&psycho->pbm_B.pci_bus,
- &psycho->pbm_B);
+ &psycho->pbm_B,
+ psycho->pbm_B.prom_node);
/* See what OBP has taken care of already. */
record_assignments(&psycho->pbm_A);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov