linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/7] [RFC] Xenon support
@ 2007-03-07 18:01 Felix Domke
  2007-03-07 18:01 ` [patch 1/7] xenon: add PCI Vendor ID: Microsoft Felix Domke
                   ` (8 more replies)
  0 siblings, 9 replies; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This series of patches add support for the Xbox 360 gaming console.

Note that these patches were written by different people, who want
to remain anonymous. These drivers were written without hardware 
documentation being available.

There are probably more than some rough edges. Please comment 
and/or provide patches.

To actually run this, you need a special loader which exploits the
recently announced vulnerability. This loader was developed seperately
and should be available soon.

thanks,
Felix

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 1/7] xenon: add PCI Vendor ID: Microsoft
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 18:01 ` [patch 2/7] xenon: add platform support Felix Domke
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 include/linux/pci_ids.h |    2 ++
 1 file changed, 2 insertions(+)

Index: linux-2.6.20/include/linux/pci_ids.h
===================================================================
--- linux-2.6.20.orig/include/linux/pci_ids.h	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/include/linux/pci_ids.h	2007-03-07 19:01:20.000000000 +0100
@@ -2383,3 +2383,5 @@
 
 #define PCI_VENDOR_ID_QUICKNET		0x15E2
 #define PCI_DEVICE_ID_QUICKNET_XJ	0x0500
+
+#define PCI_VENDOR_ID_MICROSOFT		0x1414

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 2/7] xenon: add platform support
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
  2007-03-07 18:01 ` [patch 1/7] xenon: add PCI Vendor ID: Microsoft Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 23:06   ` Arnd Bergmann
  2007-03-07 18:01 ` [patch 3/7] xenon: udbg support (ugly) Felix Domke
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This patch adds platform support for the 'Xenon' platform (Xbox 360).

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 arch/powerpc/Kconfig                     |    7 
 arch/powerpc/boot/Makefile               |    5 
 arch/powerpc/kernel/cputable.c           |   12 +
 arch/powerpc/platforms/Makefile          |    1 
 arch/powerpc/platforms/xenon/Makefile    |    4 
 arch/powerpc/platforms/xenon/interrupt.c |  303 +++++++++++++++++++++++++++++++
 arch/powerpc/platforms/xenon/interrupt.h |   11 +
 arch/powerpc/platforms/xenon/pci.c       |  188 +++++++++++++++++++
 arch/powerpc/platforms/xenon/setup.c     |  151 +++++++++++++++
 arch/powerpc/platforms/xenon/smp.c       |  157 ++++++++++++++++
 include/asm-powerpc/cputable.h           |    6 
 11 files changed, 845 insertions(+)

Index: linux-2.6.20/arch/powerpc/Kconfig
===================================================================
--- linux-2.6.20.orig/arch/powerpc/Kconfig	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/arch/powerpc/Kconfig	2007-03-07 19:01:21.000000000 +0100
@@ -463,6 +463,13 @@
 	select PPC_970_NAP
 	default y
 
+config PPC_XENON
+	bool "Xenon"
+	depends on PPC_MULTIPLATFORM  && PPC64
+	select PPC_RTAS
+	select PPC_NATIVE
+	default y
+
 config PPC_PREP
 	bool "PowerPC Reference Platform (PReP) based machines"
 	depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
Index: linux-2.6.20/arch/powerpc/boot/Makefile
===================================================================
--- linux-2.6.20.orig/arch/powerpc/boot/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/arch/powerpc/boot/Makefile	2007-03-07 19:01:21.000000000 +0100
@@ -149,6 +149,10 @@
 $(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
 	$(call cmd,wrap_initrd,miboot)
 
+$(obj)/zImage.xenon: vmlinux $(wrapperbits)
+	$(call cmd,wrap,chrp)
+	${CROSS}objcopy -O elf32-powerpc vmlinux vmlinux.xenon
+
 $(obj)/zImage.ps3: vmlinux
 	$(STRIP) -s -R .comment $< -o $@
 
@@ -161,6 +165,7 @@
 image-$(CONFIG_PPC_PSERIES)		+= zImage.pseries
 image-$(CONFIG_PPC_MAPLE)		+= zImage.pseries
 image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
+image-$(CONFIG_PPC_XENON)		+= zImage.xenon
 image-$(CONFIG_PPC_PS3)			+= zImage.ps3
 image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
 image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
Index: linux-2.6.20/arch/powerpc/kernel/cputable.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/kernel/cputable.c	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/arch/powerpc/kernel/cputable.c	2007-03-07 19:01:21.000000000 +0100
@@ -355,6 +355,18 @@
 		.num_pmcs		= 6,
 		.platform		= "pa6t",
 	},
+	{	/* Xenon */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value	= 0x00710000,
+		.cpu_name		= "Xenon",
+		.cpu_features		= CPU_FTRS_XENON,
+		.cpu_user_features	= COMMON_USER_PPC64 |
+			PPC_FEATURE_HAS_ALTIVEC_COMP |
+			PPC_FEATURE_SMT,
+		.icache_bsize		= 128,
+		.dcache_bsize		= 128,
+		.platform		= "xenon",
+	},
 	{	/* default match */
 		.pvr_mask		= 0x00000000,
 		.pvr_value		= 0x00000000,
Index: linux-2.6.20/arch/powerpc/platforms/Makefile
===================================================================
--- linux-2.6.20.orig/arch/powerpc/platforms/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/arch/powerpc/platforms/Makefile	2007-03-07 19:01:21.000000000 +0100
@@ -18,3 +18,4 @@
 obj-$(CONFIG_PPC_CELL)		+= cell/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
 obj-$(CONFIG_EMBEDDED6xx)	+= embedded6xx/
+obj-$(CONFIG_PPC_XENON)	  += xenon/
Index: linux-2.6.20/arch/powerpc/platforms/xenon/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/arch/powerpc/platforms/xenon/Makefile	2007-03-07 19:01:21.000000000 +0100
@@ -0,0 +1,4 @@
+obj-$(CONFIG_PPC_XENON)		+= setup.o interrupt.o pci.o
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_PPC_XENON)		+= smp.o
+endif
Index: linux-2.6.20/arch/powerpc/platforms/xenon/interrupt.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/arch/powerpc/platforms/xenon/interrupt.c	2007-03-07 19:01:21.000000000 +0100
@@ -0,0 +1,303 @@
+/*
+ * Xenon interrupt controller,
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License v2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/ptrace.h>
+#include <asm/machdep.h>
+
+#include "interrupt.h"
+
+static void *iic_base,
+	*bridge_base, // ea000000
+	*biu,         // e1000000
+	*graphics;    // ec800000
+static struct irq_host *host;
+
+#define XENON_NR_IRQS 128
+
+#define PRIO_IPI_4       0x08
+#define PRIO_IPI_3       0x10
+#define PRIO_SMM         0x14
+#define PRIO_SFCX        0x18
+#define PRIO_SATA_HDD    0x20
+#define PRIO_SATA_CDROM  0x24
+#define PRIO_OHCI_0      0x2c
+#define PRIO_EHCI_0      0x30
+#define PRIO_OHCI_1      0x34
+#define PRIO_EHCI_1      0x38
+#define PRIO_XMA         0x40
+#define PRIO_AUDIO       0x44
+#define PRIO_ENET        0x4C
+#define PRIO_XPS         0x54
+#define PRIO_GRAPHICS    0x58
+#define PRIO_PROFILER    0x60
+#define PRIO_BIU         0x64
+#define PRIO_IOC         0x68
+#define PRIO_FSB         0x6c
+#define PRIO_IPI_2       0x70
+#define PRIO_CLOCK       0x74
+#define PRIO_IPI_1       0x78
+
+/* bridge (PCI) IRQ -> CPU IRQ */
+static int xenon_pci_irq_map[] = {
+		PRIO_CLOCK, PRIO_SATA_CDROM, PRIO_SATA_HDD, PRIO_SMM,
+		PRIO_OHCI_0, PRIO_EHCI_0, PRIO_OHCI_1, PRIO_EHCI_1,
+		-1, -1, PRIO_ENET, PRIO_XMA,
+		PRIO_AUDIO, PRIO_SFCX, -1, -1};
+
+static void disconnect_pci_irq(int prio)
+{
+	int i;
+
+	for (i=0; i<0x10; ++i)
+		if (xenon_pci_irq_map[i] == prio)
+			writel(0, bridge_base + 0x10 + i * 4);
+}
+
+	/* connects an PCI IRQ to CPU #0 */
+static void connect_pci_irq(int prio)
+{
+	int i;
+
+	for (i=0; i<0x10; ++i)
+		if (xenon_pci_irq_map[i] == prio)
+			writel(0x0800180 | (xenon_pci_irq_map[i]/4), bridge_base + 0x10 + i * 4);
+}
+
+static void iic_mask(unsigned int irq)
+{
+	disconnect_pci_irq(irq);
+}
+
+static void iic_unmask(unsigned int irq)
+{
+	int i;
+	connect_pci_irq(irq);
+	for (i=0; i<6; ++i)
+		__raw_writeq(0, iic_base + i * 0x1000 + 0x68);
+}
+
+void xenon_init_irq_on_cpu(int cpu)
+{
+		/* init that cpu's interrupt controller */
+	__raw_writeq(0x7C, iic_base + cpu * 0x1000 + 0x70);
+	__raw_writeq(0, iic_base + cpu * 0x1000 + 0x8);      /* irql */
+	__raw_writeq(1<<cpu, iic_base + cpu * 0x1000);       /* "who am i" */
+
+		/* ack all outstanding interrupts */
+	while (__raw_readq(iic_base + cpu * 0x1000 + 0x50) != 0x7C);
+	__raw_writeq(0, iic_base + cpu * 0x1000 + 0x68);
+}
+
+static void iic_eoi(unsigned int irq)
+{
+	int cpu = hard_smp_processor_id();
+	void *my_iic_base = iic_base + cpu * 0x1000;
+	__raw_writeq(0, my_iic_base + 0x68);
+	mb();
+	__raw_readq(my_iic_base + 0x8);
+}
+
+static struct irq_chip xenon_pic = {
+	.typename = " XENON-PIC ",
+	.mask = iic_mask,
+	.unmask = iic_unmask,
+	.eoi = iic_eoi,
+};
+
+/* Get an IRQ number from the pending state register of the IIC */
+static unsigned int iic_get_irq(void)
+{
+	int cpu = hard_smp_processor_id();
+	void *my_iic_base;
+	int index;
+
+	my_iic_base = iic_base + cpu * 0x1000;
+
+	index = __raw_readq(my_iic_base + 0x50) & 0x7F; /* read destructive pending interrupt */
+
+	__raw_writeq(0x7c, my_iic_base + 0x08); /* current task priority */
+	mb();
+	__raw_readq(my_iic_base + 0x8);
+
+		/* HACK: we will handle some (otherwise unhandled) interrupts here
+		   to prevent them flooding. */
+	switch (index)
+	{
+	case PRIO_GRAPHICS:
+		writel(0, graphics + 0xed0);
+		writel(0, graphics + 0x6540);
+		break;
+	case PRIO_IOC:
+	{
+		writel(0, biu + 0x4002c);
+		break;
+	}
+	case PRIO_CLOCK:
+	{
+		writel(0, bridge_base + 0x106C);
+		break;
+	}
+	default:
+		break;
+	}
+
+		/* HACK: we need to ACK unhandled interrupts here */
+	if (!irq_desc[index].action)
+	{
+		printk(KERN_WARNING "IRQ %02x unhandled, doing local EOI\n", index);
+		__raw_writeq(0, my_iic_base + 0x60);
+		iic_eoi(index);
+		return NO_IRQ;
+	}
+
+	if (index == 0x7C)
+		return NO_IRQ;
+	else
+		return index;
+}
+
+static int xenon_irq_host_map(struct irq_host *h, unsigned int virq,
+				irq_hw_number_t hw)
+{
+	set_irq_chip_and_handler(virq, &xenon_pic, handle_percpu_irq);
+	return 0;
+}
+
+static int xenon_irq_host_match(struct irq_host *h, struct device_node *node)
+{
+	return h->host_data != NULL && node == h->host_data;
+}
+
+static struct irq_host_ops xenon_irq_host_ops = {
+	.map = xenon_irq_host_map,
+	.match = xenon_irq_host_match,
+};
+
+void __init xenon_iic_init_IRQ(void)
+{
+	int i;
+	struct device_node *dn;
+
+	printk("XENON init IRQ\n");
+
+			/* search for our interrupt controller inside the device tree */
+	for (dn = NULL;
+	     (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
+		if (!device_is_compatible(dn,
+				     "xenon"))
+			continue;
+
+		irq_set_virq_count(0x80);
+		iic_base = ioremap_nocache(0x20000050000, 0x10000);
+
+		host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &xenon_irq_host_ops, 0);
+		host->host_data = of_node_get(dn);
+		BUG_ON(host == NULL);
+		irq_set_default_host(host);
+	}
+
+	ppc_md.get_irq = iic_get_irq;
+
+	bridge_base = ioremap_nocache(0xea000000, 0x10000);
+	biu = ioremap_nocache(0xe1000000, 0x2000000);
+	graphics = ioremap_nocache(0xec800000, 0x10000);
+
+		/* initialize interrupts */
+	writel(0, bridge_base);
+	writel(0x40000000, bridge_base + 4);
+
+	writel(0x40000000, biu + 0x40074);
+	writel(0xea000050, biu + 0x40078);
+
+	writel(0, bridge_base + 0xc);
+	writel(0x3, bridge_base);
+
+	/* disconnect all PCI IRQs until they are requested */
+	for (i=0; i<0x10; ++i)
+		writel(0, bridge_base + 0x10 + i * 4);
+
+	xenon_init_irq_on_cpu(0);
+}
+
+#ifdef CONFIG_SMP
+
+static int ipi_to_prio(int ipi)
+{
+	switch (ipi)
+	{
+	case PPC_MSG_CALL_FUNCTION:
+		return PRIO_IPI_1;
+		break;
+	case PPC_MSG_RESCHEDULE:
+		return PRIO_IPI_2;
+		break;
+	//case PPC_MSG_MIGRATE_TASK:
+	//	return PRIO_IPI_3;
+	//	break;
+	case PPC_MSG_DEBUGGER_BREAK:
+		return PRIO_IPI_4;
+		break;
+	default:
+		BUG();
+	}
+	return 0;
+}
+
+void xenon_cause_IPI(int target, int msg)
+{
+	int ipi_prio;
+
+	ipi_prio = ipi_to_prio(msg);
+
+	__raw_writeq( (0x10000<<target) | ipi_prio, iic_base + 0x10 + hard_smp_processor_id() * 0x1000);
+}
+
+static irqreturn_t xenon_ipi_action(int irq, void *dev_id)
+{
+	int ipi = (int)(long)dev_id;
+	smp_message_recv(ipi);
+	return IRQ_HANDLED;
+}
+
+static void xenon_request_ipi(int ipi, const char *name)
+{
+	int prio = ipi_to_prio(ipi), virq;
+
+	virq = irq_create_mapping(host, prio);
+	if (virq == NO_IRQ)
+	{
+		printk(KERN_ERR
+				"xenon_request_ipi: failed to map IPI%d (%s)\n", prio, name);
+		return;
+	}
+
+	if (request_irq(prio, xenon_ipi_action, IRQF_DISABLED,
+			name, (void *)(long)ipi))
+		printk(KERN_ERR "request irq for ipi failed!\n");
+}
+
+void xenon_request_IPIs(void)
+{
+	xenon_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call");
+	xenon_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched");
+#ifdef CONFIG_DEBUGGER
+	xenon_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
+#endif /* CONFIG_DEBUGGER */
+}
+
+#endif
Index: linux-2.6.20/arch/powerpc/platforms/xenon/interrupt.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/arch/powerpc/platforms/xenon/interrupt.h	2007-03-07 19:01:21.000000000 +0100
@@ -0,0 +1,11 @@
+#ifndef ASM_XENON_PIC_H
+#define ASM_XENON_PIC_H
+#ifdef __KERNEL__
+
+extern void xenon_init_irq_on_cpu(int cpu);
+extern void __init xenon_iic_init_IRQ(void);
+extern void xenon_cause_IPI(int target, int msg);
+extern void xenon_request_IPIs(void);
+
+#endif
+#endif /* ASM_XENON_PIC_H */
Index: linux-2.6.20/arch/powerpc/platforms/xenon/pci.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/arch/powerpc/platforms/xenon/pci.c	2007-03-07 19:01:21.000000000 +0100
@@ -0,0 +1,188 @@
+/*
+ * based on:
+ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
+ *		      IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+// #define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/iommu.h>
+#include <asm/ppc-pci.h>
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
+#define OFFSET(devfn) ((devfn+256)<<12)
+
+static int xenon_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+			      int offset, int len, u32 *val)
+{
+	struct pci_controller *hose;
+	void* addr;
+
+	hose = pci_bus_to_host(bus);
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	DBG("xenon_pci_read_config,slot %d, func %d\n", PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+	if (PCI_SLOT(devfn) >= 32)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (PCI_SLOT(devfn) == 3)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (PCI_SLOT(devfn) == 6)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (PCI_SLOT(devfn) >= 0xB)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (PCI_FUNC(devfn) >= 2)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	DBG("xenon_pci_read_config, %p, devfn=%d, offset=%d, len=%d\n", bus, devfn, offset, len);
+
+	addr = ((void*)hose->cfg_addr) + OFFSET(devfn) + offset;
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *)addr);
+		break;
+	case 2:
+		*val = in_le16((u16 *)addr);
+		break;
+	default:
+		*val = in_le32((u32 *)addr);
+		break;
+	}
+	DBG("->%08x\n", (int)*val);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int xenon_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+			       int offset, int len, u32 val)
+{
+	struct pci_controller *hose;
+	void *addr;
+
+	hose = pci_bus_to_host(bus);
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (PCI_SLOT(devfn) >= 32)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (PCI_SLOT(devfn) == 3)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	DBG("xenon_pci_write_config, %p, devfn=%d, offset=%x, len=%d, val=%08x\n", bus, devfn, offset, len, val);
+
+	addr = ((void*)hose->cfg_addr) + OFFSET(devfn) + offset;
+	if (len == 4)
+		DBG("was: %08x\n", readl(addr));
+	if (len == 2)
+		DBG("was: %04x\n", readw(addr));
+	if (len == 1)
+		DBG("was: %02x\n", readb(addr));
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		writeb(val, addr);
+		break;
+	case 2:
+		writew(val, addr);
+		break;
+	default:
+		writel(val, addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops xenon_pci_ops =
+{
+	xenon_pci_read_config,
+	xenon_pci_write_config
+};
+
+void __init xenon_pci_init(void)
+{
+	struct pci_controller *hose;
+	struct device_node *np, *root;
+	struct device_node *dev = NULL;
+
+	root = of_find_node_by_path("/");
+	if (root == NULL) {
+		printk(KERN_CRIT "xenon_pci_init: can't find root of device tree\n");
+		return;
+	}
+	for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
+		if (np->name == NULL)
+			continue;
+		if (strcmp(np->name, "pci") == 0) {
+			of_node_get(np);
+			dev = np;
+		}
+	}
+	of_node_put(root);
+
+	if (!dev)
+	{
+		printk("couldn't find PCI node!\n");
+		return;
+	}
+
+	hose = pcibios_alloc_controller(dev);
+	if (hose == NULL)
+	{
+		printk("pcibios_alloc_controller failed!\n");
+		return;
+	}
+
+	hose->first_busno = 0;
+	hose->last_busno = 0;
+
+	hose->ops = &xenon_pci_ops;
+	hose->cfg_addr = ioremap(0xd0000000, 0x1000000);
+
+	pci_process_bridge_OF_ranges(hose, dev, 1);
+	pci_setup_phb_io(hose, 1);
+
+	/* Setup the linkage between OF nodes and PHBs */
+	pci_devs_phb_init();
+
+	/* Tell pci.c to not change any resource allocations.  */
+	pci_probe_only = 1;
+
+	of_node_put(dev);
+	DBG("PCI initialized\n");
+
+	pci_io_base = 0;
+
+	ppc_md.pci_dma_dev_setup = NULL;
+	ppc_md.pci_dma_bus_setup = NULL;
+	pci_dma_ops = &dma_direct_ops;
+}
Index: linux-2.6.20/arch/powerpc/platforms/xenon/setup.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/arch/powerpc/platforms/xenon/setup.c	2007-03-07 19:01:21.000000000 +0100
@@ -0,0 +1,151 @@
+/*
+ *  linux/arch/powerpc/platforms/xenon/xenon_setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified by PPC64 Team, IBM Corp
+ *  Modified by Cell Team, IBM Deutschland Entwicklung GmbH
+ *  Modified by anonymous xbox360 hacker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define DEBUG
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/console.h>
+#include <linux/mutex.h>
+#include <linux/memory_hotplug.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/kexec.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+#include <asm/cputable.h>
+#include <asm/ppc-pci.h>
+#include <asm/irq.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+#include <asm/udbg.h>
+#include <asm/cacheflush.h>
+#include "interrupt.h"
+
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+void __init xenon_pci_init(void);
+#ifdef CONFIG_SMP
+extern void smp_init_xenon(void);
+#endif
+
+
+static void xenon_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	const char *model = "";
+
+	root = of_find_node_by_path("/");
+	if (root)
+		model = get_property(root, "model", NULL);
+	seq_printf(m, "machine\t\t: CHRP %s\n", model);
+	of_node_put(root);
+}
+
+static void xenon_progress(char *s, unsigned short hex)
+{
+	printk("*** %04x : %s\n", hex, s ? s : "");
+}
+
+static void __init xenon_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+
+	for_each_pci_dev(dev)
+		pci_read_irq_line(dev);
+}
+
+static void __init xenon_init_irq(void)
+{
+	xenon_iic_init_IRQ();
+}
+
+static void __init xenon_setup_arch(void)
+{
+#ifdef CONFIG_SMP
+	smp_init_xenon();
+#endif
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+
+	if (ROOT_DEV == 0) {
+		printk("No ramdisk, default root is /dev/hda2\n");
+		ROOT_DEV = Root_HDA2;
+	}
+
+	xenon_pci_init();
+	/* Find and initialize PCI host bridges */
+	init_pci_config_tokens();
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+}
+
+void __init xenon_hpte_init(unsigned long htab_size);
+
+static int __init xenon_probe(void)
+{
+	hpte_init_native();
+
+	return 1;
+}
+
+static int xenon_check_legacy_ioport(unsigned int baseport)
+{
+	return -ENODEV;
+}
+
+define_machine(xenon) {
+	.name			= "Xenon",
+	.probe			= xenon_probe,
+	.setup_arch		= xenon_setup_arch,
+	.show_cpuinfo		= xenon_show_cpuinfo,
+	.calibrate_decr		= generic_calibrate_decr,
+	.check_legacy_ioport	= xenon_check_legacy_ioport,
+	.progress		= xenon_progress,
+	.init_IRQ       	= xenon_init_irq,
+	.pcibios_fixup		= xenon_pcibios_fixup,
+#ifdef CONFIG_KEXEC
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
+#endif
+};
Index: linux-2.6.20/arch/powerpc/platforms/xenon/smp.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/arch/powerpc/platforms/xenon/smp.c	2007-03-07 19:01:21.000000000 +0100
@@ -0,0 +1,157 @@
+/*
+ * SMP support for Xenon machines.
+ *
+ * Based on CBE's smp.c.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+// #define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/cpu.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/paca.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/cputable.h>
+#include <asm/firmware.h>
+#include <asm/system.h>
+#include <asm/rtas.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/*
+ * The primary thread of each non-boot processor is recorded here before
+ * smp init.
+ */
+static cpumask_t of_spin_map;
+
+void smp_init_xenon(void);
+
+extern void xenon_request_IPIs(void);
+extern void xenon_init_irq_on_cpu(int cpu);
+
+static int __init smp_xenon_probe(void)
+{
+	xenon_request_IPIs();
+
+	return cpus_weight(cpu_possible_map);
+}
+
+static void __devinit smp_xenon_setup_cpu(int cpu)
+{
+	if (cpu != boot_cpuid)
+		xenon_init_irq_on_cpu(cpu);
+}
+
+static void __devinit smp_xenon_kick_cpu(int nr)
+{
+	BUG_ON(nr < 0 || nr >= NR_CPUS);
+
+	DBG("smp_xenon_kick_cpu %d\n", nr);
+
+	/*
+	 * The processor is currently spinning, waiting for the
+	 * cpu_start field to become non-zero After we set cpu_start,
+	 * the processor will continue on to secondary_start
+	 */
+	paca[nr].cpu_start = 1;
+}
+
+static int smp_xenon_cpu_bootable(unsigned int nr)
+{
+	/* Special case - we inhibit secondary thread startup
+	 * during boot if the user requests it.  Odd-numbered
+	 * cpus are assumed to be secondary threads.
+	 */
+	if (system_state < SYSTEM_RUNNING &&
+	    cpu_has_feature(CPU_FTR_SMT) &&
+	    !smt_enabled_at_boot && nr % 2 != 0)
+		return 0;
+
+		/* FIXME: secondary threads behave instable. */
+	if (nr & 1)
+		return 0;
+
+	return 1;
+}
+
+extern void xenon_cause_IPI(int target, int msg);
+
+static void smp_xenon_message_pass(int target, int msg)
+{
+	unsigned int i;
+
+	if (target < NR_CPUS) {
+		xenon_cause_IPI(target, msg);
+	} else {
+		for_each_online_cpu(i) {
+			if (target == MSG_ALL_BUT_SELF
+			    && i == smp_processor_id())
+				continue;
+			xenon_cause_IPI(i, msg);
+		}
+	}
+}
+
+static struct smp_ops_t xenon_smp_ops = {
+	.message_pass	= smp_xenon_message_pass,
+	.probe		= smp_xenon_probe,
+	.kick_cpu	= smp_xenon_kick_cpu,
+	.setup_cpu	= smp_xenon_setup_cpu,
+	.cpu_bootable	= smp_xenon_cpu_bootable,
+};
+
+/* This is called very early */
+void __init smp_init_xenon(void)
+{
+	int i;
+
+	DBG(" -> smp_init_xenon()\n");
+
+	smp_ops = &xenon_smp_ops;
+
+	/* Mark threads which are still spinning in hold loops. */
+	if (cpu_has_feature(CPU_FTR_SMT)) {
+		for_each_present_cpu(i) {
+			if (i % 2 == 0)
+				/*
+				 * Even-numbered logical cpus correspond to
+				 * primary threads.
+				 */
+				cpu_set(i, of_spin_map);
+		}
+	} else {
+		of_spin_map = cpu_present_map;
+	}
+
+	cpu_clear(boot_cpuid, of_spin_map);
+
+	DBG(" <- smp_init_xenon()\n");
+}
Index: linux-2.6.20/include/asm-powerpc/cputable.h
===================================================================
--- linux-2.6.20.orig/include/asm-powerpc/cputable.h	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/include/asm-powerpc/cputable.h	2007-03-07 19:01:21.000000000 +0100
@@ -347,6 +347,12 @@
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
+#define CPU_FTRS_XENON ((CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
+	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
+	    CPU_FTR_CTRL )&~CPU_FTR_16M_PAGE)
+// | CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE  /* we need to setup large pages before, and we don't do that yet */
+
 #define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
 	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 3/7] xenon: udbg support (ugly)
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
  2007-03-07 18:01 ` [patch 1/7] xenon: add PCI Vendor ID: Microsoft Felix Domke
  2007-03-07 18:01 ` [patch 2/7] xenon: add platform support Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 21:00   ` Geert Uytterhoeven
  2007-03-07 18:01 ` [patch 4/7] xenon: add southbridge ethernet support Felix Domke
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This adds support for a serial kernel output on the Xenon platform.

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 arch/powerpc/kernel/misc_64.S |    2 +-
 arch/powerpc/kernel/udbg.c    |   14 ++++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

