All of lore.kernel.org
 help / color / mirror / Atom feed
From: Felix Domke <tmbinc@elitedvb.net>
To: Linuxppc-dev@ozlabs.org
Subject: [patch 2/7] xenon: add platform support
Date: Wed, 07 Mar 2007 19:01:46 +0100	[thread overview]
Message-ID: <20070307180525.774243000@elitedvb.net> (raw)
In-Reply-To: 20070307180144.812594000@elitedvb.net

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 | \

--

  parent reply	other threads:[~2007-03-07 18:01 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2007-03-07 23:06   ` [patch 2/7] xenon: add platform support 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:03 ` [patch 5/7] [RFC] xenon: add SATA support Felix Domke
2007-03-08  7:54   ` Tejun Heo
2007-03-09 16:06   ` Jeff Garzik
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070307180525.774243000@elitedvb.net \
    --to=tmbinc@elitedvb.net \
    --cc=Linuxppc-dev@ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.