Cobalt fixes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Some may have been following the beginning of this thread on linux-kernel,
see for example

  http://www.opensubscriber.com/message/linux-kernel@xxxxxxxxxxxxxxx/8161812.html

for non-subscribers.  Linus has reverted the offending patch
fd6e732186ab522c812ab19c2c5e5befb8ec8115 in question so now the PCI and
I/O port code needs to be fixed up to be able to handle such a setup.

A test report of this patch which is meant to be applied on top of
today's lmo git kernel on a Cobalt would be appreciated.

  Ralf

[MIPS] Cobalt: Sort out legacy I/O port addressing.

Thanks to the brainfucked GT-64111 which passes CPU addresses in the PCI I/O
window to the PCI bus without any translation a Cobalt cannot generate
a low I/O port address that is below < 0x10000000 in the GT-64111 default
configuration.  Fortunately the VIA VT82C586 southbridge used in Cobalts
only decodes the low 16 bits of the I/O port address for its legacy devices.
This can be exploited to generate equivalent addresses but need to use
an address different from mips_io_port_base as the base to work.  In
addition PCI fixups need to be prevented from tinkering with legacy
addresses.

Signed-off-by: Ralf Baechle <ralf@xxxxxxxxxxxxxx>

diff --git a/arch/mips/cobalt/pci.c b/arch/mips/cobalt/pci.c
index cfce7af..b1fc6bd 100644
--- a/arch/mips/cobalt/pci.c
+++ b/arch/mips/cobalt/pci.c
@@ -24,8 +24,8 @@ static struct resource cobalt_mem_resource = {
 };
 
 static struct resource cobalt_io_resource = {
-	.start	= 0x1000,
-	.end	= GT_DEF_PCI0_IO_SIZE - 1,
+	.start	= GT_DEF_PCI0_IO_BASE + 0x1000,
+	.end	= GT_DEF_PCI0_IO_BASE + GT_DEF_PCI0_IO_SIZE - 1,
 	.name	= "PCI I/O",
 	.flags	= IORESOURCE_IO,
 };
@@ -34,7 +34,7 @@ static struct pci_controller cobalt_pci_controller = {
 	.pci_ops	= &gt64xxx_pci0_ops,
 	.mem_resource	= &cobalt_mem_resource,
 	.io_resource	= &cobalt_io_resource,
-	.io_offset	= 0 - GT_DEF_PCI0_IO_BASE,
+	.io_offset	= 0,
 	.io_map_base	= CKSEG1ADDR(GT_DEF_PCI0_IO_BASE),
 };
 
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index dd23beb..f99eaa9 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -79,10 +79,11 @@ void __init plat_mem_setup(void)
 	_machine_halt = cobalt_machine_halt;
 	pm_power_off = cobalt_machine_halt;
 
-	set_io_port_base(CKSEG1ADDR(GT_DEF_PCI0_IO_BASE));
+	set_io_port_base(IO_BASE);
+	set_legacy_io_port_base(CKSEG1ADDR(GT_DEF_PCI0_IO_BASE));
 
 	/* I/O port resource must include LCD/buttons */
-	ioport_resource.end = 0x0fffffff;
+	ioport_resource.end =  GT_DEF_PCI0_IO_BASE + GT_DEF_PCI0_IO_SIZE - 1;
 
 	/* These resources have been reserved by VIA SuperI/O chip. */
 	for (i = 0; i < ARRAY_SIZE(cobalt_reserved_resources); i++)
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 7f6ddcb..f8b3f5a 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -60,11 +60,14 @@ static char command_line[CL_SIZE];
        char arcs_cmdline[CL_SIZE]=CONFIG_CMDLINE;
 
 /*
- * mips_io_port_base is the begin of the address space to which x86 style
- * I/O ports are mapped.
+ * mips_io_port_base is the base of the address range into which the I/O ports
+ * are mapped.  mips_legacy_io_port_base is the same but used only for legacy
+ * addresses below legacy_io_port_top.
  */
 const unsigned long mips_io_port_base __read_mostly = -1;
 EXPORT_SYMBOL(mips_io_port_base);