Index: linux-2.6.20/arch/powerpc/kernel/misc_64.S
===================================================================
--- linux-2.6.20.orig/arch/powerpc/kernel/misc_64.S	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/arch/powerpc/kernel/misc_64.S	2007-03-07 19:01:21.000000000 +0100
@@ -247,7 +247,7 @@
 	blr
 
 
-#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
+#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_XENON)
 /*
  * Do an IO access in real mode
  */
Index: linux-2.6.20/arch/powerpc/kernel/udbg.c
===================================================================
--- linux-2.6.20.orig/arch/powerpc/kernel/udbg.c	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/arch/powerpc/kernel/udbg.c	2007-03-07 19:01:21.000000000 +0100
@@ -25,6 +25,18 @@
  * Early debugging facilities. You can enable _one_ of these via .config,
  * if you do so your kernel _will not boot_ on anything else. Be careful.
  */
+
+extern u8 real_readb(volatile u8 __iomem  *addr);
+extern void real_writeb(u8 data, volatile u8 __iomem *addr);
+
+void udbg_xenon_real_putc(char c)
+{
+	if (c == '\n')
+		udbg_xenon_real_putc('\r');
+	while (!(real_readb((void*)0x80000200ea001018ULL)&0x02));
+	real_writeb(c, (void*)0x80000200ea001014ULL);
+}
+
 void __init udbg_early_init(void)
 {
 #if defined(CONFIG_PPC_EARLY_DEBUG_LPAR)
@@ -46,6 +58,7 @@
 	/* For iSeries - hit Ctrl-x Ctrl-x to see the output */
 	udbg_init_iseries();
 #endif
+	udbg_putc = udbg_xenon_real_putc;
 }
 
 /* udbg library, used by xmon et al */
@@ -150,6 +163,7 @@
 		printk(KERN_INFO "early console immortal !\n");
 		return;
 	}
+	return;
 	unregister_console(&udbg_console);
 	early_console_initialized = 0;
 }

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 4/7] xenon: add southbridge ethernet support
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
                   ` (2 preceding siblings ...)
  2007-03-07 18:01 ` [patch 3/7] xenon: udbg support (ugly) Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 23:27   ` Arnd Bergmann
  2007-03-07 18:01 ` [patch 5/7] xenon: add SATA support Felix Domke
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This adds support for the Ethernet controller used in the Xenon southbridge.

It is based on the skeleton code, and works surprisingly good. It has some 
rough edges, especially regarding SMP locks, and probably needs some code
cleanup.

Signed-off-by: Felix Domke <tmbinc@elitevb.net>

---
 drivers/net/Kconfig     |    4 
 drivers/net/Makefile    |    2 
 drivers/net/xenon_net.c |  725 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 731 insertions(+)

Index: linux-2.6.20/drivers/net/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/net/Kconfig	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/net/Kconfig	2007-03-07 19:01:22.000000000 +0100
@@ -1622,6 +1622,10 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called 8139cp.  This is recommended.
 
+config XENON_ENET
+	tristate "Xenon Fast Ethernet Adapter support"
+	depends on NET_PCI && PCI
+
 config 8139TOO
 	tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
 	depends on NET_PCI && PCI
Index: linux-2.6.20/drivers/net/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/net/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/net/Makefile	2007-03-07 19:01:22.000000000 +0100
@@ -217,3 +217,5 @@
 obj-$(CONFIG_FS_ENET) += fs_enet/
 
 obj-$(CONFIG_NETXEN_NIC) += netxen/
+
+obj-$(CONFIG_XENON_ENET) += xenon_net.o
Index: linux-2.6.20/drivers/net/xenon_net.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/net/xenon_net.c	2007-03-07 19:01:22.000000000 +0100
@@ -0,0 +1,725 @@
+/*
+ * based on skeleton code.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <asm/io.h>
+
+#define assert(expr) \
+        if(!(expr)) {					\
+        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
+        #expr,__FILE__,__FUNCTION__,__LINE__);		\
+        }
+
+#define XENONNET_VERSION		"1.0.0"
+#define MODNAME			"xenon_net"
+#define XENONNET_DRIVER_LOAD_MSG	"Xenon Fast Ethernet driver " XENONNET_VERSION " loaded"
+#define PFX			MODNAME ": "
+
+#define RX_RING_SIZE 16
+#define TX_RING_SIZE 16
+
+#define TX_TIMEOUT    (6*HZ)
+
+static char version[] __devinitdata =
+KERN_INFO XENONNET_DRIVER_LOAD_MSG "\n"
+KERN_INFO "\n";
+
+static struct pci_device_id xenon_net_pci_tbl[] = {
+	{0x1414, 0x580a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE (pci, xenon_net_pci_tbl);
+
+/* Symbolic offsets to registers. */
+enum XENONNET_registers {
+	TxConfig = 0x00,
+	TxDescriptorBase = 0x04,
+	TxDescriptorStatus = 0x0C,
+	RxConfig = 0x10,
+	RxDescriptorBase = 0x14,
+	InterruptStatus = 0x20,
+	InterruptMask = 0x24,
+	Config0 = 0x28,
+	Power = 0x30,
+	PhyConfig = 0x40,
+	PhyControl = 0x44,
+	Config1 = 0x50,
+	RetryCount = 0x54,
+	MulticastFilterControl = 0x60,
+	Address0 = 0x62,
+	MulticastHash = 0x68,
+	MaxPacketSize = 0x78,
+	Address1 = 0x7A
+};
+
+struct xenon_net_private {
+	void *mmio_addr;
+	struct pci_dev *pdev;
+	struct net_device_stats stats;
+
+	/* we maintain a list of rx and tx descriptors */
+	void *tx_descriptor_base;
+	void *rx_descriptor_base;
+	dma_addr_t tx_descriptor_base_dma;
+	dma_addr_t rx_descriptor_base_dma;
+
+	struct sk_buff *rx_skbuff[RX_RING_SIZE];
+	dma_addr_t rx_skbuff_dma[RX_RING_SIZE];
+
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	dma_addr_t tx_skbuff_dma[TX_RING_SIZE];
+
+	atomic_t tx_next_free, tx_next_done, rx_next;
+
+	int rx_buf_sz;
+
+	spinlock_t lock;
+};
+
+static int xenon_net_open (struct net_device *dev);
+static void xenon_net_tx_timeout (struct net_device *dev);
+static void xenon_net_init_ring (struct net_device *dev);
+static int xenon_net_start_xmit (struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t xenon_net_interrupt(int irq, void *dev_id);
+static int xenon_net_close (struct net_device *dev);
+static void xenon_net_hw_start (struct net_device *dev);
+static int xenon_net_poll(struct net_device *dev, int *budget);
+
+#define XENONNET_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
+#define XENONNET_W16(reg, val16)	writew ((val16), ioaddr + (reg))
+#define XENONNET_W32(reg, val32)	do { writel ((val32), ioaddr + (reg));  } while (0)
+#define XENONNET_R8(reg)		readb (ioaddr + (reg))
+#define XENONNET_R16(reg)		readw (ioaddr + (reg))
+#define XENONNET_R32(reg)		((u32) readl (ioaddr + (reg)))
+
+static int __devinit xenon_net_init_board (struct pci_dev *pdev,
+					 struct net_device **dev_out,
+					 void **ioaddr_out)
+{
+	void *ioaddr = NULL;
+	struct net_device *dev;
+	struct xenon_net_private *tp;
+	int rc, i;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+	assert (pdev != NULL);
+	assert (ioaddr_out != NULL);
+
+	*ioaddr_out = NULL;
+	*dev_out = NULL;
+
+	/* dev zeroed in alloc_etherdev */
+	dev = alloc_etherdev (sizeof (*tp));
+	if (dev == NULL) {
+		dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+		printk ("EXIT, returning -ENOMEM\n");
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	tp = dev->priv;
+
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	rc = pci_enable_device (pdev);
+	if (rc)
+		goto err_out;
+
+	mmio_start = pci_resource_start (pdev, 0);
+	mmio_end = pci_resource_end (pdev, 0);
+	mmio_flags = pci_resource_flags (pdev, 0);
+	mmio_len = pci_resource_len (pdev, 0);
+
+	/* make sure PCI base addr 0 is MMIO */
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		dev_err(&pdev->dev, "region #0 not an MMIO resource, aborting\n");
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rc = pci_request_regions (pdev, MODNAME);
+	if (rc)
+		goto err_out;
+
+	pci_set_master (pdev);
+
+	/* ioremap MMIO region */
+	ioaddr = ioremap (mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out_free_res;
+	}
+
+	i = register_netdev (dev);
+	if (i)
+		goto err_out_unmap;
+
+	*ioaddr_out = ioaddr;
+	*dev_out = dev;
+	return 0;
+
+err_out_unmap:
+#ifndef USE_IO_OPS
+	iounmap(ioaddr);
+err_out_free_res:
+#endif
+	pci_release_regions (pdev);
+err_out:
+	free_netdev (dev);
+	return rc;
+}
+
+
+static int __devinit xenon_net_init_one (struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
+{
+	struct net_device *dev = NULL;
+	struct xenon_net_private *tp;
+	int i;
+	void *ioaddr = NULL;
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
+	assert (pdev != NULL);
+	assert (ent != NULL);
+
+	i = xenon_net_init_board (pdev, &dev, &ioaddr);
+	if (i < 0) {
+		printk ("EXIT, returning %d\n", i);
+		return i;
+	}
+
+	tp = dev->priv;
+
+	assert (ioaddr != NULL);
+	assert (dev != NULL);
+	assert (tp != NULL);
+
+	memcpy(dev->dev_addr, "\0\0\1\2\3\4", 6);
+
+	dev->open = xenon_net_open;
+	dev->hard_start_xmit = xenon_net_start_xmit;
+	dev->stop = xenon_net_close;
+//	dev->get_stats = xenon_net_get_stats;
+//	dev->set_multicast_list = xenon_net_set_rx_mode;
+//	dev->do_ioctl = xenon_net_ioctl;
+	dev->poll = xenon_net_poll;
+	dev->weight = 64;
+
+	dev->tx_timeout = xenon_net_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	dev->irq = pdev->irq;
+	dev->base_addr = (unsigned long) ioaddr;
+
+	/* dev->priv/tp zeroed and aligned in alloc_etherdev */
+	tp = dev->priv;
+
+	tp->pdev = pdev;
+	tp->mmio_addr = ioaddr;
+	spin_lock_init(&tp->lock);
+
+	pci_set_drvdata(pdev, dev);
+
+	printk (KERN_INFO "%s: at 0x%lx, "
+		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		"IRQ %d\n",
+		dev->name,
+		dev->base_addr,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5],
+		dev->irq);
+
+	return 0;
+}
+
+
+static void __devexit xenon_net_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct xenon_net_private *np;
+
+	assert (dev != NULL);
+
+	np = dev->priv;
+	assert (np != NULL);
+
+	unregister_netdev (dev);
+
+#ifndef USE_IO_OPS
+	iounmap (np->mmio_addr);
+#endif /* !USE_IO_OPS */
+
+	pci_release_regions (pdev);
+
+	free_netdev (dev);
+
+	pci_set_drvdata (pdev, NULL);
+
+	pci_disable_device (pdev);
+}
+
+static int xenon_net_open (struct net_device *dev)
+{
+//	struct xenon_net_private *tp = dev->priv;
+	int retval;
+#ifdef XENONNET_DEBUG
+	void *ioaddr = tp->mmio_addr;
+#endif
+
+	retval = request_irq (dev->irq, xenon_net_interrupt, IRQF_SHARED, dev->name, dev);
+	if (retval) {
+		printk ("EXIT, returning %d\n", retval);
+		return retval;
+	}
+
+	xenon_net_init_ring (dev); /* allocates ringbuffer, clears them */
+	xenon_net_hw_start (dev);  /* start HW */
+
+	return 0;
+}
+
+
+/* Start the hardware at open or resume. */
+static void xenon_net_hw_start (struct net_device *dev)
+{
+	struct xenon_net_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+
+	/* Soft reset the chip. */
+	XENONNET_W32(InterruptMask, 0);
+	XENONNET_W32(Config0, 0x08558001);
+	udelay (100);
+	XENONNET_W32(Config0, 0x08550001);
+
+	XENONNET_W32(PhyControl, 4);
+	udelay (100);
+	XENONNET_W32(PhyControl, 0);
+
+	XENONNET_W16(MaxPacketSize, 0x5f2);
+
+	XENONNET_W32(Config1, 0x2360);
+
+	XENONNET_W16(MulticastFilterControl, 0x0e38);
+
+	/* Restore our idea of the MAC address. */
+	XENONNET_W16(Address0    , cpu_to_le16 (*(u16 *) (dev->dev_addr + 0)));
+	XENONNET_W32(Address0 + 2, cpu_to_le32 (*(u32 *) (dev->dev_addr + 2)));
+
+	XENONNET_W16(Address1    , cpu_to_le16 (*(u16 *) (dev->dev_addr + 0)));
+	XENONNET_W32(Address1 + 2, cpu_to_le32 (*(u32 *) (dev->dev_addr + 2)));
+
+	XENONNET_W32(MulticastHash, 0);
+	XENONNET_W32(MulticastHash + 4, 0);
+
+	XENONNET_W32(TxConfig, 0x00001c00);
+	XENONNET_W32(RxConfig, 0x00101c00);
+
+	XENONNET_W32(PhyConfig, 0x04001901);
+
+	atomic_set(&tp->rx_next, 0);
+
+	XENONNET_W32(TxConfig, 0x00001c00);
+	XENONNET_W32(TxDescriptorBase, tp->tx_descriptor_base_dma);
+	XENONNET_W32(TxConfig, 0x00011c00);
+	XENONNET_W32(TxDescriptorBase, tp->tx_descriptor_base_dma);
+	XENONNET_W32(TxConfig, 0x00001c00);
+
+	XENONNET_W32(RxDescriptorBase, tp->rx_descriptor_base_dma);
+	XENONNET_W32(PhyConfig, 0x04001001);
+	XENONNET_W32(Config1, 0);
+
+	XENONNET_W32(Config0, 0x08550001);
+
+	XENONNET_W32(TxConfig, 0x00001c01); /* enable tx */
+	XENONNET_W32(RxConfig, 0x00101c11); /* enable rx */
+
+	XENONNET_W32(InterruptMask, 0x00010054);
+	XENONNET_W32(InterruptStatus, 0x00010054);
+
+	netif_start_queue (dev);
+}
+
+static void xenon_set_tx_descriptor (struct xenon_net_private *tp, int index, u32 len, dma_addr_t addr, int valid)
+{
+	volatile u32 *descr = tp->tx_descriptor_base + index * 0x10;
+//	printk("xenon_set_tx_descriptor: %d, len=%x, addr=%x, valid=%d\n", index, len, (int)addr, valid);
+	descr[0] = cpu_to_le32(len);
+	descr[2] = cpu_to_le32(addr);
+	descr[3] = cpu_to_le32(len | ((index == TX_RING_SIZE - 1) ? 0x80000000 : 0));
+	wmb();
+	if (valid)
+		descr[1] = cpu_to_le32(0xc0230000);
+	else
+		descr[1] = 0;
+}
+
+static void xenon_set_rx_descriptor (struct xenon_net_private *tp, int index, u32 len, dma_addr_t addr, int valid)
+{
+	volatile u32 *descr = tp->rx_descriptor_base + index * 0x10;
+//	printk("xenon_set_rx_descriptor: %d, len=%x, addr=%x, valid=%d\n", index, len, (int)addr, valid);
+	descr[0] = cpu_to_le32(0);
+	descr[2] = cpu_to_le32(addr);
+	descr[3] = cpu_to_le32(len | ((index == RX_RING_SIZE - 1) ? 0x80000000 : 0));
+	wmb();
+	if (valid)
+		descr[1] = cpu_to_le32(0xc0000000);
+	else
+		descr[1] = 0;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void xenon_net_init_ring (struct net_device *dev)
+{
+	struct xenon_net_private *tp = dev->priv;
+	int i;
+
+	atomic_set (&tp->rx_next, 0);
+	atomic_set (&tp->tx_next_done, 0);
+	atomic_set (&tp->tx_next_free, 0);
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = NULL;
+		tp->tx_skbuff_dma[i] = 0;
+	}
+
+			/* allocate descriptor memory */
+	tp->tx_descriptor_base = pci_alloc_consistent(tp->pdev,
+			TX_RING_SIZE * 0x10 + RX_RING_SIZE * 0x10,
+			&tp->tx_descriptor_base_dma);
+			/* rx is right after tx */
+	tp->rx_descriptor_base = tp->tx_descriptor_base + TX_RING_SIZE * 0x10;
+	tp->rx_descriptor_base_dma = tp->tx_descriptor_base_dma + TX_RING_SIZE * 0x10;
+
+	for (i = 0; i < TX_RING_SIZE; ++i)
+		xenon_set_tx_descriptor(tp, i, 0, 0, 0);
+
+	tp->rx_buf_sz = dev->mtu + 32;
+
+	for (i = 0; i < RX_RING_SIZE; ++i)
+	{
+		struct sk_buff *skb = dev_alloc_skb(tp->rx_buf_sz);
+		tp->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;	/* Mark as being used by this device. */
+		tp->rx_skbuff_dma[i] = pci_map_single(tp->pdev, skb->data, tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+		xenon_set_rx_descriptor(tp, i, tp->rx_buf_sz, tp->rx_skbuff_dma[i], 1);
+	}
+}
+
+
+static void xenon_net_tx_clear (struct xenon_net_private *tp)
+{
+	int i;
+
+	atomic_set (&tp->tx_next_free, 0);
+	atomic_set (&tp->tx_next_done, 0);
+
+	/* Dump the unsent Tx packets. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (tp->tx_skbuff_dma[i] != 0) {
+			pci_unmap_single (tp->pdev, tp->tx_skbuff_dma[i],
+					  tp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+		}
+		if (tp->tx_skbuff[i])
+		{
+			dev_kfree_skb (tp->tx_skbuff[i]);
+			tp->tx_skbuff[i] = NULL;
+			tp->stats.tx_dropped++;
+		}
+	}
+}
+
+
+static void xenon_net_tx_timeout (struct net_device *dev)
+{
+	/* Error handling was taken from eexpress.c */
+	struct xenon_net_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int flags;
+
+	XENONNET_W32(InterruptMask, 0);
+
+	disable_irq(dev->irq);
+
+	printk(KERN_INFO "%s: transmit timed out, reseting.\n", dev->name);
+
+	/* Stop a shared interrupt from scavenging while we are. */
+	//spin_lock_irq(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
+	xenon_net_tx_clear(tp);
+	xenon_net_hw_start(dev);
+	//spin_unlock_irq(&tp->lock);
+	spin_unlock_irqrestore(&tp->lock, flags);
+	enable_irq(dev->irq);
+
+	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
+	netif_wake_queue(dev);
+
+	/*
+	printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
+		(SCB_complete(status)?"lost interrupt":
+		 "board on fire"));
+	printk("unhandled net tx timeout\n");
+	struct net_local *lp = netdev_priv(dev);
+	lp->stats.tx_errors++;
+	lp->txing = 0;
+	netif_wake_queue(dev);
+	*/
+}
+
+static int xenon_net_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+	struct xenon_net_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int entry;
+	dma_addr_t mapping;
+	u32 len;
+	int flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+//	printk("xenon_net_start_xmit, next_free=%d, next_done=%d\n", atomic_read (&tp->tx_next_free), atomic_read (&tp->tx_next_done));
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = atomic_read (&tp->tx_next_free) % TX_RING_SIZE;
+
+	assert (tp->tx_skbuff[entry] == NULL);
+	assert (tp->tx_skbuff_dma[entry] == 0);
+	assert (skb_shinfo(skb)->nr_frags == 0);
+
+	tp->tx_skbuff[entry] = skb;
+
+	len = skb->len;
+
+	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	tp->tx_skbuff_dma[entry] = mapping;
+
+	xenon_set_tx_descriptor(tp, entry, skb->len, mapping, 1);
+
+	dev->trans_start = jiffies;
+	atomic_inc (&tp->tx_next_free);
+	if ((atomic_read (&tp->tx_next_free) - atomic_read (&tp->tx_next_done)) >= TX_RING_SIZE)
+	{
+//		printk("tx queue full\n");
+		netif_stop_queue (dev);
+	}
+
+
+//	printk("TxDescriptorStatus: %08x\n", XENONNET_R32(TxDescriptorStatus));
+
+//	printk("%s: Queued Tx packet at %p size %u to slot %d.\n",
+//		 dev->name, skb->data, skb->len, entry);
+
+	XENONNET_W32(TxConfig, 0x00101c11); /* enable TX */
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return 0;
+}
+
+
+static void xenon_net_tx_interrupt (struct net_device *dev,
+				  struct xenon_net_private *tp,
+				  void *ioaddr)
+{
+	assert (dev != NULL);
+	assert (tp != NULL);
+	assert (ioaddr != NULL);
+
+//	printk("!! net tx interrupt, %d<%d\n", atomic_read(&tp->tx_next_done), atomic_read(&tp->tx_next_free));
+
+	while (atomic_read(&tp->tx_next_free) != atomic_read(&tp->tx_next_done))
+	{
+		int e = atomic_read(&tp->tx_next_done) % TX_RING_SIZE;
+
+		volatile u32 *descr = tp->tx_descriptor_base + e * 0x10;
+//		printk("entry %d: %08x\n", e, le32_to_cpu(descr[1]));
+		if (le32_to_cpu(descr[1]) & 0x80000000)
+			break;
+
+		if (!tp->tx_skbuff[e])
+		{
+			printk("spurious TX complete?!\n");
+			break;
+		}
+
+		pci_unmap_single(tp->pdev, tp->tx_skbuff_dma[e], tp->tx_skbuff[e]->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(tp->tx_skbuff[e]);
+
+		tp->tx_skbuff[e] = 0;
+		tp->tx_skbuff_dma[e] = 0;
+
+		atomic_inc(&tp->tx_next_done);
+	}
+
+	if ((atomic_read(&tp->tx_next_free) - atomic_read(&tp->tx_next_done)) < TX_RING_SIZE)
+		netif_start_queue (dev);
+}
+
+static void xenon_net_rx_interrupt (struct net_device *dev,
+				  struct xenon_net_private *tp, void *ioaddr)
+{
+	assert (dev != NULL);
+	assert (tp != NULL);
+	assert (ioaddr != NULL);
+
+//	printk("!! net rx interrupt\n");
+
+	while (1)
+	{
+		int index = atomic_read(&tp->rx_next);
+		volatile u32 *descr = tp->rx_descriptor_base + index * 0x10;
+		dma_addr_t mapping;
+		u32 size;
+		struct sk_buff *skb = tp->rx_skbuff[index], *new_skb;
+
+		if (le32_to_cpu(descr[1]) & 0x80000000)
+		{
+//			printk("index %d is not busy.\n", index);
+			break;
+		}
+		size = le32_to_cpu(descr[0]) & 0xFFFF;
+//		printk("received frame (index %d): size %d\n", index, size);
+
+		mapping = tp->rx_skbuff_dma[index];
+
+		new_skb = dev_alloc_skb(tp->rx_buf_sz);
+		new_skb->dev = dev;
+
+		pci_unmap_single(tp->pdev, mapping, tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+		skb->ip_summed = CHECKSUM_NONE;
+		skb_put(skb, size);
+		skb->protocol = eth_type_trans (skb, dev);
+//		printk("detected protocol: %08x\n", skb->protocol);
+		netif_receive_skb(skb);
+		dev->last_rx = jiffies;
+
+		mapping = tp->rx_skbuff_dma[index] = pci_map_single(tp->pdev,
+				new_skb->data, tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		tp->rx_skbuff[index] = new_skb;
+
+		xenon_set_rx_descriptor(tp, index, tp->rx_buf_sz, tp->rx_skbuff_dma[index], 1);
+
+		index++; index %= RX_RING_SIZE; atomic_set(&tp->rx_next, index);
+	}
+	XENONNET_W32(RxConfig, 0x00101c11);
+}
+
+static int xenon_net_poll(struct net_device *dev, int *budget)
+{
+	struct xenon_net_private *tp = dev->priv;
+	xenon_net_rx_interrupt(dev, tp, tp->mmio_addr);
+
+	__netif_rx_complete(dev);
+	return 0;
+}
+
+static irqreturn_t xenon_net_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct xenon_net_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u32 status;
+
+	spin_lock (&tp->lock);
+
+	status = XENONNET_R32(InterruptStatus);
+
+	if (status & 0x40)
+	{
+		if (netif_rx_schedule_prep(dev)) {
+			status &= ~0x40;
+			__netif_rx_schedule (dev);
+		}
+	}
+
+	if (status & 4)
+	{
+		xenon_net_tx_interrupt(dev, tp, ioaddr);
+		status &= ~0x4;
+	}
+
+//	if (status)
+//		printk("other interrupt: %08x\n", status);
+
+	spin_unlock (&tp->lock);
+
+	return IRQ_HANDLED;
+}
+
+
+static int xenon_net_close (struct net_device *dev)
+{
+	struct xenon_net_private *tp = dev->priv;
+//	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	printk ("ENTER\n");
+
+	netif_stop_queue (dev);
+	spin_lock_irqsave (&tp->lock, flags);
+	spin_unlock_irqrestore (&tp->lock, flags);
+	synchronize_irq (dev->irq);
+	free_irq (dev->irq, dev);
+	xenon_net_tx_clear (tp);
+
+	pci_free_consistent(tp->pdev, TX_RING_SIZE * 0x10 + RX_RING_SIZE * 0x10,
+			    tp->tx_descriptor_base, tp->tx_descriptor_base_dma);
+	tp->tx_descriptor_base = NULL;
+	tp->rx_descriptor_base = NULL;
+
+	printk ("EXIT\n");
+	return 0;
+}
+
+
+static struct pci_driver xenon_net_pci_driver = {
+	.name		= MODNAME,
+	.id_table	= xenon_net_pci_tbl,
+	.probe		= xenon_net_init_one,
+	.remove		= __devexit_p(xenon_net_remove_one),
+};
+
+
+static int __init xenon_net_init_module (void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
+	printk("xenon_net_init_module\n");
+	return pci_module_init (&xenon_net_pci_driver);
+}
+
+
+static void __exit xenon_net_cleanup_module (void)
+{
+	pci_unregister_driver (&xenon_net_pci_driver);
+}
+
+
+module_init(xenon_net_init_module);
+module_exit(xenon_net_cleanup_module);

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 5/7] xenon: add SATA support
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
                   ` (3 preceding siblings ...)
  2007-03-07 18:01 ` [patch 4/7] xenon: add southbridge ethernet support Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 21:02   ` Sergei Shtylyov
  2007-03-07 18:01 ` [patch 6/7] xenon: add SMC support Felix Domke
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This adds support for the HDD and DVD SATA controller on the xenon southbridge.

It also disables ATA_TFLAG_POLLING in libata-core, which prevented the DVD drive
from being detected. It needs to be investigated what exactly is wrong here. 

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 drivers/ata/Kconfig       |    8 +
 drivers/ata/Makefile      |    1 
 drivers/ata/libata-core.c |    2 
 drivers/ata/sata_xenon.c  |  272 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 282 insertions(+), 1 deletion(-)

Index: linux-2.6.20/drivers/ata/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/ata/Kconfig	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/ata/Kconfig	2007-03-07 19:01:22.000000000 +0100
@@ -123,6 +123,14 @@
 
 	  If unsure, say N.
 
+config SATA_XENON
+	tristate "Xenon SATA support"
+	depends on PCI
+	help
+	  This option enables support for Xenon southbridge.
+
+	  If unsure, say N.
+
 config SATA_ULI
 	tristate "ULi Electronics SATA support"
 	depends on PCI
Index: linux-2.6.20/drivers/ata/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/ata/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/ata/Makefile	2007-03-07 19:01:22.000000000 +0100
@@ -11,6 +11,7 @@
 obj-$(CONFIG_SATA_VIA)		+= sata_via.o
 obj-$(CONFIG_SATA_VITESSE)	+= sata_vsc.o
 obj-$(CONFIG_SATA_SIS)		+= sata_sis.o
+obj-$(CONFIG_SATA_XENON)	+= sata_xenon.o
 obj-$(CONFIG_SATA_SX4)		+= sata_sx4.o
 obj-$(CONFIG_SATA_NV)		+= sata_nv.o
 obj-$(CONFIG_SATA_ULI)		+= sata_uli.o
Index: linux-2.6.20/drivers/ata/libata-core.c
===================================================================
--- linux-2.6.20.orig/drivers/ata/libata-core.c	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/ata/libata-core.c	2007-03-07 19:01:22.000000000 +0100
@@ -1478,7 +1478,7 @@
 	}
 
 	tf.protocol = ATA_PROT_PIO;
-	tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */
+//	tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */
 
 	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
 				     id, sizeof(id[0]) * ATA_ID_WORDS);
Index: linux-2.6.20/drivers/ata/sata_xenon.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/ata/sata_xenon.c	2007-03-07 19:01:22.000000000 +0100
@@ -0,0 +1,272 @@
+/*
+ *  sata_xenon.c - SATA support for xenon southbridge
+ *
+ *  based on sata_sis.c, modifications by anonymous xbox360 hacker,
+ *
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_xenon"
+#define DRV_VERSION	"0.1"
+
+	/* small note: it's completely unknown whether the xenon southbridge sata
+	   is really based on SiS technology.
+	   Most of SATA is standardized anyway.
+
+
+	   So, we have these two pci devices, one for each port.
+
+	   They have two BARs, one for the IDE registers (0..7,
+	   altstatus/devctl is +0xA), and one for the BMDMA.
+
+	   SCR seem to be sis-like in pci config space, but that should
+	   be verified!
+
+	   Note on the DVD-ROM part:
+
+	   The drives usually require some tweaks to be usable under linux.
+
+	   You either need to hack the scsi layer, or, in case of the GDR3120L,
+	   set 'modeB' in the bootloader.
+	*/
+
+enum {
+	/* PCI configuration registers */
+	SIS_SCR_BASE		= 0xc0, /* sata0 phy SCR registers */
+};
+
+extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
+						 const struct ata_port_info *port);
+
+static int xenon_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 xenon_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void xenon_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static const struct pci_device_id xenon_pci_tbl[] = {
+	{ PCI_VDEVICE(MICROSOFT, 0x5803), 0 },
+	{ PCI_VDEVICE(MICROSOFT, 0x5802), 0 },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver xenon_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= xenon_pci_tbl,
+	.probe			= xenon_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static struct scsi_host_template xenon_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= ATA_MAX_PRD,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	.bios_param		= ata_std_bios_param,
+};
+
+static const struct ata_port_operations xenon_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.data_xfer		= ata_pio_data_xfer,
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= ata_bmdma_error_handler,
+	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= xenon_scr_read,
+	.scr_write		= xenon_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+	.host_stop		= ata_host_stop,
+};
+
+static struct ata_port_info xenon_port_info = {
+	.sht		= &xenon_sht,
+	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x7,
+	.udma_mask	= 0x7f,
+	.port_ops	= &xenon_ops,
+};
+
+
+MODULE_DESCRIPTION("low-level driver for Xenon Southbridge SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, xenon_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
+{
+	unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+
+	return addr;
+}
+
+static u32 xenon_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
+	u32 val;
+
+	if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
+		return 0; /* assume no error */
+
+	pci_read_config_dword(pdev, cfg_addr, &val);
+
+	return val;
+}
+
+static void xenon_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
+
+	if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+		return;
+
+	pci_write_config_dword(pdev, cfg_addr, val);
+}
+
+static u32 xenon_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	return xenon_scr_cfg_read(ap, sc_reg);
+}
+
+static void xenon_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+
+	xenon_scr_cfg_write(ap, sc_reg, val);
+}
+
+static int xenon_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	int rc;
+	int pci_dev_busy = 0;
+
+	if (!printed_version++)
+		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), &xenon_port_info);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = IRQF_SHARED;
+
+	probe_ent->port->cmd_addr = (long)ioremap(pci_resource_start(pdev, 0), PAGE_SIZE);
+	probe_ent->port->altstatus_addr = probe_ent->port->cmd_addr + 0xa;
+	probe_ent->port->ctl_addr = probe_ent->port->cmd_addr + 0xa;
+	probe_ent->port->bmdma_addr = (long)ioremap(pci_resource_start(pdev, 1), PAGE_SIZE);
+	ata_std_ports(probe_ent->port);
+	probe_ent->n_ports = 1;
+
+	pci_set_master(pdev);
+	pci_intx(pdev, 1);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+
+}
+
+static int __init xenon_init(void)
+{
+	return pci_register_driver(&xenon_pci_driver);
+}
+
+static void __exit xenon_exit(void)
+{
+	pci_unregister_driver(&xenon_pci_driver);
+}
+
+module_init(xenon_init);
+module_exit(xenon_exit);
+

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 6/7] xenon: add SMC support
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
                   ` (4 preceding siblings ...)
  2007-03-07 18:01 ` [patch 5/7] xenon: add SATA support Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 21:54   ` Arnd Bergmann
  2007-03-08 23:29   ` Linas Vepstas
  2007-03-07 18:01 ` [patch 7/7] xenon: add framebuffer support (ugly) Felix Domke
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This adds lowlevel support for the "System Management Controller"
on the Xenon southbridge, which controls power, the frontpanel leds, 
infrared remote, tilt switch, AVIP detection, RTC and DVD tray control.

It requires a userspace daemon.

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 drivers/char/Kconfig     |    6 +
 drivers/char/Makefile    |    1 
 drivers/char/xenon_smc.c |  280 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)

Index: linux-2.6.20/drivers/char/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/char/Kconfig	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/char/Kconfig	2007-03-07 19:01:22.000000000 +0100
@@ -350,6 +350,12 @@
 	  this case.  If you have never heard about all this, it's safe to
 	  say N.
 
+config XENON_SMC
+	bool "Xenon SMC"
+	depends on PPC_XENON
+	help
+	  SMC controller in the Xbox 360.
+
 config STALLION
 	tristate "Stallion EasyIO or EC8/32 support"
 	depends on STALDRV && BROKEN_ON_SMP
Index: linux-2.6.20/drivers/char/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/char/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/char/Makefile	2007-03-07 19:01:22.000000000 +0100
@@ -55,6 +55,7 @@
 obj-$(CONFIG_HVCS)		+= hvcs.o
 obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
 obj-$(CONFIG_BRIQ_PANEL)	+= briq_panel.o
+obj-$(CONFIG_XENON_SMC)  += xenon_smc.o
 
 obj-$(CONFIG_PRINTER)		+= lp.o
 obj-$(CONFIG_TIPAR)		+= tipar.o
Index: linux-2.6.20/drivers/char/xenon_smc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/char/xenon_smc.c	2007-03-07 19:01:22.000000000 +0100
@@ -0,0 +1,280 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#define DRV_NAME	"xenon_smc"
+#define DRV_VERSION	"0.1"
+
+struct xenon_smc
+{
+	void __iomem *base;
+	unsigned long is_active;
+	wait_queue_head_t wait;
+};
+
+static struct xenon_smc *first_smc;
+
+#define to_smc(pdev) dev_get_drvdata(&pdev->dev)
+
+static int get_smc(struct xenon_smc *ctx, u8 *msg);
+static void send_smc(struct xenon_smc *ctx, void *msg);
+static irqreturn_t xenon_smc_irq(int irq, void *dev_id);
+static ssize_t smc_write(struct file *file, const char __user *data,
+				size_t len, loff_t *ppos);
+static int smc_ioctl(struct inode *inode, struct file *file,
+				unsigned int cmd, unsigned long arg);
+static ssize_t smc_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos);
+static int smc_open(struct inode *inode, struct file *file);
+static int smc_release(struct inode *inode, struct file *file);
+static int xenon_smc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void __devexit xenon_smc_remove(struct pci_dev *pdev);
+
+static const struct pci_device_id xenon_smc_pci_tbl[] = {
+	{ PCI_VDEVICE(MICROSOFT, 0x580d), 0 },
+	{ }	/* terminate list */
+};
+
+static struct pci_driver xenon_smc_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= xenon_smc_pci_tbl,
+	.probe			= xenon_smc_init_one,
+	.remove     = __devexit_p(xenon_smc_remove)
+};
+
+static const struct file_operations smc_fops = {
+	.owner =  THIS_MODULE,
+	.llseek = no_llseek,
+	.write =  smc_write,
+	.ioctl =  smc_ioctl,
+	.open =	  smc_open,
+	.read =   smc_read,
+	.release = smc_release,
+};
+
+static struct miscdevice smc_miscdev = {
+	.minor =  RTC_MINOR,
+	.name =   "smc",
+	.fops =	  &smc_fops,
+};
+
+MODULE_DESCRIPTION("Driver for Xenon Southbridge SMC");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, xenon_smc_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static int get_smc(struct xenon_smc *ctx, u8 *msg)
+{
+	if (readl(ctx->base + 0x94) & 4)
+	{
+		u32 *message = (u32*)msg;
+		int i;
+		writel(4, ctx->base + 0x94);
+		for (i=0; i<4; ++i)
+			message[i] = __raw_readl(ctx->base + 0x90);
+		writel(0, ctx->base + 0x94);
+		return 1;
+	}
+	return 0;
+}
+
+static void send_smc(struct xenon_smc *ctx, void *msg)
+{
+	while (!(readl(ctx->base + 0x84) & 4));
+	writel(4, ctx->base + 0x84);
+	__raw_writel(*(u32*)(msg+0), ctx->base + 0x80);
+	__raw_writel(*(u32*)(msg+4), ctx->base + 0x80);
+	__raw_writel(*(u32*)(msg+8), ctx->base + 0x80);
+	__raw_writel(*(u32*)(msg+12), ctx->base + 0x80);
+	writel(0, ctx->base + 0x84);
+}
+
+static irqreturn_t xenon_smc_irq(int irq, void *dev_id)
+{
+	struct pci_dev *pdev = dev_id;
+	struct xenon_smc *ctx = to_smc(pdev);
+
+	unsigned int irqs = readl(ctx->base + 0x50) & 0x10000000;
+	if (irqs)
+		wake_up(&ctx->wait);
+
+	writel(irqs, ctx->base + 0x58); // ack irq
+
+	return IRQ_HANDLED;
+}
+
+static ssize_t smc_write(struct file *file, const char __user *data,
+			     size_t len, loff_t *ppos)
+{
+	unsigned char msg[16];
+	if (len != 16)
+		return -EINVAL;
+
+	if (copy_from_user(msg, data, 16))
+		return -EFAULT;
+
+	send_smc(first_smc, msg);
+
+	return 16;
+}
+
+static int smc_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static ssize_t smc_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	struct xenon_smc *ctx = first_smc;
+	int ret;
+	u8 msg[0x10];
+
+	if (len != 16)
+		return -EINVAL;
+
+	if (!(readl(ctx->base + 0x94) & 4))
+	{
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		ret = wait_event_interruptible(ctx->wait, readl(ctx->base + 0x94) & 4);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (get_smc(ctx, msg) == 0)
+		return -EAGAIN;
+
+	if (copy_to_user(data, msg, 0x10))
+		return -EFAULT;
+
+	return 0x10;
+}
+
+static int smc_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &first_smc->is_active))
+		return -EBUSY;
+
+	return nonseekable_open(inode, file);
+}
+
+static int smc_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &first_smc->is_active);
+	return 0;
+}
+
+static void show_logo(struct xenon_smc *ctx)
+{
+	unsigned char msg[16] = {0x99, 0x01, 0x63, 0};
+	send_smc(ctx, msg);
+}
+
+static int xenon_smc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	int rc;
+	int pci_dev_busy = 0;
+	struct xenon_smc *ctx;
+	unsigned long mmio_start;
+
+	if (!printed_version++)
+		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	ctx = kzalloc(sizeof(struct xenon_smc), GFP_KERNEL);
+	if (!ctx)
+		goto err_out_free;
+
+	dev_set_drvdata(&pdev->dev, ctx);
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	pci_intx(pdev, 1);
+
+	printk(KERN_INFO "attached to xenon SMC\n");
+
+	rc = misc_register(&smc_miscdev);
+	if (rc != 0)
+	{
+		printk(KERN_ERR "xenonsmc: misc_register failed.\n");
+		goto err_out_regions;
+	}
+
+	mmio_start = pci_resource_start (pdev, 0);
+	ctx->base = ioremap(mmio_start, 0x100);
+
+	if (!first_smc)
+		first_smc = ctx;
+
+	init_waitqueue_head(&ctx->wait);
+
+	if (request_irq(pdev->irq, xenon_smc_irq, IRQF_SHARED, "xenonsmc", pdev))
+	{
+		printk(KERN_ERR "xenonsmc: request_irq failed\n");
+		goto err_out_ioremap;
+	}
+
+	show_logo(ctx);
+
+	return 0;
+
+err_out_ioremap:
+	iounmap(ctx->base);
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out_free:
+	kfree(ctx);
+
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+
+}
+
+static void __devexit xenon_smc_remove(struct pci_dev *pdev)
+{
+	struct xenon_smc *ctx = to_smc(pdev);
+
+	if (ctx == first_smc)
+		first_smc = 0;
+
+	misc_deregister(&smc_miscdev);
+	iounmap(ctx->base);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static int __init xenon_smc_init(void)
+{
+	return pci_register_driver(&xenon_smc_pci_driver);
+}
+
+static void __exit xenon_smc_exit(void)
+{
+	pci_unregister_driver(&xenon_smc_pci_driver);
+}
+
+module_init(xenon_smc_init);
+module_exit(xenon_smc_exit);

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [patch 7/7] xenon: add framebuffer support (ugly)
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
                   ` (5 preceding siblings ...)
  2007-03-07 18:01 ` [patch 6/7] xenon: add SMC support Felix Domke
@ 2007-03-07 18:01 ` Felix Domke
  2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
  2007-03-08  0:35 ` Stephen Rothwell
  8 siblings, 0 replies; 23+ messages in thread
From: Felix Domke @ 2007-03-07 18:01 UTC (permalink / raw)
  To: Linuxppc-dev

This adds support for a framebuffer on the "Xenos" graphics chip used in the
Xbox 360 machine. It requires a pre-initialized framebuffer.

The major problem is that the graphics chip only supports a 'tiled' mode,
thus this patch also uses some serious ugly patches to allow the framebuffer
console to handle this. So this patch is given just for completeness, to have 
a working console output, and of course not meant for inclusion into the 
kernel.

This patch can probably be rewritten using the deferred io support in a
much nicer way.

Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

---
 drivers/video/Kconfig     |    9 +
 drivers/video/Makefile    |    1 
 drivers/video/cfbimgblt.c |   23 +--
 drivers/video/xenonfb.c   |  337 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fb.h        |   12 +
 5 files changed, 373 insertions(+), 9 deletions(-)

Index: linux-2.6.20/drivers/video/Kconfig
===================================================================
--- linux-2.6.20.orig/drivers/video/Kconfig	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/video/Kconfig	2007-03-07 19:01:23.000000000 +0100
@@ -568,6 +568,15 @@
 	help
 	  This is the frame buffer device driver for the Intel-based Macintosh
 
+config FB_XENON
+	bool "Xbox 360 Framebuffer Support"
+	depends on (FB = y) && PPC
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the frame buffer device driver for the Microsoft Xbox 360.
+
 config FB_HGA
 	tristate "Hercules mono graphics support"
 	depends on FB && X86
Index: linux-2.6.20/drivers/video/Makefile
===================================================================
--- linux-2.6.20.orig/drivers/video/Makefile	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/video/Makefile	2007-03-07 19:01:23.000000000 +0100
@@ -104,6 +104,7 @@
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_IMAC)             += imacfb.o
+obj-$(CONFIG_FB_XENON)            += xenonfb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
 
Index: linux-2.6.20/drivers/video/cfbimgblt.c
===================================================================
--- linux-2.6.20.orig/drivers/video/cfbimgblt.c	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/drivers/video/cfbimgblt.c	2007-03-07 19:01:23.000000000 +0100
@@ -72,8 +72,13 @@
 	0x00000000, 0xffffffff
 };
 
-#define FB_WRITEL fb_writel
-#define FB_READL  fb_readl
+#if 0
+#define FB_WRITEL(p,b,addr) fb_writel(b,addr)
+#define FB_READL(p,addr)  fb_readl(addr)
+#else
+#define FB_READL(p,addr)  fb_readl(xenon_convert(p, addr))
+#define FB_WRITEL(p,b,addr) fb_writel(b, xenon_convert(p, addr))
+#endif
 
 static inline void color_imageblit(const struct fb_image *image, 
 				   struct fb_info *p, u8 __iomem *dst1, 
@@ -97,7 +102,7 @@
 		
 		if (start_index) {
 			u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
-			val = FB_READL(dst) & start_mask;
+			val = FB_READL(p, dst) & start_mask;
 			shift = start_index;
 		}
 		while (n--) {
@@ -109,7 +114,7 @@
 			color <<= FB_LEFT_POS(bpp);
 			val |= FB_SHIFT_HIGH(color, shift);
 			if (shift >= null_bits) {
-				FB_WRITEL(val, dst++);
+				FB_WRITEL(p, val, dst++);
 	
 				val = (shift == null_bits) ? 0 : 
 					FB_SHIFT_LOW(color, 32 - shift);
@@ -121,7 +126,7 @@
 		if (shift) {
 			u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
 
-			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+			FB_WRITEL(p, (FB_READL(p, dst) & end_mask) | val, dst);
 		}
 		dst1 += p->fix.line_length;
 		if (pitch_index) {
@@ -162,7 +167,7 @@
 		/* write leading bits */
 		if (start_index) {
 			u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
-			val = FB_READL(dst) & start_mask;
+			val = FB_READL(p, dst) & start_mask;
 			shift = start_index;
 		}
 
@@ -173,7 +178,7 @@
 			
 			/* Did the bitshift spill bits to the next long? */
 			if (shift >= null_bits) {
-				FB_WRITEL(val, dst++);
+				FB_WRITEL(p, val, dst++);
 				val = (shift == null_bits) ? 0 :
 					FB_SHIFT_LOW(color,32 - shift);
 			}
@@ -186,7 +191,7 @@
  		if (shift) {
 			u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
 
-			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
+			FB_WRITEL(p, (FB_READL(p, dst) & end_mask) | val, dst);
 		}
 		
 		dst1 += pitch;
@@ -251,7 +256,7 @@
 		for (j = k; j--; ) {
 			shift -= ppw;
 			end_mask = tab[(*src >> shift) & bit_mask];
-			FB_WRITEL((end_mask & eorx)^bgx, dst++);
+			FB_WRITEL(p, (end_mask & eorx)^bgx, dst++);
 			if (!shift) { shift = 8; src++; }		
 		}
 		dst1 += p->fix.line_length;
Index: linux-2.6.20/include/linux/fb.h
===================================================================
--- linux-2.6.20.orig/include/linux/fb.h	2007-03-07 19:01:12.000000000 +0100
+++ linux-2.6.20/include/linux/fb.h	2007-03-07 19:01:23.000000000 +0100
@@ -907,6 +907,18 @@
 	}
 }
 
+static inline int *xenon_convert(struct fb_info *p, int *addr)
+{
+	int index = ((char*)addr) - ((char*)p->screen_base);
+	int y = index / (p->fix.line_length);
+	int x = index % (p->fix.line_length)/4;
+	unsigned int base = ((((y & ~31)*p->var.xres) + (x & ~31)*32 ) +
+	 (((x&3) + ((y&1)<<2) + ((x&28)<<1) + ((y&30)<<5)) ^ ((y&8)<<2))) * 4;
+
+	return (int*)(((char*)p->screen_base)+base);
+}
+
+
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
Index: linux-2.6.20/drivers/video/xenonfb.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.20/drivers/video/xenonfb.c	2007-03-07 19:01:23.000000000 +0100
@@ -0,0 +1,337 @@
+/*
+ * framebuffer driver for Microsoft Xbox 360
+ *
+ * (c) 2006 ...
+ * Original vesafb driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+
+#include <video/vga.h>
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo xenonfb_defined __initdata = {
+	.activate		= FB_ACTIVATE_NOW,
+	.height			= -1,
+	.width			= -1,
+	.right_margin		= 32,
+	.upper_margin		= 16,
+	.lower_margin		= 4,
+	.vsync_len		= 4,
+	.vmode			= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo xenonfb_fix __initdata = {
+	.id			= "XENON FB",
+	.type			= FB_TYPE_PACKED_PIXELS,
+	.accel			= FB_ACCEL_NONE,
+	.visual			= FB_VISUAL_TRUECOLOR,
+};
+
+typedef struct {
+	uint32_t unknown1[4];
+	uint32_t base;
+	uint32_t unknown2[8];
+	uint32_t width;
+	uint32_t height;
+} ati_info;
+
+#define	DEFAULT_FB_MEM	1024*1024*16
+
+/* --------------------------------------------------------------------- */
+
+static int xenonfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *info)
+{
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	if (regno < 16) {
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+	}
+	return 0;
+}
+
+#define XENON_XY_TO_STD_PTR(x,y) ((int*)(((char*)p->screen_base)+y*p->fix.line_length+x*(p->var.bits_per_pixel/8)))
+#define XENON_XY_TO_XENON_PTR(x,y) xenon_convert(p, XENON_XY_TO_STD_PTR(x,y))
+
+inline void xenon_pset(struct fb_info *p, int x, int y, int color)
+{
+	fb_writel(color, XENON_XY_TO_XENON_PTR(x,y));
+}
+
+inline int xenon_pget(struct fb_info *p, int x, int y)
+{
+	return fb_readl(XENON_XY_TO_XENON_PTR(x,y));
+}
+
+void xenon_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+
+	__u32 x, y;
+	for (y=0; y<rect->height; y++) {
+		for (x=0; x<rect->width; x++) {
+			xenon_pset(p, rect->dx+x, rect->dy+y, rect->color);
+
+		}
+	}
+}
+
+void xenon_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+
+	/* if the beginning of the target area might overlap with the end of
+	the source area, be have to copy the area reverse. */
+	if ((area->dy == area->sy && area->dx > area->sx) || (area->dy > area->sy)) {
+		__s32 x, y;
+		for (y=area->height-1; y>0; y--) {
+			for (x=area->width-1; x>0; x--) {
+				xenon_pset(p, area->dx+x, area->dy+y, xenon_pget(p, area->sx+x, area->sy+y));
+			}
+		}
+	} else {
+		__u32 x, y;
+		for (y=0; y<area->height; y++) {
+			for (x=0; x<area->width; x++) {
+				xenon_pset(p, area->dx+x, area->dy+y, xenon_pget(p, area->sx+x, area->sy+y));
+			}
+		}
+	}
+}
+
+static struct fb_ops xenonfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= xenonfb_setcolreg,
+	.fb_fillrect	= xenon_fillrect,
+	.fb_copyarea	= xenon_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __init xenonfb_probe(struct platform_device *dev)
+{
+	struct fb_info *info;
+	int err;
+	unsigned int size_vmode;
+	unsigned int size_remap;
+	unsigned int size_total;
+
+	screen_info.lfb_depth = 32;
+	screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
+	screen_info.pages=1;
+	screen_info.blue_size = 8;
+	screen_info.blue_pos = 24;
+	screen_info.green_size = 8;
+	screen_info.green_pos = 16;
+	screen_info.red_size = 8;
+	screen_info.red_pos = 8;
+	screen_info.rsvd_size = 8;
+	screen_info.rsvd_pos = 0;
+
+	ati_info *ai = ioremap(0x200ec806100ULL, sizeof(ati_info));
+
+
+
+
+
+
+
+	screen_info.lfb_base = ai->base;
+	screen_info.lfb_width = ai->width;
+	screen_info.lfb_height = ai->height;
+	screen_info.lfb_linelength = screen_info.lfb_width * screen_info.lfb_depth/4;
+
+	printk(KERN_INFO "xenonfb: detected %dx%d framebuffer @ 0x%08x\n", screen_info.lfb_width, screen_info.lfb_height, screen_info.lfb_base);
+
+
+	iounmap(ai);
+
+	xenonfb_fix.smem_start = screen_info.lfb_base;
+	xenonfb_defined.bits_per_pixel = screen_info.lfb_depth;
+	xenonfb_defined.xres = screen_info.lfb_width;
+	xenonfb_defined.yres = screen_info.lfb_height;
+	xenonfb_defined.xoffset = 0;
+	xenonfb_defined.yoffset = 0;
+	xenonfb_fix.line_length = screen_info.lfb_linelength;
+
+	/*   size_vmode -- that is the amount of memory needed for the
+	 *                 used video mode, i.e. the minimum amount of
+	 *                 memory we need. */
+	size_vmode = xenonfb_defined.yres * xenonfb_fix.line_length;
+
+	/*   size_total -- all video memory we have. Used for
+	 *                 entries, ressource allocation and bounds
+	 *                 checking. */
+	size_total = screen_info.lfb_size * 65536;
+	if (size_total < size_vmode)
+		size_total = size_vmode;
+
+	/*   size_remap -- the amount of video memory we are going to
+	 *                 use for xenonfb.  With modern cards it is no
+	 *                 option to simply use size_total as that
+	 *                 wastes plenty of kernel address space. */
+	size_remap  = size_vmode * 2;
+	if (size_remap < size_vmode)
+		size_remap = size_vmode;
+	if (size_remap > size_total)
+		size_remap = size_total;
+	xenonfb_fix.smem_len = size_remap;
+
+	if (!request_mem_region(xenonfb_fix.smem_start, size_total, "xenonfb")) {
+		printk(KERN_WARNING
+		       "xenonfb: cannot reserve video memory at 0x%lx\n",
+			xenonfb_fix.smem_start);
+		/* We cannot make this fatal. Sometimes this comes from magic
+		   spaces our resource handlers simply don't know about */
+	}
+
+	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+	if (!info) {
+		err = -ENOMEM;
+		goto err_release_mem;
+	}
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+
+	info->screen_base = ioremap(xenonfb_fix.smem_start, xenonfb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR "xenonfb: abort, cannot ioremap video memory "
+				"0x%x @ 0x%lx\n",
+			xenonfb_fix.smem_len, xenonfb_fix.smem_start);
+		err = -EIO;
+		goto err_unmap;
+	}
+
+	printk(KERN_INFO "xenonfb: framebuffer at 0x%lx, mapped to 0x%p, "
+	       "using %dk, total %dk\n",
+	       xenonfb_fix.smem_start, info->screen_base,
+	       size_remap/1024, size_total/1024);
+	printk(KERN_INFO "xenonfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+	       xenonfb_defined.xres, xenonfb_defined.yres,
+	       xenonfb_defined.bits_per_pixel, xenonfb_fix.line_length,
+	       screen_info.pages);
+
+	xenonfb_defined.xres_virtual = xenonfb_defined.xres;
+	xenonfb_defined.yres_virtual = xenonfb_fix.smem_len /
+					xenonfb_fix.line_length;
+	printk(KERN_INFO "xenonfb: scrolling: redraw\n");
+	xenonfb_defined.yres_virtual = xenonfb_defined.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	xenonfb_defined.pixclock     = 10000000 / xenonfb_defined.xres *
+					1000 / xenonfb_defined.yres;
+	xenonfb_defined.left_margin  = (xenonfb_defined.xres / 8) & 0xf8;
+	xenonfb_defined.hsync_len    = (xenonfb_defined.xres / 8) & 0xf8;
+
+	xenonfb_defined.red.offset    = screen_info.red_pos;
+	xenonfb_defined.red.length    = screen_info.red_size;
+	xenonfb_defined.green.offset  = screen_info.green_pos;
+	xenonfb_defined.green.length  = screen_info.green_size;
+	xenonfb_defined.blue.offset   = screen_info.blue_pos;
+	xenonfb_defined.blue.length   = screen_info.blue_size;
+	xenonfb_defined.transp.offset = screen_info.rsvd_pos;
+	xenonfb_defined.transp.length = screen_info.rsvd_size;
+
+	printk(KERN_INFO "xenonfb: %s: "
+	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+	       "Truecolor",
+	       screen_info.rsvd_size,
+	       screen_info.red_size,
+	       screen_info.green_size,
+	       screen_info.blue_size,
+	       screen_info.rsvd_pos,
+	       screen_info.red_pos,
+	       screen_info.green_pos,
+	       screen_info.blue_pos);
+
+	xenonfb_fix.ypanstep  = 0;
+	xenonfb_fix.ywrapstep = 0;
+
+	/* request failure does not faze us, as vgacon probably has this
+	 * region already (FIXME) */
+	request_region(0x3c0, 32, "xenonfb");
+
+	info->fbops = &xenonfb_ops;
+	info->var = xenonfb_defined;
+	info->fix = xenonfb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		err = -ENOMEM;
+		goto err_unmap;
+	}
+	if (register_framebuffer(info)<0) {
+		err = -EINVAL;
+		goto err_fb_dealoc;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+	return 0;
+
+err_fb_dealoc:
+	fb_dealloc_cmap(&info->cmap);
+err_unmap:
+	iounmap(info->screen_base);
+	framebuffer_release(info);
+err_release_mem:
+	release_mem_region(xenonfb_fix.smem_start, size_total);
+	return err;
+}
+
+static struct platform_driver xenonfb_driver = {
+	.probe	= xenonfb_probe,
+	.driver	= {
+		.name	= "xenonfb",
+	},
+};
+
+static struct platform_device xenonfb_device = {
+	.name	= "xenonfb",
+};
+
+static int __init xenonfb_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&xenonfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&xenonfb_device);
+		if (ret)
+			platform_driver_unregister(&xenonfb_driver);
+	}
+	return ret;
+}
+module_init(xenonfb_init);
+
+MODULE_LICENSE("GPL");
+

--

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 3/7] xenon: udbg support (ugly)
  2007-03-07 18:01 ` [patch 3/7] xenon: udbg support (ugly) Felix Domke
@ 2007-03-07 21:00   ` Geert Uytterhoeven
  0 siblings, 0 replies; 23+ messages in thread
From: Geert Uytterhoeven @ 2007-03-07 21:00 UTC (permalink / raw)
  To: Felix Domke; +Cc: Linux/PPC Development

On Wed, 7 Mar 2007, Felix Domke wrote:
> --- linux-2.6.20.orig/arch/powerpc/kernel/udbg.c	2007-03-07 19:01:12.000000000 +0100
> +++ linux-2.6.20/arch/powerpc/kernel/udbg.c	2007-03-07 19:01:21.000000000 +0100
> @@ -25,6 +25,18 @@
>   * Early debugging facilities. You can enable _one_ of these via .config,
>   * if you do so your kernel _will not boot_ on anything else. Be careful.
>   */
> +
> +extern u8 real_readb(volatile u8 __iomem  *addr);
> +extern void real_writeb(u8 data, volatile u8 __iomem *addr);
> +
> +void udbg_xenon_real_putc(char c)
> +{
> +	if (c == '\n')
> +		udbg_xenon_real_putc('\r');
> +	while (!(real_readb((void*)0x80000200ea001018ULL)&0x02));
> +	real_writeb(c, (void*)0x80000200ea001014ULL);
> +}
> +
>  void __init udbg_early_init(void)
>  {
>  #if defined(CONFIG_PPC_EARLY_DEBUG_LPAR)
> @@ -46,6 +58,7 @@
>  	/* For iSeries - hit Ctrl-x Ctrl-x to see the output */
>  	udbg_init_iseries();
>  #endif
> +	udbg_putc = udbg_xenon_real_putc;

No #ifdef?

>  }
>  
>  /* udbg library, used by xmon et al */
> @@ -150,6 +163,7 @@
>  		printk(KERN_INFO "early console immortal !\n");
>  		return;
>  	}
> +	return;

??

>  	unregister_console(&udbg_console);
>  	early_console_initialized = 0;
>  }

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 5/7] xenon: add SATA support
  2007-03-07 18:01 ` [patch 5/7] xenon: add SATA support Felix Domke
@ 2007-03-07 21:02   ` Sergei Shtylyov
  2007-03-07 21:07     ` Felix Domke
  0 siblings, 1 reply; 23+ messages in thread
From: Sergei Shtylyov @ 2007-03-07 21:02 UTC (permalink / raw)
  To: Felix Domke; +Cc: Linuxppc-dev, Linux IDE

Felix Domke wrote:
> This adds support for the HDD and DVD SATA controller on the xenon southbridge.

   Pleas post this to linux-ide@vger.kernel.org in the future.

> It also disables ATA_TFLAG_POLLING in libata-core, which prevented the DVD drive
> from being detected. It needs to be investigated what exactly is wrong here. 

> Signed-off-by: Felix Domke <tmbinc@elitedvb.net>

> ---
>  drivers/ata/Kconfig       |    8 +
>  drivers/ata/Makefile      |    1 
>  drivers/ata/libata-core.c |    2 
>  drivers/ata/sata_xenon.c  |  272 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 282 insertions(+), 1 deletion(-)
> 
> Index: linux-2.6.20/drivers/ata/Kconfig
> ===================================================================
> --- linux-2.6.20.orig/drivers/ata/Kconfig	2007-03-07 19:01:12.000000000 +0100
> +++ linux-2.6.20/drivers/ata/Kconfig	2007-03-07 19:01:22.000000000 +0100
> @@ -123,6 +123,14 @@
>  
>  	  If unsure, say N.
>  
> +config SATA_XENON
> +	tristate "Xenon SATA support"
> +	depends on PCI
> +	help
> +	  This option enables support for Xenon southbridge.
> +
> +	  If unsure, say N.
> +
>  config SATA_ULI
>  	tristate "ULi Electronics SATA support"
>  	depends on PCI
> Index: linux-2.6.20/drivers/ata/Makefile
> ===================================================================
> --- linux-2.6.20.orig/drivers/ata/Makefile	2007-03-07 19:01:12.000000000 +0100
> +++ linux-2.6.20/drivers/ata/Makefile	2007-03-07 19:01:22.000000000 +0100
> @@ -11,6 +11,7 @@
>  obj-$(CONFIG_SATA_VIA)		+= sata_via.o
>  obj-$(CONFIG_SATA_VITESSE)	+= sata_vsc.o
>  obj-$(CONFIG_SATA_SIS)		+= sata_sis.o
> +obj-$(CONFIG_SATA_XENON)	+= sata_xenon.o
>  obj-$(CONFIG_SATA_SX4)		+= sata_sx4.o
>  obj-$(CONFIG_SATA_NV)		+= sata_nv.o
>  obj-$(CONFIG_SATA_ULI)		+= sata_uli.o
> Index: linux-2.6.20/drivers/ata/libata-core.c
> ===================================================================
> --- linux-2.6.20.orig/drivers/ata/libata-core.c	2007-03-07 19:01:12.000000000 +0100
> +++ linux-2.6.20/drivers/ata/libata-core.c	2007-03-07 19:01:22.000000000 +0100
> @@ -1478,7 +1478,7 @@
>  	}
>  
>  	tf.protocol = ATA_PROT_PIO;
> -	tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */
> +//	tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */

    I doubt that this could *ever* get accepted.

>  	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
>  				     id, sizeof(id[0]) * ATA_ID_WORDS);
> Index: linux-2.6.20/drivers/ata/sata_xenon.c
> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.20/drivers/ata/sata_xenon.c	2007-03-07 19:01:22.000000000 +0100
> @@ -0,0 +1,272 @@
> +/*
> + *  sata_xenon.c - SATA support for xenon southbridge
> + *
> + *  based on sata_sis.c, modifications by anonymous xbox360 hacker,
> + *
> + *  		    Please ALWAYS copy linux-ide@vger.kernel.org
> + *		    on emails.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2, or (at your option)
> + *  any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; see the file COPYING.  If not, write to
> + *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + *
> + *  libata documentation is available via 'make {ps|pdf}docs',
> + *  as Documentation/DocBook/libata.*
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/init.h>
> +#include <linux/blkdev.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <scsi/scsi_host.h>
> +#include <linux/libata.h>
> +
> +#define DRV_NAME	"sata_xenon"
> +#define DRV_VERSION	"0.1"
> +
> +	/* small note: it's completely unknown whether the xenon southbridge sata
> +	   is really based on SiS technology.
> +	   Most of SATA is standardized anyway.
> +
> +
> +	   So, we have these two pci devices, one for each port.
> +
> +	   They have two BARs, one for the IDE registers (0..7,
> +	   altstatus/devctl is +0xA), and one for the BMDMA.
> +
> +	   SCR seem to be sis-like in pci config space, but that should
> +	   be verified!
> +
> +	   Note on the DVD-ROM part:
> +
> +	   The drives usually require some tweaks to be usable under linux.
> +
> +	   You either need to hack the scsi layer, or, in case of the GDR3120L,
> +	   set 'modeB' in the bootloader.
> +	*/
> +
> +enum {
> +	/* PCI configuration registers */
> +	SIS_SCR_BASE		= 0xc0, /* sata0 phy SCR registers */
> +};
> +
> +extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
> +						 const struct ata_port_info *port);
> +
> +static int xenon_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
> +static u32 xenon_scr_read (struct ata_port *ap, unsigned int sc_reg);
> +static void xenon_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
> +
> +static const struct pci_device_id xenon_pci_tbl[] = {
> +	{ PCI_VDEVICE(MICROSOFT, 0x5803), 0 },
> +	{ PCI_VDEVICE(MICROSOFT, 0x5802), 0 },
> +
> +	{ }	/* terminate list */
> +};
> +
> +static struct pci_driver xenon_pci_driver = {
> +	.name			= DRV_NAME,
> +	.id_table		= xenon_pci_tbl,
> +	.probe			= xenon_init_one,
> +	.remove			= ata_pci_remove_one,
> +};
> +
> +static struct scsi_host_template xenon_sht = {
> +	.module			= THIS_MODULE,
> +	.name			= DRV_NAME,
> +	.ioctl			= ata_scsi_ioctl,
> +	.queuecommand		= ata_scsi_queuecmd,
> +	.can_queue		= ATA_DEF_QUEUE,
> +	.this_id		= ATA_SHT_THIS_ID,
> +	.sg_tablesize		= ATA_MAX_PRD,
> +	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
> +	.emulated		= ATA_SHT_EMULATED,
> +	.use_clustering		= ATA_SHT_USE_CLUSTERING,
> +	.proc_name		= DRV_NAME,
> +	.dma_boundary		= ATA_DMA_BOUNDARY,
> +	.slave_configure	= ata_scsi_slave_config,
> +	.slave_destroy		= ata_scsi_slave_destroy,
> +	.bios_param		= ata_std_bios_param,
> +};
> +
> +static const struct ata_port_operations xenon_ops = {
> +	.port_disable		= ata_port_disable,
> +	.tf_load		= ata_tf_load,
> +	.tf_read		= ata_tf_read,
> +	.check_status		= ata_check_status,
> +	.exec_command		= ata_exec_command,
> +	.dev_select		= ata_std_dev_select,
> +	.bmdma_setup            = ata_bmdma_setup,
> +	.bmdma_start            = ata_bmdma_start,
> +	.bmdma_stop		= ata_bmdma_stop,
> +	.bmdma_status		= ata_bmdma_status,
> +	.qc_prep		= ata_qc_prep,
> +	.qc_issue		= ata_qc_issue_prot,
> +	.data_xfer		= ata_pio_data_xfer,
> +	.freeze			= ata_bmdma_freeze,
> +	.thaw			= ata_bmdma_thaw,
> +	.error_handler		= ata_bmdma_error_handler,
> +	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
> +	.irq_handler		= ata_interrupt,
> +	.irq_clear		= ata_bmdma_irq_clear,
> +	.scr_read		= xenon_scr_read,
> +	.scr_write		= xenon_scr_write,
> +	.port_start		= ata_port_start,
> +	.port_stop		= ata_port_stop,
> +	.host_stop		= ata_host_stop,
> +};
> +
> +static struct ata_port_info xenon_port_info = {
> +	.sht		= &xenon_sht,
> +	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
> +	.pio_mask	= 0x1f,
> +	.mwdma_mask	= 0x7,
> +	.udma_mask	= 0x7f,
> +	.port_ops	= &xenon_ops,
> +};
> +
> +
> +MODULE_DESCRIPTION("low-level driver for Xenon Southbridge SATA controller");
> +MODULE_LICENSE("GPL");
> +MODULE_DEVICE_TABLE(pci, xenon_pci_tbl);
> +MODULE_VERSION(DRV_VERSION);
> +
> +static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
> +{
> +	unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
> +

    Why we need device and port_no arguments here?

> +	return addr;
> +}
> +
> +static u32 xenon_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
> +{
> +	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
> +	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
> +	u32 val;
> +
> +	if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
> +		return 0; /* assume no error */

    Since SCR_ERROR == 1, this check seems broken.

> +
> +	pci_read_config_dword(pdev, cfg_addr, &val);
> +
> +	return val;
> +}
> +
> +static void xenon_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
> +{
> +	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
> +	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
> +
> +	if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
> +		return;

    Same here.

> +
> +	pci_write_config_dword(pdev, cfg_addr, val);
> +}
> +
> +static u32 xenon_scr_read (struct ata_port *ap, unsigned int sc_reg)
> +{
> +	if (sc_reg > SCR_CONTROL)
> +		return 0xffffffffU;
> +
> +	return xenon_scr_cfg_read(ap, sc_reg);
> +}
> +
> +static void xenon_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
> +{
> +	if (sc_reg > SCR_CONTROL)
> +		return;
> +
> +	xenon_scr_cfg_write(ap, sc_reg, val);
> +}
> +

    Reading SATA regs via config. space... isn't that ugly? :-]

> +static int xenon_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> +	static int printed_version;
> +	struct ata_probe_ent *probe_ent = NULL;
> +	int rc;
> +	int pci_dev_busy = 0;
> +
> +	if (!printed_version++)
> +		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
> +
> +	rc = pci_enable_device(pdev);
> +	if (rc)
> +		return rc;
> +
> +	rc = pci_request_regions(pdev, DRV_NAME);
> +	if (rc) {
> +		pci_dev_busy = 1;
> +		goto err_out;
> +	}
> +
> +	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
> +	if (rc)
> +		goto err_out_regions;
> +	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
> +	if (rc)
> +		goto err_out_regions;
> +
> +	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), &xenon_port_info);
> +	if (!probe_ent) {
> +		rc = -ENOMEM;
> +		goto err_out_regions;
> +	}
> +
> +	probe_ent->irq = pdev->irq;
> +	probe_ent->irq_flags = IRQF_SHARED;
> +
> +	probe_ent->port->cmd_addr = (long)ioremap(pci_resource_start(pdev, 0), PAGE_SIZE);
> +	probe_ent->port->altstatus_addr = probe_ent->port->cmd_addr + 0xa;
> +	probe_ent->port->ctl_addr = probe_ent->port->cmd_addr + 0xa;
> +	probe_ent->port->bmdma_addr = (long)ioremap(pci_resource_start(pdev, 1), PAGE_SIZE);
> +	ata_std_ports(probe_ent->port);
> +	probe_ent->n_ports = 1;
> +
> +	pci_set_master(pdev);
> +	pci_intx(pdev, 1);
> +
> +	/* FIXME: check ata_device_add return value */
> +	ata_device_add(probe_ent);
> +	kfree(probe_ent);
> +
> +	return 0;
> +
> +err_out_regions:
> +	pci_release_regions(pdev);
> +
> +err_out:
> +	if (!pci_dev_busy)
> +		pci_disable_device(pdev);
> +	return rc;
> +
> +}
> +
> +static int __init xenon_init(void)
> +{
> +	return pci_register_driver(&xenon_pci_driver);
> +}
> +
> +static void __exit xenon_exit(void)
> +{
> +	pci_unregister_driver(&xenon_pci_driver);
> +}
> +
> +module_init(xenon_init);
> +module_exit(xenon_exit);
> +

MBR, Sergei

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
                   ` (6 preceding siblings ...)
  2007-03-07 18:01 ` [patch 7/7] xenon: add framebuffer support (ugly) Felix Domke
@ 2007-03-07 21:06 ` Josh Boyer
  2007-03-07 21:14   ` Felix Domke
  2007-03-08  9:48   ` Benjamin Herrenschmidt
  2007-03-08  0:35 ` Stephen Rothwell
  8 siblings, 2 replies; 23+ messages in thread
From: Josh Boyer @ 2007-03-07 21:06 UTC (permalink / raw)
  To: Felix Domke; +Cc: Linuxppc-dev

On Wed, 2007-03-07 at 19:01 +0100, Felix Domke wrote:
> This series of patches add support for the Xbox 360 gaming console.
> 
> Note that these patches were written by different people, who want
> to remain anonymous. These drivers were written without hardware 
> documentation being available.

Taking anonymous contributions to the kernel goes against the
Developer's Certificate of Origin.  Are you sure you can certify it's
origin and are willing to take responsibility for the code?

Personally, I'd NAK this whole series.

josh

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 5/7] xenon: add SATA support
  2007-03-07 21:02   ` Sergei Shtylyov
@ 2007-03-07 21:07     ` Felix Domke
  2007-03-07 21:14       ` Sergei Shtylyov
  0 siblings, 1 reply; 23+ messages in thread
From: Felix Domke @ 2007-03-07 21:07 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: Linuxppc-dev, Linux IDE

Sergei Shtylyov wrote:
> Felix Domke wrote:
>> This adds support for the HDD and DVD SATA controller on the xenon
>> southbridge.
>   Pleas post this to linux-ide@vger.kernel.org in the future.
I'll do.

>> It also disables ATA_TFLAG_POLLING in libata-core, which prevented the
>> DVD drive
>> from being detected. It needs to be investigated what exactly is wrong
>> here. 

>>      tf.protocol = ATA_PROT_PIO;
>> -    tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */
>> +//    tf.flags |= ATA_TFLAG_POLLING; /* for polling presence
>> detection */
>    I doubt that this could *ever* get accepted.
It was not meant to be accepted, but to work around the problem which
was introduced in 2.6.19. I have far too less knowledge of the SATA
layer to understand why this flag exactly causes the detection of the
DVD-Drive fail.

As said, this needs to be investigated, and fixed (in the driver, of
course, not in the subsystem).

>> +static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned
>> int sc_reg, int device)
>> +{
>> +    unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
>> +
>    Why we need device and port_no arguments here?
As there is only one device/port per PCI device, the arguments should
probably be removed from this function, right.

>> +    if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
>> +        return 0; /* assume no error */
>    Since SCR_ERROR == 1, this check seems broken.
Why?


Felix

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
@ 2007-03-07 21:14   ` Felix Domke
  2007-03-08  9:48   ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 23+ messages in thread
From: Felix Domke @ 2007-03-07 21:14 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linuxppc-dev

Josh Boyer wrote:
> On Wed, 2007-03-07 at 19:01 +0100, Felix Domke wrote:
>> This series of patches add support for the Xbox 360 gaming console.
>> Note that these patches were written by different people, who want
>> to remain anonymous. These drivers were written without hardware 
>> documentation being available.
> Taking anonymous contributions to the kernel goes against the
> Developer's Certificate of Origin.  Are you sure you can certify it's
> origin and are willing to take responsibility for the code?

>>> (c) The contribution was provided directly to me by some other
>>>     person who certified (a), (b) or (c) and I have not modified
>>>     it.
This is true for the patch series. I understand that as far as the
original authors want to remain anonymous, this isn't worth a cent.

My guess is that the original authors either need to take resposibility
for their code, or the code needs to be rewritten from scratch. I hope
to be able to fix that up in the next days.

Felix

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 5/7] xenon: add SATA support
  2007-03-07 21:07     ` Felix Domke
@ 2007-03-07 21:14       ` Sergei Shtylyov
  0 siblings, 0 replies; 23+ messages in thread
From: Sergei Shtylyov @ 2007-03-07 21:14 UTC (permalink / raw)
  To: Felix Domke; +Cc: Linuxppc-dev, Linux IDE

Felix Domke wrote:
>>Felix Domke wrote:

>>>This adds support for the HDD and DVD SATA controller on the xenon
>>>southbridge.

>>  Pleas post this to linux-ide@vger.kernel.org in the future.

> I'll do.

>>>It also disables ATA_TFLAG_POLLING in libata-core, which prevented the
>>>DVD drive
>>>from being detected. It needs to be investigated what exactly is wrong
>>>here. 

>>>     tf.protocol = ATA_PROT_PIO;
>>>-    tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */
>>>+//    tf.flags |= ATA_TFLAG_POLLING; /* for polling presence
>>>detection */

>>   I doubt that this could *ever* get accepted.

> It was not meant to be accepted, but to work around the problem which
> was introduced in 2.6.19. I have far too less knowledge of the SATA
> layer to understand why this flag exactly causes the detection of the
> DVD-Drive fail.

> As said, this needs to be investigated, and fixed (in the driver, of
> course, not in the subsystem).

    Yeah, I've missed it in the patch description. :-<

>>>+static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned
>>>int sc_reg, int device)
>>>+{
>>>+    unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
>>>+

>>   Why we need device and port_no arguments here?

> As there is only one device/port per PCI device, the arguments should
> probably be removed from this function, right.

>>>+    if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
>>>+        return 0; /* assume no error */
>>
>>   Since SCR_ERROR == 1, this check seems broken.

> Why?

    Since get_scr_cfg_addr() will never return 1... oh wait, we're checking 
another variable... :-<
    Maybe worth merging to get_scr_cfg_addr() then, along with (sc_reg > 
SCR_CONTROL) checks, to avoid duplicate code.

> Felix

MBR, Sergei

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 6/7] xenon: add SMC support
  2007-03-07 18:01 ` [patch 6/7] xenon: add SMC support Felix Domke
@ 2007-03-07 21:54   ` Arnd Bergmann
  2007-03-08 23:29   ` Linas Vepstas
  1 sibling, 0 replies; 23+ messages in thread
From: Arnd Bergmann @ 2007-03-07 21:54 UTC (permalink / raw)
  To: linuxppc-dev

On Wednesday 07 March 2007 19:01:50 Felix Domke wrote:

> It requires a userspace daemon.

Is that available somewhere? You should probably list a URL
for this in the driver and/or changelog

> +config XENON_SMC
> +	bool "Xenon SMC"
> +	depends on PPC_XENON
> +	help
> +	  SMC controller in the Xbox 360.
> +

Please expand the acronym here. It's not a particularly unique
TLA after all.

> +struct xenon_smc
> +{
> +	void __iomem *base;
> +	unsigned long is_active;
> +	wait_queue_head_t wait;
> +};
> +
> +static struct xenon_smc *first_smc;

Why do you think you need the global instance variable?
Normally, this should be pointed to by the pci device
private data.

> +#define to_smc(pdev) dev_get_drvdata(&pdev->dev)
> +
> +static int get_smc(struct xenon_smc *ctx, u8 *msg);
> +static void send_smc(struct xenon_smc *ctx, void *msg);
> +static irqreturn_t xenon_smc_irq(int irq, void *dev_id);
> +static ssize_t smc_write(struct file *file, const char __user *data,
> +				size_t len, loff_t *ppos);
> +static int smc_ioctl(struct inode *inode, struct file *file,
> +				unsigned int cmd, unsigned long arg);
> +static ssize_t smc_read(struct file *file, char __user *data,
> +				size_t len, loff_t *ppos);
> +static int smc_open(struct inode *inode, struct file *file);
> +static int smc_release(struct inode *inode, struct file *file);
> +static int xenon_smc_init_one (struct pci_dev *pdev, const struct
> pci_device_id *ent); +static void __devexit xenon_smc_remove(struct pci_dev
> *pdev);

Don't do forward declarations of static functions, please instead
reorder them so you don't need these.

> +static struct miscdevice smc_miscdev = {
> +	.minor =  RTC_MINOR,
> +	.name =   "smc",
> +	.fops =	  &smc_fops,
> +};

You can't grab the RTC device number if you don't support the
respective interfaces. Use a dynamic minor number instead!

> +static int get_smc(struct xenon_smc *ctx, u8 *msg)
> +{
> +	if (readl(ctx->base + 0x94) & 4)
> +	{
> +		u32 *message = (u32*)msg;
> +		int i;
> +		writel(4, ctx->base + 0x94);
> +		for (i=0; i<4; ++i)
> +			message[i] = __raw_readl(ctx->base + 0x90);
> +		writel(0, ctx->base + 0x94);
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +static void send_smc(struct xenon_smc *ctx, void *msg)
> +{
> +	while (!(readl(ctx->base + 0x84) & 4));
> +	writel(4, ctx->base + 0x84);
> +	__raw_writel(*(u32*)(msg+0), ctx->base + 0x80);
> +	__raw_writel(*(u32*)(msg+4), ctx->base + 0x80);
> +	__raw_writel(*(u32*)(msg+8), ctx->base + 0x80);
> +	__raw_writel(*(u32*)(msg+12), ctx->base + 0x80);
> +	writel(0, ctx->base + 0x84);
> +}

This needs to be cleaned up:

- don't use __raw_read/write on pci devices
- in the endless loop, use cpu_relax()
- avoid the casts if you can

> +static ssize_t smc_write(struct file *file, const char __user *data,
> +			     size_t len, loff_t *ppos)
> +{
> +	unsigned char msg[16];
> +	if (len != 16)
> +		return -EINVAL;
> +
> +	if (copy_from_user(msg, data, 16))
> +		return -EFAULT;
> +
> +	send_smc(first_smc, msg);
> +
> +	return 16;
> +}

You can get the pointer to the smc from file->f_dentry->d_inode->i_private
if you put it in there 

> +static int smc_ioctl(struct inode *inode, struct file *file,
> +			  unsigned int cmd, unsigned long arg)
> +{
> +	return -ENODEV;
> +}

please kill this function, it's not needed.

> +static ssize_t smc_read(struct file *file, char __user *data,
> +				size_t len, loff_t *ppos)
> +{
> +	struct xenon_smc *ctx = first_smc;
> +	int ret;
> +	u8 msg[0x10];
> +
> +	if (len != 16)
> +		return -EINVAL;
> +
> +	if (!(readl(ctx->base + 0x94) & 4))
> +	{
> +		if (file->f_flags & O_NONBLOCK)
> +			return -EAGAIN;
> +
> +		ret = wait_event_interruptible(ctx->wait, readl(ctx->base + 0x94) & 4);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	if (get_smc(ctx, msg) == 0)
> +		return -EAGAIN;
> +
> +	if (copy_to_user(data, msg, 0x10))
> +		return -EFAULT;
> +
> +	return 0x10;
> +}
> +
> +static int smc_open(struct inode *inode, struct file *file)
> +{
> +	if (test_and_set_bit(0, &first_smc->is_active))
> +		return -EBUSY;
> +
> +	return nonseekable_open(inode, file);
> +}

This doesn't guarantee that you have only one fd to the device,
you can still get multiple copies through dup or fork.

> +
> +	rc = misc_register(&smc_miscdev);
> +	if (rc != 0)
> +	{

You should be consistant with the indentation, opening braces here
and in other places (except function bodies) go at the end of the
previous line.

It's also more common to write 'if (!rc)' than comparing return values
against 0 or NULL.

	Arnd <><

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 2/7] xenon: add platform support
  2007-03-07 18:01 ` [patch 2/7] xenon: add platform support Felix Domke
@ 2007-03-07 23:06   ` Arnd Bergmann
  0 siblings, 0 replies; 23+ messages in thread
From: Arnd Bergmann @ 2007-03-07 23:06 UTC (permalink / raw)
  To: linuxppc-dev

> +#define PRIO_IPI_4       0x08
> +#define PRIO_IPI_3       0x10
> +#define PRIO_SMM         0x14
> +#define PRIO_SFCX        0x18
> +#define PRIO_SATA_HDD    0x20
> +#define PRIO_SATA_CDROM  0x24
> +#define PRIO_OHCI_0      0x2c
> +#define PRIO_EHCI_0      0x30
> +#define PRIO_OHCI_1      0x34
> +#define PRIO_EHCI_1      0x38
> +#define PRIO_XMA         0x40
> +#define PRIO_AUDIO       0x44
> +#define PRIO_ENET        0x4C
> +#define PRIO_XPS         0x54
> +#define PRIO_GRAPHICS    0x58
> +#define PRIO_PROFILER    0x60
> +#define PRIO_BIU         0x64
> +#define PRIO_IOC         0x68
> +#define PRIO_FSB         0x6c
> +#define PRIO_IPI_2       0x70
> +#define PRIO_CLOCK       0x74
> +#define PRIO_IPI_1       0x78

These should probably all come from the device tree
instead of compile-time constants.

> +void __init xenon_iic_init_IRQ(void)
> +{
> +	int i;
> +	struct device_node *dn;
> +
> +	printk("XENON init IRQ\n");

needs a printk level, KERN_DEBUG or KERN_INFO.

> +			/* search for our interrupt controller inside the device tree */
> +	for (dn = NULL;
> +	     (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
> +		if (!device_is_compatible(dn,
> +				     "xenon"))
> +			continue;
> +
> +		irq_set_virq_count(0x80);
> +		iic_base = ioremap_nocache(0x20000050000, 0x10000);

This should come from the 'reg' property of the above node.


> +void xenon_cause_IPI(int target, int msg)
> +{
> +	int ipi_prio;
> +
> +	ipi_prio = ipi_to_prio(msg);
> +
> +	__raw_writeq( (0x10000<<target) | ipi_prio, iic_base + 0x10 +
> hard_smp_processor_id() * 0x1000); +}
> +

You seem to have a line wrapping problem and might need to fix your
mail client.
Also, don't use __raw_writeq here. In order to access on-chip data,
use out_be64().

> +	hose->ops = &xenon_pci_ops;
> +	hose->cfg_addr = ioremap(0xd0000000, 0x1000000);
> +
The addresses should come from the device tree, don't hardcode
them in the source.

> +#define DEBUG
> +

really?


> +void __init xenon_pci_init(void);
> +#ifdef CONFIG_SMP
> +extern void smp_init_xenon(void);
> +#endif

move these declarations to a header

> +static void xenon_show_cpuinfo(struct seq_file *m)
> +{
> +	struct device_node *root;
> +	const char *model = "";
> +
> +	root = of_find_node_by_path("/");
> +	if (root)
> +		model = get_property(root, "model", NULL);
> +	seq_printf(m, "machine\t\t: CHRP %s\n", model);
> +	of_node_put(root);
> +}

CHRP???

> +static void __init xenon_pcibios_fixup(void)
> +{
> +	struct pci_dev *dev = NULL;
> +
> +	for_each_pci_dev(dev)
> +		pci_read_irq_line(dev);
> +}

I guess you copied that from cell? You should not need it.

> +	if (ROOT_DEV == 0) {
> +		printk("No ramdisk, default root is /dev/hda2\n");
> +		ROOT_DEV = Root_HDA2;
> +	}

kill this, it's unnecessary (and probably wrong in your case)

> +static int __init xenon_probe(void)
> +{
> +       hpte_init_native();
> +
> +       return 1;
> +}

This definitely needs to check the device tree whether it's running
on the right platform, otherwise you can not build a multiplatform
kernel.

> +void __init xenon_hpte_init(unsigned long htab_size);
> +
move this to a header file


> +#include <asm/rtas.h>

rtas???

> +#ifdef DEBUG
> +#define DBG(fmt...) printk(fmt)
> +#else
> +#define DBG(fmt...)
> +#endif
> +

Don't define your own macros like this, use the pr_debug()
one from kernel.h.

> +void smp_init_xenon(void);
> +
> +extern void xenon_request_IPIs(void);
> +extern void xenon_init_irq_on_cpu(int cpu);
> +
> +extern void xenon_cause_IPI(int target, int msg);

extern declarations should go to header files, not into
the implementation.


> +	/* Mark threads which are still spinning in hold loops. */
> +	if (cpu_has_feature(CPU_FTR_SMT)) {
> +		for_each_present_cpu(i) {
> +			if (i % 2 == 0)
> +				/*
> +				 * Even-numbered logical cpus correspond to
> +				 * primary threads.
> +				 */
> +				cpu_set(i, of_spin_map);
> +		}
> +	} else {
> +		of_spin_map = cpu_present_map;
> +	}

Yes, we wrote code like that for CBE, but that doesn't mean it's good
enough to copy it ;-)

Relying on the cpu number to mean something specific is bad, and
we're trying to get rid of that in other places, so you should
not introduce it again here.

> +#define CPU_FTRS_XENON ((CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
> +	    CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
> +	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
> +	    CPU_FTR_CTRL )&~CPU_FTR_16M_PAGE)
> +// | CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE  /* we need to setup large

If the CPU doesn't do 16M pages, you need to make sure that CPU_FTRS_ALWAYS
is adapted properly.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 4/7] xenon: add southbridge ethernet support
  2007-03-07 18:01 ` [patch 4/7] xenon: add southbridge ethernet support Felix Domke
@ 2007-03-07 23:27   ` Arnd Bergmann
  0 siblings, 0 replies; 23+ messages in thread
From: Arnd Bergmann @ 2007-03-07 23:27 UTC (permalink / raw)
  To: linuxppc-dev

On Wednesday 07 March 2007 19:01:48 Felix Domke wrote:
> This adds support for the Ethernet controller used in the Xenon
> southbridge.
>
> It is based on the skeleton code, and works surprisingly good. It has some
> rough edges, especially regarding SMP locks, and probably needs some code
> cleanup.

Right, though it appears that some of the code that needs to be cleaned
up even comes from the skeleton driver...

It's also the wrong mailing list to post this to, it should go to netdev.

Furthermore, this driver should have MODULE_LICENSE, MODULE_AUTHOR
and MODULE_DESCRIPTION field, like any loadable module.

> +0100 @@ -0,0 +1,725 @@
> +/*
> + * based on skeleton code.
> + */

Your other files have a long copyright notice, why the inconsistency?

> +#define assert(expr) \
> +        if(!(expr)) {					\
> +        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
> +        #expr,__FILE__,__FUNCTION__,__LINE__);		\
> +        }

use BUG_ON() instead of assert()

> +/* Symbolic offsets to registers. */
> +enum XENONNET_registers {
> +	TxConfig = 0x00,
> +	TxDescriptorBase = 0x04,
> +	TxDescriptorStatus = 0x0C,
> +	RxConfig = 0x10,
> +	RxDescriptorBase = 0x14,
> +	InterruptStatus = 0x20,
> +	InterruptMask = 0x24,
> +	Config0 = 0x28,
> +	Power = 0x30,
> +	PhyConfig = 0x40,
> +	PhyControl = 0x44,
> +	Config1 = 0x50,
> +	RetryCount = 0x54,
> +	MulticastFilterControl = 0x60,
> +	Address0 = 0x62,
> +	MulticastHash = 0x68,
> +	MaxPacketSize = 0x78,
> +	Address1 = 0x7A
> +};

Don't use mixed case identifiers.

> +static int xenon_net_open (struct net_device *dev);
> +static void xenon_net_tx_timeout (struct net_device *dev);
> +static void xenon_net_init_ring (struct net_device *dev);
> +static int xenon_net_start_xmit (struct sk_buff *skb, struct net_device
> *dev); +static irqreturn_t xenon_net_interrupt(int irq, void *dev_id);
> +static int xenon_net_close (struct net_device *dev);
> +static void xenon_net_hw_start (struct net_device *dev);
> +static int xenon_net_poll(struct net_device *dev, int *budget);

avoid forward declarations for static functions

> +#define XENONNET_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
> +#define XENONNET_W16(reg, val16)	writew ((val16), ioaddr + (reg))
> +#define XENONNET_W32(reg, val32)	do { writel ((val32), ioaddr + (reg));  }
> while (0) +#define XENONNET_R8(reg)		readb (ioaddr + (reg))
> +#define XENONNET_R16(reg)		readw (ioaddr + (reg))
> +#define XENONNET_R32(reg)		((u32) readl (ioaddr + (reg)))

get rid of these, just use the {read,write}{b,w,l} directly

> +		printk ("EXIT, returning -ENOMEM\n");

use proper printk levels or kill this output. also watch
your whitespace.

> +	SET_MODULE_OWNER(dev);

SET_MODULE_OWNER is deprecated, just remove this.

> +	memcpy(dev->dev_addr, "\0\0\1\2\3\4", 6);

use random_ether_address

> +	while (1)
> +	{
> +		int index = atomic_read(&tp->rx_next);
> +		volatile u32 *descr = tp->rx_descriptor_base + index * 0x10;

'volatile' is most likely wrong here, I guess you need to convert this
to use the right barriers.

> +static irqreturn_t xenon_net_interrupt(int irq, void *dev_id)
> +{
> +	struct net_device *dev = dev_id;
> +	struct xenon_net_private *tp = dev->priv;
> +	void *ioaddr = tp->mmio_addr;
> +	u32 status;
> +
> +	spin_lock (&tp->lock);
> +
> +	status = XENONNET_R32(InterruptStatus);
> +
> +	if (status & 0x40)
> +	{
> +		if (netif_rx_schedule_prep(dev)) {
> +			status &= ~0x40;
> +			__netif_rx_schedule (dev);
> +		}
> +	}
> +
> +	if (status & 4)
> +	{
> +		xenon_net_tx_interrupt(dev, tp, ioaddr);
> +		status &= ~0x4;
> +	}
> +
> +//	if (status)
> +//		printk("other interrupt: %08x\n", status);
> +
> +	spin_unlock (&tp->lock);
> +
> +	return IRQ_HANDLED;
> +}

Usually, you'd want to use a single poll function for both receive
and transmit, and call __netif_rx_schedule in both cases.

> +	spin_lock_irqsave (&tp->lock, flags);
> +	spin_unlock_irqrestore (&tp->lock, flags);

huh?

> +	synchronize_irq (dev->irq);
> +	free_irq (dev->irq, dev);

free_irq does syncronize_irq itself, iirc

	Arnd <><

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
                   ` (7 preceding siblings ...)
  2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
@ 2007-03-08  0:35 ` Stephen Rothwell
  2007-03-08  0:52   ` Felix Domke
                     ` (2 more replies)
  8 siblings, 3 replies; 23+ messages in thread
From: Stephen Rothwell @ 2007-03-08  0:35 UTC (permalink / raw)
  To: Felix Domke; +Cc: Linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 576 bytes --]

On Wed, 07 Mar 2007 19:01:44 +0100 Felix Domke <tmbinc@elitedvb.net> wrote:
>
> Note that these patches were written by different people, who want
> to remain anonymous. These drivers were written without hardware
> documentation being available.

Sorry, but given the anonymity requirement above, I do not want to even
read these patches.  Tracking of the pedigree of code in Linux has become
an issue and deevelopers want to be anonymous really pokes a big hole in
that.

--
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-08  0:35 ` Stephen Rothwell
@ 2007-03-08  0:52   ` Felix Domke
  2007-03-08 11:02   ` Christoph Hellwig
  2007-03-08 23:50   ` Linas Vepstas
  2 siblings, 0 replies; 23+ messages in thread
From: Felix Domke @ 2007-03-08  0:52 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: Linuxppc-dev

Stephen Rothwell wrote:
> On Wed, 07 Mar 2007 19:01:44 +0100 Felix Domke <tmbinc@elitedvb.net> wrote:
>> Note that these patches were written by different people, who want
>> to remain anonymous. These drivers were written without hardware
>> documentation being available.
> Sorry, but given the anonymity requirement above, I do not want to even
> read these patches.  Tracking of the pedigree of code in Linux has become
> an issue and deevelopers want to be anonymous really pokes a big hole in
> that.
Let me check back with the original authors. They either need to become
responsible for their code, or I will remove the code. It can still be
rewritten.

Felix

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
  2007-03-07 21:14   ` Felix Domke
@ 2007-03-08  9:48   ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 23+ messages in thread
From: Benjamin Herrenschmidt @ 2007-03-08  9:48 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linuxppc-dev

On Wed, 2007-03-07 at 15:06 -0600, Josh Boyer wrote:
> On Wed, 2007-03-07 at 19:01 +0100, Felix Domke wrote:
> > This series of patches add support for the Xbox 360 gaming console.
> > 
> > Note that these patches were written by different people, who want
> > to remain anonymous. These drivers were written without hardware 
> > documentation being available.
> 
> Taking anonymous contributions to the kernel goes against the
> Developer's Certificate of Origin.  Are you sure you can certify it's
> origin and are willing to take responsibility for the code?
> 
> Personally, I'd NAK this whole series.

The whole serie can't be merged anyway, the patches aren't in good
enough shape.

Regarding the legal status I think the serie can't be merged at least
not by any of the maintainer for the reason you mention.

What should happen at this stage is that somebody writes a documentation
of the hardware based on those patches and somebody else writes patches
based on that documentation.

The fact that the initial patches were posted publically make the
process a bit harder but still somewhat possible (if the final code is
obviously not inherited from the original one in any way).

Ben.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-08  0:35 ` Stephen Rothwell
  2007-03-08  0:52   ` Felix Domke
@ 2007-03-08 11:02   ` Christoph Hellwig
  2007-03-08 23:50   ` Linas Vepstas
  2 siblings, 0 replies; 23+ messages in thread
From: Christoph Hellwig @ 2007-03-08 11:02 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: Linuxppc-dev

On Thu, Mar 08, 2007 at 11:35:45AM +1100, Stephen Rothwell wrote:
> On Wed, 07 Mar 2007 19:01:44 +0100 Felix Domke <tmbinc@elitedvb.net> wrote:
> >
> > Note that these patches were written by different people, who want
> > to remain anonymous. These drivers were written without hardware
> > documentation being available.
> 
> Sorry, but given the anonymity requirement above, I do not want to even
> read these patches.  Tracking of the pedigree of code in Linux has become
> an issue and deevelopers want to be anonymous really pokes a big hole in
> that.

Then please go away from Linux mailinglist, instead of these kinds of
stupid rants.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 6/7] xenon: add SMC support
  2007-03-07 18:01 ` [patch 6/7] xenon: add SMC support Felix Domke
  2007-03-07 21:54   ` Arnd Bergmann
@ 2007-03-08 23:29   ` Linas Vepstas
  1 sibling, 0 replies; 23+ messages in thread
From: Linas Vepstas @ 2007-03-08 23:29 UTC (permalink / raw)
  To: Felix Domke; +Cc: Linuxppc-dev

On Wed, Mar 07, 2007 at 07:01:50PM +0100, Felix Domke wrote:
> This adds lowlevel support for the "System Management Controller"
> on the Xenon southbridge, which controls power, the frontpanel leds, 
> infrared remote, tilt switch, AVIP detection, RTC and DVD tray control.

Unlike Arndt, I'd suggest that these three lines appear in the C file
as well. I've spent too many days wondering what some some file was 
supposed to be doing, because the author didn't even bother to mention
something as basic as this. This is particularly important when 
documentation is not generally available.

--linas

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [patch 0/7] [RFC] Xenon support
  2007-03-08  0:35 ` Stephen Rothwell
  2007-03-08  0:52   ` Felix Domke
  2007-03-08 11:02   ` Christoph Hellwig
@ 2007-03-08 23:50   ` Linas Vepstas
  2 siblings, 0 replies; 23+ messages in thread
From: Linas Vepstas @ 2007-03-08 23:50 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: Linuxppc-dev

On Thu, Mar 08, 2007 at 11:35:45AM +1100, Stephen Rothwell wrote:
> 
> Sorry, but given the anonymity requirement above, I do not want to even
> read these patches.  Tracking of the pedigree of code in Linux has become
> an issue and deevelopers want to be anonymous really pokes a big hole in
> that.

Please note that legal systems do have pretty robust notions about 
"reasonable people" and "reasonable behaviour".  Having gone through
the patches, I can affirm that these are utterly unremarkable, perfectly
ordinary patches, and there is no way that any "reasonable person" will 
get "contaminated" reading this stuff. The code looks like any other 
ethernet or ide or sata code; a few register definitions are different, 
but that's about it. 

Concepts like "pedigree" and "contamination" and "certificate of 
originality" and etc. apply when the code in question starts doing
things that are unique, novel, "not obvious to practitioners
versed in the state of the art".  When some code implements something
unusual, then there can be legitimate concerns about infringing on
some patent, etc.

At most, one might argue that there are some "trade secrets" in that
code. However, "trade secrets" are not protected by law: once they're
public, the're not secret any more, and the holder of the secret is
plain out-of-luck, and has no legal recourse. 

Oh, did I mention I'm not a lawyer, never studied law, etc. etc.?
The above is all my personal opinion, not that or my employer etc. 

--linas

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2007-03-08 23:50 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-07 18:01 [patch 0/7] [RFC] Xenon support Felix Domke
2007-03-07 18:01 ` [patch 1/7] xenon: add PCI Vendor ID: Microsoft Felix Domke
2007-03-07 18:01 ` [patch 2/7] xenon: add platform support Felix Domke
2007-03-07 23:06   ` Arnd Bergmann
2007-03-07 18:01 ` [patch 3/7] xenon: udbg support (ugly) Felix Domke
2007-03-07 21:00   ` Geert Uytterhoeven
2007-03-07 18:01 ` [patch 4/7] xenon: add southbridge ethernet support Felix Domke
2007-03-07 23:27   ` Arnd Bergmann
2007-03-07 18:01 ` [patch 5/7] xenon: add SATA support Felix Domke
2007-03-07 21:02   ` Sergei Shtylyov
2007-03-07 21:07     ` Felix Domke
2007-03-07 21:14       ` Sergei Shtylyov
2007-03-07 18:01 ` [patch 6/7] xenon: add SMC support Felix Domke
2007-03-07 21:54   ` Arnd Bergmann
2007-03-08 23:29   ` Linas Vepstas
2007-03-07 18:01 ` [patch 7/7] xenon: add framebuffer support (ugly) Felix Domke
2007-03-07 21:06 ` [patch 0/7] [RFC] Xenon support Josh Boyer
2007-03-07 21:14   ` Felix Domke
2007-03-08  9:48   ` Benjamin Herrenschmidt
2007-03-08  0:35 ` Stephen Rothwell
2007-03-08  0:52   ` Felix Domke
2007-03-08 11:02   ` Christoph Hellwig
2007-03-08 23:50   ` Linas Vepstas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).