8266 PCI on 2.6.x

David Woodhouse dwmw2 at infradead.org
Thu Jun 17 23:05:39 EST 2004


On Fri, 2004-06-11 at 16:27 -0500, Rune Torgersen wrote:
> I am trying to get it to work on 2.6.6 and 2.6.7rc3 (both mainstream
> and linuxppc-2.5), but the workaround for PCI errata 9 hangs on
> anything newer that 2.6.5...

The out-of-line read[bwl] functions are doing the IDMA thing even for
non-PCI addresses. I suspect that's probably what causes your problem.

My current 82xx PCI bk tree is at bk://linux-mtd.bkbits.net/new82xx-2.6

Add your board support to it if necessary, and try with this patch:

The workaround really doesn't make me happy though.

diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig	2004-06-17 14:01:00 +01:00
+++ b/arch/ppc/Kconfig	2004-06-17 14:01:00 +01:00
@@ -1026,6 +1026,29 @@
 	depends on PCI && 8260 && !8272
 	default y

+config 8260_PCI9
+	bool "  Enable workaround for MPC826x erratum PCI 9"
+	depends on PCI_8260
+	default y
+
+choice
+	prompt "  IDMA channel for PCI 9 workaround"
+	depends on 8260_PCI9
+
+config 8260_PCI9_IDMA1
+	bool "IDMA1"
+
+config 8260_PCI9_IDMA2
+	bool "IDMA2"
+
+config 8260_PCI9_IDMA3
+	bool "IDMA3"
+
+config 8260_PCI9_IDMA4
+	bool "IDMA4"
+
+endchoice
+
 config PCI_PERMEDIA
 	bool "PCI for Permedia2"
 	depends on !4xx && !8xx && APUS
diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile	2004-06-17 14:01:00 +01:00
+++ b/arch/ppc/syslib/Makefile	2004-06-17 14:01:00 +01:00
@@ -68,6 +68,7 @@
 				   todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o cpm2_pic.o
 obj-$(CONFIG_PCI_8260)		+= m8260_pci.o indirect_pci.o
+obj-$(CONFIG_8260_PCI9)		+= m8260_pci_erratum9.o
 obj-$(CONFIG_CPM2)		+= cpm2_common.o
 ifeq ($(CONFIG_PPC_GEN550),y)
 obj-$(CONFIG_KGDB)		+= gen550_kgdb.o gen550_dbg.o
diff -Nru a/arch/ppc/syslib/m8260_pci.c b/arch/ppc/syslib/m8260_pci.c
--- a/arch/ppc/syslib/m8260_pci.c	2004-06-17 14:01:00 +01:00
+++ b/arch/ppc/syslib/m8260_pci.c	2004-06-17 14:01:00 +01:00
@@ -164,9 +164,9 @@
 	hose->bus_offset = 0;
 	hose->last_busno = 0xff;

-	setup_indirect_pci(hose,
-			   (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
-			   (unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
+	setup_m8260_indirect_pci(hose,
+				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
+				 (unsigned long)&cpm2_immr->im_pci.pci_cfg_data);

 	m8260_setup_pci(hose);
         hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET;
diff -Nru a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h
--- a/arch/ppc/syslib/m8260_pci.h	2004-06-17 14:01:00 +01:00
+++ b/arch/ppc/syslib/m8260_pci.h	2004-06-17 14:01:00 +01:00
@@ -65,4 +65,11 @@
 #define _IO_BASE isa_io_base
 #endif

+#ifdef CONFIG_8260_PCI9
+extern void setup_m8260_indirect_pci(struct pci_controller* hose,
+				     u32 cfg_addr, u32 cfg_data);
+#else
+#define setup_m8260_indirect_pci setup_indirect_pci
+#endif
+
 #endif /* _PPC_KERNEL_M8260_PCI_H */
diff -Nru a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/arch/ppc/syslib/m8260_pci_erratum9.c	2004-06-17 14:01:00 +01:00
@@ -0,0 +1,474 @@
+/*
+ * arch/ppc/platforms/mpc8260_pci9.c
+ *
+ * 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 at 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/config.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 "m8260_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 = cpm2_dpalloc(sizeof(idma_dpram_t), 64);
+	idma_dpram =
+		(volatile idma_dpram_t *)&immap->im_dprambase[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("<4>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 >= MPC826x_PCI_LOWER_MMIO &&
+	    addr <= MPC826x_PCI_UPPER_MMIO)
+		return 1;
+	if (addr >= MPC826x_PCI_LOWER_MEM &&
+	    addr <= MPC826x_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 insw_ns(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_ns(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(insw_ns);
+EXPORT_SYMBOL(insl_ns);
+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);
+}
diff -Nru a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c
--- a/arch/ppc/syslib/m8260_setup.c	2004-06-17 14:01:00 +01:00
+++ b/arch/ppc/syslib/m8260_setup.c	2004-06-17 14:01:00 +01:00
@@ -54,6 +54,7 @@

 extern void cpm2_reset(void);
 extern void m8260_find_bridges(void);
+extern void idma_pci9_init(void);

 static void __init
 m8260_setup_arch(void)
@@ -61,6 +62,10 @@
 	/* Reset the Communication Processor Module.
 	*/
 	cpm2_reset();
+#ifdef CONFIG_8260_PCI9
+	/* Initialise IDMA for PCI erratum workaround */
+	idma_pci9_init();
+#endif
 #ifdef CONFIG_PCI_8260
 	m8260_find_bridges();
 #endif
diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h	2004-06-17 14:01:00 +01:00
+++ b/include/asm-ppc/io.h	2004-06-17 14:01:00 +01:00
@@ -138,18 +138,27 @@
 		: : "r" (val), "r" (port + _IO_BASE));	\
 }

-__do_in_asm(inb, "lbzx")
 __do_out_asm(outb, "stbx")
 #ifdef CONFIG_APUS
+__do_in_asm(inb, "lbzx")
 __do_in_asm(inw, "lhz%U1%X1")
 __do_in_asm(inl, "lwz%U1%X1")
 __do_out_asm(outl,"stw%U0%X0")
 __do_out_asm(outw, "sth%U0%X0")
+#elif defined (CONFIG_8260_PCI9)
+/* in asm cannot be defined if PCI9 workaround is used */
+#define inb(port)		in_8((u8 *)((port)+_IO_BASE))
+#define inw(port)		in_le16((u16 *)((port)+_IO_BASE))
+#define inl(port)		in_le32((u32 *)((port)+_IO_BASE))
+__do_out_asm(outw, "sthbrx")
+__do_out_asm(outl, "stwbrx")
 #else
+__do_in_asm(inb, "lbzx")
 __do_in_asm(inw, "lhbrx")
 __do_in_asm(inl, "lwbrx")
 __do_out_asm(outw, "sthbrx")
 __do_out_asm(outl, "stwbrx")
+
 #endif

 #define inb_p(port)		inb((port))
@@ -389,4 +398,9 @@
 }

 #endif /* _PPC_IO_H */
+
+#ifdef CONFIG_8260_PCI9
+#include <asm/mpc8260_pci9.h>
+#endif
+
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/mpc8260_pci9.h b/include/asm-ppc/mpc8260_pci9.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/asm-ppc/mpc8260_pci9.h	2004-06-17 14:01:00 +01:00
@@ -0,0 +1,51 @@
+/* include/asm-ppc/mpc8260_pci9.h
+ *
+ * Undefine the PCI read* and in* macros so we can define them as functions
+ * that implement the workaround for the MPC8260 device erratum PCI 9.
+ *
+ * This header file should only be included at the end of include/asm-ppc/io.h
+ * and never included directly anywhere else.
+ *
+ * Author:  andy_lowe at 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.
+ */
+#ifndef _PPC_IO_H
+#error "Do not include mpc8260_pci9.h directly."
+#endif
+
+#ifdef __KERNEL__
+#ifndef __CONFIG_8260_PCI9_DEFS
+#define __CONFIG_8260_PCI9_DEFS
+
+#undef readb
+#undef readw
+#undef readl
+#undef insb
+#undef insw
+#undef insl
+#undef inb
+#undef inw
+#undef inl
+#undef insw_ns
+#undef insl_ns
+#undef memcpy_fromio
+
+extern int readb(volatile unsigned char *addr);
+extern int readw(volatile unsigned short *addr);
+extern unsigned readl(volatile unsigned *addr);
+extern void insb(unsigned port, void *buf, int ns);
+extern void insw(unsigned port, void *buf, int ns);
+extern void insl(unsigned port, void *buf, int nl);
+extern int inb(unsigned port);
+extern int inw(unsigned port);
+extern unsigned inl(unsigned port);
+extern void insw_ns(unsigned port, void *buf, int ns);
+extern void insl_ns(unsigned port, void *buf, int nl);
+extern void *memcpy_fromio(void *dest, unsigned long src, size_t count);
+
+#endif /* !__CONFIG_8260_PCI9_DEFS */
+#endif /* __KERNEL__ */





 )


> Below is the function (uses IDMA to read PCI config registers)
> This function gets called when a readb, readw or readl is issued.
>
> On 2.6.6 & 7 it hangs on the line
> 	while(bd->flags & IDMA_BD_V);
>
> Problem is that this function works when the kernel is scanning the PCI
> bus, and initializing the IDE controller.
> It only hangs right before starting init.
>
> What changed between 2.6.5 and 2.6.6? I am doing diffs, and trying to
> see what changed that coud affect this, but have no clue what I'm
> looking for.
>
>
> /* 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 immap_t *immap = (immap_t *)IMAP_ADDR;
>
> 	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;
> }
>
>
>
> Linux version 2.6.6 (runet at ernie.innovsys.com) (gcc version 3.2.2
> 20030217 (Yellow Dog Linux 3.0 3.2.2-2a_1)) #7 Fri Jun 11 16:12:24
> Innovative Systems LLC AP2 port
> Using IDMA4 for MPC8260 device erratum PCI 9 workaround
> On node 0 totalpages: 65536
>   DMA zone: 65536 pages, LIFO batch:16
>   Normal zone: 0 pages, LIFO batch:1
>   HighMem zone: 0 pages, LIFO batch:1
> Built 1 zonelists
> Kernel command line: console=ttyS0,115200 root=/dev/hda3 rw
> ip=172.23.11.125:172.23.14.39:172.23.8.150:255.255.248.0:gold4_cpu1:ethe
> PID hash table entries: 2048 (order 11: 16384 bytes)
> Warning: real time clock seems stuck!
> Memory: 257280k available (1664k kernel code, 436k data, 248k init, 0k
> highmem)
> Calibrating delay loop... 192.00 BogoMIPS
> Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
> Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
> Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
> POSIX conformance testing by UNIFIX
> NET: Registered protocol family 16
> PCI: Probing PCI hardware
> Installing knfsd (copyright (C) 1996 okir at monad.swb.de).
> Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
> ide: Assuming 33MHz system bus speed for PIO modes; override with
> idebus=xx
> SiI680: IDE controller at PCI slot 0000:00:11.0
> SiI680: chipset revision 2
> SiI680: BASE CLOCK == 133
> SiI680: 100% native mode on irq 69
>     ide0: MMIO-DMA , BIOS settings: hda:pio, hdb:pio
>     ide1: MMIO-DMA , BIOS settings: hdc:pio, hdd:pio
> Probing IDE interface ide0...
> hda: Maxtor 5A250J0, ATA DISK drive
> Using anticipatory io scheduler
> ide0 at 0xd1000f80-0xd1000f87,0xd1000f8a on irq 69
> Probing IDE interface ide1...
> hda: max request size: 64KiB
> hda: 490234752 sectors (251000 MB) w/2048KiB Cache, CHS=30515/255/63,
> UDMA(133)
>  hda: hda1 hda2 hda3 hda4
> CPM UART driver version 0.02
> ttyS0 on SMC1 at 0x0000, BRG7
> ttyS1 on SCC1 at 0x0040, BRG8
> eth0: FCC ENET Version 0.3, 00:30:d7:00:01:09
> eth1: FCC ENET Version 0.3, 00:30:d7:00:01:0a
> NET: Registered protocol family 2
> IP: routing cache hash table of 2048 buckets, 16Kbytes
> TCP: Hash tables configured (established 16384 bind 32768)
> NET: Registered protocol family 1
> NET: Registered protocol family 17
> IP-Config: Complete:
>       device=eth1, addr=172.23.11.125, mask=255.255.248.0,
> gw=172.23.8.150,
>      host=gold4_cpu1, domain=, nis-domain=(none),
>      bootserver=172.23.14.39, rootserver=172.23.14.39, rootpath=
> Rune Torgersen
> System Developer
> Innovative Systems LLC
> 1000 Innovative Drive
> Mitchell, SD 57301
> Ph: 605-995-6120
> www.innovsys.com
>

--
dwmw2

** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/





More information about the Linuxppc-embedded mailing list