diff options
Diffstat (limited to 'arch/ppc/syslib/m8260_pci_erratum9.c')
-rw-r--r-- | arch/ppc/syslib/m8260_pci_erratum9.c | 455 |
1 files changed, 0 insertions, 455 deletions
diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c deleted file mode 100644 index ebb8c8f8f30c..000000000000 --- a/arch/ppc/syslib/m8260_pci_erratum9.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Workaround for device erratum PCI 9. - * See Motorola's "XPC826xA Family Device Errata Reference." - * The erratum applies to all 8260 family Hip4 processors. It is scheduled - * to be fixed in HiP4 Rev C. Erratum PCI 9 states that a simultaneous PCI - * inbound write transaction and PCI outbound read transaction can result in a - * bus deadlock. The suggested workaround is to use the IDMA controller to - * perform all reads from PCI configuration, memory, and I/O space. - * - * Author: andy_lowe@mvista.com - * - * 2003 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/types.h> -#include <linux/string.h> - -#include <asm/io.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/byteorder.h> -#include <asm/mpc8260.h> -#include <asm/immap_cpm2.h> -#include <asm/cpm2.h> - -#include "m82xx_pci.h" - -#ifdef CONFIG_8260_PCI9 -/*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */ - -#define IDMA_XFER_BUF_SIZE 64 /* size of the IDMA transfer buffer */ - -/* define a structure for the IDMA dpram usage */ -typedef struct idma_dpram_s { - idma_t pram; /* IDMA parameter RAM */ - u_char xfer_buf[IDMA_XFER_BUF_SIZE]; /* IDMA transfer buffer */ - idma_bd_t bd; /* buffer descriptor */ -} idma_dpram_t; - -/* define offsets relative to start of IDMA dpram */ -#define IDMA_XFER_BUF_OFFSET (sizeof(idma_t)) -#define IDMA_BD_OFFSET (sizeof(idma_t) + IDMA_XFER_BUF_SIZE) - -/* define globals */ -static volatile idma_dpram_t *idma_dpram; - -/* Exactly one of CONFIG_8260_PCI9_IDMAn must be defined, - * where n is 1, 2, 3, or 4. This selects the IDMA channel used for - * the PCI9 workaround. - */ -#ifdef CONFIG_8260_PCI9_IDMA1 -#define IDMA_CHAN 0 -#define PROFF_IDMA PROFF_IDMA1_BASE -#define IDMA_PAGE CPM_CR_IDMA1_PAGE -#define IDMA_SBLOCK CPM_CR_IDMA1_SBLOCK -#endif -#ifdef CONFIG_8260_PCI9_IDMA2 -#define IDMA_CHAN 1 -#define PROFF_IDMA PROFF_IDMA2_BASE -#define IDMA_PAGE CPM_CR_IDMA2_PAGE -#define IDMA_SBLOCK CPM_CR_IDMA2_SBLOCK -#endif -#ifdef CONFIG_8260_PCI9_IDMA3 -#define IDMA_CHAN 2 -#define PROFF_IDMA PROFF_IDMA3_BASE -#define IDMA_PAGE CPM_CR_IDMA3_PAGE -#define IDMA_SBLOCK CPM_CR_IDMA3_SBLOCK -#endif -#ifdef CONFIG_8260_PCI9_IDMA4 -#define IDMA_CHAN 3 -#define PROFF_IDMA PROFF_IDMA4_BASE -#define IDMA_PAGE CPM_CR_IDMA4_PAGE -#define IDMA_SBLOCK CPM_CR_IDMA4_SBLOCK -#endif - -void idma_pci9_init(void) -{ - uint dpram_offset; - volatile idma_t *pram; - volatile im_idma_t *idma_reg; - volatile cpm2_map_t *immap = cpm2_immr; - - /* allocate IDMA dpram */ - dpram_offset = cpm_dpalloc(sizeof(idma_dpram_t), 64); - idma_dpram = cpm_dpram_addr(dpram_offset); - - /* initialize the IDMA parameter RAM */ - memset((void *)idma_dpram, 0, sizeof(idma_dpram_t)); - pram = &idma_dpram->pram; - pram->ibase = dpram_offset + IDMA_BD_OFFSET; - pram->dpr_buf = dpram_offset + IDMA_XFER_BUF_OFFSET; - pram->ss_max = 32; - pram->dts = 32; - - /* initialize the IDMA_BASE pointer to the IDMA parameter RAM */ - *((ushort *) &immap->im_dprambase[PROFF_IDMA]) = dpram_offset; - - /* initialize the IDMA registers */ - idma_reg = (volatile im_idma_t *) &immap->im_sdma.sdma_idsr1; - idma_reg[IDMA_CHAN].idmr = 0; /* mask all IDMA interrupts */ - idma_reg[IDMA_CHAN].idsr = 0xff; /* clear all event flags */ - - printk(KERN_WARNING - "Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n", - IDMA_CHAN + 1); - - return; -} - -/* Use the IDMA controller to transfer data from I/O memory to local RAM. - * The src address must be a physical address suitable for use by the DMA - * controller with no translation. The dst address must be a kernel virtual - * address. The dst address is translated to a physical address via - * virt_to_phys(). - * The sinc argument specifies whether or not the source address is incremented - * by the DMA controller. The source address is incremented if and only if sinc - * is non-zero. The destination address is always incremented since the - * destination is always host RAM. - */ -static void -idma_pci9_read(u8 *dst, u8 *src, int bytes, int unit_size, int sinc) -{ - unsigned long flags; - volatile idma_t *pram = &idma_dpram->pram; - volatile idma_bd_t *bd = &idma_dpram->bd; - volatile cpm2_map_t *immap = cpm2_immr; - - local_irq_save(flags); - - /* initialize IDMA parameter RAM for this transfer */ - if (sinc) - pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC - | IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM; - else - pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_DINC - | IDMA_DCM_SD_MEM2MEM; - pram->ibdptr = pram->ibase; - pram->sts = unit_size; - pram->istate = 0; - - /* initialize the buffer descriptor */ - bd->dst = virt_to_phys(dst); - bd->src = (uint) src; - bd->len = bytes; - bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL - | IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB; - - /* issue the START_IDMA command to the CP */ - while (immap->im_cpm.cp_cpcr & CPM_CR_FLG); - immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0, - CPM_CR_START_IDMA) | CPM_CR_FLG; - while (immap->im_cpm.cp_cpcr & CPM_CR_FLG); - - /* wait for transfer to complete */ - while(bd->flags & IDMA_BD_V); - - local_irq_restore(flags); - - return; -} - -/* Use the IDMA controller to transfer data from I/O memory to local RAM. - * The dst address must be a physical address suitable for use by the DMA - * controller with no translation. The src address must be a kernel virtual - * address. The src address is translated to a physical address via - * virt_to_phys(). - * The dinc argument specifies whether or not the dest address is incremented - * by the DMA controller. The source address is incremented if and only if sinc - * is non-zero. The source address is always incremented since the - * source is always host RAM. - */ -static void -idma_pci9_write(u8 *dst, u8 *src, int bytes, int unit_size, int dinc) -{ - unsigned long flags; - volatile idma_t *pram = &idma_dpram->pram; - volatile idma_bd_t *bd = &idma_dpram->bd; - volatile cpm2_map_t *immap = cpm2_immr; - - local_irq_save(flags); - - /* initialize IDMA parameter RAM for this transfer */ - if (dinc) - pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC - | IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM; - else - pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC - | IDMA_DCM_SD_MEM2MEM; - pram->ibdptr = pram->ibase; - pram->sts = unit_size; - pram->istate = 0; - - /* initialize the buffer descriptor */ - bd->dst = (uint) dst; - bd->src = virt_to_phys(src); - bd->len = bytes; - bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL - | IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB; - - /* issue the START_IDMA command to the CP */ - while (immap->im_cpm.cp_cpcr & CPM_CR_FLG); - immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0, - CPM_CR_START_IDMA) | CPM_CR_FLG; - while (immap->im_cpm.cp_cpcr & CPM_CR_FLG); - - /* wait for transfer to complete */ - while(bd->flags & IDMA_BD_V); - - local_irq_restore(flags); - - return; -} - -/* Same as idma_pci9_read, but 16-bit little-endian byte swapping is performed - * if the unit_size is 2, and 32-bit little-endian byte swapping is performed if - * the unit_size is 4. - */ -static void -idma_pci9_read_le(u8 *dst, u8 *src, int bytes, int unit_size, int sinc) -{ - int i; - u8 *p; - - idma_pci9_read(dst, src, bytes, unit_size, sinc); - switch(unit_size) { - case 2: - for (i = 0, p = dst; i < bytes; i += 2, p += 2) - swab16s((u16 *) p); - break; - case 4: - for (i = 0, p = dst; i < bytes; i += 4, p += 4) - swab32s((u32 *) p); - break; - default: - break; - } -} -EXPORT_SYMBOL(idma_pci9_init); -EXPORT_SYMBOL(idma_pci9_read); -EXPORT_SYMBOL(idma_pci9_read_le); - -static inline int is_pci_mem(unsigned long addr) -{ - if (addr >= M82xx_PCI_LOWER_MMIO && - addr <= M82xx_PCI_UPPER_MMIO) - return 1; - if (addr >= M82xx_PCI_LOWER_MEM && - addr <= M82xx_PCI_UPPER_MEM) - return 1; - return 0; -} - -#define is_pci_mem(pa) ( (pa > 0x80000000) && (pa < 0xc0000000)) -int readb(volatile unsigned char *addr) -{ - u8 val; - unsigned long pa = iopa((unsigned long) addr); - - if (!is_pci_mem(pa)) - return in_8(addr); - - idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0); - return val; -} - -int readw(volatile unsigned short *addr) -{ - u16 val; - unsigned long pa = iopa((unsigned long) addr); - - if (!is_pci_mem(pa)) - return in_le16(addr); - - idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0); - return swab16(val); -} - -unsigned readl(volatile unsigned *addr) -{ - u32 val; - unsigned long pa = iopa((unsigned long) addr); - - if (!is_pci_mem(pa)) - return in_le32(addr); - - idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0); - return swab32(val); -} - -int inb(unsigned port) -{ - u8 val; - u8 *addr = (u8 *)(port + _IO_BASE); - - idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0); - return val; -} - -int inw(unsigned port) -{ - u16 val; - u8 *addr = (u8 *)(port + _IO_BASE); - - idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0); - return swab16(val); -} - -unsigned inl(unsigned port) -{ - u32 val; - u8 *addr = (u8 *)(port + _IO_BASE); - - idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0); - return swab32(val); -} - -void insb(unsigned port, void *buf, int ns) -{ - u8 *addr = (u8 *)(port + _IO_BASE); - - idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u8), sizeof(u8), 0); -} - -void insw(unsigned port, void *buf, int ns) -{ - u8 *addr = (u8 *)(port + _IO_BASE); - - idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0); -} - -void insl(unsigned port, void *buf, int nl) -{ - u8 *addr = (u8 *)(port + _IO_BASE); - - idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0); -} - -void *memcpy_fromio(void *dest, unsigned long src, size_t count) -{ - unsigned long pa = iopa((unsigned long) src); - - if (is_pci_mem(pa)) - idma_pci9_read((u8 *)dest, (u8 *)pa, count, 32, 1); - else - memcpy(dest, (void *)src, count); - return dest; -} - -EXPORT_SYMBOL(readb); -EXPORT_SYMBOL(readw); -EXPORT_SYMBOL(readl); -EXPORT_SYMBOL(inb); -EXPORT_SYMBOL(inw); -EXPORT_SYMBOL(inl); -EXPORT_SYMBOL(insb); -EXPORT_SYMBOL(insw); -EXPORT_SYMBOL(insl); -EXPORT_SYMBOL(memcpy_fromio); - -#endif /* ifdef CONFIG_8260_PCI9 */ - -/* Indirect PCI routines adapted from arch/ppc/kernel/indirect_pci.c. - * Copyright (C) 1998 Gabriel Paubert. - */ -#ifndef CONFIG_8260_PCI9 -#define cfg_read(val, addr, type, op) *val = op((type)(addr)) -#else -#define cfg_read(val, addr, type, op) \ - idma_pci9_read_le((u8*)(val),(u8*)(addr),sizeof(*(val)),sizeof(*(val)),0) -#endif - -#define cfg_write(val, addr, type, op) op((type *)(addr), (val)) - -static int indirect_write_config(struct pci_bus *pbus, unsigned int devfn, int where, - int size, u32 value) -{ - struct pci_controller *hose = pbus->sysdata; - u8 cfg_type = 0; - if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(pbus->number, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (hose->set_cfg_type) - if (pbus->number != hose->first_busno) - cfg_type = 1; - - out_be32(hose->cfg_addr, - (((where & 0xfc) | cfg_type) << 24) | (devfn << 16) - | ((pbus->number - hose->bus_offset) << 8) | 0x80); - - switch (size) - { - case 1: - cfg_write(value, hose->cfg_data + (where & 3), u8, out_8); - break; - case 2: - cfg_write(value, hose->cfg_data + (where & 2), u16, out_le16); - break; - case 4: - cfg_write(value, hose->cfg_data + (where & 0), u32, out_le32); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int indirect_read_config(struct pci_bus *pbus, unsigned int devfn, int where, - int size, u32 *value) -{ - struct pci_controller *hose = pbus->sysdata; - u8 cfg_type = 0; - if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(pbus->number, devfn)) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (hose->set_cfg_type) - if (pbus->number != hose->first_busno) - cfg_type = 1; - - out_be32(hose->cfg_addr, - (((where & 0xfc) | cfg_type) << 24) | (devfn << 16) - | ((pbus->number - hose->bus_offset) << 8) | 0x80); - - switch (size) - { - case 1: - cfg_read(value, hose->cfg_data + (where & 3), u8 *, in_8); - break; - case 2: - cfg_read(value, hose->cfg_data + (where & 2), u16 *, in_le16); - break; - case 4: - cfg_read(value, hose->cfg_data + (where & 0), u32 *, in_le32); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops indirect_pci_ops = -{ - .read = indirect_read_config, - .write = indirect_write_config, -}; - -void -setup_m8260_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) -{ - hose->ops = &indirect_pci_ops; - hose->cfg_addr = (unsigned int *) ioremap(cfg_addr, 4); - hose->cfg_data = (unsigned char *) ioremap(cfg_data, 4); -} |