/* Wait until GRPCI2 signals that CFG access is done, it should be * done instantaneously unless a DMA operation is ongoing...
*/ while ((REGLOAD(priv->regs->sts_cap) & STS_CFGERRVALID) == 0)
;
if (REGLOAD(priv->regs->sts_cap) & STS_CFGERR) {
*val = 0xffffffff;
} else { /* Bus always little endian (unaffected by byte-swapping) */
*val = swab32(tmp);
}
return 0;
}
staticint grpci2_cfg_r16(struct grpci2_priv *priv, unsignedint bus, unsignedint devfn, int where, u32 *val)
{
u32 v; int ret;
if (where & 0x1) return -EINVAL;
ret = grpci2_cfg_r32(priv, bus, devfn, where & ~0x3, &v);
*val = 0xffff & (v >> (8 * (where & 0x3))); return ret;
}
staticint grpci2_cfg_r8(struct grpci2_priv *priv, unsignedint bus, unsignedint devfn, int where, u32 *val)
{
u32 v; int ret;
ret = grpci2_cfg_r32(priv, bus, devfn, where & ~0x3, &v);
*val = 0xff & (v >> (8 * (where & 3)));
/* Wait until GRPCI2 signals that CFG access is done, it should be * done instantaneously unless a DMA operation is ongoing...
*/ while ((REGLOAD(priv->regs->sts_cap) & STS_CFGERRVALID) == 0)
;
return 0;
}
staticint grpci2_cfg_w16(struct grpci2_priv *priv, unsignedint bus, unsignedint devfn, int where, u32 val)
{ int ret;
u32 v;
if (where & 0x1) return -EINVAL;
ret = grpci2_cfg_r32(priv, bus, devfn, where&~3, &v); if (ret) return ret;
v = (v & ~(0xffff << (8 * (where & 0x3)))) |
((0xffff & val) << (8 * (where & 0x3))); return grpci2_cfg_w32(priv, bus, devfn, where & ~0x3, v);
}
staticint grpci2_cfg_w8(struct grpci2_priv *priv, unsignedint bus, unsignedint devfn, int where, u32 val)
{ int ret;
u32 v;
ret = grpci2_cfg_r32(priv, bus, devfn, where & ~0x3, &v); if (ret != 0) return ret;
v = (v & ~(0xff << (8 * (where & 0x3)))) |
((0xff & val) << (8 * (where & 0x3))); return grpci2_cfg_w32(priv, bus, devfn, where & ~0x3, v);
}
/* Read from Configuration Space. When entering here the PCI layer has taken * the pci_lock spinlock and IRQ is off.
*/ staticint grpci2_read_config(struct pci_bus *bus, unsignedint devfn, int where, int size, u32 *val)
{ struct grpci2_priv *priv = grpci2priv; unsignedint busno = bus->number; int ret;
/* Write to Configuration Space. When entering here the PCI layer has taken * the pci_lock spinlock and IRQ is off.
*/ staticint grpci2_write_config(struct pci_bus *bus, unsignedint devfn, int where, int size, u32 val)
{ struct grpci2_priv *priv = grpci2priv; unsignedint busno = bus->number;
if (PCI_SLOT(devfn) > 15 || busno > 255) return 0;
/* GENIRQ IRQ chip implementation for GRPCI2 irqmode=0..2. In configuration * 3 where all PCI Interrupts has a separate IRQ on the system IRQ controller * this is not needed and the standard IRQ controller can be used.
*/
/* Handle one or multiple IRQs from the PCI core */ staticvoid grpci2_pci_flow_irq(struct irq_desc *desc)
{ struct grpci2_priv *priv = grpci2priv; int i, ack = 0; unsignedint ctrl, sts_cap, pci_ints;
/* PCI Interrupt? */
pci_ints = ((~sts_cap) >> STS_INTSTS_BIT) & ctrl & CTRL_HOSTINT; if (pci_ints) { /* Call respective PCI Interrupt handler */ for (i = 0; i < 4; i++) { if (pci_ints & (1 << i))
generic_handle_irq(priv->irq_map[i]);
}
ack = 1;
}
/* * Decode DMA Interrupt only when shared with Err and PCI INTX#, when * the DMA is a unique IRQ the DMA interrupts doesn't end up here, they * goes directly to DMA ISR.
*/ if ((priv->irq_mode == 0) && (sts_cap & (STS_IDMA | STS_IDMAERR))) {
generic_handle_irq(priv->virq_dma);
ack = 1;
}
/* * Call "first level" IRQ chip end-of-irq handler. It will ACK LEON IRQ * Controller, this must be done after IRQ sources have been handled to * avoid double IRQ generation
*/ if (ack)
desc->irq_data.chip->irq_eoi(&desc->irq_data);
}
/* Reset any earlier setup */ if (priv->do_reset) {
printk(KERN_INFO "GRPCI2: Resetting PCI bus\n");
REGSTORE(regs->ctrl, CTRL_RESET);
ssleep(1); /* Wait for boards to settle */
}
REGSTORE(regs->ctrl, 0);
REGSTORE(regs->sts_cap, ~0); /* Clear Status */
REGSTORE(regs->dma_ctrl, 0);
REGSTORE(regs->dma_bdbase, 0);
/* Translate I/O accesses to 0, I/O Space always @ PCI low 64Kbytes */
REGSTORE(regs->io_map, REGLOAD(regs->io_map) & 0x0000ffff);
/* set 1:1 mapping between AHB -> PCI memory space, for all Masters * Each AHB master has its own mapping registers. Max 16 AHB masters.
*/ for (i = 0; i < 16; i++)
REGSTORE(regs->ahbmst_map[i], priv->pci_area);
/* Get the GRPCI2 Host PCI ID */
grpci2_cfg_r32(priv, TGT, 0, PCI_VENDOR_ID, &priv->pciid);
/* Get address to first (always defined) capability structure */
grpci2_cfg_r8(priv, TGT, 0, PCI_CAPABILITY_LIST, &capptr);
/* Setup the Host's PCI Target BARs for other peripherals to access, * and do DMA to the host's memory. The target BARs can be sized and * enabled individually. * * User may set custom target BARs, but default is: * The first BARs is used to map kernel low (DMA is part of normal * region on sparc which is SRMMU_MAXMEM big) main memory 1:1 to the * PCI bus, the other BARs are disabled. We assume that the first BAR * is always available.
*/ for (i = 0; i < 6; i++) { if (barcfg[i].pciadr != ~0 && barcfg[i].ahbadr != ~0) { /* Target BARs must have the proper alignment */
ahbadr = barcfg[i].ahbadr;
pciadr = barcfg[i].pciadr;
bar_sz = ((pciadr - 1) & ~pciadr) + 1;
} else { if (i == 0) { /* Map main memory */
bar_sz = 0xf0000008; /* 256MB prefetchable */
ahbadr = 0xf0000000 & (u32)__pa(PAGE_ALIGN(
(unsignedlong) &_end));
pciadr = ahbadr;
} else {
bar_sz = 0;
ahbadr = 0;
pciadr = 0;
}
}
grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_BARSIZE_OFS+i*4,
bar_sz);
grpci2_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0+i*4, pciadr);
grpci2_cfg_w32(priv, TGT, 0, capptr+CAP9_BAR_OFS+i*4, ahbadr);
printk(KERN_INFO " TGT BAR[%d]: 0x%08x (PCI)-> 0x%08x\n",
i, pciadr, ahbadr);
}
/* set as bus master and enable pci memory responses */
grpci2_cfg_r32(priv, TGT, 0, PCI_COMMAND, &data);
data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
grpci2_cfg_w32(priv, TGT, 0, PCI_COMMAND, data);
/* * Check that we're in Host Slot and that we can act as a Host Bridge * and not only as target.
*/
capability = REGLOAD(regs->sts_cap); if ((capability & STS_HOST) || !(capability & STS_MST)) {
printk(KERN_INFO "GRPCI2: not in host system slot\n");
err = -EIO; goto err1;
}
printk(KERN_INFO "GRPCI2: MEMORY SPACE [0x%08lx - 0x%08lx]\n" " I/O SPACE [0x%08lx - 0x%08lx]\n" " CONFIG SPACE [0x%08lx - 0x%08lx]\n",
priv->pci_area, priv->pci_area_end-1,
priv->pci_io, priv->pci_conf-1,
priv->pci_conf, priv->pci_conf_end-1);
/* * I/O Space resources in I/O Window mapped into Virtual Adr Space * We never use low 4KB because some devices seem have problems using * address 0.
*/
memset(&priv->info.io_space, 0, sizeof(struct resource));
priv->info.io_space.name = "GRPCI2 PCI I/O Space";
priv->info.io_space.start = priv->pci_io_va + 0x1000;
priv->info.io_space.end = priv->pci_io_va + 0x10000 - 1;
priv->info.io_space.flags = IORESOURCE_IO;
/* * GRPCI2 has no prefetchable memory, map everything as * non-prefetchable memory
*/
memset(&priv->info.mem_space, 0, sizeof(struct resource));
priv->info.mem_space.name = "GRPCI2 PCI MEM Space";
priv->info.mem_space.start = priv->pci_area;
priv->info.mem_space.end = priv->pci_area_end - 1;
priv->info.mem_space.flags = IORESOURCE_MEM;
if (request_resource(&iomem_resource, &priv->info.mem_space) < 0) goto err3; if (request_resource(&ioport_resource, &priv->info.io_space) < 0) goto err4;
/* * Get PCI Interrupt to System IRQ mapping and setup IRQ handling * Error IRQ always on PCI INTA.
*/ if (priv->irq_mode < 2) { /* All PCI interrupts are shared using the same system IRQ */
leon_update_virq_handling(priv->irq, grpci2_pci_flow_irq, "pcilvl", 0);
/* * Enable Error Interrupts. PCI interrupts are unmasked once request_irq * is called by the PCI Device drivers
*/
REGSTORE(regs->ctrl, REGLOAD(regs->ctrl) | CTRL_EI | CTRL_SI);
/* Init common layer and scan buses */
priv->info.ops = &grpci2_ops;
priv->info.map_irq = grpci2_map_irq;
leon_pci_init(ofdev, &priv->info);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.