+const unsigned long mips_legacy_io_port_base __read_mostly = -1;
+EXPORT_SYMBOL(mips_legacy_io_port_base);
 
 /*
  * isa_slot_offset is the address where E(ISA) busaddress 0 is mapped
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index f7df114..7da133b 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -51,6 +51,18 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
 	 qube_raq_galileo_early_fixup);
 
+static void __devinit cobalt_via_ide_native_mode_fixup(struct pci_dev *dev)
+{
+	unsigned char pif;
+
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &pif);
+	pif |= 4;
+	pci_write_config_byte(dev, PCI_CLASS_PROG, pif);
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
+	 cobalt_via_ide_native_mode_fixup);
+
 static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 {
 	unsigned short cfgword;
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 589b745..6e6981f 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -242,6 +242,8 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev,
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 		if (!dev->resource[i].start)
 			continue;
+		if (dev->resource[i].flags & IORESOURCE_PCI_FIXED)
+			continue;
 		if (dev->resource[i].flags & IORESOURCE_IO)
 			offset = hose->io_offset;
 		else if (dev->resource[i].flags & IORESOURCE_MEM)
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index e62058b..953be3b 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -53,11 +53,16 @@
 /*
  * On MIPS I/O ports are memory mapped, so we access them using normal
  * load/store instructions. mips_io_port_base is the virtual address to
- * which all ports are being mapped.  For sake of efficiency some code
- * assumes that this is an address that can be loaded with a single lui
- * instruction, so the lower 16 bits must be zero.  Should be true on
- * on any sane architecture; generic code does not use this assumption.
+ * which all ports are being mapped.  mips_legacy_io_port_base the same
+ * but used for ports below legacy_io_port_top.  This special treatment
+ * of legacy addresses is used for example on Cobalt systems where the
+ * GT-64111 system controller doesn't allow access to low ports but aliasing
+ * can be exploited to access them anyway.  So on a GT-64111 system
+ * mips_legacy_io_port_base would point to the base of the address range
+ * to which I/O ports are aliased.  Having the legacy_io_port_top default of
+ * zero leaves this special treatment disabled by default.
  */
+extern const unsigned long mips_legacy_io_port_base;
 extern const unsigned long mips_io_port_base;
 
 /*
@@ -75,6 +80,12 @@ static inline void set_io_port_base(unsigned long base)
 	barrier();
 }
 
+static inline void set_legacy_io_port_base(unsigned long base)
+{
+	* (unsigned long *) &mips_legacy_io_port_base = base;
+	barrier();
+}
+
 /*
  * Thanks to James van Artsdalen for a better timing-fix than
  * the two short jumps: using outb's to a nonexistent port seems
@@ -375,9 +386,14 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem)	\
 static inline void pfx##out##bwlq##p(type val, unsigned long port)	\
 {									\
 	volatile type *__addr;						\
+	unsigned long __vaddr;						\
 	type __val;							\
 									\
-	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
+	if (port < legacy_io_port_top)					\
+		__vaddr = mips_legacy_io_port_base + port;		\
+	else								\
+		__vaddr = mips_io_port_base + port;			\
+	__addr = (void *)__swizzle_addr_##bwlq(__vaddr);		\
 									\
 	__val = pfx##ioswab##bwlq(__addr, val);				\
 									\
@@ -391,9 +407,14 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port)	\
 static inline type pfx##in##bwlq##p(unsigned long port)			\
 {									\
 	volatile type *__addr;						\
+	unsigned long __vaddr;						\
 	type __val;							\
 									\
-	__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
+	if (port < legacy_io_port_top)					\
+		__vaddr = mips_legacy_io_port_base + port;		\
+	else								\
+		__vaddr = mips_io_port_base + port;			\
+	__addr = (void *)__swizzle_addr_##bwlq(__vaddr);		\
 									\
 	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
 									\
diff --git a/include/asm-mips/mach-cobalt/mangle-port.h b/include/asm-mips/mach-cobalt/mangle-port.h
new file mode 100644
index 0000000..bdf5450
--- /dev/null
+++ b/include/asm-mips/mach-cobalt/mangle-port.h
@@ -0,0 +1,27 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003, 2004, 2007 Ralf Baechle (ralf@xxxxxxxxxxxxxx)
+ */
+#ifndef __ASM_MACH_COBALT_MANGLE_PORT_H
+#define __ASM_MACH_COBALT_MANGLE_PORT_H
+
+#define __swizzle_addr_b(port)	(port)
+#define __swizzle_addr_w(port)	(port)
+#define __swizzle_addr_l(port)	(port)
+#define __swizzle_addr_q(port)	(port)
+
+# define ioswabb(a, x)		(x)
+# define __mem_ioswabb(a, x)	(x)
+# define ioswabw(a, x)		(x)
+# define __mem_ioswabw(a, x)	cpu_to_le16(x)
+# define ioswabl(a, x)		(x)
+# define __mem_ioswabl(a, x)	cpu_to_le32(x)
+# define ioswabq(a, x)		(x)
+# define __mem_ioswabq(a, x)	cpu_to_le32(x)
+
+#define legacy_io_port_top	0
+
+#endif /* __ASM_MACH_COBALT_MANGLE_PORT_H */
diff --git a/include/asm-mips/mach-generic/mangle-port.h b/include/asm-mips/mach-generic/mangle-port.h
index f49dc99..7f59bff 100644
--- a/include/asm-mips/mach-generic/mangle-port.h
+++ b/include/asm-mips/mach-generic/mangle-port.h
@@ -49,4 +49,6 @@
 
 #endif
 
+#define legacy_io_port_top	0
+
 #endif /* __ASM_MACH_GENERIC_MANGLE_PORT_H */


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux