Revision 140d0b2108faebc77c6523296e211e509cb9f5f9 authored by Linus Torvalds on 05 August 2011, 05:35:59 UTC, committed by Linus Torvalds on 05 August 2011, 05:35:59 UTC
This isn't really critical any more, since other patches (commit
298507d4d2cf: "shm: optimize exit_shm()") have caused us to not actually
need to touch the rw_mutex unless there are actual shm segments
associated with the namespace, but we really should do tne shm_init_ns()
earlier than we do now.

This, together with commit 288d5abec831 ("Boot up with usermodehelper
disabled") will mean that we really do initialize the initial ipc
namespace data structure before we run any tasks.

Tested-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 24f0eed
Raw File
sys_wildfire.c
/*
 *  linux/arch/alpha/kernel/sys_wildfire.c
 *
 *  Wildfire support.
 *
 *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>

#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/core_wildfire.h>
#include <asm/hwrpb.h>
#include <asm/tlbflush.h>

#include "proto.h"
#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"

static unsigned long cached_irq_mask[WILDFIRE_NR_IRQS/(sizeof(long)*8)];

DEFINE_SPINLOCK(wildfire_irq_lock);

static int doing_init_irq_hw = 0;

static void
wildfire_update_irq_hw(unsigned int irq)
{
	int qbbno = (irq >> 8) & (WILDFIRE_MAX_QBB - 1);
	int pcano = (irq >> 6) & (WILDFIRE_PCA_PER_QBB - 1);
	wildfire_pca *pca;
	volatile unsigned long * enable0;

	if (!WILDFIRE_PCA_EXISTS(qbbno, pcano)) {
		if (!doing_init_irq_hw) {
			printk(KERN_ERR "wildfire_update_irq_hw:"
			       " got irq %d for non-existent PCA %d"
			       " on QBB %d.\n",
			       irq, pcano, qbbno);
		}
		return;
	}

	pca = WILDFIRE_pca(qbbno, pcano);
	enable0 = (unsigned long *) &pca->pca_int[0].enable; /* ??? */

	*enable0 = cached_irq_mask[qbbno * WILDFIRE_PCA_PER_QBB + pcano];
	mb();
	*enable0;
}

static void __init
wildfire_init_irq_hw(void)
{
#if 0
	register wildfire_pca * pca = WILDFIRE_pca(0, 0);
	volatile unsigned long * enable0, * enable1, * enable2, *enable3;
	volatile unsigned long * target0, * target1, * target2, *target3;

	enable0 = (unsigned long *) &pca->pca_int[0].enable;
	enable1 = (unsigned long *) &pca->pca_int[1].enable;
	enable2 = (unsigned long *) &pca->pca_int[2].enable;
	enable3 = (unsigned long *) &pca->pca_int[3].enable;

	target0 = (unsigned long *) &pca->pca_int[0].target;
	target1 = (unsigned long *) &pca->pca_int[1].target;
	target2 = (unsigned long *) &pca->pca_int[2].target;
	target3 = (unsigned long *) &pca->pca_int[3].target;

	*enable0 = *enable1 = *enable2 = *enable3 = 0;

	*target0 = (1UL<<8) | WILDFIRE_QBB(0);
	*target1 = *target2 = *target3 = 0;

	mb();

	*enable0; *enable1; *enable2; *enable3;
	*target0; *target1; *target2; *target3;

#else
	int i;

	doing_init_irq_hw = 1;

	/* Need to update only once for every possible PCA. */
	for (i = 0; i < WILDFIRE_NR_IRQS; i+=WILDFIRE_IRQ_PER_PCA)
		wildfire_update_irq_hw(i);

	doing_init_irq_hw = 0;
#endif
}

static void
wildfire_enable_irq(struct irq_data *d)
{
	unsigned int irq = d->irq;

	if (irq < 16)
		i8259a_enable_irq(d);

	spin_lock(&wildfire_irq_lock);
	set_bit(irq, &cached_irq_mask);
	wildfire_update_irq_hw(irq);
	spin_unlock(&wildfire_irq_lock);
}

static void
wildfire_disable_irq(struct irq_data *d)
{
	unsigned int irq = d->irq;

	if (irq < 16)
		i8259a_disable_irq(d);

	spin_lock(&wildfire_irq_lock);
	clear_bit(irq, &cached_irq_mask);
	wildfire_update_irq_hw(irq);
	spin_unlock(&wildfire_irq_lock);
}

static void
wildfire_mask_and_ack_irq(struct irq_data *d)
{
	unsigned int irq = d->irq;

	if (irq < 16)
		i8259a_mask_and_ack_irq(d);

	spin_lock(&wildfire_irq_lock);
	clear_bit(irq, &cached_irq_mask);
	wildfire_update_irq_hw(irq);
	spin_unlock(&wildfire_irq_lock);
}

static struct irq_chip wildfire_irq_type = {
	.name		= "WILDFIRE",
	.irq_unmask	= wildfire_enable_irq,
	.irq_mask	= wildfire_disable_irq,
	.irq_mask_ack	= wildfire_mask_and_ack_irq,
};

static void __init
wildfire_init_irq_per_pca(int qbbno, int pcano)
{
	int i, irq_bias;
	static struct irqaction isa_enable = {
		.handler	= no_action,
		.name		= "isa_enable",
	};

	irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA)
		 + pcano * WILDFIRE_IRQ_PER_PCA;

#if 0
	unsigned long io_bias;

	/* Only need the following for first PCI bus per PCA. */
	io_bias = WILDFIRE_IO(qbbno, pcano<<1) - WILDFIRE_IO_BIAS;

	outb(0, DMA1_RESET_REG + io_bias);
	outb(0, DMA2_RESET_REG + io_bias);
	outb(DMA_MODE_CASCADE, DMA2_MODE_REG + io_bias);
	outb(0, DMA2_MASK_REG + io_bias);
#endif

#if 0
	/* ??? Not sure how to do this, yet... */
	init_i8259a_irqs(); /* ??? */
#endif

	for (i = 0; i < 16; ++i) {
		if (i == 2)
			continue;
		irq_set_chip_and_handler(i + irq_bias, &wildfire_irq_type,
					 handle_level_irq);
		irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
	}

	irq_set_chip_and_handler(36 + irq_bias, &wildfire_irq_type,
				 handle_level_irq);
	irq_set_status_flags(36 + irq_bias, IRQ_LEVEL);
	for (i = 40; i < 64; ++i) {
		irq_set_chip_and_handler(i + irq_bias, &wildfire_irq_type,
					 handle_level_irq);
		irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
	}

	setup_irq(32+irq_bias, &isa_enable);
}

static void __init
wildfire_init_irq(void)
{
	int qbbno, pcano;

#if 1
	wildfire_init_irq_hw();
	init_i8259a_irqs();
#endif

	for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) {
	  if (WILDFIRE_QBB_EXISTS(qbbno)) {
	    for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) {
	      if (WILDFIRE_PCA_EXISTS(qbbno, pcano)) {
		wildfire_init_irq_per_pca(qbbno, pcano);
	      }
	    }
	  }
	}
}

static void 
wildfire_device_interrupt(unsigned long vector)
{
	int irq;

	irq = (vector - 0x800) >> 4;

	/*
	 * bits 10-8:	source QBB ID
	 * bits 7-6:	PCA
	 * bits 5-0:	irq in PCA
	 */

	handle_irq(irq);
	return;
}

/*
 * PCI Fixup configuration.
 *
 * Summary per PCA (2 PCI or HIPPI buses):
 *
 * Bit      Meaning
 * 0-15     ISA
 *
 *32        ISA summary
 *33        SMI
 *34        NMI
 *36        builtin QLogic SCSI (or slot 0 if no IO module)
 *40        Interrupt Line A from slot 2 PCI0
 *41        Interrupt Line B from slot 2 PCI0
 *42        Interrupt Line C from slot 2 PCI0
 *43        Interrupt Line D from slot 2 PCI0
 *44        Interrupt Line A from slot 3 PCI0
 *45        Interrupt Line B from slot 3 PCI0
 *46        Interrupt Line C from slot 3 PCI0
 *47        Interrupt Line D from slot 3 PCI0
 *
 *48        Interrupt Line A from slot 4 PCI1
 *49        Interrupt Line B from slot 4 PCI1
 *50        Interrupt Line C from slot 4 PCI1
 *51        Interrupt Line D from slot 4 PCI1
 *52        Interrupt Line A from slot 5 PCI1
 *53        Interrupt Line B from slot 5 PCI1
 *54        Interrupt Line C from slot 5 PCI1
 *55        Interrupt Line D from slot 5 PCI1
 *56        Interrupt Line A from slot 6 PCI1
 *57        Interrupt Line B from slot 6 PCI1
 *58        Interrupt Line C from slot 6 PCI1
 *50        Interrupt Line D from slot 6 PCI1
 *60        Interrupt Line A from slot 7 PCI1
 *61        Interrupt Line B from slot 7 PCI1
 *62        Interrupt Line C from slot 7 PCI1
 *63        Interrupt Line D from slot 7 PCI1
 * 
 *
 * IdSel	
 *   0	 Cypress Bridge I/O (ISA summary interrupt)
 *   1	 64 bit PCI 0 option slot 1 (SCSI QLogic builtin)
 *   2	 64 bit PCI 0 option slot 2
 *   3	 64 bit PCI 0 option slot 3
 *   4	 64 bit PCI 1 option slot 4
 *   5	 64 bit PCI 1 option slot 5
 *   6	 64 bit PCI 1 option slot 6
 *   7	 64 bit PCI 1 option slot 7
 */

static int __init
wildfire_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
	static char irq_tab[8][5] __initdata = {
		/*INT    INTA   INTB   INTC   INTD */
		{ -1,    -1,    -1,    -1,    -1}, /* IdSel 0 ISA Bridge */
		{ 36,    36,    36+1, 36+2, 36+3}, /* IdSel 1 SCSI builtin */
		{ 40,    40,    40+1, 40+2, 40+3}, /* IdSel 2 PCI 0 slot 2 */
		{ 44,    44,    44+1, 44+2, 44+3}, /* IdSel 3 PCI 0 slot 3 */
		{ 48,    48,    48+1, 48+2, 48+3}, /* IdSel 4 PCI 1 slot 4 */
		{ 52,    52,    52+1, 52+2, 52+3}, /* IdSel 5 PCI 1 slot 5 */
		{ 56,    56,    56+1, 56+2, 56+3}, /* IdSel 6 PCI 1 slot 6 */
		{ 60,    60,    60+1, 60+2, 60+3}, /* IdSel 7 PCI 1 slot 7 */
	};
	long min_idsel = 0, max_idsel = 7, irqs_per_slot = 5;

	struct pci_controller *hose = dev->sysdata;
	int irq = COMMON_TABLE_LOOKUP;

	if (irq > 0) {
		int qbbno = hose->index >> 3;
		int pcano = (hose->index >> 1) & 3;
		irq += (qbbno << 8) + (pcano << 6);
	}
	return irq;
}


/*
 * The System Vectors
 */

struct alpha_machine_vector wildfire_mv __initmv = {
	.vector_name		= "WILDFIRE",
	DO_EV6_MMU,
	DO_DEFAULT_RTC,
	DO_WILDFIRE_IO,
	.machine_check		= wildfire_machine_check,
	.max_isa_dma_address	= ALPHA_MAX_ISA_DMA_ADDRESS,
	.min_io_address		= DEFAULT_IO_BASE,
	.min_mem_address	= DEFAULT_MEM_BASE,

	.nr_irqs		= WILDFIRE_NR_IRQS,
	.device_interrupt	= wildfire_device_interrupt,

	.init_arch		= wildfire_init_arch,
	.init_irq		= wildfire_init_irq,
	.init_rtc		= common_init_rtc,
	.init_pci		= common_init_pci,
	.kill_arch		= wildfire_kill_arch,
	.pci_map_irq		= wildfire_map_irq,
	.pci_swizzle		= common_swizzle,

	.pa_to_nid		= wildfire_pa_to_nid,
	.cpuid_to_nid		= wildfire_cpuid_to_nid,
	.node_mem_start		= wildfire_node_mem_start,
	.node_mem_size		= wildfire_node_mem_size,
};
ALIAS_MV(wildfire)
back to top