summaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/8xx_io/.cvsignore2
-rw-r--r--arch/ppc/8xx_io/Makefile13
-rw-r--r--arch/ppc/8xx_io/commproc.c222
-rw-r--r--arch/ppc/8xx_io/commproc.h464
-rw-r--r--arch/ppc/8xx_io/enet.c912
-rw-r--r--arch/ppc/8xx_io/uart.c2530
-rw-r--r--arch/ppc/Makefile41
-rw-r--r--arch/ppc/boot/Makefile131
-rw-r--r--arch/ppc/boot/head.S182
-rw-r--r--arch/ppc/boot/mbxtty.c118
-rw-r--r--arch/ppc/boot/misc.c121
-rw-r--r--arch/ppc/boot/vreset.c173
-rw-r--r--arch/ppc/chrp_defconfig321
-rw-r--r--arch/ppc/chrpboot/main.c10
-rw-r--r--arch/ppc/chrpboot/misc.S8
-rw-r--r--arch/ppc/coffboot/main.c11
-rw-r--r--arch/ppc/coffboot/misc.S13
-rw-r--r--arch/ppc/common_defconfig331
-rw-r--r--arch/ppc/config.in75
-rw-r--r--arch/ppc/defconfig177
-rw-r--r--arch/ppc/kernel/Makefile34
-rw-r--r--arch/ppc/kernel/align.c16
-rw-r--r--arch/ppc/kernel/chrp_pci.c22
-rw-r--r--arch/ppc/kernel/chrp_setup.c103
-rw-r--r--arch/ppc/kernel/chrp_time.c9
-rw-r--r--arch/ppc/kernel/head.S818
-rw-r--r--arch/ppc/kernel/idle.c205
-rw-r--r--arch/ppc/kernel/irq.c334
-rw-r--r--arch/ppc/kernel/mbx_pci.c254
-rw-r--r--arch/ppc/kernel/mbx_setup.c169
-rw-r--r--arch/ppc/kernel/misc.S59
-rw-r--r--arch/ppc/kernel/mk_defs.c4
-rw-r--r--arch/ppc/kernel/pci.c116
-rw-r--r--arch/ppc/kernel/pmac_pci.c65
-rw-r--r--arch/ppc/kernel/pmac_setup.c160
-rw-r--r--arch/ppc/kernel/pmac_support.c26
-rw-r--r--arch/ppc/kernel/pmac_time.c46
-rw-r--r--arch/ppc/kernel/ppc-stub.c705
-rw-r--r--arch/ppc/kernel/ppc_htab.c15
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c22
-rw-r--r--arch/ppc/kernel/prep_pci.c23
-rw-r--r--arch/ppc/kernel/prep_setup.c18
-rw-r--r--arch/ppc/kernel/prep_time.c2
-rw-r--r--arch/ppc/kernel/process.c110
-rw-r--r--arch/ppc/kernel/prom.c353
-rw-r--r--arch/ppc/kernel/ptrace.c11
-rw-r--r--arch/ppc/kernel/residual.c2
-rw-r--r--arch/ppc/kernel/setup.c395
-rw-r--r--arch/ppc/kernel/signal.c14
-rw-r--r--arch/ppc/kernel/smp.c189
-rw-r--r--arch/ppc/kernel/softemu8xx.c96
-rw-r--r--arch/ppc/kernel/time.c196
-rw-r--r--arch/ppc/kernel/time.h7
-rw-r--r--arch/ppc/kernel/traps.c93
-rw-r--r--arch/ppc/lib/locks.c160
-rw-r--r--arch/ppc/mbx_defconfig196
-rw-r--r--arch/ppc/mm/fault.c125
-rw-r--r--arch/ppc/mm/init.c612
-rw-r--r--arch/ppc/pmac_defconfig148
-rw-r--r--arch/ppc/prep_defconfig113
60 files changed, 10219 insertions, 1681 deletions
diff --git a/arch/ppc/8xx_io/.cvsignore b/arch/ppc/8xx_io/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/arch/ppc/8xx_io/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile
new file mode 100644
index 000000000..b33919a5d
--- /dev/null
+++ b/arch/ppc/8xx_io/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux MPC8xx ppc-specific parts of comm processor
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := 8xx_io.a
+O_OBJS = commproc.o uart.o enet.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
new file mode 100644
index 000000000..7e95afd08
--- /dev/null
+++ b/arch/ppc/8xx_io/commproc.c
@@ -0,0 +1,222 @@
+
+/*
+ * General Purpose functions for the global management of the
+ * Communication Processor Module.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space. The allocator for that is here. When the communication
+ * process is reset, we reclaim the memory available. There is
+ * currently no deallocator for this memory.
+ * The amount of space available is platform dependent. On the
+ * MBX, the EPPC software loads additional microcode into the
+ * communication processor, and uses some of the DP ram for this
+ * purpose. Current, the first 512 bytes and the last 256 bytes of
+ * memory are used. Right now I am conservative and only use the
+ * memory that can never be used for microcode. If there are
+ * applications that require more DP ram, we can expand the boundaries
+ * but then we have to be careful of any downloaded microcode.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/mbx.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/8xx_immap.h>
+#include "commproc.h"
+
+static uint dp_alloc_base; /* Starting offset in DP ram */
+static uint dp_alloc_top; /* Max offset + 1 */
+static uint host_buffer; /* One page of host buffer */
+static uint host_end; /* end + 1 */
+cpm8xx_t *cpmp; /* Pointer to comm processor space */
+
+/* CPM interrupt vector functions.
+*/
+struct cpm_action {
+ void (*handler)(void *);
+ void *dev_id;
+};
+static struct cpm_action cpm_vecs[CPMVEC_NR];
+static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
+static void cpm_error_interrupt(void *);
+
+void
+mbx_cpm_reset(uint host_page_addr)
+{
+ volatile immap_t *imp;
+ volatile cpm8xx_t *commproc;
+ pte_t *pte;
+
+ imp = (immap_t *)MBX_IMAP_ADDR;
+ commproc = (cpm8xx_t *)&imp->im_cpm;
+
+#ifdef notdef
+ /* We can't do this. It seems to blow away the microcode
+ * patch that EPPC-Bug loaded for us. EPPC-Bug uses SCC1 for
+ * Ethernet, SMC1 for the console, and I2C for serial EEPROM.
+ * Our own drivers quickly reset all of these.
+ */
+
+ /* Perform a reset.
+ */
+ commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
+
+ /* Wait for it.
+ */
+ while (commproc->cp_cpcr & CPM_CR_FLG);
+#endif
+
+ /* Set SDMA Bus Request priority 5.
+ */
+ imp->im_siu_conf.sc_sdcr = 1;
+
+ /* Reclaim the DP memory for our use.
+ */
+ dp_alloc_base = CPM_DATAONLY_BASE;
+ dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE;
+
+ /* Set the host page for allocation.
+ */
+ host_buffer = host_page_addr; /* Host virtual page address */
+ host_end = host_page_addr + PAGE_SIZE;
+ pte = va_to_pte(&init_task, host_page_addr);
+ pte_val(*pte) |= _PAGE_NO_CACHE;
+ flush_tlb_page(current->mm->mmap, host_buffer);
+
+ /* Tell everyone where the comm processor resides.
+ */
+ cpmp = (cpm8xx_t *)commproc;
+
+ /* Initialize the CPM interrupt controller.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cicr =
+ (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
+ ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
+ ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr = 0;
+
+ /* Set our interrupt handler with the core CPU.
+ */
+ if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
+ panic("Could not allocate CPM IRQ!");
+
+ /* Install our own error handler.
+ */
+ cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
+
+ ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
+}
+
+/* CPM interrupt controller interrupt.
+*/
+static void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+ uint vec;
+
+ /* Get the vector by setting the ACK bit and then reading
+ * the register.
+ */
+ ((volatile immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_civr = 1;
+ vec = ((volatile immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_civr;
+ vec >>= 11;
+
+ if (cpm_vecs[vec].handler != 0)
+ (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id);
+ else
+ ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+
+ /* After servicing the interrupt, we have to remove the status
+ * indicator.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
+
+}
+
+/* The CPM can generate the error interrupt when there is a race condition
+ * between generating and masking interrupts. All we have to do is ACK it
+ * and return. This is a no-op function so we don't need any special
+ * tests in the interrupt handler.
+ */
+static void
+cpm_error_interrupt(void *dev)
+{
+}
+
+/* Install a CPM interrupt handler.
+*/
+void
+cpm_install_handler(int vec, void (*handler)(void *), void *dev_id)
+{
+ if (cpm_vecs[vec].handler != 0)
+ printk("CPM interrupt %x replacing %x\n",
+ (uint)handler, (uint)cpm_vecs[vec].handler);
+ cpm_vecs[vec].handler = handler;
+ cpm_vecs[vec].dev_id = dev_id;
+ ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
+}
+
+/* Allocate some memory from the dual ported ram. We may want to
+ * enforce alignment restrictions, but right now everyone is a good
+ * citizen.
+ */
+uint
+mbx_cpm_dpalloc(uint size)
+{
+ uint retloc;
+
+ if ((dp_alloc_base + size) >= dp_alloc_top)
+ return(CPM_DP_NOSPACE);
+
+ retloc = dp_alloc_base;
+ dp_alloc_base += size;
+
+ return(retloc);
+}
+
+/* We also own one page of host buffer space for the allocation of
+ * UART "fifos" and the like.
+ */
+uint
+mbx_cpm_hostalloc(uint size)
+{
+ uint retloc;
+
+ if ((host_buffer + size) >= host_end)
+ return(0);
+
+ retloc = host_buffer;
+ host_buffer += size;
+
+ return(retloc);
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * four BRGs, any of which can be wired to any channel.
+ * The internal baud rate clock is the system clock divided by 16.
+ * I need to find a way to get this system clock frequency, which is
+ * part of the VPD.......
+ */
+#define BRG_INT_CLK (40000000/16)
+
+void
+mbx_cpm_setbrg(uint brg, uint rate)
+{
+ volatile uint *bp;
+
+ /* This is good enough to get SMCs running.....
+ */
+ bp = (uint *)&cpmp->cp_brgc1;
+ bp += brg;
+ *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+}
diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h
new file mode 100644
index 000000000..38046a31c
--- /dev/null
+++ b/arch/ppc/8xx_io/commproc.h
@@ -0,0 +1,464 @@
+
+/*
+ * MPC8xx Communication Processor Module.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * This file contains structures and information for the communication
+ * processor channels. Some CPM control and status is available
+ * throught the MPC8xx internal memory map. See immap.h for details.
+ * This file only contains what I need for the moment, not the total
+ * CPM capabilities. I (or someone else) will add definitions as they
+ * are needed. -- Dan
+ *
+ * On the MBX board, EPPC-Bug loads CPM microcode into the first 512
+ * bytes of the DP RAM and relocates the I2C parameter area to the
+ * IDMA1 space. The remaining DP RAM is available for buffer descriptors
+ * or other use.
+ */
+#ifndef __CPM_8XX__
+#define __CPM_8XX__
+
+#include <asm/8xx_immap.h>
+
+/* CPM Command register.
+*/
+#define CPM_CR_RST ((ushort)0x8000)
+#define CPM_CR_OPCODE ((ushort)0x0f00)
+#define CPM_CR_CHAN ((ushort)0x00f0)
+#define CPM_CR_FLG ((ushort)0x0001)
+
+/* Some commands (there are more...later)
+*/
+#define CPM_CR_INIT_TRX ((ushort)0x0000)
+#define CPM_CR_INIT_RX ((ushort)0x0001)
+#define CPM_CR_INIT_TX ((ushort)0x0002)
+#define CPM_CR_STOP_TX ((ushort)0x0004)
+#define CPM_CR_RESTART_TX ((ushort)0x0006)
+#define CPM_CR_SET_GADDR ((ushort)0x0008)
+
+/* Channel numbers.
+*/
+#define CPM_CR_CH_SCC1 ((ushort)0x0000)
+#define CPM_CR_CH_I2C ((ushort)0x0001) /* I2C and IDMA1 */
+#define CPM_CR_CH_SCC2 ((ushort)0x0004)
+#define CPM_CR_CH_SPI ((ushort)0x0005) /* SPI / IDMA2 / Timers */
+#define CPM_CR_CH_SCC3 ((ushort)0x0008)
+#define CPM_CR_CH_SMC1 ((ushort)0x0009) /* SMC1 / DSP1 */
+#define CPM_CR_CH_SCC4 ((ushort)0x000c)
+#define CPM_CR_CH_SMC2 ((ushort)0x000d) /* SMC2 / DSP2 */
+
+#define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4))
+
+/* The dual ported RAM is multi-functional. Some areas can be (and are
+ * being) used for microcode. There is an area that can only be used
+ * as data ram for buffer descriptors, which is all we use right now.
+ * Currently the first 512 and last 256 bytes are used for microcode.
+ */
+#define CPM_DATAONLY_BASE ((uint)0x0800)
+#define CPM_DATAONLY_SIZE ((uint)0x0700)
+#define CPM_DP_NOSPACE ((uint)0x7fffffff)
+
+/* Export the base address of the communication processor registers
+ * and dual port ram.
+ */
+extern cpm8xx_t *cpmp; /* Pointer to comm processor */
+uint mbx_cpm_dpalloc(uint size);
+uint mbx_cpm_hostalloc(uint size);
+void mbx_cpm_setbrg(uint brg, uint rate);
+
+/* Buffer descriptors used by many of the CPM protocols.
+*/
+typedef struct cpm_buf_desc {
+ ushort cbd_sc; /* Status and Control */
+ ushort cbd_datlen; /* Data length in buffer */
+ uint cbd_bufaddr; /* Buffer address in host memory */
+} cbd_t;
+
+#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */
+#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */
+#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */
+#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */
+#define BD_SC_CM ((ushort)0x0200) /* Continous mode */
+#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */
+#define BD_SC_P ((ushort)0x0100) /* xmt preamble */
+#define BD_SC_BR ((ushort)0x0020) /* Break received */
+#define BD_SC_FR ((ushort)0x0010) /* Framing error */
+#define BD_SC_PR ((ushort)0x0008) /* Parity error */
+#define BD_SC_OV ((ushort)0x0002) /* Overrun */
+#define BD_SC_CD ((ushort)0x0001) /* ?? */
+
+/* Define enough so I can at least use the MBX serial port as a UART.
+ * The MBX uses SMC1 as the host serial port.
+ */
+typedef struct smc_uart {
+ ushort smc_rbase; /* Rx Buffer descriptor base address */
+ ushort smc_tbase; /* Tx Buffer descriptor base address */
+ u_char smc_rfcr; /* Rx function code */
+ u_char smc_tfcr; /* Tx function code */
+ ushort smc_mrblr; /* Max receive buffer length */
+ uint smc_rstate; /* Internal */
+ uint smc_idp; /* Internal */
+ ushort smc_rbptr; /* Internal */
+ ushort smc_ibc; /* Internal */
+ uint smc_rxtmp; /* Internal */
+ uint smc_tstate; /* Internal */
+ uint smc_tdp; /* Internal */
+ ushort smc_tbptr; /* Internal */
+ ushort smc_tbc; /* Internal */
+ uint smc_txtmp; /* Internal */
+ ushort smc_maxidl; /* Maximum idle characters */
+ ushort smc_tmpidl; /* Temporary idle counter */
+ ushort smc_brklen; /* Last received break length */
+ ushort smc_brkec; /* rcv'd break condition counter */
+ ushort smc_brkcr; /* xmt break count register */
+ ushort smc_rmask; /* Temporary bit mask */
+} smc_uart_t;
+
+#define PROFF_SMC1 ((uint)0x0280) /* Offset in Parameter RAM */
+#define PROFF_SMC2 ((uint)0x0380)
+
+/* Function code bits.
+*/
+#define SMC_EB ((u_char)0x10) /* Set big endian byte order */
+
+/* SMC uart mode register.
+*/
+#define SMCMR_REN ((ushort)0x0001)
+#define SMCMR_TEN ((ushort)0x0002)
+#define SMCMR_DM ((ushort)0x000c)
+#define SMCMR_SM_GCI ((ushort)0x0000)
+#define SMCMR_SM_UART ((ushort)0x0020)
+#define SMCMR_SM_TRANS ((ushort)0x0030)
+#define SMCMR_SM_MASK ((ushort)0x0030)
+#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */
+#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */
+#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */
+#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */
+#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK)
+
+/* SMC Event and Mask register.
+*/
+#define SMCM_TXE ((unsigned char)0x10)
+#define SMCM_BSY ((unsigned char)0x14)
+#define SMCM_TX ((unsigned char)0x02)
+#define SMCM_RX ((unsigned char)0x01)
+
+/* Baud rate generators.
+*/
+#define CPM_BRG_RST ((uint)0x00020000)
+#define CPM_BRG_EN ((uint)0x00010000)
+#define CPM_BRG_EXTC_INT ((uint)0x00000000)
+#define CPM_BRG_EXTC_CLK2 ((uint)0x00004000)
+#define CPM_BRG_EXTC_CLK6 ((uint)0x00008000)
+#define CPM_BRG_ATB ((uint)0x00002000)
+#define CPM_BRG_CD_MASK ((uint)0x00001ffe)
+#define CPM_BRG_DIV16 ((uint)0x00000001)
+
+/* SCCs.
+*/
+#define SCC_GSMRH_IRP ((uint)0x00040000)
+#define SCC_GSMRH_GDE ((uint)0x00010000)
+#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000)
+#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000)
+#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000)
+#define SCC_GSMRH_REVD ((uint)0x00002000)
+#define SCC_GSMRH_TRX ((uint)0x00001000)
+#define SCC_GSMRH_TTX ((uint)0x00000800)
+#define SCC_GSMRH_CDP ((uint)0x00000400)
+#define SCC_GSMRH_CTSP ((uint)0x00000200)
+#define SCC_GSMRH_CDS ((uint)0x00000100)
+#define SCC_GSMRH_CTSS ((uint)0x00000080)
+#define SCC_GSMRH_TFL ((uint)0x00000040)
+#define SCC_GSMRH_RFW ((uint)0x00000020)
+#define SCC_GSMRH_TXSY ((uint)0x00000010)
+#define SCC_GSMRH_SYNL16 ((uint)0x0000000c)
+#define SCC_GSMRH_SYNL8 ((uint)0x00000008)
+#define SCC_GSMRH_SYNL4 ((uint)0x00000004)
+#define SCC_GSMRH_RTSM ((uint)0x00000002)
+#define SCC_GSMRH_RSYN ((uint)0x00000001)
+
+#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */
+#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000)
+#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000)
+#define SCC_GSMRL_EDGE_POS ((uint)0x20000000)
+#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000)
+#define SCC_GSMRL_TCI ((uint)0x10000000)
+#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000)
+#define SCC_GSMRL_TSNC_4 ((uint)0x08000000)
+#define SCC_GSMRL_TSNC_14 ((uint)0x04000000)
+#define SCC_GSMRL_TSNC_INF ((uint)0x00000000)
+#define SCC_GSMRL_RINV ((uint)0x02000000)
+#define SCC_GSMRL_TINV ((uint)0x01000000)
+#define SCC_GSMRL_TPL_128 ((uint)0x00c00000)
+#define SCC_GSMRL_TPL_64 ((uint)0x00a00000)
+#define SCC_GSMRL_TPL_48 ((uint)0x00800000)
+#define SCC_GSMRL_TPL_32 ((uint)0x00600000)
+#define SCC_GSMRL_TPL_16 ((uint)0x00400000)
+#define SCC_GSMRL_TPL_8 ((uint)0x00200000)
+#define SCC_GSMRL_TPL_NONE ((uint)0x00000000)
+#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000)
+#define SCC_GSMRL_TPP_01 ((uint)0x00100000)
+#define SCC_GSMRL_TPP_10 ((uint)0x00080000)
+#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000)
+#define SCC_GSMRL_TEND ((uint)0x00040000)
+#define SCC_GSMRL_TDCR_32 ((uint)0x00030000)
+#define SCC_GSMRL_TDCR_16 ((uint)0x00020000)
+#define SCC_GSMRL_TDCR_8 ((uint)0x00010000)
+#define SCC_GSMRL_TDCR_1 ((uint)0x00000000)
+#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000)
+#define SCC_GSMRL_RDCR_16 ((uint)0x00008000)
+#define SCC_GSMRL_RDCR_8 ((uint)0x00004000)
+#define SCC_GSMRL_RDCR_1 ((uint)0x00000000)
+#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000)
+#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000)
+#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000)
+#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800)
+#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000)
+#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600)
+#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400)
+#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200)
+#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100)
+#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000)
+#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */
+#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080)
+#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040)
+#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000)
+#define SCC_GSMRL_ENR ((uint)0x00000020)
+#define SCC_GSMRL_ENT ((uint)0x00000010)
+#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c)
+#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009)
+#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008)
+#define SCC_GSMRL_MODE_V14 ((uint)0x00000007)
+#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006)
+#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005)
+#define SCC_GSMRL_MODE_UART ((uint)0x00000004)
+#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003)
+#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002)
+#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000)
+
+#define SCC_TODR_TOD ((ushort)0x8000)
+
+typedef struct scc_param {
+ ushort scc_rbase; /* Rx Buffer descriptor base address */
+ ushort scc_tbase; /* Tx Buffer descriptor base address */
+ u_char scc_rfcr; /* Rx function code */
+ u_char scc_tfcr; /* Tx function code */
+ ushort scc_mrblr; /* Max receive buffer length */
+ uint scc_rstate; /* Internal */
+ uint scc_idp; /* Internal */
+ ushort scc_rbptr; /* Internal */
+ ushort scc_ibc; /* Internal */
+ uint scc_rxtmp; /* Internal */
+ uint scc_tstate; /* Internal */
+ uint scc_tdp; /* Internal */
+ ushort scc_tbptr; /* Internal */
+ ushort scc_tbc; /* Internal */
+ uint scc_txtmp; /* Internal */
+ uint scc_rcrc; /* Internal */
+ uint scc_tcrc; /* Internal */
+} sccp_t;
+
+/* Function code bits.
+*/
+#define SCC_EB ((u_char)0x10) /* Set big endian byte order */
+
+/* CPM Ethernet through SCC1.
+ */
+typedef struct scc_enet {
+ sccp_t sen_genscc;
+ uint sen_cpres; /* Preset CRC */
+ uint sen_cmask; /* Constant mask for CRC */
+ uint sen_crcec; /* CRC Error counter */
+ uint sen_alec; /* alignment error counter */
+ uint sen_disfc; /* discard frame counter */
+ ushort sen_pads; /* Tx short frame pad character */
+ ushort sen_retlim; /* Retry limit threshold */
+ ushort sen_retcnt; /* Retry limit counter */
+ ushort sen_maxflr; /* maximum frame length register */
+ ushort sen_minflr; /* minimum frame length register */
+ ushort sen_maxd1; /* maximum DMA1 length */
+ ushort sen_maxd2; /* maximum DMA2 length */
+ ushort sen_maxd; /* Rx max DMA */
+ ushort sen_dmacnt; /* Rx DMA counter */
+ ushort sen_maxb; /* Max BD byte count */
+ ushort sen_gaddr1; /* Group address filter */
+ ushort sen_gaddr2;
+ ushort sen_gaddr3;
+ ushort sen_gaddr4;
+ uint sen_tbuf0data0; /* Save area 0 - current frame */
+ uint sen_tbuf0data1; /* Save area 1 - current frame */
+ uint sen_tbuf0rba; /* Internal */
+ uint sen_tbuf0crc; /* Internal */
+ ushort sen_tbuf0bcnt; /* Internal */
+ ushort sen_paddrh; /* physical address (MSB) */
+ ushort sen_paddrm;
+ ushort sen_paddrl; /* physical address (LSB) */
+ ushort sen_pper; /* persistence */
+ ushort sen_rfbdptr; /* Rx first BD pointer */
+ ushort sen_tfbdptr; /* Tx first BD pointer */
+ ushort sen_tlbdptr; /* Tx last BD pointer */
+ uint sen_tbuf1data0; /* Save area 0 - current frame */
+ uint sen_tbuf1data1; /* Save area 1 - current frame */
+ uint sen_tbuf1rba; /* Internal */
+ uint sen_tbuf1crc; /* Internal */
+ ushort sen_tbuf1bcnt; /* Internal */
+ ushort sen_txlen; /* Tx Frame length counter */
+ ushort sen_iaddr1; /* Individual address filter */
+ ushort sen_iaddr2;
+ ushort sen_iaddr3;
+ ushort sen_iaddr4;
+ ushort sen_boffcnt; /* Backoff counter */
+
+ /* NOTE: Some versions of the manual have the following items
+ * incorrectly documented. Below is the proper order.
+ */
+ ushort sen_taddrh; /* temp address (MSB) */
+ ushort sen_taddrm;
+ ushort sen_taddrl; /* temp address (LSB) */
+} scc_enet_t;
+
+#define PROFF_SCC1 ((uint)0x0000) /* Offset in Parameter RAM */
+
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use. The TCLK and RCLK seem unique
+ * to the MBX860 board. Any two of the four available clocks could be
+ * used, and the MPC860 cookbook manual has an example using different
+ * clock pins.
+ */
+#define PA_ENET_RXD ((ushort)0x0001)
+#define PA_ENET_TXD ((ushort)0x0002)
+#define PA_ENET_TCLK ((ushort)0x0200)
+#define PA_ENET_RCLK ((ushort)0x0800)
+#define PC_ENET_TENA ((ushort)0x0001)
+#define PC_ENET_CLSN ((ushort)0x0010)
+#define PC_ENET_RENA ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x0000003d)
+
+/* SCC Event register as used by Ethernet.
+*/
+#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */
+#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */
+#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */
+#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */
+#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */
+#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */
+
+/* SCC Mode Register (PMSR) as used by Ethernet.
+*/
+#define SCC_PMSR_HBC ((ushort)0x8000) /* Enable heartbeat */
+#define SCC_PMSR_FC ((ushort)0x4000) /* Force collision */
+#define SCC_PMSR_RSH ((ushort)0x2000) /* Receive short frames */
+#define SCC_PMSR_IAM ((ushort)0x1000) /* Check individual hash */
+#define SCC_PMSR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */
+#define SCC_PMSR_PRO ((ushort)0x0200) /* Promiscuous mode */
+#define SCC_PMSR_BRO ((ushort)0x0100) /* Catch broadcast pkts */
+#define SCC_PMSR_SBT ((ushort)0x0080) /* Special backoff timer */
+#define SCC_PMSR_LPB ((ushort)0x0040) /* Set Loopback mode */
+#define SCC_PMSR_SIP ((ushort)0x0020) /* Sample Input Pins */
+#define SCC_PMSR_LCW ((ushort)0x0010) /* Late collision window */
+#define SCC_PMSR_NIB22 ((ushort)0x000a) /* Start frame search */
+#define SCC_PMSR_FDE ((ushort)0x0001) /* Full duplex enable */
+
+/* Buffer descriptor control/status used by Ethernet receive.
+*/
+#define BD_ENET_RX_EMPTY ((ushort)0x8000)
+#define BD_ENET_RX_WRAP ((ushort)0x2000)
+#define BD_ENET_RX_INTR ((ushort)0x1000)
+#define BD_ENET_RX_LAST ((ushort)0x0800)
+#define BD_ENET_RX_FIRST ((ushort)0x0400)
+#define BD_ENET_RX_MISS ((ushort)0x0100)
+#define BD_ENET_RX_LG ((ushort)0x0020)
+#define BD_ENET_RX_NO ((ushort)0x0010)
+#define BD_ENET_RX_SH ((ushort)0x0008)
+#define BD_ENET_RX_CR ((ushort)0x0004)
+#define BD_ENET_RX_OV ((ushort)0x0002)
+#define BD_ENET_RX_CL ((ushort)0x0001)
+#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+*/
+#define BD_ENET_TX_READY ((ushort)0x8000)
+#define BD_ENET_TX_PAD ((ushort)0x4000)
+#define BD_ENET_TX_WRAP ((ushort)0x2000)
+#define BD_ENET_TX_INTR ((ushort)0x1000)
+#define BD_ENET_TX_LAST ((ushort)0x0800)
+#define BD_ENET_TX_TC ((ushort)0x0400)
+#define BD_ENET_TX_DEF ((ushort)0x0200)
+#define BD_ENET_TX_HB ((ushort)0x0100)
+#define BD_ENET_TX_LC ((ushort)0x0080)
+#define BD_ENET_TX_RL ((ushort)0x0040)
+#define BD_ENET_TX_RCMASK ((ushort)0x003c)
+#define BD_ENET_TX_UN ((ushort)0x0002)
+#define BD_ENET_TX_CSL ((ushort)0x0001)
+#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
+
+/* SCC Event and Mask registers when it is used as a UART.
+*/
+#define UART_SCCM_GLR ((ushort)0x1000)
+#define UART_SCCM_GLT ((ushort)0x0800)
+#define UART_SCCM_AB ((ushort)0x0200)
+#define UART_SCCM_IDL ((ushort)0x0100)
+#define UART_SCCM_GRA ((ushort)0x0080)
+#define UART_SCCM_BRKE ((ushort)0x0040)
+#define UART_SCCM_BRKS ((ushort)0x0020)
+#define UART_SCCM_CCR ((ushort)0x0008)
+#define UART_SCCM_BSY ((ushort)0x0004)
+#define UART_SCCM_TX ((ushort)0x0002)
+#define UART_SCCM_RX ((ushort)0x0001)
+
+/* CPM interrupts. There are nearly 32 interrupts generated by CPM
+ * channels or devices. All of these are presented to the PPC core
+ * as a single interrupt. The CPM interrupt handler dispatches its
+ * own handlers, in a similar fashion to the PPC core handler. We
+ * use the table as defined in the manuals (i.e. no special high
+ * priority and SCC1 == SCCa, etc...).
+ */
+#define CPMVEC_NR 32
+#define CPMVEC_PIO_PC15 ((ushort)0x1f)
+#define CPMVEC_SCC1 ((ushort)0x1e)
+#define CPMVEC_SCC2 ((ushort)0x1d)
+#define CPMVEC_SCC3 ((ushort)0x1c)
+#define CPMVEC_SCC4 ((ushort)0x1b)
+#define CPMVEC_PIO_PC14 ((ushort)0x1a)
+#define CPMVEC_TIMER1 ((ushort)0x19)
+#define CPMVEC_PIO_PC13 ((ushort)0x18)
+#define CPMVEC_PIO_PC12 ((ushort)0x17)
+#define CPMVEC_SDMA_CB_ERR ((ushort)0x16)
+#define CPMVEC_IDMA1 ((ushort)0x15)
+#define CPMVEC_IDMA2 ((ushort)0x14)
+#define CPMVEC_TIMER2 ((ushort)0x12)
+#define CPMVEC_RISCTIMER ((ushort)0x11)
+#define CPMVEC_I2C ((ushort)0x10)
+#define CPMVEC_PIO_PC11 ((ushort)0x0f)
+#define CPMVEC_PIO_PC10 ((ushort)0x0e)
+#define CPMVEC_TIMER3 ((ushort)0x0c)
+#define CPMVEC_PIO_PC9 ((ushort)0x0b)
+#define CPMVEC_PIO_PC8 ((ushort)0x0a)
+#define CPMVEC_PIO_PC7 ((ushort)0x09)
+#define CPMVEC_TIMER4 ((ushort)0x07)
+#define CPMVEC_PIO_PC6 ((ushort)0x06)
+#define CPMVEC_SPI ((ushort)0x05)
+#define CPMVEC_SMC1 ((ushort)0x04)
+#define CPMVEC_SMC2 ((ushort)0x03)
+#define CPMVEC_PIO_PC5 ((ushort)0x02)
+#define CPMVEC_PIO_PC4 ((ushort)0x01)
+#define CPMVEC_ERROR ((ushort)0x00)
+
+extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
+
+/* CPM interrupt configuration vector.
+*/
+#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */
+#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */
+#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */
+#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */
+#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */
+#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */
+#define CICR_IEN ((uint)0x00000080) /* Int. enable */
+#define CICR_SPS ((uint)0x00000001) /* SCC Spread */
+#endif /* __CPM_8XX__ */
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
new file mode 100644
index 000000000..1c43ddce0
--- /dev/null
+++ b/arch/ppc/8xx_io/enet.c
@@ -0,0 +1,912 @@
+/*
+ * Ethernet driver for Motorola MPC8xx.
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * I copied the basic skeleton from the lance driver, because I did not
+ * know how to write the Linux driver, but I did know how the LANCE worked.
+ * This version of the driver is specific to the MBX implementation,
+ * since the board contains control registers external to the processor
+ * for the control of the MC68160 SIA/transceiver. The MPC860 manual
+ * describes connections using the internal parallel port I/O.
+ *
+ * The MBX860 uses the CPM SCC1 serial port for the Ethernet interface.
+ * Buffer descriptors are kept in the CPM dual port RAM, and the frame
+ * buffers are in the host memory.
+ *
+ * Right now, I am very watseful with the buffers. I allocate memory
+ * pages and then divide them into 2K frame buffers. This way I know I
+ * have buffers large enough to hold one frame within one buffer descriptor.
+ * Once I get this working, I will use 64 or 128 byte CPM buffers, which
+ * will be much more memory efficient and will easily handle lots of
+ * small packets.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/8xx_immap.h>
+#include <asm/pgtable.h>
+#include <asm/mbx.h>
+#include "commproc.h"
+#include <linux/delay.h>
+
+/*
+ * Theory of Operation
+ *
+ * The MPC8xx CPM performs the Ethernet processing on SCC1. It can use
+ * an aribtrary number of buffers on byte boundaries, but must have at
+ * least two receive buffers to prevent constand overrun conditions.
+ *
+ * The buffer descriptors are allocated from the CPM dual port memory
+ * with the data buffers allocated from host memory, just like all other
+ * serial communication protocols. The host memory buffers are allocated
+ * from the free page pool, and then divided into smaller receive and
+ * transmit buffers. The size of the buffers should be a power of two,
+ * since that nicely divides the page. This creates a ring buffer
+ * structure similar to the LANCE and other controllers.
+ *
+ * Like the LANCE driver:
+ * The driver runs as two independent, single-threaded flows of control. One
+ * is the send-packet routine, which enforces single-threaded use by the
+ * dev->tbusy flag. The other thread is the interrupt handler, which is single
+ * threaded by the hardware and other software.
+ *
+ * The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+ * flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+ * queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+ * the 'lp->tx_full' flag.
+ *
+ * The MBX has a control register external to the MPC8xx that has some
+ * control of the Ethernet interface. Control Register 1 has the
+ * following format:
+ * bit 0 - Set to enable Ethernet transceiver
+ * bit 1 - Set to enable Ethernet internal loopback
+ * bit 2 - Set to auto select AUI or TP port
+ * bit 3 - if bit 2 is 0, set to select TP port
+ * bit 4 - Set to disable full duplex (loopback)
+ * bit 5 - Set to disable XCVR collision test
+ * bit 6, 7 - Used for RS-232 control.
+ *
+ * EPPC-Bug sets this register to 0x98 for normal Ethernet operation,
+ * so we should not have to touch it.
+ *
+ * The following I/O is used by the MBX implementation of the MPC8xx to
+ * the MC68160 transceiver. It DOES NOT exactly follow the cookbook
+ * example from the MPC860 manual.
+ * Port A, 15 - SCC1 Ethernet Rx
+ * Port A, 14 - SCC1 Ethernet Tx
+ * Port A, 6 (CLK2) - SCC1 Ethernet Tx Clk
+ * Port A, 4 (CLK4) - SCC1 Ethernet Rx Clk
+ * Port C, 15 - SCC1 Ethernet Tx Enable
+ * Port C, 11 - SCC1 Ethernet Collision
+ * Port C, 10 - SCC1 Ethernet Rx Enable
+ */
+
+/* The number of Tx and Rx buffers. These are allocated from the page
+ * pool. The code may assume these are power of two, so it it best
+ * to keep them that size.
+ * We don't need to allocate pages for the transmitter. We just use
+ * the skbuffer directly.
+ */
+#define CPM_ENET_RX_PAGES 4
+#define CPM_ENET_RX_FRSIZE 2048
+#define CPM_ENET_RX_FRPPG (PAGE_SIZE / CPM_ENET_RX_FRSIZE)
+#define RX_RING_SIZE (CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES)
+#define TX_RING_SIZE 8 /* Must be power of two */
+#define TX_RING_MOD_MASK 7 /* for this to work */
+
+/* The CPM stores dest/src/type, data, and checksum for receive packets.
+ */
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+
+/* The CPM buffer descriptors track the ring buffers. The rx_bd_base and
+ * tx_bd_base always point to the base of the buffer descriptors. The
+ * cur_rx and cur_tx point to the currently available buffer.
+ * The dirty_tx tracks the current buffer that is being sent by the
+ * controller. The cur_tx and dirty_tx are equal under both completely
+ * empty and completely full conditions. The empty/ready indicator in
+ * the buffer descriptor determines the actual condition.
+ */
+struct cpm_enet_private {
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ ushort skb_cur;
+ ushort skb_dirty;
+
+ /* CPM dual port RAM relative addresses.
+ */
+ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */
+ cbd_t *tx_bd_base;
+ cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
+ cbd_t *dirty_tx; /* The ring entries to be free()ed. */
+ scc_t *sccp;
+ struct net_device_stats stats;
+ char tx_full;
+ unsigned long lock;
+};
+
+static int cpm_enet_open(struct device *dev);
+static int cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev);
+static int cpm_enet_rx(struct device *dev);
+static void cpm_enet_interrupt(void *dev_id);
+static int cpm_enet_close(struct device *dev);
+static struct net_device_stats *cpm_enet_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev);
+
+/* GET THIS FROM THE VPD!!!!
+*/
+static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };
+
+/* Initialize the CPM Ethernet on SCC1. If EPPC-Bug loaded us, or performed
+ * some other network I/O, a whole bunch of this has already been set up.
+ * It is no big deal if we do it again, we just have to disable the
+ * transmit and receive to make sure we don't catch the CPM with some
+ * inconsistent control information.
+ */
+__initfunc(int cpm_enet_init(void))
+{
+ struct device *dev;
+ struct cpm_enet_private *cep;
+ int i, j;
+ unsigned char *eap;
+ unsigned long mem_addr;
+ pte_t *pte;
+ volatile cbd_t *bdp;
+ volatile cpm8xx_t *cp;
+ volatile scc_t *sccp;
+ volatile scc_enet_t *ep;
+ volatile immap_t *immap;
+
+ cp = cpmp; /* Get pointer to Communication Processor */
+
+ immap = (immap_t *)MBX_IMAP_ADDR; /* and to internal registers */
+
+ /* Allocate some private information.
+ */
+ cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+ memset(cep, 0, sizeof(*cep));
+
+ /* Create an Ethernet device instance.
+ */
+ dev = init_etherdev(0, 0);
+
+ /* Get pointer to SCC1 area in parameter RAM.
+ */
+ ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_SCC1]);
+
+ /* And another to the SCC register area.
+ */
+ sccp = (volatile scc_t *)(&cp->cp_scc[0]);
+ cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */
+
+ /* Disable receive and transmit in case EPPC-Bug started it.
+ */
+ sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ /* Cookbook style from the MPC860 manual.....
+ * Not all of this is necessary if EPPC-Bug has initialized
+ * the network.
+ */
+
+ /* Configure port A pins for Txd and Rxd.
+ */
+ immap->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
+ immap->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
+ immap->im_ioport.iop_paodr &= ~PA_ENET_TXD;
+
+ /* Configure port C pins to enable CLSN and RENA.
+ */
+ immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
+
+ /* Configure port A for TCLK and RCLK.
+ */
+ immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
+ immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
+
+ /* Configure Serial Interface clock routing.
+ * First, clear all SCC1 bits to zero, then set the ones we want.
+ */
+ cp->cp_sicr &= ~SICR_ENET_MASK;
+ cp->cp_sicr |= SICR_ENET_CLKRT;
+
+ /* Manual says set SDDR, but I can't find anything with that
+ * name. I think it is a misprint, and should be SDCR. This
+ * has already been set by the communication processor initialization.
+ */
+
+ /* Allocate space for the buffer descriptors in the DP ram.
+ * These are relative offsets in the DP ram address space.
+ * Initialize base addresses for the buffer descriptors.
+ */
+ i = mbx_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE);
+ ep->sen_genscc.scc_rbase = i;
+ cep->rx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
+
+ i = mbx_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE);
+ ep->sen_genscc.scc_tbase = i;
+ cep->tx_bd_base = (cbd_t *)&cp->cp_dpmem[i];
+
+ cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
+ cep->cur_rx = cep->rx_bd_base;
+
+ /* Issue init Rx BD command for SCC1.
+ * Manual says to perform an Init Rx parameters here. We have
+ * to perform both Rx and Tx because the SCC may have been
+ * already running.
+ * In addition, we have to do it later because we don't yet have
+ * all of the BD control/status set properly.
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_RX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+ */
+
+ /* Initialize function code registers for big-endian.
+ */
+ ep->sen_genscc.scc_rfcr = SCC_EB;
+ ep->sen_genscc.scc_tfcr = SCC_EB;
+
+ /* Set maximum bytes per receive buffer.
+ * This appears to be an Ethernet frame size, not the buffer
+ * fragment size. It must be a multiple of four.
+ */
+ ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE;
+
+ /* Set CRC preset and mask.
+ */
+ ep->sen_cpres = 0xffffffff;
+ ep->sen_cmask = 0xdebb20e3;
+
+ ep->sen_crcec = 0; /* CRC Error counter */
+ ep->sen_alec = 0; /* alignment error counter */
+ ep->sen_disfc = 0; /* discard frame counter */
+
+ ep->sen_pads = 0x8888; /* Tx short frame pad character */
+ ep->sen_retlim = 15; /* Retry limit threshold */
+
+ ep->sen_maxflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
+ ep->sen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
+
+ ep->sen_maxd1 = PKT_MAXBUF_SIZE; /* maximum DMA1 length */
+ ep->sen_maxd2 = PKT_MAXBUF_SIZE; /* maximum DMA2 length */
+
+ /* Clear hash tables.
+ */
+ ep->sen_gaddr1 = 0;
+ ep->sen_gaddr2 = 0;
+ ep->sen_gaddr3 = 0;
+ ep->sen_gaddr4 = 0;
+ ep->sen_iaddr1 = 0;
+ ep->sen_iaddr2 = 0;
+ ep->sen_iaddr3 = 0;
+ ep->sen_iaddr4 = 0;
+
+ /* Set Ethernet station address. This must come from the
+ * Vital Product Data (VPD) EEPROM.....as soon as I get the
+ * I2C interface working.....
+ *
+ * Since we performed a diskless boot, the Ethernet controller
+ * has been initialized and we copy the address out into our
+ * own structure.
+ */
+#ifdef notdef
+ ep->sen_paddrh = my_enet_addr[0];
+ ep->sen_paddrm = my_enet_addr[1];
+ ep->sen_paddrl = my_enet_addr[2];
+#else
+ eap = (unsigned char *)&(ep->sen_paddrh);
+ for (i=5; i>=0; i--)
+ dev->dev_addr[i] = *eap++;
+#endif
+
+ ep->sen_pper = 0; /* 'cause the book says so */
+ ep->sen_taddrl = 0; /* temp address (LSB) */
+ ep->sen_taddrm = 0;
+ ep->sen_taddrh = 0; /* temp address (MSB) */
+
+ /* Now allocate the host memory pages and initialize the
+ * buffer descriptors.
+ */
+ bdp = cep->tx_bd_base;
+ for (i=0; i<TX_RING_SIZE; i++) {
+
+ /* Initialize the BD for every fragment in the page.
+ */
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap.
+ */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ bdp = cep->rx_bd_base;
+ for (i=0; i<CPM_ENET_RX_PAGES; i++) {
+
+ /* Allocate a page.
+ */
+ mem_addr = __get_free_page(GFP_KERNEL);
+
+ /* Make it uncached.
+ */
+ pte = va_to_pte(&init_task, mem_addr);
+ pte_val(*pte) |= _PAGE_NO_CACHE;
+ flush_tlb_page(current->mm->mmap, mem_addr);
+
+ /* Initialize the BD for every fragment in the page.
+ */
+ for (j=0; j<CPM_ENET_RX_FRPPG; j++) {
+ bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR;
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ mem_addr += CPM_ENET_RX_FRSIZE;
+ bdp++;
+ }
+ }
+
+ /* Set the last buffer to wrap.
+ */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ /* Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ cep->skb_cur = cep->skb_dirty = 0;
+
+ sccp->scc_scce = 0xffff; /* Clear any pending events */
+
+ /* Enable interrupts for transmit error, complete frame
+ * received, and any transmit buffer we have also set the
+ * interrupt flag.
+ */
+ sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
+
+ /* Install our interrupt handler.
+ */
+ cpm_install_handler(CPMVEC_SCC1, cpm_enet_interrupt, dev);
+
+ /* Set GSMR_H to enable all normal operating modes.
+ * Set GSMR_L to enable Ethernet to MC68160.
+ */
+ sccp->scc_gsmrh = 0;
+ sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET);
+
+ /* Set sync/delimiters.
+ */
+ sccp->scc_dsr = 0xd555;
+
+ /* Set processing mode. Use Ethernet CRC, catch broadcast, and
+ * start frame search 22 bit times after RENA.
+ */
+ sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_BRO | SCC_PMSR_NIB22);
+
+ /* It is now OK to enable the Ethernet transmitter.
+ */
+ immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
+ immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+
+ dev->base_addr = (unsigned long)ep;
+ dev->priv = cep;
+ dev->name = "CPM_ENET";
+
+ /* The CPM Ethernet specific entries in the device structure. */
+ dev->open = cpm_enet_open;
+ dev->hard_start_xmit = cpm_enet_start_xmit;
+ dev->stop = cpm_enet_close;
+ dev->get_stats = cpm_enet_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+
+ /* And last, enable the transmit and receive processing.
+ */
+ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+ printk("CPM ENET Version 0.1, ");
+ for (i=0; i<5; i++)
+ printk("%02x:", dev->dev_addr[i]);
+ printk("%02x\n", dev->dev_addr[5]);
+
+ return 0;
+}
+
+static int
+cpm_enet_open(struct device *dev)
+{
+
+ /* I should reset the ring buffers here, but I don't yet know
+ * a simple way to do that.
+ */
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ return 0; /* Always succeed */
+}
+
+static int
+cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+ volatile cbd_t *bdp;
+ unsigned long flags;
+
+ /* Transmitter timeout, serious problems. */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 20)
+ return 1;
+ printk("%s: transmit timed out.\n", dev->name);
+ cep->stats.tx_errors++;
+#ifndef final_version
+ {
+ int i;
+ cbd_t *bdp;
+ printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n",
+ cep->cur_tx, cep->tx_full ? " (full)" : "",
+ cep->cur_rx);
+ bdp = cep->tx_bd_base;
+ for (i = 0 ; i < TX_RING_SIZE; i++)
+ printk("%04x %04x %08x\n",
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ bdp->cbd_bufaddr);
+ bdp = cep->rx_bd_base;
+ for (i = 0 ; i < RX_RING_SIZE; i++)
+ printk("%04x %04x %08x\n",
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ bdp->cbd_bufaddr);
+ }
+#endif
+
+ dev->tbusy=0;
+ dev->trans_start = jiffies;
+
+ return 0;
+ }
+
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ return 1;
+ }
+
+ if (test_and_set_bit(0, (void*)&cep->lock) != 0) {
+ printk("%s: tx queue lock!.\n", dev->name);
+ /* don't clear dev->tbusy flag. */
+ return 1;
+ }
+
+ /* Fill in a Tx ring entry */
+ bdp = cep->cur_tx;
+
+#ifndef final_version
+ if (bdp->cbd_sc & BD_ENET_TX_READY) {
+ /* Ooops. All transmit buffers are full. Bail out.
+ * This should not happen, since dev->tbusy should be set.
+ */
+ printk("%s: tx queue full!.\n", dev->name);
+ cep->lock = 0;
+ return 1;
+ }
+#endif
+
+ /* Clear all of the status flags.
+ */
+ bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+
+ /* If the frame is short, tell CPM to pad it.
+ */
+ if (skb->len <= ETH_ZLEN)
+ bdp->cbd_sc |= BD_ENET_TX_PAD;
+ else
+ bdp->cbd_sc &= ~BD_ENET_TX_PAD;
+
+ /* Set buffer length and buffer pointer.
+ */
+ bdp->cbd_datlen = skb->len;
+ bdp->cbd_bufaddr = __pa(skb->data);
+
+ /* Save skb pointer.
+ */
+ cep->tx_skbuff[cep->skb_cur] = skb;
+
+ cep->stats.tx_bytes += skb->len;
+ cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
+
+ /* Push the data cache so the CPM does not get stale memory
+ * data.
+ */
+ /*flush_dcache_range(skb->data, skb->data + skb->len);*/
+
+ /* Send it on its way. Tell CPM its ready, interrupt when done,
+ * its the last BD of the frame, and to put the CRC on the end.
+ */
+ bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+
+ dev->trans_start = jiffies;
+
+ /* If this was the last BD in the ring, start at the beginning again.
+ */
+ if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+ bdp = cep->tx_bd_base;
+ else
+ bdp++;
+
+ save_flags(flags);
+ cli();
+ cep->lock = 0;
+ if (bdp->cbd_sc & BD_ENET_TX_READY)
+ cep->tx_full = 1;
+ else
+ dev->tbusy=0;
+ restore_flags(flags);
+
+ cep->cur_tx = (cbd_t *)bdp;
+
+ return 0;
+}
+
+/* The interrupt handler.
+ * This is called from the CPM handler, not the MPC core interrupt.
+ */
+static void
+cpm_enet_interrupt(void *dev_id)
+{
+ struct device *dev = dev_id;
+ struct cpm_enet_private *cep;
+ volatile cbd_t *bdp;
+ ushort int_events;
+ int must_restart;
+
+ cep = (struct cpm_enet_private *)dev->priv;
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+ dev->interrupt = 1;
+
+ /* Get the interrupt events that caused us to be here.
+ */
+ int_events = cep->sccp->scc_scce;
+ must_restart = 0;
+
+ /* Handle receive event in its own function.
+ */
+ if (int_events & SCCE_ENET_RXF)
+ cpm_enet_rx(dev_id);
+
+ /* Check for a transmit error. The manual is a little unclear
+ * about this, so the debug code until I get it figured out. It
+ * appears that if TXE is set, then TXB is not set. However,
+ * if carrier sense is lost during frame transmission, the TXE
+ * bit is set, "and continues the buffer transmission normally."
+ * I don't know if "normally" implies TXB is set when the buffer
+ * descriptor is closed.....trial and error :-).
+ */
+ if (int_events & SCCE_ENET_TXE) {
+
+ /* Transmission errors.
+ */
+ bdp = cep->dirty_tx;
+#ifndef final_version
+ printk("CPM ENET xmit error %x\n", bdp->cbd_sc);
+ if (bdp->cbd_sc & BD_ENET_TX_READY)
+ printk("HEY! Enet xmit interrupt and TX_READY.\n");
+#endif
+ if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */
+ cep->stats.tx_heartbeat_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */
+ cep->stats.tx_window_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */
+ cep->stats.tx_aborted_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */
+ cep->stats.tx_fifo_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+ cep->stats.tx_carrier_errors++;
+
+ cep->stats.tx_errors++;
+
+ /* No heartbeat or Lost carrier are not really bad errors.
+ * The others require a restart transmit command.
+ */
+ if (bdp->cbd_sc &
+ (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN))
+ must_restart = 1;
+ }
+
+ /* Transmit OK, or non-fatal error. Update the buffer descriptors.
+ */
+ if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+ cep->stats.tx_packets++;
+ bdp = cep->dirty_tx;
+#ifndef final_version
+ if (bdp->cbd_sc & BD_ENET_TX_READY)
+ printk("HEY! Enet xmit interrupt and TX_READY.\n");
+#endif
+ /* Deferred means some collisions occurred during transmit,
+ * but we eventually sent the packet OK.
+ */
+ if (bdp->cbd_sc & BD_ENET_TX_DEF)
+ cep->stats.collisions++;
+
+ /* Free the sk buffer associated with this last transmit.
+ */
+ dev_kfree_skb(cep->tx_skbuff[cep->skb_dirty]/*, FREE_WRITE*/);
+ cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+ /* Update pointer to next buffer descriptor to be transmitted.
+ */
+ if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+ bdp = cep->tx_bd_base;
+ else
+ bdp++;
+
+ /* I don't know if we can be held off from processing these
+ * interrupts for more than one frame time. I really hope
+ * not. In such a case, we would now want to check the
+ * currently available BD (cur_tx) and determine if any
+ * buffers between the dirty_tx and cur_tx have also been
+ * sent. We would want to process anything in between that
+ * does not have BD_ENET_TX_READY set.
+ */
+
+ /* Since we have freed up a buffer, the ring is no longer
+ * full.
+ */
+ if (cep->tx_full && dev->tbusy) {
+ cep->tx_full = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+
+ cep->dirty_tx = (cbd_t *)bdp;
+ }
+
+ if (must_restart) {
+ volatile cpm8xx_t *cp;
+
+ /* Some transmit errors cause the transmitter to shut
+ * down. We now issue a restart transmit. Since the
+ * errors close the BD and update the pointers, the restart
+ * _should_ pick up without having to reset any of our
+ * pointers either.
+ */
+ cp = cpmp;
+ cp->cp_cpcr =
+ mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+ }
+
+ /* Check for receive busy, i.e. packets coming but no place to
+ * put them. This "can't happen" because the receive interrupt
+ * is tossing previous frames.
+ */
+ if (int_events & SCCE_ENET_BSY) {
+ cep->stats.rx_dropped++;
+ printk("CPM ENET: BSY can't happen.\n");
+ }
+
+ /* Write the SCC event register with the events we have handled
+ * to clear them. Maybe we should do this sooner?
+ */
+ cep->sccp->scc_scce = int_events;
+
+ dev->interrupt = 0;
+
+ return;
+}
+
+/* During a receive, the cur_rx points to the current incoming buffer.
+ * When we update through the ring, if the next incoming buffer has
+ * not been given to the system, we just set the empty indicator,
+ * effectively tossing the packet.
+ */
+static int
+cpm_enet_rx(struct device *dev)
+{
+ struct cpm_enet_private *cep;
+ volatile cbd_t *bdp;
+ struct sk_buff *skb;
+ ushort pkt_len;
+
+ cep = (struct cpm_enet_private *)dev->priv;
+
+ /* First, grab all of the stats for the incoming packet.
+ * These get messed up if we get called due to a busy condition.
+ */
+ bdp = cep->cur_rx;
+
+for (;;) {
+ if (bdp->cbd_sc & BD_ENET_RX_EMPTY)
+ break;
+
+#ifndef final_version
+ /* Since we have allocated space to hold a complete frame, both
+ * the first and last indicators should be set.
+ */
+ if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) !=
+ (BD_ENET_RX_FIRST | BD_ENET_RX_LAST))
+ printk("CPM ENET: rcv is not first+last\n");
+#endif
+
+ /* Frame too long or too short.
+ */
+ if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+ cep->stats.rx_length_errors++;
+ if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */
+ cep->stats.rx_frame_errors++;
+ if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */
+ cep->stats.rx_crc_errors++;
+ if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */
+ cep->stats.rx_crc_errors++;
+
+ /* Report late collisions as a frame error.
+ * On this error, the BD is closed, but we don't know what we
+ * have in the buffer. So, just drop this frame on the floor.
+ */
+ if (bdp->cbd_sc & BD_ENET_RX_CL) {
+ cep->stats.rx_frame_errors++;
+ }
+ else {
+
+ /* Process the incoming frame.
+ */
+ cep->stats.rx_packets++;
+ pkt_len = bdp->cbd_datlen;
+ cep->stats.rx_bytes += pkt_len;
+
+ /* This does 16 byte alignment, much more than we need.
+ */
+ skb = dev_alloc_skb(pkt_len);
+
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ cep->stats.rx_dropped++;
+ }
+ else {
+ skb->dev = dev;
+ skb_put(skb,pkt_len); /* Make room */
+ eth_copy_and_sum(skb,
+ (unsigned char *)__va(bdp->cbd_bufaddr),
+ pkt_len, 0);
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ }
+ }
+
+ /* Clear the status flags for this buffer.
+ */
+ bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+
+ /* Mark the buffer empty.
+ */
+ bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+
+ /* Update BD pointer to next entry.
+ */
+ if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+ bdp = cep->rx_bd_base;
+ else
+ bdp++;
+
+ }
+ cep->cur_rx = (cbd_t *)bdp;
+
+ return 0;
+}
+
+static int
+cpm_enet_close(struct device *dev)
+{
+ /* Don't know what to do yet.
+ */
+
+ return 0;
+}
+
+static struct net_device_stats *cpm_enet_get_stats(struct device *dev)
+{
+ struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+
+ return &cep->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ * Skeleton taken from sunlance driver.
+ * The CPM Ethernet implementation allows Multicast as well as individual
+ * MAC address filtering. Some of the drivers check to make sure it is
+ * a group multicast address, and discard those that are not. I guess I
+ * will do the same for now, but just remove the test if you want
+ * individual filtering as well (do the upper net layers want or support
+ * this kind of feature?).
+ */
+
+static void set_multicast_list(struct device *dev)
+{
+ struct cpm_enet_private *cep;
+ struct dev_mc_list *dmi;
+ u_char *mcptr, *tdptr;
+ volatile scc_enet_t *ep;
+ int i, j;
+
+ cep = (struct cpm_enet_private *)dev->priv;
+
+ /* Get pointer to SCC1 area in parameter RAM.
+ */
+ ep = (scc_enet_t *)dev->base_addr;
+
+ if (dev->flags&IFF_PROMISC) {
+ /* Log any net taps. */
+ printk("%s: Promiscuous mode enabled.\n", dev->name);
+ cep->sccp->scc_pmsr |= SCC_PMSR_PRO;
+ } else {
+
+ cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO;
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /* Catch all multicast addresses, so set the
+ * filter to all 1's.
+ */
+ ep->sen_gaddr1 = 0xffff;
+ ep->sen_gaddr2 = 0xffff;
+ ep->sen_gaddr3 = 0xffff;
+ ep->sen_gaddr4 = 0xffff;
+ }
+ else {
+ /* Clear filter and add the addresses in the list.
+ */
+ ep->sen_gaddr1 = 0;
+ ep->sen_gaddr2 = 0;
+ ep->sen_gaddr3 = 0;
+ ep->sen_gaddr4 = 0;
+
+ dmi = dev->mc_list;
+
+ for (i=0; i<dev->mc_count; i++) {
+
+ /* Only support group multicast for now.
+ */
+ if (!(dmi->dmi_addr[0] & 1))
+ continue;
+
+ /* The address in dmi_addr is LSB first,
+ * and taddr is MSB first. We have to
+ * copy bytes MSB first from dmi_addr.
+ */
+ mcptr = (u_char *)dmi->dmi_addr + 5;
+ tdptr = (u_char *)&ep->sen_taddrh;
+ for (j=0; j<6; j++)
+ *tdptr++ = *mcptr--;
+
+ /* Ask CPM to run CRC and set bit in
+ * filter mask.
+ */
+ cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG;
+ while (cpmp->cp_cpcr & CPM_CR_FLG);
+ }
+ }
+ }
+}
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
new file mode 100644
index 000000000..a60eda695
--- /dev/null
+++ b/arch/ppc/8xx_io/uart.c
@@ -0,0 +1,2530 @@
+/*
+ * UART driver for MPC860 CPM SCC or SMC
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * I used the serial.c driver as the framework for this driver.
+ * Give credit to those guys.
+ * The original code was written for the MBX860 board. I tried to make
+ * it generic, but there may be some assumptions in the structures that
+ * have to be fixed later.
+ * To save porting time, I did not bother to change any object names
+ * that are not accessed outside of this file.
+ * It still needs lots of work........When it was easy, I included code
+ * to support the SCCs, but this has never been tested, nor is it complete.
+ * Only the SCCs support modem control, so that is not complete either.
+ *
+ * This module exports the following rs232 io functions:
+ *
+ * int rs_8xx_init(void);
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#include "commproc.h"
+
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+
+/* this defines the index into rs_table for the port to use
+*/
+#ifndef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT 0
+#endif
+#endif
+
+#define TX_WAKEUP ASYNC_SHARE_IRQ
+
+static char *serial_name = "CPM UART driver";
+static char *serial_version = "0.01";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/*
+ * Serial driver configuration section. Here are the various options:
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define _INLINE_ inline
+
+#define DBG_CNT(s)
+
+/* We overload some of the items in the data structure to meet our
+ * needs. For example, the port address is the CPM parameter ram
+ * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and
+ * 2 SMCs. The "hub6" field is used to indicate the channel number, with
+ * 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs.
+ * Since these ports are so versatile, I don't yet have a strategy for
+ * their management. For example, SCC1 is used for Ethernet. Right
+ * now, just don't put them in the table. Of course, right now I just
+ * want the SMC to work as a uart :-)..
+ * The "type" field is currently set to 0, for PORT_UNKNOWN. It is
+ * not currently used. I should probably use it to indicate the port
+ * type of CMS or SCC.
+ * The SMCs do not support any modem control signals.
+ */
+#define smc_scc_num hub6
+#define SCC_NUM_BASE 2
+
+static struct serial_state rs_table[] = {
+ /* UART CLK PORT IRQ FLAGS NUM */
+ { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */
+ { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC1 ttyS0 */
+};
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+/* The number of buffer descriptors and their sizes.
+*/
+#define RX_NUM_FIFO 4
+#define RX_BUF_SIZE 32
+#define TX_NUM_FIFO 4
+#define TX_BUF_SIZE 32
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* The async_struct in serial.h does not really give us what we
+ * need, so define our own here.
+ */
+typedef struct serial_info {
+ int magic;
+ int flags;
+ struct serial_state *state;
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int line;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned long event;
+ unsigned long last_active;
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+
+ /* CPM Buffer Descriptor pointers.
+ */
+ cbd_t *rx_bd_base;
+ cbd_t *rx_cur;
+ cbd_t *tx_bd_base;
+ cbd_t *tx_cur;
+} ser_info_t;
+
+static void change_speed(ser_info_t *info);
+static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static inline int serial_paranoia_check(ser_info_t *info,
+ kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+ static const char *badmagic =
+ "Warning: bad magic number for serial struct (%s) in %s\n";
+ static const char *badinfo =
+ "Warning: null async_struct for (%s) in %s\n";
+
+ if (!info) {
+ printk(badinfo, kdevname(device), routine);
+ return 1;
+ }
+ if (info->magic != SERIAL_MAGIC) {
+ printk(badmagic, kdevname(device), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts,
+ * indexed by the termio value. The generic CPM functions are responsible
+ * for setting and assigning baud rate generators for us.
+ */
+static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_stop(struct tty_struct *tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ int idx;
+ unsigned long flags;
+ volatile scc_t *sccp;
+ volatile smc_t *smcp;
+
+ if (serial_paranoia_check(info, tty->device, "rs_stop"))
+ return;
+
+ save_flags(flags); cli();
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+ smcp->smc_smcm &= ~SMCM_TX;
+ }
+ else {
+ sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+ sccp->scc_sccm &= ~UART_SCCM_TX;
+ }
+ restore_flags(flags);
+}
+
+static void rs_8xx_start(struct tty_struct *tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ int idx;
+ unsigned long flags;
+ volatile scc_t *sccp;
+ volatile smc_t *smcp;
+
+ if (serial_paranoia_check(info, tty->device, "rs_stop"))
+ return;
+
+ save_flags(flags); cli();
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+ smcp->smc_smcm |= SMCM_TX;
+ }
+ else {
+ sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+ sccp->scc_sccm |= UART_SCCM_TX;
+ }
+ restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(ser_info_t *info,
+ int event)
+{
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(ser_info_t *info)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, *cp;
+ int ignored = 0;
+ int i;
+ ushort status;
+ struct async_icount *icount;
+ volatile cbd_t *bdp;
+
+ icount = &info->state->icount;
+
+ /* Just loop through the closed BDs and copy the characters into
+ * the buffer.
+ */
+ bdp = info->rx_cur;
+ for (;;) {
+ if (bdp->cbd_sc & BD_SC_EMPTY) /* If this one is empty */
+ break; /* we are all done */
+
+ /* The read status mask tell us what we should do with
+ * incoming characters, especially if errors occur.
+ * One special case is the use of BD_SC_EMPTY. If
+ * this is not set, we are supposed to be ignoring
+ * inputs. In this case, just mark the buffer empty and
+ * continue.
+ if (!(info->read_status_mask & BD_SC_EMPTY)) {
+ bdp->cbd_sc |= BD_SC_EMPTY;
+ bdp->cbd_sc &=
+ ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = info->rx_bd_base;
+ else
+ bdp++;
+ continue;
+ }
+ */
+
+ /* Get the number of characters and the buffer pointer.
+ */
+ i = bdp->cbd_datlen;
+ cp = (unsigned char *)__va(bdp->cbd_bufaddr);
+ status = bdp->cbd_sc;
+
+ /* Check to see if there is room in the tty buffer for
+ * the characters in our BD buffer. If not, we exit
+ * now, leaving the BD with the characters. We'll pick
+ * them up again on the next receive interrupt (which could
+ * be a timeout).
+ */
+ if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE)
+ break;
+
+ while (i-- > 0) {
+ ch = *cp++;
+ *tty->flip.char_buf_ptr = ch;
+ icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+ printk("DR%02x:%02x...", ch, *status);
+#endif
+ *tty->flip.flag_buf_ptr = 0;
+ if (status & (BD_SC_BR | BD_SC_FR |
+ BD_SC_PR | BD_SC_OV)) {
+ /*
+ * For statistics only
+ */
+ if (status & BD_SC_BR)
+ icount->brk++;
+ else if (status & BD_SC_PR)
+ icount->parity++;
+ else if (status & BD_SC_FR)
+ icount->frame++;
+ if (status & BD_SC_OV)
+ icount->overrun++;
+
+ /*
+ * Now check to see if character should be
+ * ignored, and mask off conditions which
+ * should be ignored.
+ if (status & info->ignore_status_mask) {
+ if (++ignored > 100)
+ break;
+ continue;
+ }
+ */
+ status &= info->read_status_mask;
+
+ if (status & (BD_SC_BR)) {
+#ifdef SERIAL_DEBUG_INTR
+ printk("handling break....");
+#endif
+ *tty->flip.flag_buf_ptr = TTY_BREAK;
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (status & BD_SC_PR)
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ else if (status & BD_SC_FR)
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ if (status & BD_SC_OV) {
+ /*
+ * Overrun is special, since it's
+ * reported immediately, and doesn't
+ * affect the current character
+ */
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ *tty->flip.flag_buf_ptr =
+ TTY_OVERRUN;
+ }
+ }
+ }
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ break;
+
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+
+ /* This BD is ready to be used again. Clear status.
+ * Get next BD.
+ */
+ bdp->cbd_sc |= BD_SC_EMPTY;
+ bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = info->rx_bd_base;
+ else
+ bdp++;
+ }
+
+ info->rx_cur = (cbd_t *)bdp;
+
+ queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static _INLINE_ void transmit_chars(ser_info_t *info)
+{
+
+ if (info->flags & TX_WAKEUP) {
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+ }
+
+#ifdef SERIAL_DEBUG_INTR
+ printk("THRE...");
+#endif
+}
+
+#ifdef notdef
+ /* I need to do this for the SCCs, so it is left as a reminder.
+ */
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+ int status;
+ struct async_icount *icount;
+
+ status = serial_in(info, UART_MSR);
+
+ if (status & UART_MSR_ANY_DELTA) {
+ icount = &info->state->icount;
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ icount->rng++;
+ if (status & UART_MSR_DDSR)
+ icount->dsr++;
+ if (status & UART_MSR_DDCD) {
+ icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+ if ((info->flags & ASYNC_HARDPPS_CD) &&
+ (status & UART_MSR_DCD))
+ hardpps();
+#endif
+ }
+ if (status & UART_MSR_DCTS)
+ icount->cts++;
+ wake_up_interruptible(&info->delta_msr_wait);
+ }
+
+ if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+ printk("ttys%d CD now %s...", info->line,
+ (status & UART_MSR_DCD) ? "on" : "off");
+#endif
+ if (status & UART_MSR_DCD)
+ wake_up_interruptible(&info->open_wait);
+ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("scheduling hangup...");
+#endif
+ queue_task(&info->tqueue_hangup,
+ &tq_scheduler);
+ }
+ }
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+ printk("CTS tx start...");
+#endif
+ info->tty->hw_stopped = 0;
+ info->IER |= UART_IER_THRI;
+ serial_out(info, UART_IER, info->IER);
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+ return;
+ }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+ printk("CTS tx stop...");
+#endif
+ info->tty->hw_stopped = 1;
+ info->IER &= ~UART_IER_THRI;
+ serial_out(info, UART_IER, info->IER);
+ }
+ }
+ }
+}
+#endif
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void rs_8xx_interrupt(void *dev_id)
+{
+ u_char events;
+ int idx;
+ ser_info_t *info;
+ volatile smc_t *smcp;
+
+ info = (ser_info_t *)dev_id;
+
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+ }
+ else {
+ panic("SCC UART Interrupt....not ready");
+ }
+
+ events = smcp->smc_smce;
+#ifdef SERIAL_DEBUG_INTR
+ printk("rs_interrupt_single(%d, %x)...",
+ info->state->smc_scc_num, events);
+#endif
+ if (events & SMCM_RX)
+ receive_chars(info);
+ if (events & SMCM_TX)
+ transmit_chars(info);
+ smcp->smc_smce = events;
+#ifdef modem_control
+ check_modem_status(info);
+#endif
+ info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+ printk("end.\n");
+#endif
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+ run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+ ser_info_t *info = (ser_info_t *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (scheduler tqueue) ->
+ * do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ *
+ */
+static void do_serial_hangup(void *private_)
+{
+ struct async_struct *info = (struct async_struct *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ tty_hangup(tty);
+}
+
+static void rs_8xx_timer(void)
+{
+ printk("rs_8xx_timer\n");
+}
+
+
+static int startup(ser_info_t *info)
+{
+ unsigned long flags;
+ int retval=0;
+ int idx;
+ struct serial_state *state= info->state;
+ volatile smc_t *smcp;
+ volatile scc_t *sccp;
+ volatile smc_uart_t *up;
+
+
+ save_flags(flags); cli();
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ goto errout;
+ }
+
+#ifdef maybe
+ if (!state->port || !state->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ goto errout;
+ }
+#endif
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+
+#ifdef modem_control
+ info->MCR = 0;
+ if (info->tty->termios->c_cflag & CBAUD)
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#endif
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ /*
+ * and set the speed of the serial port
+ */
+ change_speed(info);
+
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+
+ /* Enable interrupts and I/O.
+ */
+ smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+ smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+
+ /* We can tune the buffer length and idle characters
+ * to take advantage of the entire incoming buffer size.
+ * If mrblr is something other than 1, maxidl has to be
+ * non-zero or we never get an interrupt. The maxidl
+ * is the number of character times we wait after reception
+ * of the last character before we decide no more characters
+ * are coming.
+ */
+ up = (smc_uart_t *)&cpmp->cp_dparam[state->port];
+ up->smc_mrblr = 1; /* receive buffer length */
+ up->smc_maxidl = 0; /* wait forever for next char */
+ up->smc_brkcr = 1; /* number of break chars */
+ }
+ else {
+ sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+ sccp->scc_sccm |= UART_SCCM_RX;
+ }
+
+ info->flags |= ASYNC_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+
+errout:
+ restore_flags(flags);
+ return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(ser_info_t * info)
+{
+ unsigned long flags;
+ struct serial_state *state;
+ int idx;
+ volatile smc_t *smcp;
+ volatile scc_t *sccp;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("Shutting down serial port %d (irq %d)....", info->line,
+ state->irq);
+#endif
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+
+ /* Disable interrupts and I/O.
+ */
+ smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+#ifdef CONFIG_SERIAL_CONSOLE
+ /* We can't disable the transmitter if this is the
+ * system console.
+ */
+ if (idx != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+ smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+ }
+ else {
+ sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+ sccp->scc_sccm &= ~UART_SCCM_RX;
+ }
+
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(ser_info_t *info)
+{
+ int baud_rate;
+ unsigned cflag, cval, prev_mode;
+ int i, bits, idx;
+ unsigned long flags;
+ volatile smc_t *smcp;
+ volatile scc_t *sccp;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+
+ /* Character length programmed into the mode register is the
+ * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+ * 1 or 2 stop bits, minus 1.
+ * The value 'bits' counts this for us.
+ */
+ cval = 0;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5: bits = 5; break;
+ case CS6: bits = 6; break;
+ case CS7: bits = 7; break;
+ case CS8: bits = 8; break;
+ /* Never happens, but GCC is too dumb to figure it out */
+ default: bits = 8; break;
+ }
+ if (cflag & CSTOPB) {
+ cval |= SMCMR_SL; /* Two stops */
+ bits++;
+ }
+ if (cflag & PARENB) {
+ cval |= SMCMR_PEN;
+ bits++;
+ }
+ if (!(cflag & PARODD))
+ cval |= SMCMR_PM_EVEN;
+
+ /* Determine divisor based on baud rate */
+ i = cflag & CBAUD;
+ if (i & CBAUDEX) {
+ i &= ~CBAUDEX;
+ if (i < 1 || i > 4)
+ info->tty->termios->c_cflag &= ~CBAUDEX;
+ else
+ i += 15;
+ }
+
+ baud_rate = baud_table[i];
+
+ info->timeout = (TX_BUF_SIZE*HZ*bits);
+ info->timeout += HZ/50; /* Add .02 seconds of slop */
+
+#ifdef modem_control
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ if (info->flags & ASYNC_HARDPPS_CD)
+ info->IER |= UART_IER_MSI;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ } else
+ info->flags &= ~ASYNC_CTS_FLOW;
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ serial_out(info, UART_IER, info->IER);
+#endif
+
+ /*
+ * Set up parity check flag
+ */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+ info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= BD_SC_FR | BD_SC_PR;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= BD_SC_BR;
+
+ /*
+ * Characters to ignore
+ */
+ info->ignore_status_mask = 0;
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= BD_SC_BR;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= BD_SC_OV;
+ }
+ /*
+ * !!! ignore all characters if CREAD is not set
+ */
+ if ((cflag & CREAD) == 0)
+ info->read_status_mask &= ~BD_SC_EMPTY;
+ save_flags(flags); cli();
+
+ /* Start bit has not been added (so don't, because we would just
+ * subtract it later), and we need to add one for the number of
+ * stops bits (there is always at least one).
+ */
+ bits++;
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+
+ /* Set the mode register. We want to keep a copy of the
+ * enables, because we want to put them back if they were
+ * present.
+ */
+ prev_mode = smcp->smc_smcmr;
+ smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
+ smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+ }
+ else {
+ sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+ sccp->scc_sccm &= ~UART_SCCM_RX;
+ }
+
+ mbx_cpm_setbrg(info->state->smc_scc_num, baud_rate);
+
+ restore_flags(flags);
+}
+
+static void rs_8xx_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ volatile cbd_t *bdp;
+
+ if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+ return;
+
+ if (!tty)
+ return;
+
+ bdp = info->tx_cur;
+ while (bdp->cbd_sc & BD_SC_READY);
+
+ *((char *)__va(bdp->cbd_bufaddr)) = ch;
+ bdp->cbd_datlen = 1;
+ bdp->cbd_sc |= BD_SC_READY;
+
+ /* Get next BD.
+ */
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = info->tx_bd_base;
+ else
+ bdp++;
+
+ info->tx_cur = (cbd_t *)bdp;
+
+}
+
+static int rs_8xx_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, ret = 0;
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ volatile cbd_t *bdp;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty)
+ return 0;
+
+ bdp = info->tx_cur;
+
+ while (1) {
+ c = MIN(count, TX_BUF_SIZE);
+
+ if (c <= 0)
+ break;
+
+ if (bdp->cbd_sc & BD_SC_READY) {
+ info->flags |= TX_WAKEUP;
+ break;
+ }
+
+ if (from_user) {
+ if (c !=
+ copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ } else {
+ memcpy(__va(bdp->cbd_bufaddr), buf, c);
+ }
+
+ bdp->cbd_datlen = c;
+ bdp->cbd_sc |= BD_SC_READY;
+
+ buf += c;
+ count -= c;
+ ret += c;
+
+ /* Get next BD.
+ */
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = info->tx_bd_base;
+ else
+ bdp++;
+ info->tx_cur = (cbd_t *)bdp;
+ }
+ return ret;
+}
+
+static int rs_8xx_write_room(struct tty_struct *tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ int ret;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+ return 0;
+
+ if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) {
+ info->flags &= ~TX_WAKEUP;
+ ret = TX_BUF_SIZE;
+ }
+ else {
+ info->flags |= TX_WAKEUP;
+ ret = 0;
+ }
+ return ret;
+}
+
+/* I could track this with transmit counters....maybe later.
+*/
+static int rs_8xx_chars_in_buffer(struct tty_struct *tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+ return 0;
+ return 0;
+}
+
+static void rs_8xx_flush_buffer(struct tty_struct *tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+ return;
+
+ /* There is nothing to "flush", whatever we gave the CPM
+ * is on its way out.
+ */
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ info->flags &= ~TX_WAKEUP;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_8xx_send_xchar(struct tty_struct *tty, char ch)
+{
+ volatile cbd_t *bdp;
+
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+ if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+ return;
+
+ bdp = info->tx_cur;
+ while (bdp->cbd_sc & BD_SC_READY);
+
+ *((char *)__va(bdp->cbd_bufaddr)) = ch;
+ bdp->cbd_datlen = 1;
+ bdp->cbd_sc |= BD_SC_READY;
+
+ /* Get next BD.
+ */
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = info->tx_bd_base;
+ else
+ bdp++;
+
+ info->tx_cur = (cbd_t *)bdp;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_throttle(struct tty_struct * tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+ return;
+
+ if (I_IXOFF(tty))
+ rs_8xx_send_xchar(tty, STOP_CHAR(tty));
+
+#ifdef modem_control
+ if (tty->termios->c_cflag & CRTSCTS)
+ info->MCR &= ~UART_MCR_RTS;
+
+ cli();
+ serial_out(info, UART_MCR, info->MCR);
+ sti();
+#endif
+}
+
+static void rs_8xx_unthrottle(struct tty_struct * tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+ return;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ rs_8xx_send_xchar(tty, START_CHAR(tty));
+ }
+#ifdef modem_control
+ if (tty->termios->c_cflag & CRTSCTS)
+ info->MCR |= UART_MCR_RTS;
+ cli();
+ serial_out(info, UART_MCR, info->MCR);
+ sti();
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#ifdef maybe
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+ unsigned char status;
+ unsigned int result;
+
+ cli();
+ status = serial_in(info, UART_LSR);
+ sti();
+ result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+ return put_user(result,value);
+}
+#endif
+
+static int get_modem_info(ser_info_t *info, unsigned int *value)
+{
+ unsigned int result = 0;
+#ifdef modem_control
+ unsigned char control, status;
+
+ control = info->MCR;
+ cli();
+ status = serial_in(info, UART_MSR);
+ sti();
+ result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+ | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+ | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+ | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+ | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
+ | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
+ | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
+ | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+#endif
+ return put_user(result,value);
+}
+
+static int set_modem_info(ser_info_t *info, unsigned int cmd,
+ unsigned int *value)
+{
+ int error;
+ unsigned int arg;
+
+ error = get_user(arg, value);
+ if (error)
+ return error;
+#ifdef modem_control
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ info->MCR |= UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+ if (arg & TIOCM_OUT1)
+ info->MCR |= UART_MCR_OUT1;
+ if (arg & TIOCM_OUT2)
+ info->MCR |= UART_MCR_OUT2;
+#endif
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ info->MCR &= ~UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+ if (arg & TIOCM_OUT1)
+ info->MCR &= ~UART_MCR_OUT1;
+ if (arg & TIOCM_OUT2)
+ info->MCR &= ~UART_MCR_OUT2;
+#endif
+ break;
+ case TIOCMSET:
+ info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+ UART_MCR_OUT1 |
+ UART_MCR_OUT2 |
+#endif
+ UART_MCR_DTR))
+ | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+ | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+ | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+ | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+ break;
+ default:
+ return -EINVAL;
+ }
+ cli();
+ serial_out(info, UART_MCR, info->MCR);
+ sti();
+#endif
+ return 0;
+}
+
+/* Sending a break is a two step process on the SMC/SCC. It is accomplished
+ * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
+ * command. We take advantage of the begin/end functions to make this
+ * happen.
+ */
+static void begin_break(ser_info_t *info)
+{
+ volatile cpm8xx_t *cp;
+ ushort chan;
+ ushort num;
+
+ cp = cpmp;
+
+ if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ if (num == 0)
+ chan = CPM_CR_CH_SMC1;
+ else
+ chan = CPM_CR_CH_SMC2;
+ }
+ else {
+ num -= SCC_NUM_BASE;
+ switch (num) {
+ case 0: chan = CPM_CR_CH_SCC1; break;
+ case 1: chan = CPM_CR_CH_SCC2; break;
+ case 2: chan = CPM_CR_CH_SCC3; break;
+ case 3: chan = CPM_CR_CH_SCC4; break;
+ default: return;
+ }
+ }
+ cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+}
+
+static void end_break(ser_info_t *info)
+{
+ volatile cpm8xx_t *cp;
+ ushort chan;
+ ushort num;
+
+ cp = cpmp;
+
+ if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ if (num == 0)
+ chan = CPM_CR_CH_SMC1;
+ else
+ chan = CPM_CR_CH_SMC2;
+ }
+ else {
+ num -= SCC_NUM_BASE;
+ switch (num) {
+ case 0: chan = CPM_CR_CH_SCC1; break;
+ case 1: chan = CPM_CR_CH_SCC2; break;
+ case 2: chan = CPM_CR_CH_SCC3; break;
+ case 3: chan = CPM_CR_CH_SCC4; break;
+ default: return;
+ }
+ }
+ cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(ser_info_t *info, int duration)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + duration;
+#ifdef SERIAL_DEBUG_SEND_BREAK
+ printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
+#endif
+ begin_break(info);
+ schedule();
+ end_break(info);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+ printk("done jiffies=%lu\n", jiffies);
+#endif
+}
+
+
+static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int error;
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ int retval;
+ struct async_icount cnow; /* kernel counter temps */
+ struct serial_icounter_struct *p_cuser; /* user space */
+
+ if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+ return -ENODEV;
+
+ if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ if (!arg) {
+ send_break(info, HZ/4); /* 1/4 second */
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ if (signal_pending(current))
+ return -EINTR;
+ return 0;
+ case TIOCSBRK:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ begin_break(info);
+ return 0;
+ case TIOCCBRK:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ end_break(info);
+ return 0;
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+ case TIOCSSOFTCAR:
+ error = get_user(arg, (unsigned int *) arg);
+ if (error)
+ return error;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCMGET:
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *) arg);
+#ifdef maybe
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, (unsigned int *) arg);
+#endif
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+#ifdef modem_control
+ cli();
+ /* note the counters on entry */
+ cprev = info->state->icount;
+ sti();
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ cli();
+ cnow = info->state->icount; /* atomic copy */
+ sti();
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+#else
+ return 0;
+#endif
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ cli();
+ cnow = info->state->icount;
+ sti();
+ p_cuser = (struct serial_icounter_struct *) arg;
+ error = put_user(cnow.cts, &p_cuser->cts);
+ if (error) return error;
+ error = put_user(cnow.dsr, &p_cuser->dsr);
+ if (error) return error;
+ error = put_user(cnow.rng, &p_cuser->rng);
+ if (error) return error;
+ error = put_user(cnow.dcd, &p_cuser->dcd);
+ if (error) return error;
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+/* FIX UP modem control here someday......
+*/
+static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+ if ( (tty->termios->c_cflag == old_termios->c_cflag)
+ && ( RELEVANT_IFLAG(tty->termios->c_iflag)
+ == RELEVANT_IFLAG(old_termios->c_iflag)))
+ return;
+
+ change_speed(info);
+
+#ifdef modem_control
+ /* Handle transition to B0 status */
+ if ((old_termios->c_cflag & CBAUD) &&
+ !(tty->termios->c_cflag & CBAUD)) {
+ info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+ cli();
+ serial_out(info, UART_MCR, info->MCR);
+ sti();
+ }
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) &&
+ (tty->termios->c_cflag & CBAUD)) {
+ info->MCR |= UART_MCR_DTR;
+ if (!tty->hw_stopped ||
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ info->MCR |= UART_MCR_RTS;
+ }
+ cli();
+ serial_out(info, UART_MCR, info->MCR);
+ sti();
+ }
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ rs_8xx_start(tty);
+ }
+#endif
+
+#if 0
+ /*
+ * No need to wake up processes in open wait, since they
+ * sample the CLOCAL flag once, and don't recheck it.
+ * XXX It's not clear whether the current behavior is correct
+ * or not. Hence, this may change.....
+ */
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_8xx_close(struct tty_struct *tty, struct file * filp)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ struct serial_state *state;
+ unsigned long flags;
+ int idx;
+ volatile smc_t *smcp;
+ volatile scc_t *sccp;
+
+ if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+ return;
+
+ state = info->state;
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ DBG_CNT("before DEC-hung");
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+ if ((tty->count == 1) && (state->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. state->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "state->count is %d\n", state->count);
+ state->count = 1;
+ }
+ if (--state->count < 0) {
+ printk("rs_close: bad serial port count for ttys%d: %d\n",
+ info->line, state->count);
+ state->count = 0;
+ }
+ if (state->count) {
+ DBG_CNT("before DEC-2");
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->state->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->state->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ info->read_status_mask &= ~BD_SC_EMPTY;
+ if (info->flags & ASYNC_INITIALIZED) {
+ if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) {
+ smcp = &cpmp->cp_smc[idx];
+ smcp->smc_smcm &= ~SMCM_RX;
+ smcp->smc_smcmr &= ~SMCMR_REN;
+ }
+ else {
+ sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE];
+ sccp->scc_sccm &= ~UART_SCCM_RX;
+ }
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ rs_8xx_wait_until_sent(tty, info->timeout);
+ }
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + info->close_delay;
+ schedule();
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+ int lsr;
+ volatile cbd_t *bdp;
+
+ if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+ return;
+
+#ifdef maybe
+ if (info->state->type == PORT_UNKNOWN)
+ return;
+#endif
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = 1;
+ if (timeout)
+ char_time = MIN(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+
+ /* We go through the loop at least once because we can't tell
+ * exactly when the last character exits the shifter. There can
+ * be at least two characters waiting to be sent after the buffers
+ * are empty.
+ */
+ do {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+ current->state = TASK_INTERRUPTIBLE;
+/* current->counter = 0; /* make us low-priority */
+ current->timeout = jiffies + char_time;
+ schedule();
+ if (signal_pending(current))
+ break;
+ if (timeout && ((orig_jiffies + timeout) < jiffies))
+ break;
+ bdp = info->tx_cur;
+ } while (bdp->cbd_sc & BD_SC_READY);
+ current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_8xx_hangup(struct tty_struct *tty)
+{
+ ser_info_t *info = (ser_info_t *)tty->driver_data;
+ struct serial_state *state = info->state;
+
+ if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+ return;
+
+ state = info->state;
+
+ rs_8xx_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ state->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ ser_info_t *info)
+{
+#ifdef DO_THIS_LATER
+ struct wait_queue wait = { current, NULL };
+#endif
+ struct serial_state *state = info->state;
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ * If this is an SMC port, we don't have modem control to wait
+ * for, so just get out here.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR)) ||
+ (info->state->smc_scc_num < SCC_NUM_BASE)) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (state->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, state->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+#ifdef DO_THIS_LATER
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ state->line, state->count);
+#endif
+ cli();
+ if (!tty_hung_up_p(filp))
+ state->count--;
+ sti();
+ info->blocked_open++;
+ while (1) {
+ cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD))
+ serial_out(info, UART_MCR,
+ serial_inp(info, UART_MCR) |
+ (UART_MCR_DTR | UART_MCR_RTS));
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(info->flags & ASYNC_CLOSING) &&
+ (do_clocal || (serial_in(info, UART_MSR) &
+ UART_MSR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, state->count);
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ state->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ info->line, state->count);
+#endif
+#endif /* DO_THIS_LATER */
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int get_async_struct(int line, ser_info_t **ret_info)
+{
+ struct serial_state *sstate;
+
+ sstate = rs_table + line;
+ if (sstate->info) {
+ sstate->count++;
+ *ret_info = (ser_info_t *)sstate->info;
+ return 0;
+ }
+ else {
+ return -ENOMEM;
+ }
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_8xx_open(struct tty_struct *tty, struct file * filp)
+{
+ ser_info_t *info;
+ int retval, line;
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+ if ((line < 0) || (line >= NR_PORTS))
+ return -ENODEV;
+ retval = get_async_struct(line, &info);
+ if (retval)
+ return retval;
+ if (serial_paranoia_check(info, tty->device, "rs_open"))
+ return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+ info->state->count);
+#endif
+ tty->driver_data = info;
+ info->tty = tty;
+
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval)
+ return retval;
+
+ MOD_INC_USE_COUNT;
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ if ((info->state->count == 1) &&
+ (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->state->normal_termios;
+ else
+ *tty->termios = info->state->callout_termios;
+ change_speed(info);
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttys%d successful...", info->line);
+#endif
+ return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static int inline line_info(char *buf, struct serial_state *state)
+{
+#ifdef notdef
+ struct async_struct *info = state->info, scr_info;
+ char stat_buf[30], control, status;
+#endif
+ int ret;
+
+ ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+ state->line,
+ (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC",
+ state->port, state->irq);
+
+ if (!state->port || (state->type == PORT_UNKNOWN)) {
+ ret += sprintf(buf+ret, "\n");
+ return ret;
+ }
+
+#ifdef notdef
+ /*
+ * Figure out the current RS-232 lines
+ */
+ if (!info) {
+ info = &scr_info; /* This is just for serial_{in,out} */
+
+ info->magic = SERIAL_MAGIC;
+ info->port = state->port;
+ info->flags = state->flags;
+ info->quot = 0;
+ info->tty = 0;
+ }
+ cli();
+ status = serial_in(info, UART_MSR);
+ control = info ? info->MCR : serial_in(info, UART_MCR);
+ sti();
+
+ stat_buf[0] = 0;
+ stat_buf[1] = 0;
+ if (control & UART_MCR_RTS)
+ strcat(stat_buf, "|RTS");
+ if (status & UART_MSR_CTS)
+ strcat(stat_buf, "|CTS");
+ if (control & UART_MCR_DTR)
+ strcat(stat_buf, "|DTR");
+ if (status & UART_MSR_DSR)
+ strcat(stat_buf, "|DSR");
+ if (status & UART_MSR_DCD)
+ strcat(stat_buf, "|CD");
+ if (status & UART_MSR_RI)
+ strcat(stat_buf, "|RI");
+
+ if (info->quot) {
+ ret += sprintf(buf+ret, " baud:%d",
+ state->baud_base / info->quot);
+ }
+
+ ret += sprintf(buf+ret, " tx:%d rx:%d",
+ state->icount.tx, state->icount.rx);
+
+ if (state->icount.frame)
+ ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+
+ if (state->icount.parity)
+ ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+
+ if (state->icount.brk)
+ ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
+
+ if (state->icount.overrun)
+ ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+ /*
+ * Last thing is the RS-232 status lines
+ */
+ ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+#endif
+ return ret;
+}
+
+int rs_8xx_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int i, len = 0;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+ for (i = 0; i < NR_PORTS && len < 4000; i++) {
+ len += line_info(page + len, &rs_table[i]);
+ if (len+begin > off+count)
+ goto done;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ *eof = 1;
+done:
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+ printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+__initfunc(int rs_8xx_init(void))
+{
+ struct serial_state * state;
+ ser_info_t *info;
+ uint mem_addr, dp_addr;
+ int i, j;
+ ushort chan;
+ volatile cbd_t *bdp;
+ volatile cpm8xx_t *cp;
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+
+ init_bh(SERIAL_BH, do_serial_bh);
+#if 0
+ timer_table[RS_TIMER].fn = rs_8xx_timer;
+ timer_table[RS_TIMER].expires = 0;
+#endif
+
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.driver_name = "serial";
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = NR_PORTS;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+ serial_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_8xx_open;
+ serial_driver.close = rs_8xx_close;
+ serial_driver.write = rs_8xx_write;
+ serial_driver.put_char = rs_8xx_put_char;
+ serial_driver.write_room = rs_8xx_write_room;
+ serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer;
+ serial_driver.flush_buffer = rs_8xx_flush_buffer;
+ serial_driver.ioctl = rs_8xx_ioctl;
+ serial_driver.throttle = rs_8xx_throttle;
+ serial_driver.unthrottle = rs_8xx_unthrottle;
+ serial_driver.send_xchar = rs_8xx_send_xchar;
+ serial_driver.set_termios = rs_8xx_set_termios;
+ serial_driver.stop = rs_8xx_stop;
+ serial_driver.start = rs_8xx_start;
+ serial_driver.hangup = rs_8xx_hangup;
+ serial_driver.wait_until_sent = rs_8xx_wait_until_sent;
+ serial_driver.read_proc = rs_8xx_read_proc;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ callout_driver.read_proc = 0;
+ callout_driver.proc_entry = 0;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ cp = cpmp; /* Get pointer to Communication Processor */
+
+ /* Configure SMCs Tx/Rx instead of port B parallel I/O.
+ */
+ cp->cp_pbpar |= 0x00000cc0;
+ cp->cp_pbdir &= ~0x00000cc0;
+ cp->cp_pbodr &= ~0x00000cc0;
+
+ /* Wire BRG1 to SMC1 and BRG2 to SMC2.
+ */
+ cp->cp_simode = 0x10000000;
+
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ state->magic = SSTATE_MAGIC;
+ state->line = i;
+ state->type = PORT_UNKNOWN;
+ state->custom_divisor = 0;
+ state->close_delay = 5*HZ/10;
+ state->closing_wait = 30*HZ;
+ state->callout_termios = callout_driver.init_termios;
+ state->normal_termios = serial_driver.init_termios;
+ state->icount.cts = state->icount.dsr =
+ state->icount.rng = state->icount.dcd = 0;
+ state->icount.rx = state->icount.tx = 0;
+ state->icount.frame = state->icount.parity = 0;
+ state->icount.overrun = state->icount.brk = 0;
+ printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
+ i, state->port,
+ (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC");
+#ifdef CONFIG_SERIAL_CONSOLE
+ /* If we just printed the message on the console port, and
+ * we are about to initialize it for general use, we have
+ * to wait a couple of character times for the CR/NL to
+ * make it out of the transmit buffer.
+ */
+ if (i == CONFIG_SERIAL_CONSOLE_PORT)
+ udelay(2000);
+#endif
+ info = kmalloc(sizeof(ser_info_t), GFP_KERNEL);
+ if (info) {
+ memset(info, 0, sizeof(ser_info_t));
+ info->magic = SERIAL_MAGIC;
+ info->flags = state->flags;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->tqueue_hangup.routine = do_serial_hangup;
+ info->tqueue_hangup.data = info;
+ info->line = i;
+ info->state = state;
+ state->info = (struct async_struct *)info;
+
+ /* Right now, assume we are using SMCs.
+ */
+ sp = &cp->cp_smc[state->smc_scc_num];
+
+ up = (smc_uart_t *)&cp->cp_dparam[state->port];
+
+ /* We need to allocate a transmit and receive buffer
+ * descriptors from dual port ram, and a character
+ * buffer area from host mem.
+ */
+ dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO);
+
+ /* Allocate space for FIFOs in the host memory.
+ */
+ mem_addr = mbx_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE);
+
+ /* Set the physical address of the host memory
+ * buffers in the buffer descriptors, and the
+ * virtual address for us to work with.
+ */
+ bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
+ up->smc_rbase = dp_addr;
+ info->rx_cur = info->rx_bd_base = (cbd_t *)bdp;
+
+ for (j=0; j<(RX_NUM_FIFO-1); j++) {
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+ mem_addr += RX_BUF_SIZE;
+ bdp++;
+ }
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+ dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO);
+
+ /* Allocate space for FIFOs in the host memory.
+ */
+ mem_addr = mbx_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE);
+
+ /* Set the physical address of the host memory
+ * buffers in the buffer descriptors, and the
+ * virtual address for us to work with.
+ */
+ bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
+ up->smc_tbase = dp_addr;
+ info->tx_cur = info->tx_bd_base = (cbd_t *)bdp;
+
+ for (j=0; j<(TX_NUM_FIFO-1); j++) {
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ bdp->cbd_sc = BD_SC_INTRPT;
+ mem_addr += TX_BUF_SIZE;
+ bdp++;
+ }
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
+
+ /* Set up the uart parameters in the parameter ram.
+ */
+ up->smc_rfcr = SMC_EB;
+ up->smc_tfcr = SMC_EB;
+
+ /* Set this to 1 for now, so we get single character
+ * interrupts. Using idle charater time requires
+ * some additional tuning.
+ */
+ up->smc_mrblr = 1; /* receive buffer length */
+ up->smc_maxidl = 0; /* wait forever for next char */
+ up->smc_brkcr = 1; /* number of break chars */
+
+ /* Send the CPM an initialize command.
+ */
+ if (state->smc_scc_num == 0)
+ chan = CPM_CR_CH_SMC1;
+ else
+ chan = CPM_CR_CH_SMC2;
+ cp->cp_cpcr = mk_cr_cmd(chan,
+ CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* Set UART mode, 8 bit, no parity, one stop.
+ * Enable receive and transmit.
+ */
+ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+ /* Disable all interrupts and clear all pending
+ * events.
+ */
+ sp->smc_smcm = 0;
+ sp->smc_smce = 0xff;
+
+ /* Install interrupt handler.
+ */
+ cpm_install_handler(state->irq, rs_8xx_interrupt, info);
+
+ /* Set up the baud rate generator.
+ */
+ mbx_cpm_setbrg(state->smc_scc_num, 9600);
+
+ /* If the port is the console, enable Rx and Tx.
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+ if (i == CONFIG_SERIAL_CONSOLE_PORT)
+ sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+#endif
+ }
+ }
+ return 0;
+}
+
+/*
+ * The serial console driver used during boot. Note that these names
+ * clash with those found in "serial.c", so we currently can't support
+ * the 16xxx uarts and these at the same time. I will fix this to become
+ * an indirect function call from tty_io.c (or something).
+ */
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * Print a string to the serial port trying not to disturb any possible
+ * real use of the port...
+ */
+static void serial_console_write(struct console *c, const char *s,
+ unsigned count)
+{
+ struct serial_state *ser;
+ ser_info_t *info;
+ unsigned i;
+ volatile cbd_t *bdp, *bdbase;
+ volatile smc_uart_t *up;
+ volatile u_char *cp;
+
+ ser = rs_table + c->index;
+
+ /* If the port has been initialized for general use, we have
+ * to use the buffer descriptors allocated there. Otherwise,
+ * we simply use the single buffer allocated.
+ */
+ if ((info = (ser_info_t *)ser->info) != NULL) {
+ bdp = info->tx_cur;
+ bdbase = info->tx_bd_base;
+ }
+ else {
+ /* Pointer to UART in parameter ram.
+ */
+ up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+ /* Get the address of the host memory buffer.
+ */
+ bdp = bdbase = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+ }
+
+ /*
+ * We need to gracefully shut down the transmitter, disable
+ * interrupts, then send our bytes out.
+ */
+
+ /*
+ * Now, do each character. This is not as bad as it looks
+ * since this is a holding FIFO and not a transmitting FIFO.
+ * We could add the complexity of filling the entire transmit
+ * buffer, but we would just wait longer between accesses......
+ */
+ for (i = 0; i < count; i++, s++) {
+
+ /* Wait for transmitter fifo to empty.
+ * Ready indicates output is ready, and xmt is doing
+ * that, not that it is ready for us to send.
+ */
+ while (bdp->cbd_sc & BD_SC_READY);
+
+ /* Send the character out. */
+ cp = __va(bdp->cbd_bufaddr);
+ *cp = *s;
+ bdp->cbd_datlen = 1;
+ bdp->cbd_sc |= BD_SC_READY;
+
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = bdbase;
+ else
+ bdp++;
+
+ /* if a LF, also do CR... */
+ if (*s == 10) {
+ while (bdp->cbd_sc & BD_SC_READY);
+ cp = __va(bdp->cbd_bufaddr);
+ *cp = 13;
+ bdp->cbd_datlen = 1;
+ bdp->cbd_sc |= BD_SC_READY;
+
+ if (bdp->cbd_sc & BD_SC_WRAP) {
+ bdp = bdbase;
+ }
+ else {
+ bdp++;
+ }
+ }
+ }
+
+ /*
+ * Finally, Wait for transmitter & holding register to empty
+ * and restore the IER
+ */
+ while (bdp->cbd_sc & BD_SC_READY);
+
+ if (info)
+ info->tx_cur = (cbd_t *)bdp;
+}
+
+/*
+ * Receive character from the serial port. This only works well
+ * before the port is initialize for real use.
+ */
+static int serial_console_wait_key(struct console *co)
+{
+ struct serial_state *ser;
+ u_char c, *cp;
+ ser_info_t *info;
+ volatile cbd_t *bdp;
+ volatile smc_uart_t *up;
+
+ ser = rs_table + co->index;
+
+ /* Pointer to UART in parameter ram.
+ */
+ up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+ /* Get the address of the host memory buffer.
+ * If the port has been initialized for general use, we must
+ * use information from the port structure.
+ */
+ if ((info = ser->info))
+ bdp = info->rx_cur;
+ else
+ bdp = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ /*
+ * We need to gracefully shut down the receiver, disable
+ * interrupts, then read the input.
+ */
+ while (bdp->cbd_sc & BD_SC_EMPTY); /* Wait for a character */
+ cp = __va(bdp->cbd_bufaddr);
+
+ if (info) {
+ if (bdp->cbd_sc & BD_SC_WRAP) {
+ bdp = info->rx_bd_base;
+ }
+ else {
+ bdp++;
+ }
+ info->rx_cur = (cbd_t *)bdp;
+ }
+
+ c = *cp;
+ return((int)c);
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+ return MKDEV(TTYAUX_MAJOR, 64 + c->index);
+}
+
+/* This must always be called before the rs_8xx_init() function, otherwise
+ * it blows away the port control information.
+*/
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+ struct serial_state *ser;
+ uint mem_addr, dp_addr;
+ volatile cbd_t *bdp;
+ volatile cpm8xx_t *cp;
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+
+ co->cflag = CREAD|CLOCAL|B9600|CS8;
+
+ ser = rs_table + co->index;
+
+ cp = cpmp; /* Get pointer to Communication Processor */
+
+ /* Right now, assume we are using SMCs.
+ */
+ sp = &cp->cp_smc[ser->smc_scc_num];
+
+ /* When we get here, the CPM has been reset, so we need
+ * to configure the port.
+ * We need to allocate a transmit and receive buffer descriptor
+ * from dual port ram, and a character buffer area from host mem.
+ */
+ up = (smc_uart_t *)&cp->cp_dparam[ser->port];
+ cp->cp_pbpar = 0x00c0; /* Enable SMC1 instead of Port B I/O */
+
+ /* Allocate space for two buffer descriptors in the DP ram.
+ */
+ dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * 2);
+
+ /* Allocate space for two 2 byte FIFOs in the host memory.
+ */
+ mem_addr = mbx_cpm_hostalloc(4);
+
+ /* Set the physical address of the host memory buffers in
+ * the buffer descriptors.
+ */
+ bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ (bdp+1)->cbd_bufaddr = __pa(mem_addr+2);
+
+ /* For the receive, set empty and wrap.
+ * For transmit, set wrap.
+ */
+ bdp->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
+ (bdp+1)->cbd_sc = BD_SC_WRAP;
+
+ /* Set up the uart parameters in the parameter ram.
+ */
+ up->smc_rbase = dp_addr; /* Base of receive buffer desc. */
+ up->smc_tbase = dp_addr+sizeof(cbd_t); /* Base of xmt buffer desc. */
+ up->smc_rfcr = SMC_EB;
+ up->smc_tfcr = SMC_EB;
+
+ /* Set this to 1 for now, so we get single character interrupts.
+ */
+ up->smc_mrblr = 1; /* receive buffer length */
+ up->smc_maxidl = 0; /* wait forever for next char */
+
+ /* Send the CPM an initialize command.
+ */
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* Set UART mode, 8 bit, no parity, one stop.
+ * Enable receive and transmit.
+ */
+ sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+ /* Set up the baud rate generator.
+ */
+ mbx_cpm_setbrg(ser->smc_scc_num, 9600);
+
+ /* And finally, enable Rx and Tx.
+ */
+ sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+
+ return 0;
+}
+
+static struct console sercons = {
+ "ttyS",
+ serial_console_write,
+ NULL,
+ serial_console_device,
+ serial_console_wait_key,
+ NULL,
+ serial_console_setup,
+ CON_PRINTBUFFER,
+ CONFIG_SERIAL_CONSOLE_PORT,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+__initfunc (long console_8xx_init(long kmem_start, long kmem_end))
+{
+ register_console(&sercons);
+ return kmem_start;
+}
+
+#endif
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 832513c8d..cd81e45a4 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -12,14 +12,7 @@
# Rewritten by Cort Dougan and Paul Mackerras
#
-ifdef CONFIG_CHRP
-# XXX for now
-KERNELBASE =0x90000000
-KERNELLOAD =0x90010000
-else
-KERNELBASE =0xc0000000
-KERNELLOAD =0xc0000000
-endif
+KERNELLOAD =0xc0000000
# PowerPC (cross) tools
ifneq ($(shell uname -m),ppc)
@@ -32,21 +25,13 @@ ASFLAGS =
LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \
- -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring \
- -DKERNELBASE=$(KERNELBASE)
+ -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring
CPP = $(CC) -E $(CFLAGS)
-ifdef CONFIG_601
-CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
+ifdef CONFIG_8xx
+CFLAGS := $(CFLAGS) -mcpu=860
endif
-ifdef CONFIG_603
-CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
-endif
-
-ifdef CONFIG_604
-CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
-endif
HEAD := arch/ppc/kernel/head.o
@@ -64,6 +49,11 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot
+ifdef CONFIG_8xx
+SUBDIRS += arch/ppc/8xx_io
+DRIVERS += arch/ppc/8xx_io/8xx_io.a drivers/net/net.a
+endif
+
checks:
@$(MAKE) -C arch/$(ARCH)/kernel checks
@@ -83,6 +73,19 @@ prep_config:
rm -f .config arch/ppc/defconfig
ln -s prep_defconfig arch/ppc/defconfig
+chrp_config:
+ rm -f .config arch/ppc/defconfig
+ ln -s chrp_defconfig arch/ppc/defconfig
+
+common_config:
+ rm -f .config arch/ppc/common_defconfig
+ ln -s common_defconfig arch/ppc/defconfig
+
+mbx_config:
+ rm -f .config arch/ppc/defconfig
+ ln -s mbx_defconfig arch/ppc/defconfig
+
+
tags:
etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 02f95f577..84be805b2 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -25,31 +25,70 @@ ZOFF = 0
ZSZ = 0
IOFF = 0
ISZ = 0
+ifeq ($(CONFIG_MBX),y)
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
+else
#ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000
+endif
GZIP_FLAGS = -v9
-OBJECTS := head.o misc.o vreset.o kbd.o ../coffboot/zlib.o # inflate.o unzip.o
-#OBJECTS := crt0.o start.o vreset.o
+OBJECTS := head.o misc.o ../coffboot/zlib.o # inflate.o unzip.o
CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
+ifeq ($(CONFIG_MBX),y)
+OBJECTS += mbxtty.o
+CFLAGS += -DCONFIG_MBX
+else
+OBJECTS += vreset.o kbd.o
+endif
+
all: zImage
+ifeq ($(CONFIG_ALL_PPC),y)
+CONFIG_PREP = y
+endif
ifeq ($(CONFIG_PREP),y)
-mkprep : mkprep.c
- $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
+zvmlinux.initrd: zvmlinux
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section=initrd=ramdisk.image.gz \
+ --add-section=image=../coffboot/vmlinux.gz \
+ zvmlinux.initrd.tmp zvmlinux.initrd
+ $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset zvmlinux.initrd initrd` \
+ -DINITRD_SIZE=`sh size zvmlinux.initrd initrd` \
+ -DZIMAGE_OFFSET=`sh offset zvmlinux.initrd image` \
+ -DZIMAGE_SIZE=`sh size zvmlinux.initrd image` \
+ -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section=initrd=ramdisk.image.gz \
+ --add-section=image=../coffboot/vmlinux.gz \
+ zvmlinux.initrd.tmp $@
+ rm zvmlinux.initrd.tmp
-floppy: $(TOPDIR)/vmlinux zImage
- dd if=zImage of=/dev/fd0H1440 bs=64b
+else
+zvmlinux.initrd:
+endif
-znetboot : zImage
- cp zImage /tftpboot/zImage.prep
+zImage: zvmlinux mkprep
+ifeq ($(CONFIG_PREP),y)
+ ./mkprep -pbp zvmlinux zImage
+endif
+ifeq ($(CONFIG_MBX),y)
+ ln -sf zvmlinux zImage
+endif
-znetboot.initrd : zImage.initrd
- cp zImage.initrd /tftpboot/zImage.prep
+zImage.initrd: zvmlinux.initrd mkprep
+ifeq ($(CONFIG_PREP),y)
+ ./mkprep -pbp zvmlinux.initrd zImage.initrd
+endif
+ifeq ($(CONFIG_MBX),y)
+ ln -sf zvmlinux.initrd zImage.initrd
+endif
zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
#
@@ -63,61 +102,39 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
# then with the offset rebuild the bootloader so we know where the kernel is
#
$(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
- -DZIMAGE_OFFSET=`./offset zvmlinux image` \
- -DZIMAGE_SIZE=`./size zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+ -DZIMAGE_OFFSET=`sh offset zvmlinux image` \
+ -DZIMAGE_SIZE=`sh size zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
-c -o misc.o misc.c
$(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
zvmlinux.tmp $@
rm zvmlinux.tmp
-zvmlinux.initrd: zvmlinux
- $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
- $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
- --add-section=initrd=ramdisk.image.gz \
- --add-section=image=../coffboot/vmlinux.gz \
- zvmlinux.initrd.tmp zvmlinux.initrd
- $(CC) $(CFLAGS) -DINITRD_OFFSET=`./offset zvmlinux.initrd initrd` \
- -DINITRD_SIZE=`./size zvmlinux.initrd initrd` \
- -DZIMAGE_OFFSET=`./offset zvmlinux.initrd image` \
- -DZIMAGE_SIZE=`./size zvmlinux.initrd image` \
- -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
- $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
- $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
- --add-section=initrd=ramdisk.image.gz \
- --add-section=image=../coffboot/vmlinux.gz \
- zvmlinux.initrd.tmp $@
- rm zvmlinux.initrd.tmp
-
-zImage: zvmlinux mkprep
- ./mkprep -pbp zvmlinux zImage
-
-zImage.initrd: zvmlinux.initrd mkprep
- ./mkprep -pbp zvmlinux.initrd zImage.initrd
-else
-mkprep:
-
-floppy:
-
-znetboot:
-
-znetboot.initrd:
-
-zvmlinux:
-
-zvmlinux.initrd:
-
-zImage:
-
-zImage.initrd:
+floppy: $(TOPDIR)/vmlinux zImage
+ifeq ($(CONFIG_PREP),y)
+ dd if=zImage of=/dev/fd0H1440 bs=64b
endif
+mkprep : mkprep.c
+ifeq ($(CONFIG_PREP),y)
+ $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
+endif
+znetboot : zImage
+ifeq ($(CONFIG_PREP),y)
+ cp zImage /tftpboot/zImage.prep
+endif
+ifeq ($(CONFIG_MBX),y)
+ cp zImage /tftpboot/zImage.mbx
+endif
-# just here to match coffboot/Makefile
-vmlinux.coff:
-
-vmlinux.coff.initrd:
+znetboot.initrd : zImage.initrd
+ifeq ($(CONFIG_PREP),y)
+ cp zImage.initrd /tftpboot/zImage.prep
+endif
+ifeq ($(CONFIG_MBX),y)
+ cp zImage.initrd /tftpboot/zImage.mbx
+endif
clean:
rm -f vmlinux* zvmlinux* mkprep zImage*
@@ -128,3 +145,7 @@ fastdep:
dep:
$(CPP) -M *.S *.c > .depend
+# just here to match coffboot/Makefile
+vmlinux.coff:
+
+vmlinux.coff.initrd:
diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S
index ff0030154..26a0be180 100644
--- a/arch/ppc/boot/head.S
+++ b/arch/ppc/boot/head.S
@@ -1,19 +1,43 @@
+#include <linux/config.h>
#include "../kernel/ppc_defs.h"
#include "../kernel/ppc_asm.tmpl"
#include <asm/processor.h>
+#include <asm/cache.h>
.text
/*
* This code is loaded by the ROM loader at some arbitrary location.
* Move it to high memory so that it can load the kernel at 0x0000.
+ *
+ * The MBX EPPC-Bug understands ELF, so it loads us into the location
+ * specified in the header. This is a two step process. First, EPPC-Bug
+ * loads the file into the intermediate buffer memory location specified
+ * by the environment parameters. When it discovers this is an ELF
+ * binary, it relocates to the link address for us. Unfortunately, the
+ * header does not move with the file, so we have to find the
+ * intermediate load location and read the header from there. From
+ * information provided by Motorola (thank you), we know this intermediate
+ * location can be found from the NVRAM environment.
+ * All of these addresses must be somewhat carefully chosen to make sure
+ * we don't overlap the regions. I chose to load the kernel at 0, the
+ * compressed image loads at 0x00100000, and the MBX intermediate buffer
+ * was set to 0x00200000. Provided the loaded kernel image never grows
+ * over one megabyte (which I am going to ensure never happens :-), these
+ * will work fine. When we get called from EPPC-Bug, registers are:
+ * R1 - Stack pointer at a high memory address.
+ * R3 - Pointer to Board Information Block.
+ * R4 - Pointer to argument string.
+ * Interrupts masked, cache and MMU disabled.
*/
.globl start
start:
bl start_
start_:
- mr r11,r3 /* Save pointer to residual data */
+ mr r11,r3 /* Save pointer to residual/board data */
+
+#ifndef CONFIG_MBX
mfmsr r3 /* Turn off interrupts */
li r4,0
ori r4,r4,MSR_EE
@@ -33,7 +57,6 @@ start_:
bne 00b
mflr r21
mfctr r22
- bl flush_instruction_cache
mtlr r21
mtctr r22
bctr /* Jump to code */
@@ -70,6 +93,8 @@ relocate:
mtlr r3 /* Easiest way to do an absolute jump */
blr
start_ldr:
+#endif /* ndef CONFIG_MBX */
+
/* Clear all of BSS */
lis r3,edata@h
ori r3,r3,edata@l
@@ -89,12 +114,21 @@ start_ldr:
li r2,0x000F /* Mask pointer to 16-byte boundary */
andc r1,r1,r2
/* Run loader */
+#ifdef CONFIG_MBX
+ bl serial_init /* Init MBX serial port */
+#define ILAP_ADDRESS 0xfa000020
+ lis r8, ILAP_ADDRESS@h
+ lwz r8, ILAP_ADDRESS@l(r8)
+ li r9,end@h
+ ori r9,r9,end@l
+ sub r7,r8,r9
+ addis r8, r8, 1 /* Add 64K */
+#endif
mr r3,r8 /* Load point */
mr r4,r7 /* Program length */
mr r5,r6 /* Checksum */
mr r6,r11 /* Residual data */
bl decompress_kernel
-
/* changed to use r3 (as firmware does) for kernel
as ptr to residual -- Cort*/
lis r6,cmd_line@h
@@ -111,45 +145,25 @@ start_ldr:
lis r2,initrd_end@h
ori r2,r2,initrd_end@l
lwz r5,0(r2)
-
- li r9,0x00c /* Kernel code starts here */
+
+ /* tell kernel we're prep */
+ /*
+ * get start address of kernel code which is stored as a coff
+ * entry. see boot/head.S -- Cort
+ */
+ li r9,0x0
+ lwz r9,0(r9)
mtlr r9
+#ifndef CONFIG_MBX
+ li r9,0
+ lis r10,0xdeadc0de@h
+ ori r10,r10,0xdeadc0de@l
+ stw r10,0(r9)
+#endif
blr
hang:
b hang
- .globl _get_SP
-_get_SP:
- mr r3,r1
- blr
-
- .globl _get_PVR
-_get_PVR:
- mfspr r3,PVR
- blr
-
- .globl _get_MSR
-_get_MSR:
- mfmsr r3
- blr
-
- .globl _put_MSR
-_put_MSR:
- sync
- mtmsr r3
- blr
-
- .globl _get_HID0
-_get_HID0:
- mfspr r3,HID0
- blr
-
- .globl _put_HID0
-_put_HID0:
- sync
- mtspr HID0,r3
- blr
-
/*
* Delay for a number of microseconds
* -- Use the BUS timer (assumes 66MHz)
@@ -189,98 +203,4 @@ udelay:
blt 2b
3: blr
-/*
- * This space [buffer] is used to forceably flush the data cache when
- * running in copyback mode. This is necessary IFF the data cache could
- * contain instructions for which the instruction cache has stale data.
- * Since the instruction cache NEVER snoops the data cache, memory must
- * be made coherent with the data cache to insure that the instruction
- * cache gets a valid instruction stream. Note that this flushing is
- * only performed when switching from system to user mode since this is
- * the only juncture [as far as the OS goes] where the data cache may
- * contain instructions, e.g. after a disk read.
- */
-#define NUM_CACHE_LINES 128*8
-#define CACHE_LINE_SIZE 32
-#if 0
-cache_flush_buffer:
- .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
-#else
-#define cache_flush_buffer 0x1000
-#endif
-
-
-/*
- * Flush instruction cache
- * *** I'm really paranoid here!
- */
-_GLOBAL(flush_instruction_cache)
- mflr r5
- bl flush_data_cache
- mfspr r3,HID0 /* Caches are controlled by this register */
- li r4,0
- ori r4,r4,(HID0_ICE|HID0_ICFI)
- or r3,r3,r4 /* Need to enable+invalidate to clear */
- mtspr HID0,r3
- andc r3,r3,r4
- ori r3,r3,HID0_ICE /* Enable cache */
- mtspr HID0,r3
- mtlr r5
- blr
-
-/*
- * Flush data cache
- * *** I'm really paranoid here!
- */
-_GLOBAL(flush_data_cache)
- lis r3,cache_flush_buffer@h
- ori r3,r3,cache_flush_buffer@l
- li r4,NUM_CACHE_LINES
- mtctr r4
-#if 0
-00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
-#else
-00: lwz r4,0(r3)
-#endif
- addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
- bdnz 00b
-10: blr
-
-/*
- * Flush a particular page from the DATA cache
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- * void flush_page(void *page)
- */
-_GLOBAL(flush_page)
- li r4,0x0FFF
- andc r3,r3,r4 /* Get page base address */
- li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
- mtctr r4
-00: dcbf 0,r3 /* Clear line */
- icbi 0,r3
- addi r3,r3,CACHE_LINE_SIZE
- bdnz 00b
- blr
-
-/*
- * Execute a [foreign] function
- *
- * run(p1, p2, cp, ep, entry)
- *
- */
- .globl run
-run:
- mtctr r7 /* Entry point */
-#define IS_PreP 0x50726550 /* 'PreP' */
- lis r30,IS_PreP>>16
- ori r30,r30,IS_PreP&0xFFFF
- mr 11,r5
- mr 12,r6
- mr r28,r5
- mr r29,r6
- mr 11,r5
- mr 12,r6
- bctr
-
.comm .stack,4096*2,4
diff --git a/arch/ppc/boot/mbxtty.c b/arch/ppc/boot/mbxtty.c
new file mode 100644
index 000000000..ee6c59c90
--- /dev/null
+++ b/arch/ppc/boot/mbxtty.c
@@ -0,0 +1,118 @@
+
+
+/* Minimal serial functions needed to send messages out the serial
+ * port on the MBX console.
+ *
+ * The MBX uxes SMC1 for the serial port. We reset the port and use
+ * only the first BD that EPPC-Bug set up as a character FIFO.
+ *
+ * It's a big hack, but I don't have time right now....I want a kernel
+ * that boots.
+ */
+#include <linux/types.h>
+#include <asm/mbx.h>
+#include "../8xx_io/commproc.h"
+
+#define CPM_CPCR ((volatile ushort *)0xfa2009c0)
+#define SMC1_MODE ((volatile ushort *)0xfa200a82)
+#define SMC1_TBDF ((volatile bd_t *)0xfa202c90)
+#define SMC1_RBDF ((volatile bd_t *)0xfa202c10)
+
+static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)MBX_IMAP_ADDR)->im_cpm);
+
+void
+serial_init(void)
+{
+ volatile smc_t *sp;
+ volatile smc_uart_t *up;
+ volatile cbd_t *tbdf, *rbdf;
+ volatile cpm8xx_t *cp;
+
+ cp = cpmp;
+ sp = (smc_t*)&(cp->cp_smc[0]);
+ up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1];
+
+ /* Disable transmitter/receiver.
+ */
+ sp->smc_smcm &= ~(SMCMR_REN | SMCMR_TEN);
+
+ tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase];
+ rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase];
+
+ /* Issue a stop transmit, and wait for it.
+ */
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_STOP_TX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* Make the first buffer the only buffer.
+ */
+ tbdf->cbd_sc |= BD_SC_WRAP;
+ rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+
+ /* Single character receive.
+ */
+ up->smc_mrblr = 1;
+ up->smc_maxidl = 0;
+
+ /* Initialize Tx/Rx parameters.
+ */
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ /* Enable transmitter/receiver.
+ */
+ sp->smc_smcm |= SMCMR_REN | SMCMR_TEN;
+}
+
+void
+serial_putchar(const char c)
+{
+ volatile cbd_t *tbdf;
+ volatile char *buf;
+ volatile smc_uart_t *up;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+ tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
+
+ /* Wait for last character to go.
+ */
+ buf = (char *)tbdf->cbd_bufaddr;
+ while (tbdf->cbd_sc & BD_SC_READY);
+
+ *buf = c;
+ tbdf->cbd_datlen = 1;
+ tbdf->cbd_sc |= BD_SC_READY;
+}
+
+char
+serial_getc()
+{
+ volatile cbd_t *rbdf;
+ volatile char *buf;
+ volatile smc_uart_t *up;
+ char c;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+ rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ /* Wait for character to show up.
+ */
+ buf = (char *)rbdf->cbd_bufaddr;
+ while (rbdf->cbd_sc & BD_SC_EMPTY);
+ c = *buf;
+ rbdf->cbd_sc |= BD_SC_EMPTY;
+
+ return(c);
+}
+
+int
+serial_tstc()
+{
+ volatile cbd_t *rbdf;
+ volatile smc_uart_t *up;
+
+ up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1];
+ rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+
+ return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+}
diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c
index bc6aa088f..33c7c3e0d 100644
--- a/arch/ppc/boot/misc.c
+++ b/arch/ppc/boot/misc.c
@@ -4,25 +4,35 @@
* Adapted for PowerPC by Gary Thomas
*
* Rewritten by Cort Dougan (cort@cs.nmt.edu)
- * Soon to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
+ * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
*/
#include "../coffboot/zlib.h"
#include "asm/residual.h"
#include <elf.h>
+#include <linux/config.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+bd_t hold_board_info;
+#endif
/* this is where the INITRD gets moved to for safe keeping */
-#define INITRD_DESTINATION /*0x00f00000*/ 0x01f00000
+#define INITRD_DESTINATION /*0x00f00000*/ 0x01800000
+#ifdef CONFIG_8xx
+char *avail_ram = (char *) 0x00200000;
+char *end_avail = (char *) 0x00400000;
+#else /* CONFIG_8xx */
/* this will do for now - Cort */
char *avail_ram = (char *) 0x00800000; /* start with 8M */
/* assume 15M max since this is where we copy the initrd to -- Cort */
char *end_avail = (char *) INITRD_DESTINATION;
+#endif /* CONFIG_8xx */
+char cmd_line[256];
RESIDUAL hold_residual;
unsigned long initrd_start = 0, initrd_end = 0;
char *zimage_start;
int zimage_size;
-char cmd_line[256];
char *vidmem = (char *)0xC00B8000;
int lines, cols;
@@ -47,6 +57,7 @@ void exit()
while(1);
}
+#ifndef CONFIG_MBX
static void clear_screen()
{
int i, j;
@@ -144,6 +155,39 @@ void puts(const char *s)
orig_x = x;
orig_y = y;
}
+#else
+/* The MBX is just the serial port.
+*/
+tstc(void)
+{
+ return (serial_tstc());
+}
+
+getc(void)
+{
+ while (1) {
+ if (serial_tstc()) return (serial_getc());
+ }
+}
+
+void
+putc(const char c)
+{
+ serial_putchar(c);
+}
+
+void puts(const char *s)
+{
+ char c;
+
+ while ( ( c = *s++ ) != '\0' ) {
+ serial_putchar(c);
+ if ( c == '\n' )
+ serial_putchar('\r');
+ }
+}
+
+#endif /* CONFIG_MBX */
void * memcpy(void * __dest, __const void * __src,
int __n)
@@ -253,6 +297,8 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
inflateEnd(&s);
}
+unsigned char sanity[0x2000];
+
unsigned long
decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
{
@@ -260,31 +306,60 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
extern unsigned long start;
char *cp, ch;
unsigned long i;
-
-
+
lines = 25;
cols = 80;
orig_x = 0;
orig_y = 24;
- /* Turn off MMU. Since we are mapped 1-1, this is OK. */
- flush_instruction_cache();
- _put_HID0(_get_HID0() & ~0x0000C000);
- _put_MSR(_get_MSR() & ~0x0030);
-
+#ifndef CONFIG_8xx
vga_init(0xC0000000);
- /*clear_screen();*/
+ /* copy the residual data */
+ if (residual)
+ memcpy(&hold_residual,residual,sizeof(RESIDUAL));
+#endif /* CONFIG_8xx */
+#ifdef CONFIG_MBX
+ /* copy board data */
+ if (residual)
+ _bcopy((char *)residual, (char *)&hold_board_info,
+ sizeof(hold_board_info));
+#endif /* CONFIG_8xx */
+
- puts("loaded at: "); puthex(load_addr);
+ puts("loaded at: "); puthex(load_addr);
puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
-
- puts("relocated to: "); puthex((unsigned long)&start);
+ puts("relocated to: "); puthex((unsigned long)&start);
puts(" "); puthex((unsigned long)((unsigned long)&start + (4*num_words))); puts("\n");
-
+
+ if ( residual )
+ {
+ puts("board data at: "); puthex((unsigned long)residual);
+ puts(" ");
+#ifdef CONFIG_MBX
+ puthex((unsigned long)((unsigned long)residual + sizeof(bd_t)));
+#else
+ puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL)));
+#endif
+ puts("\n");
+ puts("relocated to: ");
+#ifdef CONFIG_MBX
+ puthex((unsigned long)&hold_board_info);
+#else
+ puthex((unsigned long)&hold_residual);
+#endif
+ puts(" ");
+#ifdef CONFIG_MBX
+ puthex((unsigned long)((unsigned long)&hold_board_info + sizeof(bd_t)));
+#else
+ puthex((unsigned long)((unsigned long)&hold_residual + sizeof(RESIDUAL)));
+#endif
+ puts("\n");
+ }
+
zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
zimage_size = ZIMAGE_SIZE;
- puts("zimage at: "); puthex((unsigned long)zimage_start);
+ puts("zimage at: "); puthex((unsigned long)zimage_start);
puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
if ( INITRD_OFFSET )
@@ -296,18 +371,19 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
/* relocate initrd */
if ( initrd_start )
{
- puts("initrd at: "); puthex(initrd_start);
+ puts("initrd at: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
memcpy ((void *)INITRD_DESTINATION,(void *)initrd_start,
INITRD_SIZE );
initrd_end = INITRD_DESTINATION + INITRD_SIZE;
initrd_start = INITRD_DESTINATION;
- puts("Moved initrd to: "); puthex(initrd_start);
+ puts("Moved initrd to: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
}
-
+#ifndef CONFIG_MBX
CRT_tstc(); /* Forces keyboard to be initialized */
+#endif
puts("\nLinux/PPC load: ");
timer = 0;
cp = cmd_line;
@@ -339,9 +415,12 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
if ( initrd_start > (16<<20))
puts("initrd_start located > 16M\n");
-
puts("Uncompressing Linux...");
- gunzip(0, 0x400000, zimage_start, &zimage_size);
+
+ /* these _bcopy() calls are here so I can add breakpoints to the boot for mbx -- Cort */
+ /*_bcopy( (char *)0x100,(char *)&sanity, 0x2000-0x100);*/
+ gunzip(0, 0x400000, zimage_start, &zimage_size);
+ /*_bcopy( (char *)&sanity,(char *)0x100,0x2000-0x100);*/
puts("done.\n");
puts("Now booting the kernel\n");
return (unsigned long)&hold_residual;
diff --git a/arch/ppc/boot/vreset.c b/arch/ppc/boot/vreset.c
index 3bc3936c6..6086372a0 100644
--- a/arch/ppc/boot/vreset.c
+++ b/arch/ppc/boot/vreset.c
@@ -434,16 +434,15 @@ vga_init(unsigned char *ISA_mem)
{
int slot;
struct VgaRegs *VgaTextRegs;
-
+#if 0
if ((_get_PVR()>>16) == PPC_601) {
return(old_vga_init(ISA_mem));
}
-
-#if 1
+#endif
+
/* See if VGA already in TEXT mode - exit if so! */
outb(0x3CE, 0x06);
if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;}
-#endif
/* If no VGA responding in text mode, then we have some work to do...
*/
@@ -522,11 +521,6 @@ vga_init(unsigned char *ISA_mem)
return (1); /* 'CRT' I/O supported */
}
-static int
-NOP(int x)
-{
-}
-
/*
* Write to VGA Attribute registers.
*/
@@ -852,166 +846,5 @@ void printslots(void)
puts(" Vendor ID: ");
puthex(PCIVendor(i)); puts("\n");
#endif
-
- }
-}
-
-/*
- * OLD vreset.c
- *
- * Initialize the VGA control registers to 80x25 text mode.
- *
- * Adapted from a program by:
- * Steve Sellgren
- * San Francisco Indigo Company
- * sfindigo!sellgren@uunet.uu.net
- */
-
-unsigned char CRTC[24] = {
- 0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F,
- 0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00, /*0x07, 0x80, */
- 0x9C, 0xAE, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3};
-unsigned char SEQ[5] = {0x3, 0x0, 0x3, 0x0, 0x2};
-unsigned char GC[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0xE, 0x0, 0xFF};
-
-#if 0
-static const unsigned char color_LUT[] =
- {
- 0x00, 0x00, 0x00, /* 0 - black */
- 0x00, 0x00, 0x2A, /* 1 - blue */
- 0x00, 0x2A, 0x00, /* 2 - green */
- 0x00, 0x2A, 0x2A, /* 3 - cyan */
- 0x2A, 0x00, 0x00, /* 4 - red */
- 0x2A, 0x00, 0x2A, /* 5 - magenta */
- 0x2A, 0x2A, 0x00, /* 6 - brown */
- 0x2A, 0x2A, 0x2A, /* 7 - white */
- 0x00, 0x00, 0x15, /* 8 - gray */
- 0x00, 0x00, 0x3F, /* 9 - light blue */
- 0x00, 0x2A, 0x15, /* 10 - light green */
- 0x00, 0x2A, 0x3F, /* 11 - light cyan */
- 0x2A, 0x00, 0x15, /* 12 - light red */
- 0x2A, 0x00, 0x3F, /* 13 - light magenta */
- 0x2A, 0x2A, 0x15, /* 14 - yellow */
- 0x2A, 0x2A, 0x3F, /* 15 - bright white */
- };
-#endif
-
-old_vga_init(unsigned char *ISA_mem)
-{
- int i, j;
- int value;
- unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
-
- /* See if VGA already in TEXT mode - exit if so! */
- outb(0x3CE, 0x06);
- if ((inb(0x3CF) & 0x01) == 0) return;
-
- /* From the S3 manual */
- outb(0x46E8, 0x10); /* Put into setup mode */
- outb(0x3C3, 0x10);
- outb(0x102, 0x01); /* Enable registers */
- outb(0x46E8, 0x08); /* Enable video */
- outb(0x3C3, 0x08);
- outb(0x4AE8, 0x00);
-
-#if 0
- outb(0x42E8, 0x80); /* Reset graphics engine? */
-#endif
-
- outb(0x3D4, 0x38); /* Unlock all registers */
- outb(0x3D5, 0x48);
- outb(0x3D4, 0x39);
- outb(0x3D5, 0xA5);
- outb(0x3D4, 0x40);
- outb(0x3D5, inb(0x3D5)|0x01);
- outb(0x3D4, 0x33);
- outb(0x3D5, inb(0x3D5)&~0x52);
- outb(0x3D4, 0x35);
- outb(0x3D5, inb(0x3D5)&~0x30);
- outb(0x3D4, 0x3A);
- outb(0x3D5, 0x00);
- outb(0x3D4, 0x53);
- outb(0x3D5, 0x00);
- outb(0x3D4, 0x31);
- outb(0x3D5, inb(0x3D5)&~0x4B);
- outb(0x3D4, 0x58);
- outb(0x3D5, 0);
-
- outb(0x3D4, 0x54);
- outb(0x3D5, 0x38);
- outb(0x3D4, 0x60);
- outb(0x3D5, 0x07);
- outb(0x3D4, 0x61);
- outb(0x3D5, 0x80);
- outb(0x3D4, 0x62);
- outb(0x3D5, 0xA1);
- outb(0x3D4, 0x69); /* High order bits for cursor address */
- outb(0x3D5, 0);
-
- outb(0x3D4, 0x32);
- outb(0x3D5, inb(0x3D5)&~0x10);
-
- outb(0x3C2, 0x67);
-
-#if 0
- /* Initialize DAC */
- outb(0x3C6,0xFF);
- inb(0x3C7);
- outb(0x3C8,0x00);
- inb(0x3C7);
- for (i=0; i<sizeof(color_LUT); i++) {
- outb(0x3C9, color_LUT[i]);
- }
- for (i; i<768; i += 3) {
- outb(0x3C9, 0x3F); /* White? */
- outb(0x3C9, 0x3F); /* White? */
- outb(0x3C9, 0x3F); /* White? */
- }
-
- /* Load font */
- NOP(inb(0x3DA)); /* Reset Address/Data FlipFlop for Attribute ctlr */
- outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
- outw(0x3C4, 0x0001); /* reset sequencer */
- outw(0x3C4, 0x0204); /* write to plane 2 */
- outw(0x3C4, 0x0407); /* enable plane graphics */
- outw(0x3C4, 0x0003); /* reset sequencer */
- outw(0x3CE, 0x0402); /* read plane 2 */
- outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
- outw(0x3CE, 0x0600); /* set graphics */
- for (i = 0; i < sizeof(font); i += 16) {
- for (j = 0; j < 16; j++) {
- font_page[(2*i)+j] = font[i+j];
- }
- }
-#else
- outw(0x3C4, 0x0120); /* disable video */
- setTextCLUT(2); /* load color lookup table */
- loadFont(ISA_mem); /* load font */
-#endif
-
- for (i = 0; i < 24; i++) {
- outb(0x3D4, i);
- outb(0x3D5, CRTC[i]);
- }
- for (i = 0; i < 5; i++) {
- outb(0x3C4, i);
- outb(0x3C5, SEQ[i]);
- }
- for (i = 0; i < 9; i++) {
- outb(0x3CE, i);
- outb(0x3CF, GC[i]);
- }
- value = inb(0x3DA); /* reset flip-flop */
- for (i = 0; i < 16; i++) {
- outb(0x3C0, i);
- outb(0x3C0, AC[i]);
- }
- for (i = 16; i < 21; i++) {
- outb(0x3C0, i | 0x20);
- outb(0x3C0, AC[i]);
}
- clearVideoMemory();
- outw(0x3C4, 0x0100); /* re-enable video */
- outb(0x3C2, 0x23);
- return (1); /* Keyboard should work */
}
diff --git a/arch/ppc/chrp_defconfig b/arch/ppc/chrp_defconfig
new file mode 100644
index 000000000..ccbc0f942
--- /dev/null
+++ b/arch/ppc/chrp_defconfig
@@ -0,0 +1,321 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+CONFIG_CHRP=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_MBX is not set
+CONFIG_MACH_SPECIFIC=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_ABSTRACT_CONSOLE is not set
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+# CONFIG_MAC_FLOPPY is not set
+CONFIG_MACMOUSE=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_XMON is not set
+CONFIG_CONTROL_VIDEO=y
+CONFIG_PLATINUM_VIDEO=y
+CONFIG_VALKYRIE_VIDEO=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+CONFIG_CHIPS_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# NEW devices (io_request, all ALPHA and dangerous)
+#
+# CONFIG_IO_REQUEST is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_RARP=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+CONFIG_SCSI_AIC7XXX=m
+# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
+# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_PAGE_ENABLE is not set
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=15
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c
index 629256eaa..05a2f85d3 100644
--- a/arch/ppc/chrpboot/main.c
+++ b/arch/ppc/chrpboot/main.c
@@ -16,11 +16,11 @@ void gunzip(void *, int, unsigned char *, int *);
#define get_16be(x) (*(unsigned short *)(x))
#define get_32be(x) (*(unsigned *)(x))
-#define RAM_START 0x90000000
-#define RAM_END 0x90800000 /* only 8M mapped with BATs */
+#define RAM_START 0x00000000
+#define RAM_END 0x00800000 /* only 8M mapped with BATs */
-#define RAM_FREE 0x90540000 /* after image of chrpboot */
-#define PROG_START 0x90010000
+#define RAM_FREE 0x00540000 /* after image of chrpboot */
+#define PROG_START 0x00010000
char *avail_ram;
char *end_avail;
@@ -40,7 +40,7 @@ chrpboot(int a1, int a2, void *prom)
unsigned initrd_start, initrd_size;
printf("chrpboot starting\n\r");
- setup_bats();
+ /* setup_bats(); */
if (initrd_len) {
initrd_size = initrd_len;
diff --git a/arch/ppc/chrpboot/misc.S b/arch/ppc/chrpboot/misc.S
index 11a612af1..b2094b9d3 100644
--- a/arch/ppc/chrpboot/misc.S
+++ b/arch/ppc/chrpboot/misc.S
@@ -23,10 +23,10 @@ setup_bats:
b 5f
4: ori 4,4,0xff /* set up BAT registers for 604 */
li 5,2
- mtdbatu 0,4
- mtdbatl 0,5
-5: mtibatu 0,4
- mtibatl 0,5
+ mtdbatu 3,4
+ mtdbatl 3,5
+5: mtibatu 3,4
+ mtibatl 3,5
isync
blr
diff --git a/arch/ppc/coffboot/main.c b/arch/ppc/coffboot/main.c
index ab0ee6c4a..e70844b62 100644
--- a/arch/ppc/coffboot/main.c
+++ b/arch/ppc/coffboot/main.c
@@ -18,9 +18,10 @@ void gunzip(void *, int, unsigned char *, int *);
#define get_32be(x) (*(unsigned *)(x))
#define RAM_START 0xc0000000
-#define RAM_END 0xc0800000 /* only 8M mapped with BATs */
+#define PROG_START RAM_START
+#define RAM_END (RAM_START + 0x800000) /* only 8M mapped with BATs */
-#define RAM_FREE 0xc0540000 /* after image of coffboot */
+#define RAM_FREE (RAM_START + 0x540000) /* after image of coffboot */
char *avail_ram;
char *end_avail;
@@ -47,7 +48,7 @@ coffboot(int a1, int a2, void *prom)
printf("error getting load-base\n");
exit();
}
- setup_bats();
+ setup_bats(RAM_START);
eh = (struct external_filehdr *) loadbase;
ns = get_16be(eh->f_nscns);
@@ -82,7 +83,7 @@ coffboot(int a1, int a2, void *prom)
im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
len = get_32be(isect->s_size);
- dst = (void *) RAM_START;
+ dst = (void *) PROG_START;
if (im[0] == 0x1f && im[1] == 0x8b) {
void *cp = (void *) RAM_FREE;
@@ -98,7 +99,7 @@ coffboot(int a1, int a2, void *prom)
flush_cache(dst, len);
- sa = *(unsigned *)dst + RAM_START;
+ sa = *(unsigned *)dst + PROG_START;
printf("start address = 0x%x\n", sa);
#if 0
diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S
index ae08ee2fa..1a9f07129 100644
--- a/arch/ppc/coffboot/misc.S
+++ b/arch/ppc/coffboot/misc.S
@@ -9,24 +9,25 @@
.text
/*
- * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ * Use the BAT0 registers to map the 1st 8MB of RAM to
+ * the address given as the 1st argument.
*/
.globl setup_bats
setup_bats:
+ mr 4,3
mfpvr 3
rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */
cmpi 0,3,1
- lis 4,0xc000
bne 4f
ori 4,4,4 /* set up BAT registers for 601 */
li 5,0x7f
b 5f
4: ori 4,4,0xff /* set up BAT registers for 604 */
li 5,2
- mtdbatu 0,4
- mtdbatl 0,5
-5: mtibatu 0,4
- mtibatl 0,5
+ mtdbatu 3,4
+ mtdbatl 3,5
+5: mtibatu 3,4
+ mtibatl 3,5
isync
blr
diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig
new file mode 100644
index 000000000..4f9983126
--- /dev/null
+++ b/arch/ppc/common_defconfig
@@ -0,0 +1,331 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+CONFIG_ALL_PPC=y
+# CONFIG_MBX is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+CONFIG_ABSTRACT_CONSOLE=y
+CONFIG_FB=y
+CONFIG_VGA_CONSOLE=y
+CONFIG_FB_COMPAT_XPMAC=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_MACMOUSE=y
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_XMON is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# NEW devices (io_request, all ALPHA and dangerous)
+#
+# CONFIG_IO_REQUEST is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ACCT=y
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_RARP=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=5
+CONFIG_SCSI_MAC53C94=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+CONFIG_PPP=y
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Frame buffer devices
+#
+CONFIG_FB_OPEN_FIRMWARE=y
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_CFB8=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 72bab8928..4ab631988 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -1,30 +1,37 @@
-# $Id: config.in,v 1.36 1997/12/29 21:36:52 geert Exp $
+# $Id: config.in,v 1.47 1998/04/10 10:19:04 geert Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
mainmenu_name "Linux/PowerPC Kernel Configuration"
+
+
mainmenu_option next_comment
comment 'Platform support'
define_bool CONFIG_PPC y
-if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then
- define_bool CONFIG_CROSSCOMPILE y
-else
- define_bool CONFIG_NATIVE y
-fi
-
-define_bool CONFIG_MACH_SPECIFIC y
-bool 'Build PowerMac Kernel (not PReP or CHRP)?' CONFIG_PMAC
-bool 'Build PReP Kernel (not PowerMac or CHRP)?' CONFIG_PREP
-bool 'Build CHRP Kernel (not PReP or PowerMac)?' CONFIG_CHRP
+#if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then
+# define_bool CONFIG_CROSSCOMPILE y
+#else
+# define_bool CONFIG_NATIVE y
+#fi
choice 'Processor type' \
- "Common CONFIG_COMMON \
- 601 CONFIG_601 \
- 603 CONFIG_603 \
- 604 CONFIG_604" Common
+ "6xx/7xx CONFIG_6xx \
+ 860/821 CONFIG_8xx" 6xx/7xx
+
+choice 'Machine Type' \
+ "PowerMac CONFIG_PMAC \
+ PReP CONFIG_PREP \
+ CHRP CONFIG_CHRP \
+ PowerMac/PReP/CHRP CONFIG_ALL_PPC \
+ APUS CONFIG_APUS \
+ MBX CONFIG_MBX" PReP
endmenu
+if [ "$CONFIG_ALL_PPC" != "y" ]; then
+ define_bool CONFIG_MACH_SPECIFIC y
+fi
+
mainmenu_option next_comment
comment 'General setup'
@@ -35,9 +42,16 @@ if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Kernel module loader' CONFIG_KMOD
fi
-define_bool CONFIG_PCI y
+if [ "$CONFIG_APUS" = "y" ]; then
+ define_bool CONFIG_PCI n
+else
+ define_bool CONFIG_PCI y
+fi
if [ "$CONFIG_PREP" = "y" ]; then
- bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+ bool 'PCI quirks' CONFIG_PCI_QUIRKS
+ if [ "$CONFIG_PCI_QUIRKS" = "y" ]; then
+ bool ' PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+ fi
fi
bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
bool 'Networking support' CONFIG_NET
@@ -51,6 +65,14 @@ define_bool CONFIG_KERNEL_ELF y
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+ dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+ bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
+ fi
+fi
+
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'New unified console driver (EXPERIMENTAL)' CONFIG_ABSTRACT_CONSOLE
fi
@@ -68,6 +90,7 @@ else
# if compiling specifically for prep or chrp, or supporting all arch's
if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then
bool 'Support for frame buffer devices' CONFIG_FB
+ bool 'Support for VGA devices' CONFIG_VGA_CONSOLE
bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
else
bool 'Support for PowerMac console' CONFIG_PMAC_CONSOLE
@@ -79,13 +102,10 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Support for PowerMac mouse (EXPERIMENTAL)' CONFIG_MACMOUSE
fi
bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+bool 'Include kgdb kernel debugger' CONFIG_KGDB
bool 'Include xmon kernel debugger' CONFIG_XMON
-if [ "$CONFIG_ABSTRACT_CONSOLE" = "y" ]; then
- if [ "$CONFIG_FB" != "y" ]; then
- define_bool CONFIG_VGA_CONSOLE y
- fi
-else
+if [ "$CONFIG_ABSTRACT_CONSOLE" != "y" ]; then
if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
bool 'Support for Apple "control" display' CONFIG_CONTROL_VIDEO
bool 'Support for Apple "platinum" display' CONFIG_PLATINUM_VIDEO
@@ -149,17 +169,6 @@ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
fi
endmenu
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then
- define_bool CONFIG_CDROM y
-else
- if [ "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then
- define_bool CONFIG_CDROM m
- else
- define_bool CONFIG_CDROM n
- fi
-fi
-
source fs/Config.in
source fs/nls/Config.in
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index 7e5caa71d..e498b5249 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -6,22 +6,21 @@
# Platform support
#
CONFIG_PPC=y
-CONFIG_NATIVE=y
-CONFIG_MACH_SPECIFIC=y
+# CONFIG_6xx is not set
+CONFIG_8xx=y
# CONFIG_PMAC is not set
-CONFIG_PREP=y
+# CONFIG_PREP is not set
# CONFIG_CHRP is not set
-CONFIG_COMMON=y
+# CONFIG_ALL_PPC is not set
+CONFIG_MBX=y
+CONFIG_MACH_SPECIFIC=y
#
# General setup
#
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_MODULES is not set
CONFIG_PCI=y
-# CONFIG_PCI_OPTIMIZE is not set
CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
# CONFIG_SYSCTL is not set
@@ -31,6 +30,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
# CONFIG_PMAC_CONSOLE is not set
# CONFIG_MAC_KEYBOARD is not set
# CONFIG_MAC_FLOPPY is not set
@@ -46,25 +46,17 @@ CONFIG_VGA_CONSOLE=y
#
# Floppy, IDE, and other block devices
#
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_TRITON is not set
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_ONLY is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -79,83 +71,30 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
# CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_ALIAS is not set
# CONFIG_SYN_COOKIES is not set
-CONFIG_INET_RARP=y
-# CONFIG_IP_NOSR is not set
-CONFIG_SKB_LARGE=y
-# CONFIG_IPV6 is not set
+# CONFIG_INET_RARP is not set
+CONFIG_IP_NOSR=y
+# CONFIG_SKB_LARGE is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_LLC is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_CPU_IS_SLOW is not set
-# CONFIG_NET_SCHED is not set
#
# SCSI support
#
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
-# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
-CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
-CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
-CONFIG_SCSI_NCR53C8XX_SYNC=5
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI is not set
#
# Network device support
@@ -164,34 +103,28 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
# CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_3COM is not set
-CONFIG_LANCE=y
+# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
-# CONFIG_TLAN is not set
-# CONFIG_ES3210 is not set
-# CONFIG_ZNET is not set
+# CONFIG_NET_EISA is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_NET_RADIO is not set
+# CONFIG_PPP is not set
# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
-# CONFIG_SHAPER is not set
+# CONFIG_WAN_DRIVERS is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
#
# ISDN subsystem
@@ -202,6 +135,7 @@ CONFIG_PPP=m
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
#
# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_CDROM is not set
#
# Filesystems
@@ -209,63 +143,52 @@ CONFIG_PPP=m
# CONFIG_QUOTA is not set
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+# CONFIG_ISO9660_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
-CONFIG_PROC_FS=y
+# CONFIG_PROC_FS is not set
CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
# CONFIG_MAC_PARTITION is not set
-
-#
-# Native Language Support
-#
# CONFIG_NLS is not set
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SOFTCURSOR is not set
+# CONFIG_VT is not set
CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_PRINTER is not set
-CONFIG_MOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-# CONFIG_UMISC is not set
+# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
# CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_BT848 is not set
# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
#
# Sound
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 37776109d..3561fd26a 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -11,14 +11,32 @@
$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
O_TARGET := kernel.o
-O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
- align.o ptrace.o irq.o openpic.o bitops.o ppc_htab.o idle.o \
- time.o prep_time.o pmac_time.o chrp_time.o \
- setup.o prep_setup.o pmac_setup.o pmac_support.o chrp_setup.o \
- pci.o prep_pci.o pmac_pci.o chrp_pci.o \
- residual.o prom.o
OX_OBJS := ppc_ksyms.o
+
+O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \
+ bitops.o ppc_htab.o setup.o ptrace.o align.o
+
+ifdef CONFIG_PCI
+O_OBJS += pci.o
+endif
+ifdef CONFIG_KGDB
+O_OBJS += ppc-stub.o
+endif
+
+ifeq ($(CONFIG_MBX),y)
+O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o
+else
+ifeq ($(CONFIG_APUS),y)
+O_OBJS += prom.o openpic.o
+else
+O_OBJS += prep_time.o pmac_time.o chrp_time.o \
+ prep_setup.o pmac_setup.o pmac_support.o chrp_setup.o \
+ prep_pci.o pmac_pci.o chrp_pci.o \
+ residual.o prom.o openpic.o
+endif
+endif
+
ifdef SMP
O_OBJS += smp.o
endif
@@ -38,10 +56,10 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
rm mk_defs.s
find_name : find_name.c
- $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o find_name find_name.c
+ $(HOSTCC) -o find_name find_name.c
checks: checks.c
- $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+ $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
./checks
include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
index 39cb04f77..70284674b 100644
--- a/arch/ppc/kernel/align.c
+++ b/arch/ppc/kernel/align.c
@@ -194,9 +194,13 @@ fix_alignment(struct pt_regs *regs)
return -EFAULT; /* bad address */
}
+#ifdef __SMP__
+ if ((flags & F) && (regs->msr & MSR_FP) )
+ smp_giveup_fpu(current);
+#else
if ((flags & F) && last_task_used_math == current)
giveup_fpu();
-
+#endif
if (flags & M)
return 0; /* too hard for now */
@@ -255,12 +259,22 @@ fix_alignment(struct pt_regs *regs)
* the kernel with -msoft-float so it doesn't use the
* fp regs for copying 8-byte objects. */
case LD+F+S:
+#ifdef __SMP__
+ if (regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
giveup_fpu();
+#endif
cvt_fd(&data.f, &current->tss.fpr[reg]);
/* current->tss.fpr[reg] = data.f; */
break;
case ST+F+S:
+#ifdef __SMP__
+ if (regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
giveup_fpu();
+#endif
cvt_df(&current->tss.fpr[reg], &data.f);
/* data.f = current->tss.fpr[reg]; */
break;
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index 16b379254..6036efc28 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -4,13 +4,13 @@
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/openpic.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/hydra.h>
#include <asm/prom.h>
@@ -22,8 +22,12 @@
volatile struct Hydra *Hydra = NULL;
-
#if 1
+/*
+ * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
+ * limit the bus number to 3 bits
+ */
+
int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
{
@@ -32,11 +36,6 @@ int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
- if (offset == PCI_INTERRUPT_LINE) {
- /* PCI interrupts are controlled by the OpenPIC */
- if (*val)
- *val = openpic_to_irq(*val);
- }
return PCIBIOS_SUCCESSFUL;
}
@@ -228,10 +227,11 @@ __initfunc(int w83c553f_init(void))
unsigned char t8;
unsigned short t16;
unsigned int t32;
- if (pcibios_find_device(PCI_VENDOR_ID_WINBOND,
- PCI_DEVICE_ID_WINBOND_83C553, 0, &bus, &dev)
- == PCIBIOS_SUCCESSFUL) {
- dev++;
+ struct pci_dev *pdev;
+ if ((pdev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_83C553, NULL))) {
+ bus = pdev->bus->number;
+ dev = pdev->devfn + 1;
chrp_pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) {
#if 0
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index 6c5d2afa5..91ca5d595 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -60,21 +60,6 @@ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
extern int rd_image_start; /* starting block # of image */
#endif
-
-int chrp_ide_irq = 0;
-
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
- ide_ioreg_t port = base;
- int i = 8;
-
- while (i--)
- *p++ = port++;
- *p++ = base + 0x206;
- if (irq != NULL)
- *irq = chrp_ide_irq;
-}
-
static const char *gg2_memtypes[4] = {
"FPM", "SDRAM", "EDO", "BEDO"
};
@@ -89,6 +74,34 @@ static const char *gg2_cachemodes[4] = {
"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
};
+#if 0
+#ifdef CONFIG_BLK_DEV_IDE
+int chrp_ide_ports_known;
+ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+ide_ioreg_t chrp_idedma_regbase; /* one for both channels */
+unsigned int chrp_ide_irq;
+
+void chrp_ide_probe(void)
+{
+}
+
+void chrp_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ int i;
+
+ *p = 0;
+ if (base == 0)
+ return;
+ for (i = 0; i < 8; ++i)
+ *p++ = base + i * 0x10;
+ *p = base + 0x160;
+ if (irq != NULL) {
+ *irq = chrp_ide_irq;
+ }
+}
+#endif /* CONFIG_BLK_DEV_IDE */
+#endif
+
int
chrp_get_cpuinfo(char *buffer)
{
@@ -139,12 +152,63 @@ chrp_get_cpuinfo(char *buffer)
}
/* L2 cache */
t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
- len += sprintf(buffer+len, "l2\t\t: %s %s (%s)\n",
+ len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n",
gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3],
gg2_cachemodes[t & 3]);
return len;
}
+ /*
+ * Fixes for the National Semiconductor PC78308VUL SuperI/O
+ *
+ * Some versions of Open Firmware incorrectly initialize the IRQ settings
+ * for keyboard and mouse
+ */
+
+__initfunc(static inline void sio_write(u8 val, u8 index))
+{
+ outb(index, 0x15c);
+ outb(val, 0x15d);
+}
+
+__initfunc(static inline u8 sio_read(u8 index))
+{
+ outb(index, 0x15c);
+ return inb(0x15d);
+}
+
+__initfunc(static void sio_init(void))
+{
+ u8 irq, type;
+
+ /* select logical device 0 (KBC/Keyboard) */
+ sio_write(0, 0x07);
+ irq = sio_read(0x70);
+ type = sio_read(0x71);
+ printk("sio: Keyboard irq %d, type %d: ", irq, type);
+ if (irq == 1 && type == 3)
+ printk("OK\n");
+ else {
+ printk("remapping to irq 1, type 3\n");
+ sio_write(1, 0x70);
+ sio_write(3, 0x71);
+ }
+
+ /* select logical device 1 (KBC/Mouse) */
+ sio_write(1, 0x07);
+ irq = sio_read(0x70);
+ type = sio_read(0x71);
+ printk("sio: Mouse irq %d, type %d: ", irq, type);
+ if (irq == 12 && type == 3)
+ printk("OK\n");
+ else {
+ printk("remapping to irq 12, type 3\n");
+ sio_write(12, 0x70);
+ sio_write(3, 0x71);
+ }
+}
+
+
__initfunc(void
chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -191,7 +255,12 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
hydra_init(); /* Mac I/O */
w83c553f_init(); /* PCI-ISA bridge and IDE */
-#ifdef CONFIG_ABSTRACT_CONSOLE
+ /*
+ * Fix the Super I/O configuration
+ */
+ sio_init();
+
+#ifdef CONFIG_FB
/* Frame buffer device based console */
conswitchp = &fb_con;
#endif
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index 73dcf9844..7109c0e5d 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -38,7 +38,7 @@ void chrp_time_init(void)
rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
if (rtcs == NULL || rtcs->addrs == NULL)
return;
- base = ((int *)rtcs->addrs)[2];
+ base = rtcs->addrs[0].address;
nvram_as1 = 0;
nvram_as0 = base;
nvram_data = base + 1;
@@ -69,7 +69,7 @@ int chrp_set_rtc_time(unsigned long nowtime)
unsigned char save_control, save_freq_select;
struct rtc_time tm;
- to_tm(nowtime + 10*60*60, &tm); /* XXX for now */
+ to_tm(nowtime, &tm);
save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
@@ -146,7 +146,7 @@ unsigned long chrp_get_rtc_time(void)
}
if ((year += 1900) < 1970)
year += 100;
- return mktime(year, mon, day, hour, min, sec) - 10*60*60 /* XXX for now */;
+ return mktime(year, mon, day, hour, min, sec);
}
@@ -155,6 +155,9 @@ void chrp_calibrate_decr(void)
struct device_node *cpu;
int freq, *fp, divisor;
+ if (via_calibrate_decr())
+ return;
+
/*
* The cpu node should have a timebase-frequency property
* to tell us the rate at which the decrementer counts.
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 2924febc5..d8540e68d 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -9,6 +9,8 @@
* Low-level exception handlers and MMU support
* rewritten by Paul Mackerras.
* Copyright (C) 1996 Paul Mackerras.
+ * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
+ * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* This file contains the low-level support and setup for the
* PowerPC platform, including trap and interrupt dispatch.
@@ -29,12 +31,14 @@
#include <linux/sys.h>
#include <linux/errno.h>
#include <linux/config.h>
+#ifdef CONFIG_8xx
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+#endif
#ifdef CONFIG_APUS
-/* At CYBERBASEp we'll find the following sum:
- * -KERNELBASE+CyberStormMemoryBase
- */
-#define CYBERBASEp (0xfff00000)
+#include <asm/amigappc.h>
#endif
/* optimization for 603 to load the tlb directly from the linux table */
@@ -78,6 +82,8 @@ LG_CACHE_LINE_SIZE = 5
isync
/* This instruction is not implemented on the PPC 603 or 601 */
+#ifndef CONFIG_8xx
+/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
li r4,128; \
mtctr r4; \
@@ -85,6 +91,7 @@ LG_CACHE_LINE_SIZE = 5
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
+#endif
#define LOAD_BAT(n, offset, reg, RA, RB) \
lwz RA,offset+0(reg); \
@@ -96,6 +103,20 @@ LG_CACHE_LINE_SIZE = 5
mtspr DBAT##n##U,RA; \
mtspr DBAT##n##L,RB
+#ifndef CONFIG_APUS
+#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h
+#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h
+#else
+#define tophys(rd,rs,rt) \
+ lis rt,CYBERBASEp@h; \
+ lwz rt,0(rt); \
+ add rd,rs,rt
+#define tovirt(rd,rs,rt) \
+ lis rt,CYBERBASEp@h; \
+ lwz rt,0(rt); \
+ sub rd,rs,rt
+#endif
+
.text
.globl _stext
_stext:
@@ -130,12 +151,44 @@ _start:
*
* This just gets a minimal mmu environment setup so we can call
* start_here() to do the real work.
- * -- Cort
+ * -- Cort
+ *
+ * MPC8xx
+ * This port was done on an MBX board with an 860. Right now I only
+ * support an ELF compressed (zImage) boot from EPPC-Bug because the
+ * code there loads up some registers before calling us:
+ * r3: ptr to board info data
+ * r4: initrd_start or if no initrd then 0
+ * r5: initrd_end - unused if r4 is 0
+ * r6: Start of command line string
+ * r7: End of command line string
+ *
+ * I decided to use conditional compilation instead of checking PVR and
+ * adding more processor specific branches around code I don't need.
+ * Since this is an embedded processor, I also appreciate any memory
+ * savings I can get.
+ *
+ * The MPC8xx does not have any BATs, but it supports large page sizes.
+ * We first initialize the MMU to support 8M byte pages, then load one
+ * entry into each of the instruction and data TLBs to map the first
+ * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to
+ * the "internal" processor registers before MMU_init is called.
+ *
+ * The TLB code currently contains a major hack. Since I use the condition
+ * code register, I have to save and restore it. I am out of registers, so
+ * I just store it in memory location 0 (the TLB handlers are not reentrant).
+ * To avoid making any decisions, I need to use the "segment" valid bit
+ * in the first level table, but that would require many changes to the
+ * Linux page directory/table functions that I don't want to do right now.
+ *
+ * I used to use SPRG2 for a temporary register in the TLB handler, but it
+ * has since been put to other uses. I now use a hack to save a register
+ * and the CCR at memory location 0.....Someday I'll fix this.....
+ * -- Dan
*/
.globl __start
__start:
-
/*
* We have to do any OF calls before we map ourselves to KERNELBASE,
* because OF may have I/O devices mapped in in that area
@@ -145,12 +198,16 @@ __start:
mr r30,r4
mr r29,r5
mr r28,r6
- mr r29,r7
+ mr r27,r7
+#ifndef CONFIG_8xx
+#ifndef CONFIG_APUS
bl prom_init
+#endif
/*
* Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to KERNELBASE.
+ * of RAM to KERNELBASE. From this point on we can't safely
+ * call OF any more.
*/
mfspr r9,PVR
rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
@@ -173,17 +230,134 @@ __start:
addis r8,r8,KERNELBASE@h
addi r8,r8,2
#endif
- mtspr DBAT0U,r11
+5: mtspr DBAT0U,r11
mtspr DBAT0L,r8
-5: mtspr IBAT0U,r11
+ mtspr IBAT0U,r11
mtspr IBAT0L,r8
isync
+
+/*
+ * We need to run with _start at physical address 0.
+ * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
+ * the exception vectors at 0 (and therefore this copy
+ * overwrites OF's exception vectors with our own).
+ * If the MMU is already turned on, we copy stuff to KERNELBASE,
+ * otherwise we copy it to 0.
+ */
+ bl reloc_offset
+ mr r26,r3
+ addis r4,r3,KERNELBASE@h /* current address of _start */
+ cmpwi 0,r4,0 /* are we already running at 0? */
+ beq 2f /* assume it's OK if so */
+ li r3,0
+ mfmsr r0
+ andi. r0,r0,MSR_DR /* MMU enabled? */
+ beq 7f
+ lis r3,KERNELBASE@h /* if so, are we */
+ cmpw 0,r4,r3 /* already running at KERNELBASE? */
+ beq 2f
+ rlwinm r4,r4,0,8,31 /* translate source address */
+ add r4,r4,r3 /* to region mapped with BATs */
+7: addis r9,r26,klimit@ha /* fetch klimit */
+ lwz r25,klimit@l(r9)
+ addis r25,r25,-KERNELBASE@h
+ li r6,0 /* Destination */
+#ifdef CONFIG_APUS
+ lis r9,0x6170
+ ori r9,r9,0x7573
+ cmpw 0,r9,r31
+ bne 8f
+ lis r6,0xfff0 /* Copy to 0xfff00000 on APUS */
+8:
+#endif
+ li r5,0x4000 /* # bytes of memory to copy */
+ bl copy_and_flush /* copy the first 0x4000 bytes */
+#ifdef CONFIG_APUS
+ cmpw 0,r9,r31 /* That's all we need on APUS. */
+ beq 2f
+#endif
+ addi r0,r3,4f@l /* jump to the address of 4f */
+ mtctr r0 /* in copy and do the rest. */
+ bctr /* jump to the copy */
+4: mr r5,r25
+ bl copy_and_flush /* copy the rest */
+2:
/*
* we now have the 1st 16M of ram mapped with the bats.
* prep needs the mmu to be turned on here, but pmac already has it on.
* this shouldn't bother the pmac since it just gets turned on again
* as we jump to our code at KERNELBASE. -- Cort
*/
+
+#else /* CONFIG_8xx */
+ tlbia /* Invalidate all TLB entries */
+ li r8, 0
+ mtspr MI_CTR, r8 /* Set instruction control to zero */
+ lis r8, MD_RESETVAL@h
+ mtspr MD_CTR, r8 /* Set data TLB control */
+
+ /* Now map the lower 8 Meg into the TLBs. For this quick hack,
+ * we can load the instruction and data TLB registers with the
+ * same values.
+ */
+ lis r8, KERNELBASE@h /* Create vaddr for TLB */
+ ori r8, r8, MI_EVALID /* Mark it valid */
+ mtspr MI_EPN, r8
+ mtspr MD_EPN, r8
+ li r8, MI_PS8MEG /* Set 8M byte page */
+ ori r8, r8, MI_SVALID /* Make it valid */
+ mtspr MI_TWC, r8
+ mtspr MD_TWC, r8
+ li r8, MI_BOOTINIT /* Create RPN for address 0 */
+ mtspr MI_RPN, r8 /* Store TLB entry */
+ mtspr MD_RPN, r8
+ lis r8, MI_Kp@h /* Set the protection mode */
+ mtspr MI_AP, r8
+ mtspr MD_AP, r8
+#ifdef CONFIG_MBX
+ /* Map another 8 MByte at 0xfa000000 to get the processor
+ * internal registers (among other things).
+ */
+ lis r8, 0xfa000000@h /* Create vaddr for TLB */
+ ori r8, r8, MD_EVALID /* Mark it valid */
+ mtspr MD_EPN, r8
+ li r8, MD_PS8MEG /* Set 8M byte page */
+ ori r8, r8, MD_SVALID /* Make it valid */
+ mtspr MD_TWC, r8
+ lis r8, 0xfa000000@h /* Create paddr for TLB */
+ ori r8, r8, MI_BOOTINIT
+ mtspr MD_RPN, r8
+#endif
+
+ /* Since the cache is enabled according to the information we
+ * just loaded into the TLB, invalidate and enable the caches here.
+ * We should probably check/set other modes....later.
+ */
+ lis r8, IDC_INVALL@h
+ mtspr IC_CST, r8
+ mtspr DC_CST, r8
+ lis r8, IDC_ENABLE@h
+ mtspr IC_CST, r8
+#ifdef notdef
+ mtspr DC_CST, r8
+#else
+ /* I still have a bug somewhere because the Ethernet driver
+ * does not want to work with copyback enabled. For now,
+ * at least enable write through.
+ */
+#if 0
+ lis r8, DC_SFWT@h
+ mtspr DC_CST, r8
+ lis r8, IDC_ENABLE@h
+ mtspr DC_CST, r8
+#endif
+#endif
+
+/* We now have the lower 8 Meg mapped into TLB entries, and the caches
+ * ready to work.
+ */
+#endif /* CONFIG_8xx */
+
mfmsr r0
ori r0,r0,MSR_DR|MSR_IR
mtspr SRR1,r0
@@ -202,48 +376,6 @@ __start:
#define STACK_UNDERHEAD 64
/*
- * Macros for storing registers into and loading registers from
- * exception frames.
- */
-#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
-#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
-#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
-#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
-#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
-#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
-#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
-#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
-#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
-#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
-
-#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base)
-#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
-#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
-#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
-#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
-#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
-#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base)
-#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base)
-#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base)
-#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
-#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
-#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-#ifndef CONFIG_APUS
-#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h
-#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h
-#else
-#define tophys(rd,rs,rt) \
- lis rt,CYBERBASEp@h; \
- lwz rt,0(rt); \
- add rd,rs,rt
-#define tovirt(rd,rs,rt) \
- lis rt,CYBERBASEp@h; \
- lwz rt,0(rt); \
- sub rd,rs,rt
-#endif
-
-/*
* Exception entry code. This code runs with address translation
* turned off, i.e. using physical addresses.
* We assume sprg3 has the physical address of the current
@@ -303,11 +435,15 @@ label: \
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
-/* Data access exception */
+/* Data access exception.
+ * This is "never generated" by the MPC8xx. We jump to it for other
+ * translation errors.
+ */
. = 0x300
DataAccess:
EXCEPTION_PROLOG
mfspr r20,DSISR
+#ifndef CONFIG_8xx
andis. r0,r20,0xa470 /* weird error? */
bne 1f /* if not, try to put a PTE */
mfspr r3,DAR /* into the hash table */
@@ -315,6 +451,7 @@ DataAccess:
rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
mfspr r5,SPRG3 /* phys addr of TSS */
bl hash_page
+#endif
1: stw r20,_DSISR(r21)
mr r5,r20
mfspr r4,DAR
@@ -326,10 +463,14 @@ DataAccess:
.long do_page_fault
.long int_return
-/* Instruction access exception */
+/* Instruction access exception.
+ * This is "never generated" by the MPC8xx. We jump to it for other
+ * translation errors.
+ */
. = 0x400
InstructionAccess:
EXCEPTION_PROLOG
+#ifndef CONFIG_8xx
andis. r0,r23,0x4000 /* no pte found? */
beq 1f /* if so, try to put a PTE */
mr r3,r22 /* into the hash table */
@@ -337,6 +478,7 @@ InstructionAccess:
mr r20,r23 /* SRR1 has reason bits */
mfspr r5,SPRG3 /* phys addr of TSS */
bl hash_page
+#endif
1: addi r3,r1,STACK_FRAME_OVERHEAD
mr r4,r22
mr r5,r23
@@ -347,7 +489,38 @@ InstructionAccess:
.long int_return
/* External interrupt */
- STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
+ . = 0x500;
+HardwareInterrupt:
+ EXCEPTION_PROLOG;
+#ifdef CONFIG_APUS
+ mfmsr 20
+ xori r20,r20,MSR_DR
+ sync
+ mtmsr r20
+ sync
+
+ lis r3,APUS_IPL_EMU@h
+
+ li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT)
+ stb r20,APUS_IPL_EMU@l(r3)
+ sync
+
+ lbz r3,APUS_IPL_EMU@l(r3)
+
+ mfmsr r20
+ xori r20,r20,MSR_DR
+ sync
+ mtmsr r20
+ sync
+
+ stw r3,(_CCR+4)(r21);
+#endif
+ addi r3,r1,STACK_FRAME_OVERHEAD;
+ li r20,MSR_KERNEL;
+ bl transfer_to_handler;
+ .long do_IRQ;
+ .long int_return
+
/* Alignment exception */
. = 0x600
@@ -375,6 +548,7 @@ ProgramCheck:
.long ProgramCheckException
.long int_return
+#ifndef CONFIG_8xx
/* Floating-point unavailable */
. = 0x800
FPUnavailable:
@@ -384,6 +558,11 @@ FPUnavailable:
bl transfer_to_handler /* if from kernel, take a trap */
.long KernelFP
.long int_return
+#else
+/* No FPU on MPC8xx. This exception is not supposed to happen.
+*/
+ STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
+#endif
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
@@ -406,6 +585,7 @@ SystemCall:
STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+#ifndef CONFIG_8xx
/*
* Handle TLB miss for instruction on 603/603e.
* Note: we get an alternate set of r0 - r3 to use automatically.
@@ -502,7 +682,14 @@ InstructionAddressInvalid:
sync /* Some chip revs have problems here... */
mtmsr r0
b InstructionAccess
+#else
+/* On the MPC8xx, this is a software emulation interrupt. It occurs
+ * for all unimplemented and illegal instructions.
+ */
+ STD_EXCEPTION(0x1000, SoftEmu, SoftwareEmulation)
+#endif
+#ifndef CONFIG_8xx
/*
* Handle TLB miss for DATA Load operation on 603/603e
*/
@@ -598,12 +785,78 @@ DataAddressInvalid:
sync /* Some chip revs have problems here... */
mtmsr r0
b DataAccess
+#else
+/*
+ * For the MPC8xx, this is a software tablewalk to load the instruction
+ * TLB. It is modelled after the example in the Motorola manual. The task
+ * switch loads the M_TWB register with the pointer to the first level table.
+ * If we discover there is no second level table (the value is zero), the
+ * plan was to load that into the TLB, which causes another fault into the
+ * TLB Error interrupt where we can handle such problems. However, that did
+ * not work, so if we discover there is no second level table, we restore
+ * registers and branch to the error exception. We have to use the MD_xxx
+ * registers for the tablewalk because the equivalent MI_xxx registers
+ * only perform the attribute functions.
+ */
+InstructionTLBMiss:
+ mtspr M_TW, r20 /* Save a couple of working registers */
+ mfcr r20
+ stw r20, 0(r0)
+ stw r21, 4(r0)
+ mfspr r20, SRR0 /* Get effective address of fault */
+ mtspr MD_EPN, r20 /* Have to use MD_EPN for walk, MI_EPN can't */
+ mfspr r20, M_TWB /* Get level 1 table entry address */
+ lwz r21, 0(r20) /* Get the level 1 entry */
+ rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */
+ beq 2f /* If zero, don't try to find a pte */
+
+ /* We have a pte table, so load the MI_TWC with the attributes
+ * for this page, which has only bit 31 set.
+ */
+ tophys(r21,r21,0)
+ ori r21,r21,1 /* Set valid bit */
+ mtspr MI_TWC, r21 /* Set page attributes */
+ mtspr MD_TWC, r21 /* Load pte table base address */
+ mfspr r21, MD_TWC /* ....and get the pte address */
+ lwz r21, 0(r21) /* Get the pte */
+
+ /* Set four subpage valid bits (24, 25, 26, and 27).
+ * Since we currently run MI_CTR.PPCS = 0, the manual says,
+ * "If the page size is larger than 4k byte, then all the
+ * 4 bits should have the same value."
+ * I don't really know what to do if the page size is 4k Bytes,
+ * but I know setting them all to 0 does not work, and setting them
+ * all to 1 does, so that is the way it is right now.
+ * BTW, these four bits map to the software only bits in the
+ * linux page table. I used to turn them all of, but now just
+ * set them all for the hardware.
+ li r20, 0x00f0
+ andc r20, r21, r20
+ ori r20, r20, 0x0080
+ */
+ ori r20, r21, 0x00f0
+ mtspr MI_RPN, r20 /* Update TLB entry */
+
+ mfspr r20, M_TW /* Restore registers */
+ lwz r21, 0(r0)
+ mtcr r21
+ lwz r21, 4(r0)
+ rfi
+
+2: mfspr r20, M_TW /* Restore registers */
+ lwz r21, 0(r0)
+ mtcr r21
+ lwz r21, 4(r0)
+ b InstructionAccess
+#endif /* CONFIG_8xx */
+
/*
* Handle TLB miss for DATA Store on 603/603e
*/
. = 0x1200
DataStoreTLBMiss:
+#ifndef CONFIG_8xx
#ifdef NO_RELOAD_HTAB
/*
* r0: stored ctr
@@ -671,27 +924,164 @@ DataStoreTLBMiss:
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
#endif /* NO_RELOAD_HTAB */
-
+#else /* CONFIG_8xx */
+ mtspr M_TW, r20 /* Save a couple of working registers */
+ mfcr r20
+ stw r20, 0(r0)
+ stw r21, 4(r0)
+ mfspr r20, M_TWB /* Get level 1 table entry address */
+ lwz r21, 0(r20) /* Get the level 1 entry */
+ rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */
+ beq 2f /* If zero, don't try to find a pte */
+
+ /* We have a pte table, so load fetch the pte from the table.
+ */
+ tophys(r21, r21, 0)
+ ori r21, r21, 1 /* Set valid bit in physical L2 page */
+ mtspr MD_TWC, r21 /* Load pte table base address */
+ mfspr r21, MD_TWC /* ....and get the pte address */
+ lwz r21, 0(r21) /* Get the pte */
+
+ /* Set four subpage valid bits (24, 25, 26, and 27).
+ * Since we currently run MD_CTR.PPCS = 0, the manual says,
+ * "If the page size is larger than 4k byte, then all the
+ * 4 bits should have the same value."
+ * I don't really know what to do if the page size is 4k Bytes,
+ * but I know setting them all to 0 does not work, and setting them
+ * all to 1 does, so that is the way it is right now.
+ * BTW, these four bits map to the software only bits in the
+ * linux page table. I used to turn them all of, but now just
+ * set them all for the hardware.
+ li r20, 0x00f0
+ andc r20, r21, r20
+ ori r20, r20, 0x0080
+ */
+ ori r20, r21, 0x00f0
+ mtspr MD_RPN, r20 /* Update TLB entry */
+
+ mfspr r20, M_TW /* Restore registers */
+ lwz r21, 0(r0)
+ mtcr r21
+ lwz r21, 4(r0)
+ rfi
+
+2: mfspr r20, M_TW /* Restore registers */
+ lwz r21, 0(r0)
+ mtcr r21
+ lwz r21, 4(r0)
+ b DataAccess
+#endif /* CONFIG_8xx */
+
+#ifndef CONFIG_8xx
/* Instruction address breakpoint exception (on 603/604) */
STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
+#else
+
+/* This is an instruction TLB error on the MPC8xx. This could be due
+ * to many reasons, such as executing guarded memory or illegal instruction
+ * addresses. There is nothing to do but handle a big time error fault.
+ */
+ . = 0x1300
+InstructionTLBError:
+ b InstructionAccess
+#endif
/* System management exception (603?) */
+#ifndef CONFIG_8xx
STD_EXCEPTION(0x1400, Trap_14, UnknownException)
+#else
+
+/* This is the data TLB error on the MPC8xx. This could be due to
+ * many reasons, including a dirty update to a pte. We can catch that
+ * one here, but anything else is an error. First, we track down the
+ * Linux pte. If it is valid, write access is allowed, but the
+ * page dirty bit is not set, we will set it and reload the TLB. For
+ * any other case, we bail out to a higher level function that can
+ * handle it.
+ */
+ . = 0x1400
+DataTLBError:
+ mtspr M_TW, r20 /* Save a couple of working registers */
+ mfcr r20
+ stw r20, 0(r0)
+ stw r21, 4(r0)
+
+ /* First, make sure this was a store operation.
+ */
+ mfspr r20, DSISR
+ andis. r21, r20, 0x0200 /* If set, indicates store op */
+ beq 2f
+
+ mfspr r20, M_TWB /* Get level 1 table entry address */
+ lwz r21, 0(r20) /* Get the level 1 entry */
+ rlwinm. r20, r21,0,0,20 /* Extract page descriptor page address */
+ beq 2f /* If zero, bail */
+
+ /* We have a pte table, so fetch the pte from the table.
+ */
+ tophys(r21, r21, 0)
+ ori r21, r21, 1 /* Set valid bit in physical L2 page */
+ mtspr MD_TWC, r21 /* Load pte table base address */
+ mfspr r21, MD_TWC /* ....and get the pte address */
+ lwz r21, 0(r21) /* Get the pte */
+
+ andi. r20, r21, _PAGE_RW /* Is it writeable? */
+ beq 2f /* Bail out if not */
+
+ ori r21, r21, _PAGE_DIRTY /* Update changed bit */
+ mfspr r20, MD_TWC /* Get pte address again */
+ stw r21, 0(r20) /* and update pte in table */
+
+ /* Set four subpage valid bits (24, 25, 26, and 27).
+ * Since we currently run MD_CTR.PPCS = 0, the manual says,
+ * "If the page size is larger than 4k byte, then all the
+ * 4 bits should have the same value."
+ * I don't really know what to do if the page size is 4k Bytes,
+ * but I know setting them all to 0 does not work, and setting them
+ * all to 1 does, so that is the way it is right now.
+ * BTW, these four bits map to the software only bits in the
+ * linux page table. I used to turn them all of, but now just
+ * set them all for the hardware.
+ li r20, 0x00f0
+ andc r20, r21, r20
+ ori r20, r20, 0x0080
+ */
+ ori r20, r21, 0x00f0
+
+ mtspr MD_RPN, r20 /* Update TLB entry */
+
+ mfspr r20, M_TW /* Restore registers */
+ lwz r21, 0(r0)
+ mtcr r21
+ lwz r21, 4(r0)
+ rfi
+2:
+ mfspr r20, M_TW /* Restore registers */
+ lwz r21, 0(r0)
+ mtcr r21
+ lwz r21, 4(r0)
+ b DataAccess
+#endif /* CONFIG_8xx */
STD_EXCEPTION(0x1500, Trap_15, UnknownException)
STD_EXCEPTION(0x1600, Trap_16, UnknownException)
- STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, TAUException)
STD_EXCEPTION(0x1800, Trap_18, UnknownException)
STD_EXCEPTION(0x1900, Trap_19, UnknownException)
STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+/* On the MPC8xx, these next four traps are used for development
+ * support of breakpoints and such. Someday I will get around to
+ * using them.
+ */
STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
-/* Run mode exception */
+#ifndef CONFIG_8xx
+ /* Run mode exception */
STD_EXCEPTION(0x2000, RunMode, RunModeException)
STD_EXCEPTION(0x2100, Trap_21, UnknownException)
@@ -711,6 +1101,9 @@ DataStoreTLBMiss:
STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
. = 0x3000
+#else
+ . = 0x2000
+#endif
/*
* This code finishes saving the registers to the exception frame
@@ -720,6 +1113,8 @@ DataStoreTLBMiss:
.globl transfer_to_handler
transfer_to_handler:
stw r22,_NIP(r21)
+ lis r22,MSR_POW@h
+ andc r23,r23,r22
stw r23,_MSR(r21)
SAVE_GPR(7, r21)
SAVE_4GPRS(8, r21)
@@ -768,6 +1163,7 @@ stack_ovf:
SYNC
rfi
+#ifndef CONFIG_8xx
/*
* Continuation of the floating-point unavailable handler.
*/
@@ -790,9 +1186,18 @@ load_up_fpu:
ori r5,r5,MSR_FP
SYNC
mtmsr r5 /* enable use of fpu now */
+#ifndef __SMP__
SYNC
cmpi 0,r4,0
beq 1f
+#else
+/*
+ * All the saving of last_task_used_math is handled
+ * by a switch_to() call to smp_giveup_fpu() in SMP so
+ * last_task_used_math is not used. -- Cort
+ */
+ b 1f
+#endif
add r4,r4,r6
addi r4,r4,TSS /* want TSS of last_task_used_math */
SAVE_32FPRS(0, r4)
@@ -810,9 +1215,11 @@ load_up_fpu:
lfd fr0,TSS_FPSCR-4(r5)
mtfsf 0xff,fr0
REST_32FPRS(0, r5)
+#ifndef __SMP__
subi r4,r5,TSS
sub r4,r4,r6
stw r4,last_task_used_math@l(r3)
+#endif /* __SMP__ */
/* restore registers and return */
lwz r3,_CCR(r21)
lwz r4,_LINK(r21)
@@ -859,16 +1266,6 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
.globl hash_page
hash_page:
-#ifdef __SMP__
- lis r6,hash_table_lock@h
- ori r6,r6,hash_table_lock@l
- tophys(r6,r6,r2)
-1011: lwarx r0,0,r6
- stwcx. r6,0,r6
- bne- 1011b
- cmpi 0,r0,0
- bne 1011b
-#endif /* __SMP__ */
/* Get PTE (linux-style) and check access */
lwz r5,PG_TABLES(r5)
tophys(r5,r5,r2) /* convert to phys addr */
@@ -1018,7 +1415,6 @@ found_slot:
lwz r3,0(r2)
addi r3,r3,1
stw r3,0(r2)
- SYNC
/* Return from the exception */
lwz r3,_CCR(r21)
@@ -1027,19 +1423,14 @@ found_slot:
mtcrf 0xff,r3
mtlr r4
mtctr r5
-#ifdef __SMP__
- lis r5,hash_table_lock@h
- ori r5,r5,hash_table_lock@l
- tophys(r5,r5,r6)
- li r6,0
- stw r6,0(r5)
-#endif /* __SMP__ */
REST_GPR(0, r21)
REST_2GPRS(1, r21)
REST_4GPRS(3, r21)
/* we haven't used xer */
+ SYNC
mtspr SRR1,r23
mtspr SRR0,r22
+ SYNC
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
@@ -1047,16 +1438,37 @@ found_slot:
rfi
hash_page_out:
-#ifdef __SMP__
- lis r5,hash_table_lock@h
- ori r5,r5,hash_table_lock@l
- tophys(r5,r5,r6)
- li r6,0
- stw r6,0(r5)
-#endif /* __SMP__ */
blr
next_slot:
.long 0
+#endif /* CONFIG_8xx */
+
+#ifndef CONFIG_APUS
+/*
+ * Copy routine used to copy the kernel to start at physical address 0
+ * and flush and invalidate the caches as needed.
+ * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
+ * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
+ */
+copy_and_flush:
+ addi r5,r5,-4
+ addi r6,r6,-4
+4: li r0,8
+ mtctr r0
+3: addi r6,r6,4 /* copy a cache line */
+ lwzx r0,r6,r4
+ stwx r0,r6,r3
+ bdnz 3b
+ dcbst r6,r3 /* write it to memory */
+ sync
+ icbi r6,r3 /* flush the icache line */
+ cmplw 0,r6,r5
+ blt 4b
+ isync
+ addi r5,r5,4
+ addi r6,r6,4
+ blr
+#endif
#ifdef CONFIG_APUS
/* On APUS the first 0x4000 bytes of the kernel will be mapped
@@ -1072,6 +1484,7 @@ next_slot:
*/
start_here:
+#ifndef CONFIG_8xx
/*
* Enable caches and 604-specific features if necessary.
*/
@@ -1108,6 +1521,7 @@ start_here:
ori r11,r11,HID0_BTCD
5: mtspr HID0,r11 /* superscalar exec & br history tbl */
4:
+#endif /* CONFIG_8xx */
/* ptr to current */
lis r2,init_task_union@h
ori r2,r2,init_task_union@l
@@ -1140,6 +1554,9 @@ start_here:
mr r6,r28
mr r7,r27
bl identify_machine
+#ifdef CONFIG_MBX
+ bl set_mbx_memory
+#endif
bl MMU_init
/*
@@ -1147,8 +1564,19 @@ start_here:
* for SDR1 (hash table pointer) and the segment registers
* and change to using our exception vectors.
*/
+#ifndef CONFIG_8xx
lis r6,_SDR1@ha
lwz r6,_SDR1@l(r6)
+#else
+ /* The right way to do this would be to track it down through
+ * init's TSS like the context switch code does, but this is
+ * easier......until someone changes init's static structures.
+ */
+ lis r6, swapper_pg_dir@h
+ tophys(r6,r6,0)
+ ori r6, r6, swapper_pg_dir@l
+ mtspr M_TWB, r6
+#endif
lis r4,2f@h
ori r4,r4,2f@l
tophys(r4,r4,r3)
@@ -1158,8 +1586,10 @@ start_here:
rfi
/* Load up the kernel context */
2:
+
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
+#ifndef CONFIG_8xx
mtspr SDR1,r6
li r0,16 /* load up segment register values */
mtctr r0 /* for context 0 */
@@ -1179,7 +1609,8 @@ start_here:
LOAD_BAT(1,16,r3,r4,r5)
LOAD_BAT(2,32,r3,r4,r5)
LOAD_BAT(3,48,r3,r4,r5)
-
+#endif /* CONFIG_8xx */
+
/* Set up for using our exception vectors */
/* ptr to phys current tss */
tophys(r4,r2,r4)
@@ -1188,36 +1619,6 @@ start_here:
li r3,0
mtspr SPRG2,r3 /* 0 => r1 has kernel sp */
-/* On CHRP copy exception vectors down to 0 */
- lis r5,_stext@ha
- addi r5,r5,_stext@l
- addis r5,r5,-KERNELBASE@h
- cmpwi 0,r5,0
- beq 77f /* vectors are already at 0 */
- li r3,0x1000
- mtctr r3
- li r4,-4
- addi r5,r5,-4
-74: lwzu r0,4(r5)
- stwu r0,4(r4)
- bdnz 74b
- /* need to flush/invalidate caches too */
- li r3,0x4000/CACHE_LINE_SIZE
- li r4,0
- mtctr r3
-73: dcbst 0,r4
- addi r4,r4,CACHE_LINE_SIZE
- bdnz 73b
- sync
- li r4,0
- mtctr r3
-72: icbi 0,r4
- addi r4,r4,CACHE_LINE_SIZE
- bdnz 72b
- sync
- isync
-77:
-
/* Now turn on the MMU for real! */
li r4,MSR_KERNEL
lis r3,start_kernel@h
@@ -1227,29 +1628,6 @@ start_here:
rfi /* enable MMU and jump to start_kernel */
- .globl reset_SDR1
-reset_SDR1:
- lis r6,_SDR1@ha
- lwz r6,_SDR1@l(r6)
- mfmsr r5
- li r4,0
- ori r4,r4,MSR_EE|MSR_IR|MSR_DR
- andc r3,r5,r4
- lis r4,2f@h
- ori r4,r4,2f@l
- tophys(r4,r4,r5)
- mtspr SRR0,r4
- mtspr SRR1,r3
- rfi
-2: /* load new SDR1 */
- tlbia
- mtspr SDR1,r6
- /* turn the mmu back on */
- mflr r3
- mtspr SRR0,r3
- mtspr SRR1,r5
- rfi
-
/*
* FP unavailable trap from kernel - print a message, but let
* the task use FP in the kernel until it returns to user mode.
@@ -1272,10 +1650,19 @@ KernelFP:
* and save its floating-point registers in its thread_struct.
* Enables the FPU for use in the kernel on return.
*/
+/* smp_giveup_fpu() takes an arg to tell it where to save the fpu
+ * regs since last_task_used_math can't be trusted (many many race
+ * conditions). -- Cort
+ */
+ .globl smp_giveup_fpu
+smp_giveup_fpu:
+ mr r4,r3
+ b 12f
.globl giveup_fpu
giveup_fpu:
lis r3,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
+12:
mfmsr r5
ori r5,r5,MSR_FP
SYNC
@@ -1284,8 +1671,10 @@ giveup_fpu:
cmpi 0,r4,0
beqlr- /* if no previous owner, done */
addi r4,r4,TSS /* want TSS of last_task_used_math */
+#ifndef __SMP__
li r5,0
stw r5,last_task_used_math@l(r3)
+#endif /* __SMP__ */
SAVE_32FPRS(0, r4)
mffs fr0
stfd fr0,TSS_FPSCR-4(r4)
@@ -1445,6 +1834,18 @@ syscall_ret_2:
*
* The code which creates the new task context is in 'copy_thread'
* in arch/ppc/kernel/process.c
+ *
+ * The MPC8xx has something that currently happens "automagically."
+ * Unshared user space address translations are subject to ASID (context)
+ * match. During each task switch, the ASID is incremented. We can
+ * guarantee (I hope :-) that no entries currently match this ASID
+ * because every task will cause at least a TLB entry to be loaded for
+ * the first instruction and data access, plus the kernel running will
+ * have displaced several more TLBs. The MMU contains 32 entries for
+ * each TLB, and there are 16 contexts, so we just need to make sure
+ * two pages get replaced for every context switch, which currently
+ * happens. There are other TLB management techniques that I will
+ * eventually implement, but this is the easiest for now. -- Dan
*/
_GLOBAL(_switch)
stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
@@ -1476,6 +1877,7 @@ _GLOBAL(_switch)
SYNC
lwz r1,KSP(r4) /* Load new stack pointer */
addi r2,r4,-TSS /* Update current */
+#ifndef CONFIG_8xx
/* Set up segment registers for new task */
rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
addis r5,r5,0x6000 /* Set Ks, Ku bits */
@@ -1486,9 +1888,32 @@ _GLOBAL(_switch)
addi r5,r5,1 /* next VSID */
addis r3,r3,0x1000 /* address of next segment */
bdnz 3b
+#else
+/* On the MPC8xx, we place the physical address of the new task
+ * page directory loaded into the MMU base register, and set the
+ * ASID compare register with the new "context".
+ */
+ mtspr M_CASID, r5 /* Update context */
+ lwz r5,MM-TSS(r4) /* Get virtual address of mm */
+ lwz r5,PGD(r5) /* get new->mm->pgd */
+ tophys(r5, r5, 0) /* convert to phys addr */
+ mtspr M_TWB, r5 /* Update MMU base address */
+#endif
SYNC
/* FALL THROUGH into int_return */
+#ifdef __SMP__
+ /* drop scheduler_lock since we weren't called by schedule() */
+ lwz r5,TSS_SMP_FORK_RET(r4)
+ cmpi 0,r5,0
+ beq+ int_return
+ li r3,0
+ lis r5,scheduler_lock@ha
+ stw r3,TSS_SMP_FORK_RET(r4)
+ stw r3,scheduler_lock@l+4(r5) /* owner_pc */
+ stw r3,scheduler_lock@l+8(r5) /* owner_cpu */
+ stw r3,scheduler_lock@l(r5) /* lock */
+#endif /* __SMP__ */
/*
* Trap exit.
@@ -1566,6 +1991,18 @@ int_return:
SYNC
rfi
+#if 0/*def __SMP__*/
+ .globl ret_from_smpfork
+ret_from_smpfork:
+ /* drop scheduler_lock since schedule() called us */
+ lis r4,scheduler_lock@ha
+ li r5,0
+ stw r5,scheduler_lock@l+4(r4) /* owner_pc */
+ stw r5,scheduler_lock@l+8(r4) /* owner_cpu */
+ stw r5,scheduler_lock@l(r4) /* lock */
+ b int_return
+#endif /* __SMP__ */
+
/*
* Fake an interrupt from kernel mode.
* This is used when enable_irq loses an interrupt.
@@ -1686,6 +2123,7 @@ _GLOBAL(flush_page_to_ram)
* Flush entries from the hash table with VSIDs in the range
* given.
*/
+#ifndef CONFIG_8xx
_GLOBAL(flush_hash_segments)
#ifdef NO_RELOAD_HTAB
/*
@@ -1700,15 +2138,6 @@ _GLOBAL(flush_hash_segments)
rlwnm. r0,r9,r0,0,0
bne 99f
#endif /* NO_RELOAD_HTAB */
-#ifdef __SMP__
- lis r6,hash_table_lock@h
- ori r6,r6,hash_table_lock@l
-1011: lwarx r0,0,r6
- stwcx. r6,0,r6
- bne- 1011b
- cmpi 0,r0,0
- bne 1011b
-#endif /* __SMP__ */
rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
oris r3,r3,0x8000 /* set V bit */
rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
@@ -1730,12 +2159,6 @@ _GLOBAL(flush_hash_segments)
stw r0,0(r5) /* invalidate entry */
2: bdnz 1b /* continue with loop */
sync
-#ifdef __SMP__
- lis r5,hash_table_lock@h
- ori r5,r5,hash_table_lock@l
- li r6,0
- stw r6,0(r5)
-#endif /* __SMP__ */
99: tlbia
isync
blr
@@ -1753,15 +2176,6 @@ _GLOBAL(flush_hash_page)
rlwnm. r0,r9,r0,0,0
bne 99f
#endif /* NO_RELOAD_HTAB */
-#ifdef __SMP__
- lis r6,hash_table_lock@h
- ori r6,r6,hash_table_lock@l
-1011: lwarx r0,0,r6
- stwcx. r6,0,r6
- bne- 1011b
- cmpi 0,r0,0
- bne 1011b
-#endif /* __SMP__ */
rlwinm r3,r3,11,1,20 /* put context into vsid */
rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
oris r3,r3,0x8000 /* set V (valid) bit */
@@ -1794,22 +2208,17 @@ _GLOBAL(flush_hash_page)
3: li r0,0
stw r0,0(r7) /* invalidate entry */
4: sync
-#ifdef __SMP__
- lis r5,hash_table_lock@h
- ori r5,r5,hash_table_lock@l
- li r6,0
- stw r6,0(r5)
-#endif /* __SMP__ */
99: tlbie r4 /* in hw tlb too */
isync
blr
-
+#endif /* CONFIG_8xx */
/*
* This routine is just here to keep GCC happy - sigh...
*/
_GLOBAL(__main)
blr
+#ifndef CONFIG_8xx
/*
* On CHRP, the Run-Time Abstraction Services (RTAS) have to be
* called with the MMU off.
@@ -1819,9 +2228,9 @@ enter_rtas:
stwu r1,-16(r1)
mflr r0
stw r0,20(r1)
- addis r3,r3,-KERNELBASE@h
lis r4,rtas_data@ha
lwz r4,rtas_data@l(r4)
+ addis r4,r4,-KERNELBASE@h
lis r6,1f@ha /* physical return address for rtas */
addi r6,r6,1f@l
addis r6,r6,-KERNELBASE@h
@@ -1829,14 +2238,15 @@ enter_rtas:
addis r7,r7,-KERNELBASE@h
lis r8,rtas_entry@ha
lwz r8,rtas_entry@l(r8)
+ addis r5,r8,-KERNELBASE@h
mfmsr r9
stw r9,8(r1)
- li r0,0
ori r0,r0,MSR_EE|MSR_SE|MSR_BE
andc r0,r9,r0
andi. r9,r9,MSR_ME|MSR_RI
sync /* disable interrupts so SRR0/1 */
mtmsr r0 /* don't get trashed */
+ li r6,0
mtlr r6
mtspr SPRG2,r7
mtspr SRR0,r8
@@ -1850,23 +2260,26 @@ enter_rtas:
mtspr SRR0,r8
mtspr SRR1,r9
rfi /* return to caller */
+#endif /* CONFIG_8xx */
+#ifdef CONFIG_8xx
+/* This is called during an exec when new page tables are created.
+ * It maps to the SET_PAGE_DIR macro. I guess I should make it an
+ * inline function.
+ */
+_GLOBAL(set_page_dir)
+ addis r3,r3,-KERNELBASE@h /* convert to phys addr */
+ mtspr M_TWB, r3 /* Update MMU base address */
+ blr
+#endif
- .globl amhere
-amhere: .long 0
-
+
#ifdef __SMP__
/*
* Secondary processor begins executing here.
*/
.globl secondary_entry
secondary_entry:
- lis r0,amhere@h
- ori r0,r0,amhere@l
- addis r0,r0,-KERNELBASE@h
- stw r0,0(r0)
- sync
- isync
/* just like __start() with a few changes -- Cort */
mfspr r9,PVR
rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
@@ -1938,16 +2351,6 @@ secondary_entry:
ori r11,r11,HID0_BTCD
5: mtspr HID0,r11 /* superscalar exec & br history tbl */
4:
- /* get ptr to current */
- lis r2,current_set@h
- ori r2,r2,current_set@l
- /* assume we're second processor for now */
- lwz r2,4(r2)
- /* stack */
- addi r1,r2,TASK_UNION_SIZE
- li r0,0
- stwu r0,-STACK_FRAME_OVERHEAD(r1)
-
/*
* init_MMU on the first processor has setup the variables
* for us - all we need to do is load them -- Cort
@@ -1969,6 +2372,18 @@ secondary_entry:
rfi
/* Load up the kernel context */
2:
+ /* get ptr to current */
+ lis r2,current_set@h
+ ori r2,r2,current_set@l
+ /* assume we're second processor for now */
+ tophys(r2,r2,r10)
+ lwz r2,4(r2)
+ /* stack */
+ addi r1,r2,TASK_UNION_SIZE
+ li r0,0
+ tophys(r3,r1,r10)
+ stwu r0,-STACK_FRAME_OVERHEAD(r3)
+
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
mtspr SDR1,r6
@@ -2025,6 +2440,31 @@ secondary_entry:
/* should never return */
.long 0
#endif /* __SMP__ */
+
+#ifdef CONFIG_MBX
+/* Jump into the system reset for the MBX rom.
+ * We first disable the MMU, and then jump to the ROM reset address.
+ *
+ * This does not work, don't bother trying. There is no place in
+ * the ROM we can jump to cause a reset. We will have to program
+ * a watchdog of some type that we don't service to cause a processor
+ * reset.
+ */
+ .globl MBX_gorom
+MBX_gorom:
+ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r4,2f@h
+ addis r4,r4,-KERNELBASE@h
+ ori r4,r4,2f@l
+ mtspr SRR0,r4
+ mtspr SRR1,r3
+ rfi
+2:
+ lis r4, 0xfe000000@h
+ addi r4, r4, 0xfe000000@l
+ mtlr r4
+ blr
+#endif
/*
* We put a few things here that have to be page-aligned.
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index f47d6f3d6..21c6966e0 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -1,5 +1,5 @@
/*
- * $Id: idle.c,v 1.13 1998/01/06 06:44:55 cort Exp $
+ * $Id: idle.c,v 1.35 1998/04/07 20:24:23 cort Exp $
*
* Idle daemon for PowerPC. Idle daemon will handle any action
* that needs to be taken when the system becomes idle.
@@ -13,6 +13,7 @@
*/
#define __KERNEL_SYSCALLS__
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -31,41 +32,44 @@
#include <asm/smp_lock.h>
#include <asm/processor.h>
#include <asm/mmu.h>
+#include <asm/cache.h>
+#ifdef CONFIG_PMAC
+#include <asm/mediabay.h>
+#endif
-int zero_paged(void *unused);
-void inline power_save(void);
+void zero_paged(void);
+void power_save(void);
void inline htab_reclaim(void);
+unsigned long htab_reclaim_on = 0;
+unsigned long zero_paged_on = 0;
+
int idled(void *unused)
{
int ret = -EPERM;
- /*
- * want one per cpu since it would be nice to have all
- * processors who aren't doing anything
- * zero-ing pages since this daemon is lock-free
- * -- Cort
- */
- /* kernel_thread(zero_paged, NULL, 0); */
-
-#ifdef __SMP__
-printk("SMP %d: in idle. current = %s/%d\n",
- current->processor,current->comm,current->pid);
-#endif /* __SMP__ */
for (;;)
{
+ __sti();
+
/* endless loop with no priority at all */
current->priority = -100;
current->counter = -100;
+
+ check_pgt_cache();
- /* endless idle loop with no priority at all */
- /* htab_reclaim(); */
- schedule();
+ if ( !need_resched && zero_paged_on ) zero_paged();
+ if ( !need_resched && htab_reclaim_on ) htab_reclaim();
+
+ /*
+ * Only processor 1 may sleep now since processor 2 would
+ * never wake up. Need to add timer code for processor 2
+ * then it can sleep. -- Cort
+ */
#ifndef __SMP__
- /* can't do this on smp since second processor
- will never wake up -- Cort */
- /* power_save(); */
-#endif /* __SMP__ */
+ if ( !need_resched ) power_save();
+#endif /* __SMP__ */
+ schedule();
}
ret = 0;
return ret;
@@ -76,13 +80,16 @@ printk("SMP %d: in idle. current = %s/%d\n",
* Mark 'zombie' pte's in the hash table as invalid.
* This improves performance for the hash table reload code
* a bit since we don't consider unused pages as valid.
- * I haven't done any rigorous performance analysis yet
- * so it's still experimental and turned off here.
* -- Cort
*/
+PTE *reclaim_ptr = 0;
void inline htab_reclaim(void)
{
+#ifndef CONFIG_8xx
+#if 0
PTE *ptr, *start;
+ static int dir = 1;
+#endif
struct task_struct *p;
unsigned long valid = 0;
extern PTE *Hash, *Hash_end;
@@ -91,28 +98,33 @@ void inline htab_reclaim(void)
/* if we don't have a htab */
if ( Hash_size == 0 )
return;
- /*lock_dcache();*/
-
+ lock_dcache(1);
+
+#if 0
/* find a random place in the htab to start each time */
- start = &Hash[jiffies%(Hash_size/sizeof(ptr))];
- for ( ptr = start; ptr < Hash_end ; ptr++)
+ start = &Hash[jiffies%(Hash_size/sizeof(PTE))];
+ /* go a different direction each time */
+ dir *= -1;
+ for ( ptr = start;
+ !need_resched && (ptr != Hash_end) && (ptr != Hash);
+ ptr += dir)
{
- if ( ptr == start )
- return;
- if ( ptr == Hash_end )
- ptr = Hash;
- valid = 0;
- if (!ptr->v)
+#else
+ if ( !reclaim_ptr ) reclaim_ptr = Hash;
+ while ( !need_resched )
+ {
+ reclaim_ptr++;
+ if ( reclaim_ptr == Hash_end ) reclaim_ptr = Hash;
+#endif
+ if (!reclaim_ptr->v)
continue;
+ valid = 0;
for_each_task(p)
{
if ( need_resched )
- {
- /*unlock_dcache();*/
- return;
- }
+ goto out;
/* if this vsid/context is in use */
- if ( (ptr->vsid >> 4) == p->mm->context )
+ if ( (reclaim_ptr->vsid >> 4) == p->mm->context )
{
valid = 1;
break;
@@ -121,19 +133,28 @@ void inline htab_reclaim(void)
if ( valid )
continue;
/* this pte isn't used */
- ptr->v = 0;
+ reclaim_ptr->v = 0;
}
- /*unlock_dcache();*/
+out:
+ if ( need_resched ) printk("need_resched: %x\n", need_resched);
+ unlock_dcache();
+#endif /* CONFIG_8xx */
}
-
+
/*
* Syscall entry into the idle task. -- Cort
*/
asmlinkage int sys_idle(void)
{
+ extern int media_bay_task(void *);
if(current->pid != 0)
return -EPERM;
+#ifdef CONFIG_PMAC
+ if (media_bay_present)
+ kernel_thread(media_bay_task, NULL, 0);
+#endif
+
idled(NULL);
return 0; /* should never execute this but it makes gcc happy -- Cort */
}
@@ -157,10 +178,8 @@ unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
unsigned long zerocount = 0; /* # currently pre-zero'd pages */
unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0; /* current page being zero'd */
unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
-static struct wait_queue * page_zerod_wait = NULL;
#define PAGE_THRESHOLD 96 /* how many pages to keep pre-zero'd */
/*
@@ -189,7 +208,6 @@ unsigned long get_prezerod_page(void)
*/
atomic_inc((atomic_t *)&zeropage_hits);
atomic_dec((atomic_t *)&zerocount);
- wake_up(&page_zerod_wait);
need_resched = 1;
/* zero out the pointer to next in the page */
@@ -201,35 +219,18 @@ unsigned long get_prezerod_page(void)
/*
* Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
+ * to speed up get_free_pages(). Zero's out pages until
+ * we've reached the limit of zero'd pages. We handle
+ * reschedule()'s in here so when we return we know we've
+ * zero'd all we need to for now.
*/
-int zero_paged(void *unused)
+void zero_paged(void)
{
- extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
- pgd_t *dir;
- pmd_t *pmd;
+ unsigned long pageptr = 0; /* current page being zero'd */
pte_t *pte;
-
- sprintf(current->comm, "zero_paged (idle)");
- /* current->blocked = ~0UL; */
-#ifdef __SMP__
- printk("Started zero_paged (cpu %d)\n", hard_smp_processor_id());
-#else
- printk("Started zero_paged\n");
-#endif /* __SMP__ */
-
- __sti();
- while ( 1 )
+ while ( zerocount <= PAGE_THRESHOLD )
{
- /* don't want to be pre-empted by swapper or power_save */
- current->priority = -98;
- current->counter = -98;
- /* we don't want to run until we have something to do */
- while ( zerocount >= PAGE_THRESHOLD )
- sleep_on(&page_zerod_wait);
/*
* Mark a page as reserved so we can mess with it
* If we're interrupted we keep this page and our place in it
@@ -237,7 +238,7 @@ int zero_paged(void *unused)
*/
pageptr = __get_free_pages(GFP_ATOMIC, 0);
if ( !pageptr )
- goto retry;
+ return;
if ( need_resched )
schedule();
@@ -245,20 +246,15 @@ int zero_paged(void *unused)
/*
* Make the page no cache so we don't blow our cache with 0's
*/
- dir = pgd_offset( init_task.mm, pageptr );
- if (dir)
+ pte = find_pte(init_task.mm, pageptr);
+ if ( !pte )
{
- pmd = pmd_offset(dir, pageptr & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, pageptr & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- pte_uncache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
- }
- }
+ printk("pte NULL in zero_paged()\n");
+ return;
}
+
+ pte_uncache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
/*
* Important here to not take time away from real processes.
@@ -308,35 +304,34 @@ int zero_paged(void *unused)
*/
atomic_inc((atomic_t *)&zerocount);
atomic_inc((atomic_t *)&zerototal);
-retry:
- schedule();
}
}
-void inline power_save(void)
+int powersave_mode = HID0_DOZE;
+
+void power_save(void)
{
unsigned long msr, hid0;
- /* no powersaving modes on the 601 */
- if( (_get_PVR()>>16) == 1 )
+ /* only sleep on the 603-family/750 processors */
+ switch (_get_PVR() >> 16) {
+ case 3: /* 603 */
+ case 6: /* 603e */
+ case 7: /* 603ev */
+ case 8: /* 750 */
+ break;
+ default:
return;
+ }
- __sti();
- asm volatile(
- /* clear powersaving modes and set nap mode */
- "mfspr %3,1008 \n\t"
- "andc %3,%3,%4 \n\t"
- "or %3,%3,%5 \n\t"
- "mtspr 1008,%3 \n\t"
- /* enter the mode */
- "mfmsr %0 \n\t"
- "oris %0,%0,%2 \n\t"
- "sync \n\t"
- "mtmsr %0 \n\t"
- "isync \n\t"
- : "=&r" (msr)
- : "0" (msr), "i" (MSR_POW>>16),
- "r" (hid0),
- "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
- "r" (HID0_NAP));
+ save_flags(msr);
+ cli();
+ if (!need_resched) {
+ asm("mfspr %0,1008" : "=r" (hid0) :);
+ hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
+ hid0 |= powersave_mode | HID0_DPM;
+ asm("mtspr 1008,%0" : : "r" (hid0));
+ msr |= MSR_POW;
+ }
+ restore_flags(msr);
}
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 4616d59a2..462805a65 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -14,6 +14,14 @@
* instead of just grabbing them. Thus setups with different IRQ numbers
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
+ *
+ * The MPC8xx has an interrupt mask in the SIU. If a bit is set, the
+ * interrupt is _enabled_. As expected, IRQ0 is bit 0 in the 32-bit
+ * mask register (of which only 16 are defined), hence the weird shifting
+ * and compliment of the cached_irq_mask. I want to be able to stuff
+ * this right into the SIU SMASK register.
+ * Many of the prep/chrp functions are conditional compiled on CONFIG_8xx
+ * to reduce code space and undefined function references.
*/
@@ -30,30 +38,41 @@
#include <linux/malloc.h>
#include <linux/openpic.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/openpic.h>
#include <asm/hydra.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/gg2.h>
+#include <asm/cache.h>
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#include <asm/mbx.h>
+#endif
#undef SHOW_IRQ
unsigned lost_interrupts = 0;
unsigned int local_irq_count[NR_CPUS];
-static struct irqaction irq_action[NR_IRQS];
+static struct irqaction *irq_action[NR_IRQS];
static int spurious_interrupts = 0;
+#ifndef CONFIG_8xx
+static unsigned int cached_irq_mask = 0xffffffff;
+#else
static unsigned int cached_irq_mask = 0xffffffff;
+#endif
static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-spinlock_t irq_controller_lock;
+/*spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;*/
#ifdef __SMP__
atomic_t __ppc_bh_counter = ATOMIC_INIT(0);
#else
int __ppc_bh_counter = 0;
#endif
+static volatile unsigned char *gg2_int_ack_special;
+extern volatile unsigned long ipi_count;
#define cached_21 (((char *)(&cached_irq_mask))[3])
#define cached_A1 (((char *)(&cached_irq_mask))[2])
@@ -61,9 +80,19 @@ int __ppc_bh_counter = 0;
/*
* These are set to the appropriate functions by init_IRQ()
*/
+#ifndef CONFIG_8xx
void (*mask_and_ack_irq)(int irq_nr);
void (*mask_irq)(unsigned int irq_nr);
void (*unmask_irq)(unsigned int irq_nr);
+#else /* CONFIG_8xx */
+/* init_IRQ() happens too late for the MBX because we initialize the
+ * CPM early and it calls request_irq() before we have these function
+ * pointers initialized.
+ */
+#define mask_and_ack_irq(irq) mbx_mask_irq(irq)
+#define mask_irq(irq) mbx_mask_irq(irq)
+#define unmask_irq(irq) mbx_unmask_irq(irq)
+#endif /* CONFIG_8xx */
/* prep */
@@ -79,9 +108,46 @@ extern unsigned long route_pci_interrupts(void);
#define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE))
+
+/* nasty hack for shared irq's since we need to do kmalloc calls but
+ * can't very very early in the boot when we need to do a request irq.
+ * this needs to be removed.
+ * -- Cort
+ */
+static char cache_bitmask = 0;
+static struct irqaction malloc_cache[4];
+extern int mem_init_done;
+
+void *irq_kmalloc(size_t size, int pri)
+{
+ unsigned int i;
+ if ( mem_init_done )
+ return kmalloc(size,pri);
+ for ( i = 0; i <= 3 ; i++ )
+ if ( ! ( cache_bitmask & (1<<i) ) )
+ {
+ cache_bitmask |= (1<<i);
+ return (void *)(&malloc_cache[i]);
+ }
+ return 0;
+}
+
+void irq_kfree(void *ptr)
+{
+ unsigned int i;
+ for ( i = 0 ; i <= 3 ; i++ )
+ if ( ptr == &malloc_cache[i] )
+ {
+ cache_bitmask &= ~(1<<i);
+ return;
+ }
+ kfree(ptr);
+}
+
+#ifndef CONFIG_8xx
void i8259_mask_and_ack_irq(int irq_nr)
{
- spin_lock(&irq_controller_lock);
+ /* spin_lock(&irq_controller_lock);*/
cached_irq_mask |= 1 << irq_nr;
if (irq_nr > 7) {
inb(0xA1); /* DUMMY */
@@ -96,20 +162,22 @@ void i8259_mask_and_ack_irq(int irq_nr)
outb(0x60|irq_nr,0x20); /* specific eoi */
}
- spin_unlock(&irq_controller_lock);
+ /* spin_unlock(&irq_controller_lock);*/
}
void pmac_mask_and_ack_irq(int irq_nr)
{
unsigned long bit = 1UL << irq_nr;
- spin_lock(&irq_controller_lock);
+ /* spin_lock(&irq_controller_lock);*/
cached_irq_mask |= bit;
lost_interrupts &= ~bit;
out_le32(IRQ_ACK, bit);
out_le32(IRQ_ENABLE, ~cached_irq_mask);
out_le32(IRQ_ACK, bit);
- spin_unlock(&irq_controller_lock);
+ /* spin_unlock(&irq_controller_lock);*/
+ /*if ( irq_controller_lock.lock )
+ panic("irq controller lock still held in mask and ack\n");*/
}
void chrp_mask_and_ack_irq(int irq_nr)
@@ -188,44 +256,96 @@ static void chrp_unmask_irq(unsigned int irq_nr)
else
openpic_enable_irq(irq_to_openpic(irq_nr));
}
+#else /* CONFIG_8xx */
+static void mbx_mask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask &= ~(1 << (31-irq_nr));
+ ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+ cached_irq_mask;
+}
+
+static void mbx_unmask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask |= (1 << (31-irq_nr));
+ ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_simask =
+ cached_irq_mask;
+}
+#endif /* CONFIG_8xx */
void disable_irq(unsigned int irq_nr)
{
- unsigned long flags;
+ /*unsigned long flags;*/
- spin_lock_irqsave(&irq_controller_lock, flags);
+ /* spin_lock_irqsave(&irq_controller_lock, flags);*/
mask_irq(irq_nr);
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
synchronize_irq();
}
void enable_irq(unsigned int irq_nr)
{
- unsigned long flags;
+ /*unsigned long flags;*/
- spin_lock_irqsave(&irq_controller_lock, flags);
+ /* spin_lock_irqsave(&irq_controller_lock, flags);*/
unmask_irq(irq_nr);
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
}
int get_irq_list(char *buf)
{
- int i, len = 0;
+ int i, len = 0, j;
struct irqaction * action;
+ len += sprintf(buf+len, " ");
+ for (j=0; j<smp_num_cpus; j++)
+ len += sprintf(buf+len, "CPU%d ",j);
+ *(char *)(buf+len++) = '\n';
+
for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_action + i;
+ action = irq_action[i];
if (!action || !action->handler)
continue;
- len += sprintf(buf+len, "%2d: %10u %s",
- i, kstat.interrupts[i], action->name);
+ len += sprintf(buf+len, "%3d: ", i);
+#ifdef __SMP__
+ for (j = 0; j < smp_num_cpus; j++)
+ len += sprintf(buf+len, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+#else
+ len += sprintf(buf+len, "%10u ", kstat_irqs(i));
+#endif /* __SMP__ */
+ switch( _machine )
+ {
+ case _MACH_prep:
+ len += sprintf(buf+len, " 82c59 ");
+ break;
+ case _MACH_Pmac:
+ len += sprintf(buf+len, " PMAC-PIC ");
+ break;
+ case _MACH_chrp:
+ if ( is_8259_irq(i) )
+ len += sprintf(buf+len, " 82c59 ");
+ else
+ len += sprintf(buf+len, " OpenPIC ");
+ break;
+ }
+
+ len += sprintf(buf+len, " %s",action->name);
for (action=action->next; action; action = action->next) {
len += sprintf(buf+len, ", %s", action->name);
}
len += sprintf(buf+len, "\n");
}
- len += sprintf(buf+len, "99: %10u spurious or short\n",
- spurious_interrupts);
+#ifdef __SMP__
+ /* should this be per processor send/receive? */
+ len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
+ for ( i = 0 ; i <= smp_num_cpus-1; i++ )
+ len += sprintf(buf+len," ");
+ len += sprintf(buf+len, " interprocessor messages received\n");
+#endif
+ len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
+ for ( i = 0 ; i <= smp_num_cpus-1; i++ )
+ len += sprintf(buf+len," ");
+ len += sprintf(buf+len, " spurious or short\n");
return len;
}
@@ -394,20 +514,31 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
int status;
int openpic_eoi_done = 0;
+ /* save the HID0 in case dcache was off - see idle.c
+ * this hack should leave for a better solution -- Cort */
+ unsigned dcache_locked;
+
+ dcache_locked = unlock_dcache();
+ hardirq_enter(cpu);
+#ifndef CONFIG_8xx
#ifdef __SMP__
if ( cpu != 0 )
- panic("cpu %d received interrupt", cpu);
-#endif /* __SMP__ */
-
- hardirq_enter(cpu);
+ {
+ if ( !lost_interrupts )
+ {
+ extern smp_message_recv(void);
+ goto out;
+
+ ipi_count++;
+ smp_message_recv();
+ goto out;
+ }
+ /* could be here due to a do_fake_interrupt call but we don't
+ mess with the controller from the second cpu -- Cort */
+ goto out;
+ }
+#endif /* __SMP__ */
- /*
- * I'll put this ugly mess of code into a function
- * such as get_pending_irq() or some such clear thing
- * so we don't have a switch in the irq code and
- * the chrp code is merged a bit with the prep.
- * -- Cort
- */
switch ( _machine )
{
case _MACH_Pmac:
@@ -425,7 +556,7 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
*
* This should go in the above mask/ack code soon. -- Cort
*/
- irq = *(volatile unsigned char *)GG2_INT_ACK_SPECIAL;
+ irq = *gg2_int_ack_special;
/*
* Acknowledge as soon as possible to allow i8259
* interrupt nesting
@@ -456,7 +587,6 @@ asmlinkage void do_IRQ(struct pt_regs *regs)
}
break;
case _MACH_prep:
-#if 1
outb(0x0C, 0x20);
irq = inb(0x20) & 7;
if (irq == 2)
@@ -470,23 +600,6 @@ retry_cascade:
irq = (irq&7) + 8;
}
bits = 1UL << irq;
-#else
- /*
- * get the isr from the intr controller since
- * the bit in the irr has been cleared
- */
- outb(0x0a, 0x20);
- bits = inb(0x20)&0xff;
- /* handle cascade */
- if ( bits & 4 )
- {
- bits &= ~4UL;
- outb(0x0a, 0xA0);
- bits |= inb(0xA0)<<8;
- }
- /* ignore masked irqs */
- bits &= ~cached_irq_mask;
-#endif
break;
}
@@ -494,43 +607,62 @@ retry_cascade:
printk("Bogus interrupt from PC = %lx\n", regs->nip);
goto out;
}
+
+#else /* CONFIG_8xx */
+ /* For MPC8xx, read the SIVEC register and shift the bits down
+ * to get the irq number.
+ */
+ bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec;
+ irq = bits >> 26;
+#endif /* CONFIG_8xx */
mask_and_ack_irq(irq);
status = 0;
- action = irq_action + irq;
- kstat.interrupts[irq]++;
- if (action->handler) {
+ action = irq_action[irq];
+ kstat.irqs[cpu][irq]++;
+ if ( action && action->handler) {
if (!(action->flags & SA_INTERRUPT))
__sti();
- status |= action->flags;
- action->handler(irq, action->dev_id, regs);
- /*if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);*/
- __cli(); /* in case the handler turned them on */
- spin_lock(&irq_controller_lock);
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ /*if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);*/
+ action = action->next;
+ } while ( action );
+ __cli();
+ /* spin_lock(&irq_controller_lock);*/
unmask_irq(irq);
- spin_unlock(&irq_controller_lock);
+ /* spin_unlock(&irq_controller_lock);*/
} else {
+#ifndef CONFIG_8xx
if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
+#endif
spurious_interrupts++;
disable_irq( irq );
}
/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
+#ifndef CONFIG_8xx
if ( is_prep && (irq > 7) )
goto retry_cascade;
/* do_bottom_half is called if necessary from int_return in head.S */
out:
if (_machine == _MACH_chrp && !openpic_eoi_done)
openpic_eoi(0);
+#endif /* CONFIG_8xx */
hardirq_exit(cpu);
+
+ /* restore the HID0 in case dcache was off - see idle.c
+ * this hack should leave for a better solution -- Cort */
+ lock_dcache(dcache_locked);
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char * devname, void *dev_id)
{
- struct irqaction * action;
+ struct irqaction *old, **p, *action;
unsigned long flags;
#ifdef SHOW_IRQ
@@ -540,49 +672,58 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
if (irq >= NR_IRQS)
return -EINVAL;
- action = irq + irq_action;
- if (action->handler)
- return -EBUSY;
+
if (!handler)
- return -EINVAL;
+ {
+ /* Free */
+ for (p = irq + irq_action; (action = *p) != NULL; p = &action->next)
+ {
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ restore_flags(flags);
+ irq_kfree(action);
+ return 0;
+ }
+ return -ENOENT;
+ }
+
+ action = (struct irqaction *)
+ irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
save_flags(flags);
cli();
+
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
action->dev_id = dev_id;
+ action->next = NULL;
enable_irq(irq);
- restore_flags(flags);
+ p = irq_action + irq;
+
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & action->flags & SA_SHIRQ))
+ return -EBUSY;
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ }
+ *p = action;
+
+ restore_flags(flags);
return 0;
}
void free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction * action = irq + irq_action;
- unsigned long flags;
-
-#ifdef SHOW_IRQ
- printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
-#endif /* SHOW_IRQ */
-
- if (irq >= NR_IRQS) {
- printk("Trying to free IRQ%d\n",irq);
- return;
- }
- if (!action->handler) {
- printk("Trying to free free IRQ%d\n",irq);
- return;
- }
- disable_irq(irq);
- save_flags(flags);
- cli();
- action->handler = NULL;
- action->flags = 0;
- action->mask = 0;
- action->name = NULL;
- action->dev_id = NULL;
- restore_flags(flags);
+ request_irq(irq, NULL, 0, NULL, dev_id);
}
unsigned long probe_irq_on (void)
@@ -595,6 +736,7 @@ int probe_irq_off (unsigned long irqs)
return 0;
}
+#ifndef CONFIG_8xx
__initfunc(static void i8259_init(void))
{
/* init master interrupt controller */
@@ -616,11 +758,17 @@ __initfunc(static void i8259_init(void))
panic("Could not allocate cascade IRQ!");
enable_irq(2); /* Enable cascade interrupt */
}
+#endif /* CONFIG_8xx */
+/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
+ * interrupts can be either edge or level triggered, but there is no
+ * reason for us to change the EPPC-bug values (it would not work if we did).
+ */
__initfunc(void init_IRQ(void))
{
extern void xmon_irq(int, void *, struct pt_regs *);
+#ifndef CONFIG_8xx
switch (_machine)
{
case _MACH_Pmac:
@@ -637,7 +785,8 @@ __initfunc(void init_IRQ(void))
mask_and_ack_irq = chrp_mask_and_ack_irq;
mask_irq = chrp_mask_irq;
unmask_irq = chrp_unmask_irq;
- ioremap(GG2_INT_ACK_SPECIAL, 1);
+ gg2_int_ack_special = (volatile unsigned char *)
+ ioremap(GG2_INT_ACK_SPECIAL, 1);
openpic_init();
i8259_init();
#ifdef CONFIG_XMON
@@ -653,7 +802,7 @@ __initfunc(void init_IRQ(void))
i8259_init();
route_pci_interrupts();
/*
- * According to the Carolina spec from ibm irq's 0,1,2, and 8
+ * According to the Carolina spec from ibm irqs 0,1,2, and 8
* must be edge triggered. Also, the pci intrs must be level
* triggered and _only_ isa intrs can be level sensitive
* which are 3-7,9-12,14-15. 13 is special - it can be level.
@@ -686,5 +835,6 @@ __initfunc(void init_IRQ(void))
}
break;
- }
+ }
+#endif /* CONFIG_8xx */
}
diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c
new file mode 100644
index 000000000..30b7b1184
--- /dev/null
+++ b/arch/ppc/kernel/mbx_pci.c
@@ -0,0 +1,254 @@
+/*
+ * MBX pci routines.
+ * The MBX uses the QSpan PCI bridge. The config address register
+ * is located 0x500 from the base of the bridge control/status registers.
+ * The data register is located at 0x504.
+ * This is a two step operation. First, the address register is written,
+ * then the data register is read/written as required.
+ * I don't know what to do about interrupts (yet).
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/mbx.h>
+
+
+/*
+ * This blows......The MBX uses the Tundra QSpan PCI bridge. When
+ * reading the configuration space, if something does not respond
+ * the bus times out and we get a machine check interrupt. So, the
+ * good ol' exception tables come to mind to trap it and return some
+ * value.
+ *
+ * On an error we just return a -1, since that is what the caller wants
+ * returned if nothing is present. I copied this from __get_user_asm,
+ * with the only difference of returning -1 instead of EFAULT.
+ * There is an associated hack in the machine check trap code.
+ *
+ * The QSPAN is also a big endian device, that is it makes the PCI
+ * look big endian to us. This presents a problem for the Linux PCI
+ * functions, which assume little endian. For example, we see the
+ * first 32-bit word like this:
+ * ------------------------
+ * | Device ID | Vendor ID |
+ * ------------------------
+ * If we read/write as a double word, that's OK. But in our world,
+ * when read as a word, device ID is at location 0, not location 2 as
+ * the little endian PCI would believe. We have to switch bits in
+ * the PCI addresses given to us to get the data to/from the correct
+ * byte lanes.
+ *
+ * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
+ * It always forces the MS bit to zero. Therefore, dev_fn values
+ * greater than 128 are returned as "no device found" errors.
+ *
+ * The QSPAN can only perform long word (32-bit) configuration cycles.
+ * The "offset" must have the two LS bits set to zero. Read operations
+ * require we read the entire word and then sort out what should be
+ * returned. Write operations other than long word require that we
+ * read the long word, update the proper word or byte, then write the
+ * entire long word back.
+ *
+ * PCI Bridge hack. We assume (correctly) that bus 0 is the primary
+ * PCI bus from the QSPAN. If we are called with a bus number other
+ * than zero, we create a Type 1 configuration access that a downstream
+ * PCI bridge will interpret.
+ */
+
+#define __get_mbx_pci_config(x, addr, op) \
+ __asm__ __volatile__( \
+ "1: "op" %0,0(%1)\n" \
+ " eieio\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,-1\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r"(x) : "r"(addr))
+
+#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500))
+#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504))
+
+#define mk_config_addr(bus, dev, offset) \
+ (((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
+
+#define mk_config_type1(bus, dev, offset) \
+ mk_config_addr(bus, dev, offset) | 1;
+
+int mbx_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ uint temp;
+ u_char *cp;
+
+ if ((bus > 7) || (dev_fn > 127)) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (bus == 0)
+ *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+ else
+ *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+ __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
+
+ offset ^= 0x03;
+ cp = ((u_char *)&temp) + (offset & 0x03);
+ *val = *cp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ uint temp;
+ ushort *sp;
+
+ if ((bus > 7) || (dev_fn > 127)) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (bus == 0)
+ *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+ else
+ *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+ __get_mbx_pci_config(temp, QS_CONFIG_DATA, "lwz");
+ offset ^= 0x02;
+
+ sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+ *val = *sp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ if ((bus > 7) || (dev_fn > 127)) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ if (bus == 0)
+ *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+ else
+ *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+ __get_mbx_pci_config(*val, QS_CONFIG_DATA, "lwz");
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ uint temp;
+ u_char *cp;
+
+ if ((bus > 7) || (dev_fn > 127))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+ offset ^= 0x03;
+ cp = ((u_char *)&temp) + (offset & 0x03);
+ *cp = val;
+
+ if (bus == 0)
+ *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+ else
+ *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+ *QS_CONFIG_DATA = temp;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ uint temp;
+ ushort *sp;
+
+ if ((bus > 7) || (dev_fn > 127))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ mbx_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+ offset ^= 0x02;
+ sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+ *sp = val;
+
+ if (bus == 0)
+ *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+ else
+ *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+ *QS_CONFIG_DATA = temp;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ if ((bus > 7) || (dev_fn > 127))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (bus == 0)
+ *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+ else
+ *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+ *(unsigned int *)QS_CONFIG_DATA = val;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int mbx_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int num, devfn;
+ unsigned int x, vendev;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (devfn = 0; devfn < 32; devfn++) {
+ mbx_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
+ if (x == vendev) {
+ if (index == num) {
+ *bus_ptr = 0;
+ *dev_fn_ptr = devfn<<3;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int mbx_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int devnr, x, num;
+
+ num = 0;
+ for (devnr = 0; devnr < 32; devnr++) {
+ mbx_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
+ if ((x>>8) == class_code) {
+ if (index == num) {
+ *bus_ptr = 0;
+ *dev_fn_ptr = devnr<<3;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
new file mode 100644
index 000000000..c028bb12d
--- /dev/null
+++ b/arch/ppc/kernel/mbx_setup.c
@@ -0,0 +1,169 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/mbx.h>
+
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+extern char saved_command_line[256];
+
+extern unsigned long find_available_memory(void);
+extern void mbx_cpm_reset(uint);
+
+
+void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+
+ *p = 0;
+ *irq = 0;
+
+ if (base != 0) /* Only map the first ATA flash drive */
+ return;
+#ifdef ATA_FLASH
+ base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+ for (i = 0; i < 8; ++i)
+ *p++ = base++;
+ *p = ++base; /* Does not matter */
+ if (irq)
+ *irq = 13;
+#endif
+}
+
+int
+mbx_get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ int len;
+ char *model;
+ bd_t *bp;
+ extern RESIDUAL res;
+
+ /* I know the MPC860 is 0x50. I don't have the book handy
+ * to check the others.
+ */
+ if ((pvr>>16) == 0x50)
+ model = "MPC860";
+ else
+ model = "unknown";
+
+#ifdef __SMP__
+#define CD(X) (cpu_data[n].X)
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+ bp = (bd_t *)&res;
+
+ len = sprintf(buffer,"processor\t: %d\n"
+ "cpu\t\t: %s\n"
+ "revision\t: %d.%d\n"
+ "clock\t\t: %d MHz\n"
+ "bus clock\t: %d MHz\n",
+ CPUN,
+ model,
+ MAJOR(pvr), MINOR(pvr),
+ bp->bi_intfreq / 1000000,
+ bp->bi_busfreq / 1000000
+ );
+
+ return len;
+}
+
+__initfunc(void
+mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+ int cpm_page;
+
+ cpm_page = *memory_start_p;
+ *memory_start_p += PAGE_SIZE;
+
+ /* Reset the Communication Processor Module.
+ */
+ mbx_cpm_reset(cpm_page);
+
+#ifdef notdef
+ ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+#endif
+
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+ ROOT_DEV = to_kdev_t(0x0200); /* floppy */
+ rd_prompt = 1;
+ rd_doload = 1;
+ rd_image_start = 0;
+#endif
+ /* initrd_start and size are setup by boot/head.S and kernel/head.S */
+ if ( initrd_start )
+ {
+ if (initrd_end > *memory_end_p)
+ {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_end,*memory_end_p);
+ initrd_start = 0;
+ }
+ }
+#endif
+
+#ifdef notdef
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+#endif
+}
+
+void
+abort(void)
+{
+#ifdef CONFIG_XMON
+ extern void xmon(void *);
+ xmon(0);
+#endif
+ machine_restart(NULL);
+}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 2c866eed8..6607e00bd 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -12,6 +12,7 @@
*
*/
+#include <linux/config.h>
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/errno.h>
@@ -19,6 +20,7 @@
#include "ppc_asm.tmpl"
#include "ppc_defs.h"
+#ifndef CONFIG_8xx
/* This instruction is not implemented on the PPC 601 or 603 */
#define tlbia \
li r4,128; \
@@ -27,7 +29,7 @@
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
-
+#endif
.text
/*
@@ -323,6 +325,18 @@ _GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
blr
+_GLOBAL(_get_THRM1)
+ mfspr r3,THRM1
+ blr
+
+_GLOBAL(_set_THRM1)
+ mtspr THRM1,r3
+ blr
+
+_GLOBAL(_get_L2CR)
+ mfspr r3,L2CR
+ blr
+
_GLOBAL(_get_PVR)
mfspr r3,PVR
blr
@@ -348,33 +362,6 @@ cvt_df:
stfs 0,0(r4)
blr
-
-_GLOBAL(lock_dcache)
- mfspr r3,PVR /* nop on 601 */
- rlwinm r3,r3,16,16,31
- cmpwi 0,r3,1
- beqlr-
- mfspr r3,HID0
- ori r3,r3,HID0_DLOCK
- mtspr HID0,r3
- sync
- isync
- blr
-
-_GLOBAL(unlock_dcache)
- mfspr r3,PVR /* nop on 601 */
- rlwinm r3,r3,16,16,31
- cmpwi 0,r3,1
- beqlr-
- mfspr r3,HID0
- li r4,HID0_DLOCK
- andc r3,r3,r4
- mtspr HID0,r3
- sync
- isync
- blr
-
-
/*
* Create a kernel thread
* __kernel_thread(flags, fn, arg)
@@ -386,6 +373,16 @@ _GLOBAL(__kernel_thread)
bnelr /* return if parent */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
+#if 0/*def __SMP__*/
+ /* drop scheduler_lock since schedule() called us */
+ lis r4,scheduler_lock@ha
+ li r5,0
+ stw r5,scheduler_lock@l+4(r4) /* owner_pc */
+ stw r5,scheduler_lock@l+8(r4) /* owner_cpu */
+ stw r5,scheduler_lock@l(r4)
+ sync
+ isync
+#endif /* __SMP__ */
blrl
li r0,__NR_exit /* exit after child exits */
li r3,0
@@ -413,7 +410,9 @@ SYSCALL(execve)
SYSCALL(open)
SYSCALL(close)
SYSCALL(waitpid)
+SYSCALL(fork)
SYSCALL(delete_module)
+SYSCALL(_exit)
/* Why isn't this a) automatic, b) written in 'C'? */
@@ -593,5 +592,7 @@ sys_call_table:
.long sys_setresgid
.long sys_getresgid /* 170 */
.long sys_prctl
- .space (NR_syscalls-171)*4
+ .long sys_xstat
+ .long sys_xmknod
+ .space (NR_syscalls-173)*4
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 8db1763db..9de056504 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -19,6 +19,7 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <asm/io.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -29,9 +30,11 @@
void
main(void)
{
+ DEFINE(KERNELBASE, KERNELBASE);
DEFINE(STATE, offsetof(struct task_struct, state));
DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
DEFINE(COUNTER, offsetof(struct task_struct, counter));
+ DEFINE(PROCESSOR, offsetof(struct task_struct, processor));
DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
DEFINE(TSS, offsetof(struct task_struct, tss));
DEFINE(MM, offsetof(struct task_struct, mm));
@@ -45,6 +48,7 @@ main(void)
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+ DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 7e39487d8..186165a46 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,24 +1,27 @@
/*
- * $Id: pci.c,v 1.18 1997/10/29 03:35:07 cort Exp $
+ * $Id: pci.c,v 1.24 1998/02/19 21:29:49 cort Exp $
* Common pmac/prep/chrp pci routines. -- Cort
*/
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include <asm/irq.h>
-#if !defined(CONFIG_MACH_SPECIFIC)
+#if !defined(CONFIG_MACH_SPECIFIC) || defined(CONFIG_PMAC)
unsigned long isa_io_base;
+#endif /* CONFIG_MACH_SPECIFIC || CONFIG_PMAC */
+#if !defined(CONFIG_MACH_SPECIFIC)
unsigned long isa_mem_base;
unsigned long pci_dram_offset;
#endif /* CONFIG_MACH_SPECIFIC */
@@ -121,49 +124,6 @@ int pcibios_present(void)
return 1;
}
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
- for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->vendor == vendor && dev->device == device_id) {
- if (curr == index) {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-/*
- * Given the class, find the n'th instance of that device
- * in the system.
- */
-int pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->class == class_code) {
- if (curr == index) {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-
__initfunc(unsigned long
pcibios_init(unsigned long mem_start,unsigned long mem_end))
{
@@ -203,6 +163,70 @@ __initfunc(void
__initfunc(unsigned long
pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
+
{
+ extern route_pci_interrupts(void);
+ struct pci_dev *dev;
+ extern struct bridge_data **bridges;
+ extern unsigned char *Motherboard_map;
+ extern unsigned char *Motherboard_routes;
+
+ /*
+ * FIXME: This is broken: We should not assign IRQ's to IRQless
+ * devices (look at PCI_INTERRUPT_PIN) and we also should
+ * honor the existence of multi-function devices where
+ * different functions have different interrupt pins. [mj]
+ */
+ switch (_machine )
+ {
+ case _MACH_prep:
+ route_pci_interrupts();
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ unsigned char d = PCI_SLOT(dev->devfn);
+ dev->irq = Motherboard_routes[Motherboard_map[d]];
+ }
+ break;
+ case _MACH_chrp:
+ /* PCI interrupts are controlled by the OpenPIC */
+ for(dev=pci_devices; dev; dev=dev->next)
+ if (dev->irq)
+ dev->irq = openpic_to_irq(dev->irq);
+ break;
+ case _MACH_Pmac:
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ /*
+ * Open Firmware often doesn't initialize the,
+ * PCI_INTERRUPT_LINE config register properly, so we
+ * should find the device node and se if it has an
+ * AAPL,interrupts property.
+ */
+ struct bridge_data *bp = bridges[dev->bus->number];
+ struct device_node *node;
+ unsigned int *reg;
+ unsigned char pin;
+
+ if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+ !pin)
+ continue; /* No interrupt generated -> no fixup */
+ for (node = bp->node->child; node != 0;
+ node = node->sibling) {
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ dev->irq = node->intrs[0].line;
+ break;
+ }
+ }
+ break;
+ }
return mem_start;
}
+
+__initfunc(char *pcibios_setup(char *str))
+{
+ return str;
+}
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index d0144a567..a71aede12 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -12,27 +12,18 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-struct bridge_data {
- volatile unsigned int *cfg_addr;
- volatile unsigned char *cfg_data;
- void *io_base;
- int bus_number;
- int max_bus;
- struct bridge_data *next;
- struct device_node *node;
-};
-
-static struct bridge_data **bridges, *bridge_list;
+struct bridge_data **bridges, *bridge_list;
static int max_bus;
static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
@@ -112,9 +103,11 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
int *bus_range;
int len;
struct bridge_data *bp;
+ struct reg_property *addr;
for (; dev != NULL; dev = dev->next) {
- if (dev->n_addrs < 1) {
+ addr = (struct reg_property *) get_property(dev, "reg", &len);
+ if (addr == NULL || len < sizeof(*addr)) {
printk(KERN_WARNING "Can't use %s: no address\n",
dev->full_name);
continue;
@@ -130,15 +123,18 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
else
printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
bus_range[1]);
- printk(" controlled by %s at %x\n",
- dev->name, dev->addrs[0].address);
+ printk(" controlled by %s at %x\n", dev->name, addr->address);
bp = (struct bridge_data *) *mem_ptr;
*mem_ptr += sizeof(struct bridge_data);
bp->cfg_addr = (volatile unsigned int *)
- ioremap(dev->addrs[0].address + 0x800000, 0x1000);
+ ioremap(addr->address + 0x800000, 0x1000);
bp->cfg_data = (volatile unsigned char *)
- ioremap(dev->addrs[0].address + 0xc00000, 0x1000);
- bp->io_base = (void *) ioremap(dev->addrs[0].address, 0x10000);
+ ioremap(addr->address + 0xc00000, 0x1000);
+ bp->io_base = (void *) ioremap(addr->address, 0x10000);
+#ifdef CONFIG_PMAC
+ if (isa_io_base == 0)
+ isa_io_base = (unsigned long) bp->io_base;
+#endif
bp->bus_number = bus_range[0];
bp->max_bus = bus_range[1];
bp->next = bridge_list;
@@ -180,7 +176,7 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
}
int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val)
+ unsigned char offset, unsigned char *val)
{
struct bridge_data *bp;
@@ -198,32 +194,11 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
}
udelay(2);
*val = in_8(bp->cfg_data + (offset & 3));
-
- if (offset == PCI_INTERRUPT_LINE) {
- /*
- * Open Firmware often doesn't initialize this
- * register properly, so we find the node and see
- * if it has an AAPL,interrupts property.
- */
- struct device_node *node;
- unsigned int *reg;
-
- for (node = bp->node->child; node != 0; node = node->sibling) {
- reg = (unsigned int *) get_property(node, "reg", 0);
- if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
- continue;
- /* this is the node, see if it has interrupts */
- if (node->n_intrs > 0)
- *val = node->intrs[0];
- break;
- }
- }
-
return PCIBIOS_SUCCESSFUL;
}
int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val)
+ unsigned char offset, unsigned short *val)
{
struct bridge_data *bp;
@@ -245,7 +220,7 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
}
int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val)
+ unsigned char offset, unsigned int *val)
{
struct bridge_data *bp;
@@ -267,7 +242,7 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
}
int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val)
+ unsigned char offset, unsigned char val)
{
struct bridge_data *bp;
@@ -288,7 +263,7 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
}
int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val)
+ unsigned char offset, unsigned short val)
{
struct bridge_data *bp;
@@ -309,7 +284,7 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
}
int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val)
+ unsigned char offset, unsigned int val)
{
struct bridge_data *bp;
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 4e37becd5..afcd4fd8b 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -47,23 +47,18 @@
#include <asm/ide.h>
#include <asm/pci-bridge.h>
#include <asm/adb.h>
+#include <asm/mediabay.h>
+#include <asm/ohare.h>
+#include <asm/mediabay.h>
#include "time.h"
-/*
- * A magic address and value to put into it on machines with the
- * "ohare" I/O controller. This makes the IDE CD work on Starmaxes.
- * Contributed by Harry Eaton.
- */
-#define OMAGICPLACE ((volatile unsigned *) 0xf3000038)
-#define OMAGICCONT 0xbeff7a
-
extern int root_mountflags;
unsigned char drive_info;
#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
-static void gc_init(const char *, int);
+static void ohare_init(void);
void
pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)
@@ -91,27 +86,44 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)
loops_per_sec = 50000000;
}
+ /* this area has the CPU identification register
+ and some registers used by smp boards */
+ ioremap(0xf8000000, 0x1000);
+
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
- gc_init("gc", 0);
- gc_init("ohare", 1);
-#ifdef CONFIG_ABSTRACT_CONSOLE
+ ohare_init();
+
+#ifdef CONFIG_FB
/* Frame buffer device based console */
conswitchp = &fb_con;
#endif
}
-static void gc_init(const char *name, int isohare)
+static volatile u32 *feature_addr;
+
+static void ohare_init(void)
{
struct device_node *np;
- for (np = find_devices(name); np != NULL; np = np->next) {
- if (np->n_addrs > 0)
- ioremap(np->addrs[0].address, np->addrs[0].size);
- if (isohare) {
- printk(KERN_INFO "Twiddling the magic ohare bits\n");
- out_le32(OMAGICPLACE, OMAGICCONT);
- }
+ np = find_devices("ohare");
+ if (np == 0)
+ return;
+ if (np->next != 0)
+ printk(KERN_WARNING "only using the first ohare\n");
+ if (np->n_addrs == 0) {
+ printk(KERN_ERR "No addresses for %s\n", np->full_name);
+ return;
+ }
+ feature_addr = (volatile u32 *)
+ ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4);
+
+ if (find_devices("via-pmu") == 0) {
+ printk(KERN_INFO "Twiddling the magic ohare bits\n");
+ out_le32(feature_addr, STARMAX_FEATURES);
+ } else {
+ out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES);
+ printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr));
}
}
@@ -125,10 +137,15 @@ kdev_t boot_dev;
unsigned long
powermac_init(unsigned long mem_start, unsigned long mem_end)
{
- pmac_nvram_init();
+#ifdef CONFIG_KGDB
+ extern void zs_kgdb_hook(int tty_num);
+ zs_kgdb_hook(0);
+#endif
adb_init();
+ pmac_nvram_init();
if (_machine == _MACH_Pmac) {
pmac_read_rtc_time();
+ media_bay_init();
}
#ifdef CONFIG_PMAC_CONSOLE
pmac_find_display();
@@ -175,7 +192,7 @@ note_scsi_host(struct device_node *node, void *host)
#include "../../../drivers/scsi/sd.h"
#include "../../../drivers/scsi/hosts.h"
-int sd_find_target(void *host, int tgt)
+kdev_t sd_find_target(void *host, int tgt)
{
Scsi_Disk *dp;
int i;
@@ -190,7 +207,7 @@ int sd_find_target(void *host, int tgt)
void find_boot_device(void)
{
- int dev;
+ kdev_t dev;
if (kdev_t_to_nr(ROOT_DEV) != 0)
return;
@@ -201,7 +218,7 @@ void find_boot_device(void)
dev = sd_find_target(boot_host, boot_target);
if (dev == 0)
return;
- boot_dev = to_kdev_t(dev + boot_part);
+ boot_dev = MKDEV(MAJOR(dev), MINOR(dev) + boot_part);
#endif
/* XXX should cope with booting from IDE also */
}
@@ -221,39 +238,92 @@ void note_bootable_part(kdev_t dev, int part)
}
}
+#ifdef CONFIG_BLK_DEV_IDE
+int pmac_ide_ports_known;
+ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
+int pmac_ide_irq[MAX_HWIFS];
+
void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
{
- struct device_node *np;
int i;
- static struct device_node *atas;
- static int atas_valid;
*p = 0;
- *irq = 0;
- if (!atas_valid) {
- atas = find_devices("ATA");
- atas_valid = 1;
- }
- for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
- ;
- if (np == NULL)
+ if (base == 0)
return;
- if (np->n_addrs == 0) {
- printk("ide: no addresses for device %s\n", np->full_name);
+ if (base == mb_cd_base && !check_media_bay(MB_CD)) {
+ mb_cd_index = -1;
return;
}
- if (np->n_intrs == 0) {
- printk("ide: no intrs for device %s, using 13\n",
- np->full_name);
- *irq = 13;
- } else {
- *irq = np->intrs[0];
- }
- base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
for (i = 0; i < 8; ++i)
*p++ = base + i * 0x10;
*p = base + 0x160;
+ if (irq != NULL) {
+ *irq = 0;
+ for (i = 0; i < MAX_HWIFS; ++i) {
+ if (base == pmac_ide_regbase[i]) {
+ *irq = pmac_ide_irq[i];
+ break;
+ }
+ }
+ }
+}
+
+void pmac_ide_probe(void)
+{
+ struct device_node *np;
+ int i;
+ struct device_node *atas;
+ struct device_node *p, **pp, *removables, **rp;
+
+ pp = &atas;
+ rp = &removables;
+ p = find_devices("ATA");
+ if (p == NULL)
+ p = find_devices("IDE");
+ /* Move removable devices such as the media-bay CDROM
+ on the PB3400 to the end of the list. */
+ for (; p != NULL; p = p->next) {
+ if (p->parent && p->parent->name
+ && strcasecmp(p->parent->name, "media-bay") == 0) {
+ *rp = p;
+ rp = &p->next;
+ } else {
+ *pp = p;
+ pp = &p->next;
+ }
+ }
+ *rp = NULL;
+ *pp = removables;
+
+ for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+ if (np->n_addrs == 0) {
+ printk(KERN_WARNING "ide: no address for device %s\n",
+ np->full_name);
+ continue;
+ }
+ pmac_ide_regbase[i] = (unsigned long)
+ ioremap(np->addrs[0].address, 0x200);
+ if (np->n_intrs == 0) {
+ printk("ide: no intrs for device %s, using 13\n",
+ np->full_name);
+ pmac_ide_irq[i] = 13;
+ } else {
+ pmac_ide_irq[i] = np->intrs[0].line;
+ }
+
+ if (np->parent && np->parent->name
+ && strcasecmp(np->parent->name, "media-bay") == 0) {
+ mb_cd_index = i;
+ mb_cd_base = pmac_ide_regbase[i];
+ mb_cd_irq = pmac_ide_irq[i];
+ }
+
+ ++i;
+ }
+
+ pmac_ide_ports_known = 1;
}
+#endif /* CONFIG_BLK_DEV_IDE */
int
pmac_get_cpuinfo(char *buffer)
diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c
index 17226f8ff..4ceaa0dc9 100644
--- a/arch/ppc/kernel/pmac_support.c
+++ b/arch/ppc/kernel/pmac_support.c
@@ -7,8 +7,11 @@
#include <linux/nvram.h>
#include <asm/ptrace.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/prom.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
/*
* Read and write the non-volatile RAM on PowerMacs and CHRP machines.
@@ -32,8 +35,7 @@ void pmac_nvram_init(void)
}
nvram_naddrs = dp->n_addrs;
if (_machine == _MACH_chrp && nvram_naddrs == 1) {
- /* XXX for now */
- nvram_data = ioremap(0xf70e0000, NVRAM_SIZE);
+ nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_mult = 1;
} else if (nvram_naddrs == 1) {
nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
@@ -41,6 +43,8 @@ void pmac_nvram_init(void)
} else if (nvram_naddrs == 2) {
nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+ } else if (nvram_naddrs == 0 && adb_hardware == ADB_VIAPMU) {
+ nvram_naddrs = -1;
} else {
printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
nvram_naddrs);
@@ -49,7 +53,16 @@ void pmac_nvram_init(void)
unsigned char nvram_read_byte(int addr)
{
+ struct adb_request req;
+
switch (nvram_naddrs) {
+ case -1:
+ if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
+ (addr >> 8) & 0xff, addr & 0xff))
+ break;
+ while (!req.complete)
+ pmu_poll();
+ return req.reply[1];
case 1:
return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
case 2:
@@ -62,7 +75,16 @@ unsigned char nvram_read_byte(int addr)
void nvram_write_byte(unsigned char val, int addr)
{
+ struct adb_request req;
+
switch (nvram_naddrs) {
+ case -1:
+ if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
+ (addr >> 8) & 0xff, addr & 0xff, val))
+ break;
+ while (!req.complete)
+ pmu_poll();
+ break;
case 1:
nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
break;
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
index 1a31ffa9a..3c976506e 100644
--- a/arch/ppc/kernel/pmac_time.c
+++ b/arch/ppc/kernel/pmac_time.c
@@ -15,8 +15,11 @@
#include <linux/mm.h>
#include <asm/adb.h>
#include <asm/cuda.h>
+#include <asm/pmu.h>
#include <asm/prom.h>
#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
#include "time.h"
@@ -44,7 +47,11 @@
/* Bits in IFR and IER */
#define T1_INT 0x40 /* Timer 1 interrupt */
-static int via_calibrate_decr(void)
+/*
+ * Calibrate the decrementer register using VIA timer 1.
+ * This is used both on powermacs and CHRP machines.
+ */
+int via_calibrate_decr(void)
{
struct device_node *vias;
volatile unsigned char *via;
@@ -54,9 +61,12 @@ static int via_calibrate_decr(void)
vias = find_devices("via-cuda");
if (vias == 0)
vias = find_devices("via-pmu");
+ if (vias == 0)
+ vias = find_devices("via");
if (vias == 0 || vias->n_addrs == 0)
return 0;
- via = (volatile unsigned char *) vias->addrs[0].address;
+ via = (volatile unsigned char *)
+ ioremap(vias->addrs[0].address, vias->addrs[0].size);
/* set timer 1 for continuous interrupts */
out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
@@ -123,14 +133,30 @@ pmac_get_rtc_time(void)
struct adb_request req;
/* Get the time from the RTC */
- cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
- while (!req.complete)
- cuda_poll();
- if (req.reply_len != 7)
- printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
- req.reply_len);
- return (req.reply[3] << 24) + (req.reply[4] << 16)
- + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+ return 0;
+ while (!req.complete)
+ cuda_poll();
+ if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return (req.reply[3] << 24) + (req.reply[4] << 16)
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+ case ADB_VIAPMU:
+ if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+ return 0;
+ while (!req.complete)
+ pmu_poll();
+ if (req.reply_len != 5)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return (req.reply[1] << 24) + (req.reply[2] << 16)
+ + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
+ default:
+ return 0;
+ }
}
int pmac_set_rtc_time(unsigned long nowtime)
diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
new file mode 100644
index 000000000..b7eab0fa1
--- /dev/null
+++ b/arch/ppc/kernel/ppc-stub.c
@@ -0,0 +1,705 @@
+/* $Id: ppc-stub.c,v 1.2 1998/04/11 17:29:03 geert Exp $
+ * ppc-stub.c: KGDB support for the Linux kernel.
+ *
+ * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
+ * some stuff borrowed from Paul Mackerras' xmon
+ * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu)
+ *
+ * Modifications to run under Linux
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * This file originally came from the gdb sources, and the
+ * copyright notices have been retained below.
+ */
+
+/****************************************************************************
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ HP offers the following for use in the public domain. HP makes no
+ warranty with regard to the software or its performance and the
+ user accepts the software "AS IS" with all faults.
+
+ HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+ TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ * Module name: remcom.c $
+ * Revision: 1.34 $
+ * Date: 91/03/09 12:29:49 $
+ * Contributor: Lake Stevens Instrument Division$
+ *
+ * Description: low level support for gdb debugger. $
+ *
+ * Considerations: only works on target hardware $
+ *
+ * Written by: Glenn Engel $
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
+ * baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/signal.h>
+#include <asm/system.h>
+#include <asm/kgdb.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+
+void breakinst(void);
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+static int initialized = 0;
+static int kgdb_active = 0;
+static u_int fault_jmp_buf[100];
+static int kdebug;
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Place where we save old trap entries for restoration - sparc*/
+/* struct tt_entry kgdb_savettable[256]; */
+/* typedef void (*trapfunc_t)(void); */
+
+#if 0
+/* Install an exception handler for kgdb */
+static void exceptionHandler(int tnum, unsigned int *tfunc)
+{
+ /* We are dorking with a live trap table, all irqs off */
+}
+#endif
+
+int
+kgdb_setjmp(long *buf)
+{
+ asm ("mflr 0; stw 0,0(%0);"
+ "stw 1,4(%0); stw 2,8(%0);"
+ "mfcr 0; stw 0,12(%0);"
+ "stmw 13,16(%0)"
+ : : "r" (buf));
+ /* XXX should save fp regs as well */
+ return 0;
+}
+void
+kgdb_longjmp(long *buf, int val)
+{
+ if (val == 0)
+ val = 1;
+ asm ("lmw 13,16(%0);"
+ "lwz 0,12(%0); mtcrf 0x38,0;"
+ "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
+ "mtlr 0; mr 3,%1"
+ : : "r" (buf), "r" (val));
+}
+/* Convert ch from a hex digit to an int */
+static int
+hex(unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ */
+static unsigned char *
+mem2hex(char *mem, char *buf, int count)
+{
+ unsigned char ch;
+
+ if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+ debugger_fault_handler = kgdb_fault_handler;
+ while (count-- > 0) {
+ ch = *mem++;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+ } else {
+ /* error condition */
+ }
+ debugger_fault_handler = 0;
+ *buf = 0;
+ return buf;
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written.
+*/
+static char *
+hex2mem(char *buf, char *mem, int count)
+{
+ int i;
+ unsigned char ch;
+
+ if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+ debugger_fault_handler = kgdb_fault_handler;
+ for (i=0; i<count; i++) {
+ ch = hex(*buf++) << 4;
+ ch |= hex(*buf++);
+ *mem++ = ch;
+ }
+ flush_icache_range((int)mem, (int)mem+count);
+ } else {
+ /* error condition */
+ }
+ debugger_fault_handler = 0;
+ return mem;
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int
+hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
+ debugger_fault_handler = kgdb_fault_handler;
+ while (**ptr) {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+ } else {
+ /* error condition */
+ }
+ debugger_fault_handler = 0;
+
+ return (numChars);
+}
+
+/* scan for the sequence $<data>#<checksum> */
+static void
+getpacket(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ unsigned char ch;
+
+ do {
+ /* wait around for the start character, ignore all other
+ * characters */
+ while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+ checksum = 0;
+ xmitcsum = -1;
+
+ count = 0;
+
+ /* now, read until a # or end of buffer is found */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+
+ if (count >= BUFMAX)
+ continue;
+
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+ xmitcsum |= hex(getDebugChar() & 0x7f);
+ if (checksum != xmitcsum)
+ putDebugChar('-'); /* failed checksum */
+ else {
+ putDebugChar('+'); /* successful transfer */
+ /* if a sequence char is present, reply the ID */
+ if (buffer[2] == ':') {
+ putDebugChar(buffer[0]);
+ putDebugChar(buffer[1]);
+ /* remove sequence chars from buffer */
+ count = strlen(buffer);
+ for (i=3; i <= count; i++)
+ buffer[i-3] = buffer[i];
+ }
+ }
+ }
+ } while (checksum != xmitcsum);
+}
+
+/* send the packet in buffer. */
+static void putpacket(unsigned char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch, recv;
+
+ /* $<packet info>#<checksum>. */
+ do {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count])) {
+ putDebugChar(ch);
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+ recv = getDebugChar();
+ } while ((recv & 0x7f) != '+');
+}
+
+static void kgdb_flush_cache_all(void)
+{
+ flush_instruction_cache();
+}
+
+static inline int get_msr()
+{
+ int msr;
+ asm volatile("mfmsr %0" : "=r" (msr):);
+ return msr;
+}
+
+static inline void set_msr(int msr)
+{
+ asm volatile("mfmsr %0" : : "r" (msr));
+}
+
+/* Set up exception handlers for tracing and breakpoints
+ * [could be called kgdb_init()]
+ */
+void set_debug_traps(void)
+{
+#if 0
+ unsigned char c;
+
+ save_and_cli(flags);
+
+ /* In case GDB is started before us, ack any packets (presumably
+ * "$?#xx") sitting there.
+ *
+ * I've found this code causes more problems than it solves,
+ * so that's why it's commented out. GDB seems to work fine
+ * now starting either before or after the kernel -bwb
+ */
+
+ while((c = getDebugChar()) != '$');
+ while((c = getDebugChar()) != '#');
+ c = getDebugChar(); /* eat first csum byte */
+ c = getDebugChar(); /* eat second csum byte */
+ putDebugChar('+'); /* ack it */
+#endif
+ debugger = kgdb;
+ debugger_bpt = kgdb_bpt;
+ debugger_sstep = kgdb_sstep;
+ debugger_iabr_match = kgdb_iabr_match;
+ debugger_dabr_match = kgdb_dabr_match;
+
+ kgdb_interruptible(1);
+ initialized = 1;
+}
+
+static void kgdb_fault_handler(struct pt_regs *regs)
+{
+ kgdb_longjmp((long*)fault_jmp_buf, 1);
+}
+
+int kgdb_bpt(struct pt_regs *regs)
+{
+ handle_exception(regs);
+ return 1;
+}
+
+int kgdb_sstep(struct pt_regs *regs)
+{
+ handle_exception(regs);
+ return 1;
+}
+
+void kgdb(struct pt_regs *regs)
+{
+ handle_exception(regs);
+}
+
+int kgdb_iabr_match(struct pt_regs *regs)
+{
+ printk("kgdb doesn't support iabr, what?!?\n");
+ handle_exception(regs);
+ return 1;
+}
+
+int kgdb_dabr_match(struct pt_regs *regs)
+{
+ printk("kgdb doesn't support dabr, what?!?\n");
+ handle_exception(regs);
+ return 1;
+}
+
+/* Convert the SPARC hardware trap type code to a unix signal number. */
+/*
+ * This table contains the mapping between PowerPC hardware trap types, and
+ * signals, which are primarily what GDB understands.
+ */
+static struct hard_trap_info
+{
+ unsigned int tt; /* Trap type code for powerpc */
+ unsigned char signo; /* Signal that we map this trap into */
+} hard_trap_info[] = {
+ { 0x200, SIGSEGV }, /* machine check */
+ { 0x300, SIGSEGV }, /* address error (store) */
+ { 0x400, SIGBUS }, /* instruction bus error */
+ { 0x500, SIGINT }, /* interrupt */
+ { 0x600, SIGBUS }, /* alingment */
+ { 0x700, SIGILL }, /* reserved instruction or sumpin' */
+ { 0x800, SIGFPE }, /* fpu unavail */
+ { 0x900, SIGALRM }, /* decrementer */
+ { 0xa00, SIGILL }, /* reserved */
+ { 0xb00, SIGILL }, /* reserved */
+ { 0xc00, SIGCHLD }, /* syscall */
+ { 0xd00, SIGINT }, /* watch */
+ { 0xe00, SIGFPE }, /* fp assist */
+ { 0, 0} /* Must be last */
+};
+
+static int computeSignal(unsigned int tt)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ if (ht->tt == tt)
+ return ht->signo;
+
+ return SIGHUP; /* default for things we don't know about */
+}
+
+/*
+ * This function does all command processing for interfacing to gdb.
+ */
+static void
+handle_exception (struct pt_regs *regs)
+{
+ int sigval;
+ int addr;
+ int length;
+ char *ptr;
+ unsigned int msr;
+
+ if (debugger_fault_handler) {
+ debugger_fault_handler(regs);
+ panic("kgdb longjump failed!\n");
+ }
+ if (kgdb_active) {
+ printk("interrupt while in kgdb, returning\n");
+ return;
+ }
+ kgdb_active = 1;
+
+ printk("kgdb: entering handle_exception; trap [0x%x]\n",
+ (unsigned int)regs->trap);
+
+ kgdb_interruptible(0);
+ lock_kernel();
+ msr = get_msr();
+ set_msr(msr & ~MSR_EE); /* disable interrupts */
+
+ if (regs->nip == (unsigned long)breakinst) {
+ /* Skip over breakpoint trap insn */
+ regs->nip += 4;
+ }
+
+ /* reply to host that an exception has occurred */
+ sigval = computeSignal(regs->trap);
+ ptr = remcomOutBuffer;
+
+ *ptr++ = 'S';
+ *ptr++ = hexchars[sigval >> 4];
+ *ptr++ = hexchars[sigval & 0xf];
+
+ *ptr++ = 0;
+
+ putpacket(remcomOutBuffer);
+
+ /* XXX We may want to add some features dealing with poking the
+ * XXX page tables, ... (look at sparc-stub.c for more info)
+ * XXX also required hacking to the gdb sources directly...
+ */
+
+ while (1) {
+ remcomOutBuffer[0] = 0;
+
+ getpacket(remcomInBuffer);
+ switch (remcomInBuffer[0]) {
+ case '?': /* report most recent signal */
+ remcomOutBuffer[0] = 'S';
+ remcomOutBuffer[1] = hexchars[sigval >> 4];
+ remcomOutBuffer[2] = hexchars[sigval & 0xf];
+ remcomOutBuffer[3] = 0;
+ break;
+#if 0
+ case 'q': /* this screws up gdb for some reason...*/
+ {
+ extern long _start, sdata, __bss_start;
+
+ ptr = &remcomInBuffer[1];
+ if (strncmp(ptr, "Offsets", 7) != 0)
+ break;
+
+ ptr = remcomOutBuffer;
+ sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
+ &_start, &sdata, &__bss_start);
+ break;
+ }
+#endif
+ case 'd':
+ /* toggle debug flag */
+ kdebug ^= 1;
+ break;
+
+ case 'g': /* return the value of the CPU registers.
+ * some of them are non-PowerPC names :(
+ * they are stored in gdb like:
+ * struct {
+ * u32 gpr[32];
+ * f64 fpr[32];
+ * u32 pc, ps, cnd, lr; (ps=msr)
+ * u32 cnt, xer, mq;
+ * }
+ */
+ {
+ int i;
+ ptr = remcomOutBuffer;
+ /* General Purpose Regs */
+ ptr = mem2hex((char *)regs, ptr, 32 * 4);
+ /* Floating Point Regs - FIXME */
+ /*ptr = mem2hex((char *), ptr, 32 * 8);*/
+ for(i=0; i<(32*8*2); i++) { /* 2chars/byte */
+ ptr[i] = '0';
+ }
+ ptr += 32*8*2;
+ /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
+ ptr = mem2hex((char *)&regs->nip, ptr, 4);
+ ptr = mem2hex((char *)&regs->msr, ptr, 4);
+ ptr = mem2hex((char *)&regs->ccr, ptr, 4);
+ ptr = mem2hex((char *)&regs->link, ptr, 4);
+ ptr = mem2hex((char *)&regs->ctr, ptr, 4);
+ ptr = mem2hex((char *)&regs->xer, ptr, 4);
+ }
+ break;
+
+ case 'G': /* set the value of the CPU registers */
+ {
+ ptr = &remcomInBuffer[1];
+
+ /*
+ * If the stack pointer has moved, you should pray.
+ * (cause only god can help you).
+ */
+
+ /* General Purpose Regs */
+ hex2mem(ptr, (char *)regs, 32 * 4);
+
+ /* Floating Point Regs - FIXME?? */
+ /*ptr = hex2mem(ptr, ??, 32 * 8);*/
+ ptr += 32*8*2;
+
+ /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
+ ptr = hex2mem(ptr, (char *)&regs->nip, 4);
+ ptr = hex2mem(ptr, (char *)&regs->msr, 4);
+ ptr = hex2mem(ptr, (char *)&regs->ccr, 4);
+ ptr = hex2mem(ptr, (char *)&regs->link, 4);
+ ptr = hex2mem(ptr, (char *)&regs->ctr, 4);
+ ptr = hex2mem(ptr, (char *)&regs->xer, 4);
+
+ strcpy(remcomOutBuffer,"OK");
+ }
+ break;
+ case 'H':
+ /* dont do anything, yet, just acknowledge */
+ hexToInt(&ptr, &addr);
+ strcpy(remcomOutBuffer,"OK");
+ break;
+
+ case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
+ /* Try to read %x,%x. */
+
+ ptr = &remcomInBuffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)) {
+ if (mem2hex((char *)addr, remcomOutBuffer,length))
+ break;
+ strcpy (remcomOutBuffer, "E03");
+ } else {
+ strcpy(remcomOutBuffer,"E01");
+ }
+ break;
+
+ case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+ /* Try to read '%x,%x:'. */
+
+ ptr = &remcomInBuffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ if (hex2mem(ptr, (char *)addr, length)) {
+ strcpy(remcomOutBuffer, "OK");
+ } else {
+ strcpy(remcomOutBuffer, "E03");
+ }
+ } else {
+ strcpy(remcomOutBuffer, "E02");
+ }
+ break;
+
+
+ case 'k': /* kill the program, actually just continue */
+ case 'c': /* cAA..AA Continue; address AA..AA optional */
+ /* try to read optional parameter, pc unchanged if no parm */
+
+ ptr = &remcomInBuffer[1];
+ if (hexToInt(&ptr, &addr)) {
+ regs->nip = addr;
+ }
+
+/* Need to flush the instruction cache here, as we may have deposited a
+ * breakpoint, and the icache probably has no way of knowing that a data ref to
+ * some location may have changed something that is in the instruction cache.
+ */
+ kgdb_flush_cache_all();
+ set_msr(msr);
+ kgdb_interruptible(1);
+ unlock_kernel();
+ kgdb_active = 0;
+ return;
+
+ case 's':
+ kgdb_flush_cache_all();
+ regs->msr |= MSR_SE;
+ set_msr(msr | MSR_SE);
+ unlock_kernel();
+ kgdb_active = 0;
+ return;
+
+ case 'r': /* Reset (if user process..exit ???)*/
+ panic("kgdb reset.");
+ break;
+ } /* switch */
+ if (remcomOutBuffer[0] && kdebug) {
+ printk("remcomInBuffer: %s\n", remcomInBuffer);
+ printk("remcomOutBuffer: %s\n", remcomOutBuffer);
+ }
+ /* reply to the request */
+ putpacket(remcomOutBuffer);
+ } /* while(1) */
+}
+
+/* This function will generate a breakpoint exception. It is used at the
+ beginning of a program to sync up with a debugger and can be used
+ otherwise as a quick means to stop program execution and "break" into
+ the debugger. */
+
+void
+breakpoint(void)
+{
+ if (!initialized) {
+ printk("breakpoint() called b4 kgdb init\n");
+ return;
+ }
+
+ asm(" .globl breakinst
+ breakinst: trap
+ ");
+}
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 386bfe3ac..e1803a269 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -1,5 +1,5 @@
/*
- * $Id: ppc_htab.c,v 1.16 1997/11/17 18:25:04 cort Exp $
+ * $Id: ppc_htab.c,v 1.17 1998/03/14 07:52:49 cort Exp $
*
* PowerPC hash table management proc entry. Will show information
* about the current hash table and will allow changes to it.
@@ -12,6 +12,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
@@ -88,6 +89,7 @@ struct inode_operations proc_ppc_htab_inode_operations = {
#define PMC1 953
#define PMC2 954
+#ifndef CONFIG_8xx
char *pmc1_lookup(unsigned long mmcr0)
{
switch ( mmcr0 & (0x7f<<7) )
@@ -123,7 +125,7 @@ char *pmc2_lookup(unsigned long mmcr0)
return "unknown";
}
}
-
+#endif /* CONFIG_8xx */
/*
* print some useful info about the hash table. This function
@@ -133,6 +135,7 @@ char *pmc2_lookup(unsigned long mmcr0)
static ssize_t ppc_htab_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
+#ifndef CONFIG_8xx
unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
int n = 0, valid;
unsigned int kptes = 0, overflow = 0, uptes = 0, zombie_ptes = 0;
@@ -249,6 +252,9 @@ return_string:
copy_to_user(buf, buffer + *ppos, n);
*ppos += n;
return n;
+#else /* CONFIG_8xx */
+ return 0;
+#endif /* CONFIG_8xx */
}
/*
@@ -257,6 +263,7 @@ return_string:
static ssize_t ppc_htab_write(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
+#ifndef CONFIG_8xx
unsigned long tmp;
if ( current->uid != 0 )
return -EACCES;
@@ -493,6 +500,9 @@ static ssize_t ppc_htab_write(struct file * file, const char * buffer,
reset_SDR1();
#endif
return count;
+#else /* CONFIG_8xx */
+ return 0;
+#endif /* CONFIG_8xx */
}
@@ -512,4 +522,3 @@ ppc_htab_lseek(struct file * file, loff_t offset, int orig)
return(-EINVAL);
}
}
-
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 6ec6258ab..29df507d3 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -4,9 +4,7 @@
#include <linux/elfcore.h>
#include <linux/sched.h>
#include <linux/string.h>
-#include <linux/bios32.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
@@ -18,9 +16,11 @@
#include <asm/pgtable.h>
#include <asm/adb.h>
#include <asm/cuda.h>
+#include <asm/pmu.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/pci-bridge.h>
+#include <asm/irq.h>
extern void transfer_to_handler(void);
extern void int_return(void);
@@ -49,9 +49,13 @@ EXPORT_SYMBOL(sys_sigreturn);
EXPORT_SYMBOL(lost_interrupts);
EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(__ppc_bh_counter);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
-#if !defined(CONFIG_MACH_SPECIFIC)
+#if !defined(CONFIG_MACH_SPECIFIC) || defined(CONFIG_PMAC)
EXPORT_SYMBOL(isa_io_base);
+#endif
+#if !defined(CONFIG_MACH_SPECIFIC)
EXPORT_SYMBOL(pci_dram_offset);
#endif
@@ -114,11 +118,15 @@ EXPORT_SYMBOL(outw);
EXPORT_SYMBOL(outl);
EXPORT_SYMBOL(outsl);*/
+EXPORT_SYMBOL(_insb);
+EXPORT_SYMBOL(_outsb);
EXPORT_SYMBOL(_insw);
EXPORT_SYMBOL(_outsw);
EXPORT_SYMBOL(_insl);
EXPORT_SYMBOL(_outsl);
EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(start_thread);
@@ -140,6 +148,10 @@ EXPORT_SYMBOL(adb_autopoll);
EXPORT_SYMBOL(adb_register);
EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(cuda_poll);
+EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_send_request);
+EXPORT_SYMBOL(pmu_poll);
EXPORT_SYMBOL(abort);
EXPORT_SYMBOL(find_devices);
EXPORT_SYMBOL(find_type_devices);
@@ -148,7 +160,3 @@ EXPORT_SYMBOL(get_property);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(note_scsi_host);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index 193ded4df..999406200 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: prep_pci.c,v 1.12 1997/10/29 03:35:08 cort Exp $
+ * $Id: prep_pci.c,v 1.16 1998/02/23 02:47:32 davem Exp $
* PReP pci functions.
* Originally by Gary Thomas
* rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -8,7 +8,6 @@
*/
#include <linux/types.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -271,6 +270,12 @@ static char Nobis_pci_IRQ_routes[] = {
#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+/*
+ * FIXME: This code incorrectly assumes there's only bus #0, breaking all
+ * PCI-to-PCI bridges. Also multi-function devices are not supported
+ * at all. [mj]
+ */
+
int
prep_pcibios_read_config_dword (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned int *val)
@@ -319,16 +324,6 @@ prep_pcibios_read_config_byte (unsigned char bus,
unsigned char _val;
volatile unsigned char *ptr;
dev >>= 3;
- /* Note: the configuration registers don't always have this right! */
- if (offset == PCI_INTERRUPT_LINE)
- {
- *val = Motherboard_routes[Motherboard_map[dev]];
-/*printk("dev %d map %d route %d on board %d\n",
- dev,Motherboard_map[dev],
- Motherboard_routes[Motherboard_map[dev]],
- *(unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1)));*/
- return PCIBIOS_SUCCESSFUL;
- }
if ((bus != 0) || (dev > MAX_DEVNR))
{
*(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
@@ -406,7 +401,7 @@ __initfunc(unsigned long route_pci_interrupts(void))
int i;
if ( _prep_type == _PREP_Motorola)
- {
+ {
switch (inb(0x800) & 0xF0)
{
case 0x10: /* MVME16xx */
@@ -430,7 +425,6 @@ __initfunc(unsigned long route_pci_interrupts(void))
break;
case 0x40: /* PowerStack */
default: /* Can't hurt, can it? */
-
Motherboard_map_name = "Blackhawk (Powerstack)";
Motherboard_map = Blackhawk_pci_IRQ_map;
Motherboard_routes = Blackhawk_pci_IRQ_routes;
@@ -474,3 +468,4 @@ __initfunc(unsigned long route_pci_interrupts(void))
*ibc_pcicon |= 0x20;
return 0;
}
+
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index 0aee7cff4..5234435ca 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -80,8 +80,7 @@ prep_get_cpuinfo(char *buffer)
{
extern char *Motherboard_map_name;
extern RESIDUAL res;
- int i;
- int len;
+ int len, i;
#ifdef __SMP__
#define CD(X) (cpu_data[n].X)
@@ -93,7 +92,7 @@ prep_get_cpuinfo(char *buffer)
if ( res.ResidualLength == 0 )
return len;
-
+
/* print info about SIMMs */
len += sprintf(buffer+len,"simms\t\t: ");
for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
@@ -106,6 +105,7 @@ prep_get_cpuinfo(char *buffer)
}
len += sprintf(buffer+len,"\n");
+#if 0
/* TLB */
len += sprintf(buffer+len,"tlb\t\t:");
switch(res.VitalProductData.TLBAttrib)
@@ -123,7 +123,6 @@ prep_get_cpuinfo(char *buffer)
len += sprintf(buffer+len," not present\n");
break;
}
-
/* L1 */
len += sprintf(buffer+len,"l1\t\t: ");
switch(res.VitalProductData.CacheAttrib)
@@ -144,6 +143,7 @@ prep_get_cpuinfo(char *buffer)
len += sprintf(buffer+len,"not present\n");
break;
}
+#endif
/* L2 */
if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
@@ -201,7 +201,11 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
}
}
#endif
-
+ /* make the serial port the console */
+ /* strcat(cmd_line,"console=ttyS0,9600n8"); */
+ /* use the normal console but send output to the serial port, too */
+ /*strcat(cmd_line,"console=tty0 console=ttyS0,9600n8");*/
+ sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line);
printk("Boot arguments: %s\n", cmd_line);
#ifdef CONFIG_CS4232
@@ -256,9 +260,5 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
#ifdef CONFIG_VGA_CONSOLE
conswitchp = &vga_con;
#endif
-#ifdef CONFIG_FB
- /* Frame buffer device based console */
- conswitchp = &fb_con;
-#endif
#endif
}
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
index 4c3a91f91..3536eab43 100644
--- a/arch/ppc/kernel/prep_time.c
+++ b/arch/ppc/kernel/prep_time.c
@@ -220,7 +220,7 @@ static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
#ifdef CONFIG_HEARTBEAT
/* use hard disk LED as a heartbeat instead -- much more useful
for debugging -- Cort */
- switch(kstat.interrupts[0] % 101)
+ switch(kstat_irqs(0) % 101)
{
/* act like an actual heart beat -- ie thump-thump-pause... */
case 0:
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 7ffaf58c0..1c993bdc1 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,4 +1,3 @@
-
/*
* linux/arch/ppc/kernel/process.c
*
@@ -77,8 +76,13 @@ struct task_struct *current_set[NR_CPUS] = {&init_task, };
int
dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
+#ifdef __SMP__
+ if ( regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
if (last_task_used_math == current)
giveup_fpu();
+#endif
memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
return 1;
}
@@ -98,7 +102,7 @@ int check_stack(struct task_struct *tsk)
printk("tss.magic bad: %08x\n", tsk->tss.magic);
}
#endif
-
+
if ( !tsk )
printk("check_stack(): tsk bad tsk %p\n",tsk);
@@ -157,17 +161,21 @@ switch_to(struct task_struct *prev, struct task_struct *new)
#endif
#ifdef SHOW_TASK_SWITCHES
- printk("%s/%d -> %s/%d cpu %d\n",
+ printk("%s/%d -> %s/%d NIP %08lx cpu %d sfr %d lock %x\n",
prev->comm,prev->pid,
- new->comm,new->pid,new->processor);
+ new->comm,new->pid,new->tss.regs->nip,new->processor,
+ new->tss.smp_fork_ret,scheduler_lock.lock);
#endif
#ifdef __SMP__
- /* bad news if last_task_used_math changes processors right now -- Cort */
- if ( (last_task_used_math == new) &&
- (new->processor != new->last_processor) )
- panic("last_task_used_math switched processors");
+ /* avoid complexity of lazy save/restore of fpu
+ * by just saving it every time we switch out -- Cort
+ */
+ if ( prev->tss.regs->msr & MSR_FP )
+ smp_giveup_fpu(prev);
+
/* be noisy about processor changes for debugging -- Cort */
- if ( new->last_processor != new->processor )
+ if ( (new->last_processor != NO_PROC_ID) &&
+ (new->last_processor != new->processor) )
printk("switch_to(): changing cpu's %d -> %d %s/%d\n",
new->last_processor,new->processor,
new->comm,new->pid);
@@ -181,11 +189,6 @@ switch_to(struct task_struct *prev, struct task_struct *new)
_enable_interrupts(s);
}
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
- return 0;
-}
-
void show_regs(struct pt_regs * regs)
{
int i;
@@ -257,12 +260,11 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
((unsigned long)p + sizeof(union task_union)
- STACK_FRAME_OVERHEAD)) - 2;
*childregs = *regs;
-
if ((childregs->msr & MSR_PR) == 0)
childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
- p->tss.regs = childregs;
+ p->tss.regs = childregs;
if (usp >= (unsigned long) regs) {
/* Stack is in kernel space - must adjust */
childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -271,18 +273,28 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childregs->gpr[1] = usp;
}
p->tss.last_syscall = -1;
-
+
/*
* copy fpu info - assume lazy fpu switch now always
* -- Cort
*/
+#ifdef __SMP__
+ if ( regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
if ( last_task_used_math == current )
giveup_fpu();
+#endif
memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
+#ifdef __SMP__
+ if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
+ p->tss.smp_fork_ret = 1;
+ p->last_processor = NO_PROC_ID;
+#endif /* __SMP__ */
return 0;
}
@@ -337,20 +349,48 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
shove_aux_table(sp);
}
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
+{
+ unsigned long clone_flags = p1;
+ int res;
+ lock_kernel();
+ res = do_fork(clone_flags, regs->gpr[1], regs);
+ /*
+ * only parent returns here, child returns to either
+ * syscall_ret_1() or kernel_thread()
+ * -- Cort
+ */
+#ifdef __SMP__
+ /* When we clone the idle task we keep the same pid but
+ * the return value of 0 for both causes problems.
+ * -- Cort
+ */
+ if ((current->pid == 0) && (current == &init_task))
+ res = 1;
+#endif /* __SMP__ */
+ unlock_kernel();
+ return res;
+}
asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
- int ret;
+ int res;
lock_kernel();
- ret = do_fork(SIGCHLD, regs->gpr[1], regs);
-#if 0/*def __SMP__*/
- if ( ret ) /* drop scheduler lock in child */
- scheduler_lock.lock = 0L;
-#endif /* __SMP__ */
+ res = do_fork(SIGCHLD, regs->gpr[1], regs);
+ /* only parent returns here */
+#ifdef __SMP__
+ /* When we clone the idle task we keep the same pid but
+ * the return value of 0 for both causes problems.
+ * -- Cort
+ */
+ if ((current->pid == 0) && (current == &init_task))
+ res = 1;
+#endif /* __SMP__ */
unlock_kernel();
- return ret;
+ return res;
}
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
@@ -374,28 +414,6 @@ out:
return error;
}
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
- struct pt_regs *regs)
-{
- unsigned long clone_flags = p1;
- int res;
-
- lock_kernel();
- res = do_fork(clone_flags, regs->gpr[1], regs);
-#ifdef __SMP__
- /* When we clone the idle task we keep the same pid but
- * the return value of 0 for both causes problems.
- * -- Cort
- */
- if ((current->pid == 0) && (current == &init_task))
- res = 1;
- if ( 0 /*res*/ ) /* drop scheduler lock in child */
- scheduler_lock.lock = 0L;
-#endif /* __SMP__ */
- unlock_kernel();
- return res;
-}
-
void
print_backtrace(unsigned long *sp)
{
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index 121ffea73..0e656caa1 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -16,6 +16,8 @@
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
/*
* Properties whose value is longer than this get excluded from our
@@ -50,6 +52,19 @@ struct pci_range {
unsigned size_lo;
};
+struct isa_reg_property {
+ unsigned space;
+ unsigned address;
+ unsigned size;
+};
+
+typedef unsigned long interpret_func(struct device_node *, unsigned long);
+static interpret_func interpret_pci_props;
+static interpret_func interpret_dbdma_props;
+static interpret_func interpret_isa_props;
+static interpret_func interpret_macio_props;
+static interpret_func interpret_root_props;
+
char *prom_display_paths[FB_MAX] __initdata = { 0, };
unsigned int prom_num_displays = 0;
@@ -60,19 +75,21 @@ extern char *klimit;
char *bootpath = 0;
char *bootdevice = 0;
-unsigned int rtas_data = 0;
-unsigned int rtas_entry = 0;
+unsigned int rtas_data = 0; /* virtual pointer */
+unsigned int rtas_entry = 0; /* physical pointer */
+unsigned int rtas_size = 0;
+char chunk[PAGE_SIZE*64];
static struct device_node *allnodes = 0;
static void *call_prom(const char *service, int nargs, int nret, ...);
-static void prom_print(const char *msg);
+ void prom_print(const char *msg);
static void prom_exit(void);
static unsigned long copy_device_tree(unsigned long, unsigned long);
static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
unsigned long, struct device_node ***);
static unsigned long finish_node(struct device_node *, unsigned long,
- unsigned long);
+ interpret_func *);
static unsigned long check_display(unsigned long);
static int prom_next_node(phandle *);
@@ -119,6 +136,18 @@ prom_exit()
;
}
+void
+prom_enter(void)
+{
+ struct prom_args args;
+ unsigned long offset = reloc_offset();
+
+ args.service = RELOC("enter");
+ args.nargs = 0;
+ args.nret = 0;
+ RELOC(prom)(&args);
+}
+
static void *
call_prom(const char *service, int nargs, int nret, ...)
{
@@ -140,7 +169,7 @@ call_prom(const char *service, int nargs, int nret, ...)
return prom_args.args[nargs];
}
-static void
+void
prom_print(const char *msg)
{
const char *p, *q;
@@ -160,6 +189,11 @@ prom_print(const char *msg)
}
}
+
+#ifdef CONFIG_ALL_PPC
+unsigned char OF_type[16], OF_model[16];
+#endif
+
/*
* We enter here early on, when the Open Firmware prom is still
* handling exceptions and the MMU hash table for us.
@@ -169,11 +203,14 @@ prom_init(int r3, int r4, prom_entry pp)
{
unsigned long mem;
ihandle prom_rtas;
- unsigned int rtas_size;
unsigned long offset = reloc_offset();
int l;
char *p, *d;
+ /* check if we're prep, return if we are */
+ if ( *(unsigned long *)(0) == 0xdeadc0de )
+ return;
+
/* First get a handle for the stdout device */
RELOC(prom) = pp;
RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,
@@ -209,27 +246,57 @@ prom_init(int r3, int r4, prom_entry pp)
prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
if (prom_rtas != (void *) -1) {
- rtas_size = 0;
+ RELOC(rtas_size) = 0;
call_prom(RELOC("getprop"), 4, 1, prom_rtas,
- RELOC("rtas-size"), &rtas_size, sizeof(rtas_size));
+ RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size));
prom_print(RELOC("instantiating rtas..."));
- if (rtas_size == 0) {
+ if (RELOC(rtas_size) == 0) {
RELOC(rtas_data) = 0;
} else {
mem = (mem + 4095) & -4096; /* round to page bdry */
RELOC(rtas_data) = mem - KERNELBASE;
- mem += rtas_size;
+ mem += RELOC(rtas_size);
+ }
+ prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
+ RELOC(rtas_data) = ((ulong)chunk+4095)&-4096;
+ {
+ int i, nargs;
+ struct prom_args prom_args;
+ nargs = 3;
+ prom_args.service = RELOC("call-method");
+ prom_args.nargs = nargs;
+ prom_args.nret = 2;
+ prom_args.args[0] = RELOC("instantiate-rtas");
+ prom_args.args[1] = prom_rtas;
+ prom_args.args[2] = ((void *)RELOC(rtas_data)-KERNELBASE);
+ RELOC(prom)(&prom_args);
+ if (prom_args.args[nargs] != 0)
+ i = 0;
+ else
+ i = (int)prom_args.args[nargs+1];
+ RELOC(rtas_entry) = i;
}
- RELOC(rtas_entry) = (unsigned int)
- call_prom(RELOC("instantiate-rtas"), 1, 1,
- RELOC(rtas_data));
- if (RELOC(rtas_entry) == -1)
+ if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0))
prom_print(RELOC(" failed\n"));
else
prom_print(RELOC(" done\n"));
}
RELOC(klimit) = (char *) (mem - offset);
+#ifdef CONFIG_ALL_PPC
+ {
+
+ ihandle prom_root;
+
+ RELOC(prom_root) = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
+ call_prom(RELOC("getprop"), 4, 1, RELOC(prom_root),
+ RELOC("device_type"), RELOC(OF_type),
+ (void *) 16);
+ call_prom(RELOC("getprop"), 4, 1, RELOC(prom_root),
+ RELOC("model"), RELOC(OF_model),
+ (void *) 16);
+ }
+#endif
}
/*
@@ -397,12 +464,18 @@ inspect_node(phandle node, struct device_node *dad,
return mem_start;
}
+/*
+ * finish_device_tree is called once things are running normally
+ * (i.e. with text and data mapped to the address they were linked at).
+ * It traverses the device tree and fills in the name, type,
+ * {n_}addrs and {n_}intrs fields of each node.
+ */
void
finish_device_tree(void)
{
unsigned long mem = (unsigned long) klimit;
- mem = finish_node(allnodes, mem, 0UL);
+ mem = finish_node(allnodes, mem, NULL);
printk(KERN_INFO "device tree used %lu bytes\n",
mem - (unsigned long) allnodes);
klimit = (char *) mem;
@@ -410,23 +483,53 @@ finish_device_tree(void)
static unsigned long
finish_node(struct device_node *np, unsigned long mem_start,
- unsigned long base_address)
+ interpret_func *ifunc)
{
- struct reg_property *rp;
- struct pci_reg_property *pci_addrs;
- struct address_range *adr;
struct device_node *child;
- int i, l;
np->name = get_property(np, "name", 0);
np->type = get_property(np, "device_type", 0);
- /* get all the device addresses and interrupts */
- adr = (struct address_range *) mem_start;
+ /* get the device addresses and interrupts */
+ if (ifunc != NULL)
+ mem_start = ifunc(np, mem_start);
+
+ if (!strcmp(np->name, "device-tree"))
+ ifunc = interpret_root_props;
+ else if (np->type == 0)
+ ifunc = NULL;
+ else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
+ ifunc = interpret_pci_props;
+ else if (!strcmp(np->type, "dbdma")
+ || (ifunc == interpret_dbdma_props
+ && (!strcmp(np->type, "escc")
+ || !strcmp(np->type, "media-bay"))))
+ ifunc = interpret_dbdma_props;
+ else if (!strcmp(np->type, "mac-io"))
+ ifunc = interpret_macio_props;
+ else if (!strcmp(np->type, "isa"))
+ ifunc = interpret_isa_props;
+ else
+ ifunc = NULL;
+
+ for (child = np->child; child != NULL; child = child->sibling)
+ mem_start = finish_node(child, mem_start, ifunc);
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_pci_props(struct device_node *np, unsigned long mem_start)
+{
+ struct address_range *adr;
+ struct pci_reg_property *pci_addrs;
+ int i, l, *ip;
+
pci_addrs = (struct pci_reg_property *)
get_property(np, "assigned-addresses", &l);
- i = 0;
- if (pci_addrs != 0) {
+ if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
while ((l -= sizeof(struct pci_reg_property)) >= 0) {
/* XXX assumes PCI addresses mapped 1-1 to physical */
adr[i].space = pci_addrs[i].addr.a_hi;
@@ -434,36 +537,194 @@ finish_node(struct device_node *np, unsigned long mem_start,
adr[i].size = pci_addrs[i].size_lo;
++i;
}
- } else {
- rp = (struct reg_property *) get_property(np, "reg", &l);
- if (rp != 0) {
- while ((l -= sizeof(struct reg_property)) >= 0) {
- adr[i].space = 0;
- adr[i].address = rp[i].address + base_address;
- adr[i].size = rp[i].size;
- ++i;
- }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / sizeof(int);
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 0;
+ }
+ }
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_dbdma_props(struct device_node *np, unsigned long mem_start)
+{
+ struct reg_property *rp;
+ struct address_range *adr;
+ unsigned long base_address;
+ int i, l, *ip;
+ struct device_node *db;
+
+ base_address = 0;
+ for (db = np->parent; db != NULL; db = db->parent) {
+ if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
+ base_address = db->addrs[0].address;
+ break;
}
}
- if (i > 0) {
+
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = 0;
+ adr[i].address = rp[i].address + base_address;
+ adr[i].size = rp[i].size;
+ ++i;
+ }
np->addrs = adr;
np->n_addrs = i;
mem_start += i * sizeof(struct address_range);
}
- np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
- if (np->intrs == 0)
- np->intrs = (int *) get_property(np, "interrupts", &l);
- if (np->intrs != 0)
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
np->n_intrs = l / sizeof(int);
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 0;
+ }
+ }
- if (np->type != 0 && np->n_addrs > 0
- && (strcmp(np->type, "dbdma") == 0
- || strcmp(np->type, "mac-io") == 0))
- base_address = np->addrs[0].address;
+ return mem_start;
+}
- for (child = np->child; child != NULL; child = child->sibling)
- mem_start = finish_node(child, mem_start, base_address);
+static unsigned long
+interpret_macio_props(struct device_node *np, unsigned long mem_start)
+{
+ struct reg_property *rp;
+ struct address_range *adr;
+ unsigned long base_address;
+ int i, l, *ip;
+ struct device_node *db;
+
+ base_address = 0;
+ for (db = np->parent; db != NULL; db = db->parent) {
+ if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
+ base_address = db->addrs[0].address;
+ break;
+ }
+ }
+
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = 0;
+ adr[i].address = rp[i].address + base_address;
+ adr[i].size = rp[i].size;
+ ++i;
+ }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / (2 * sizeof(int));
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = openpic_to_irq(*ip++);
+ np->intrs[i].sense = *ip++;
+ }
+ }
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_isa_props(struct device_node *np, unsigned long mem_start)
+{
+ struct isa_reg_property *rp;
+ struct address_range *adr;
+ int i, l, *ip;
+
+ rp = (struct isa_reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = rp[i].space;
+ adr[i].address = rp[i].address
+ + (adr[i].space? 0: _ISA_MEM_BASE);
+ adr[i].size = rp[i].size;
+ ++i;
+ }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / (2 * sizeof(int));
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = *ip++;
+ }
+ }
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_root_props(struct device_node *np, unsigned long mem_start)
+{
+ struct reg_property *rp;
+ struct address_range *adr;
+ int i, l, *ip;
+
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = 0;
+ adr[i].address = rp[i].address;
+ adr[i].size = rp[i].size;
+ ++i;
+ }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / sizeof(int);
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 0;
+ }
+ }
return mem_start;
}
@@ -648,14 +909,14 @@ call_rtas(const char *service, int nargs, int nret,
printk(KERN_ERR "No RTAS service called %s\n", service);
return -1;
}
- u.words[0] = *tokp;
+ u.words[0] = __pa(*tokp);
u.words[1] = nargs;
u.words[2] = nret;
va_start(list, outputs);
for (i = 0; i < nargs; ++i)
u.words[i+3] = va_arg(list, unsigned long);
va_end(list);
- enter_rtas(&u);
+ enter_rtas((void *)__pa(&u));
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret-1; ++i)
outputs[i] = u.words[i+nargs+4];
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index 4f6068c6d..ce2f35058 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -390,8 +390,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
tmp = get_reg(child, addr);
}
else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
+#ifdef __SMP__
+ if (child->tss.regs->msr & MSR_FP )
+ smp_giveup_fpu(child);
+#else
+ /* only current can be last task to use math on SMP */
if (last_task_used_math == child)
giveup_fpu();
+#endif
tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
}
else
@@ -423,8 +429,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
}
if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+#ifndef __SMP__
+ if (child->tss.regs->msr & MSR_FP )
+ smp_giveup_fpu(child);
+#else
if (last_task_used_math == child)
giveup_fpu();
+#endif
((long *)child->tss.fpr)[addr - PT_FPR0] = data;
ret = 0;
goto out;
diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c
index fdf62e921..b5516d0e5 100644
--- a/arch/ppc/kernel/residual.c
+++ b/arch/ppc/kernel/residual.c
@@ -1,5 +1,5 @@
/*
- * $Id: residual.c,v 1.5 1997/10/30 21:25:19 cort Exp $
+ * $Id: residual.c,v 1.7 1998/03/08 05:49:20 davem Exp $
*
* Code to deal with the PReP residual data.
*
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 86407e273..bdf05af76 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: setup.c,v 1.48 1998/01/01 10:04:44 paulus Exp $
+ * $Id: setup.c,v 1.68 1998/04/07 08:20:33 geert Exp $
* Common prep/pmac/chrp boot and setup code.
*/
@@ -13,10 +13,26 @@
#include <asm/adb.h>
#include <asm/cuda.h>
+#include <asm/pmu.h>
#include <asm/residual.h>
#include <asm/io.h>
#include <asm/ide.h>
#include <asm/prom.h>
+#include <asm/processor.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
+/* ifdef APUS specific stuff until the merge is completed. -jskov */
+#ifdef CONFIG_APUS
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigappc.h>
+extern unsigned long m68k_machtype;
+extern void amiga_reset (void);
+extern struct mem_info m68k_ramdisk;
+extern int m68k_parse_bootinfo(const struct bi_record *);
+extern char _end[];
+#endif
extern char cmd_line[512];
char saved_command_line[256];
@@ -26,13 +42,13 @@ unsigned char aux_device_present;
unsigned long ISA_DMA_THRESHOLD;
unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
int _machine;
+/* if we have openfirmware */
+unsigned long have_of;
#endif /* ! CONFIG_MACH_SPECIFIC */
/* copy of the residual data */
RESIDUAL res;
int _prep_type;
-/* if we have openfirmware */
-unsigned long have_of;
/*
* Perhaps we can put the pmac screen_info[] here
@@ -40,6 +56,7 @@ unsigned long have_of;
* Until we get multiple-console support in here
* that is. -- Cort
*/
+#ifndef CONFIG_MBX
#if !defined(CONFIG_PMAC_CONSOLE)
struct screen_info screen_info = {
0, 25, /* orig-x, orig-y */
@@ -65,29 +82,66 @@ void pmac_find_display(void)
}
#endif
+#else /* CONFIG_MBX */
+
+/* We need this to satisfy some external references until we can
+ * strip the kernel down.
+ */
+struct screen_info screen_info = {
+ 0, 25, /* orig-x, orig-y */
+ { 0, 0 }, /* unused */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 80, /* orig-video-cols */
+ 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 25, /* orig-video-lines */
+ 0, /* orig-video-isVGA */
+ 16 /* orig-video-points */
+};
+#endif /* CONFIG_MBX */
+
/* cmd is ignored for now... */
void machine_restart(char *cmd)
{
struct adb_request req;
unsigned long flags;
unsigned long i = 10000;
-#if 0
+#if 0
int err;
#endif
switch(_machine)
{
case _MACH_Pmac:
- cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
- for (;;)
- cuda_poll();
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ break;
+ case ADB_VIAPMU:
+ pmu_request(&req, NULL, 1, PMU_RESET);
+ for (;;)
+ pmu_poll();
+ break;
+ default:
+ }
break;
+
case _MACH_chrp:
#if 0 /* RTAS doesn't seem to work on Longtrail.
For now, do it the same way as the PReP. */
- err = call_rtas("system-reboot", 0, 1, NULL);
+ /*err = call_rtas("system-reboot", 0, 1, NULL);
printk("RTAS system-reboot returned %d\n", err);
- for (;;);
+ for (;;);*/
+
+ {
+ extern unsigned int rtas_entry, rtas_data, rtas_size;
+ unsigned long status, value;
+ printk("rtas_entry: %08x rtas_data: %08x rtas_size: %08x\n",
+ rtas_entry,rtas_data,rtas_size);
+ }
#endif
case _MACH_prep:
_disable_interrupts();
@@ -104,6 +158,23 @@ void machine_restart(char *cmd)
while ( i != 0 ) i++;
panic("restart failed\n");
break;
+ case _MACH_apus:
+ cli();
+ /* APUS:FIXME: Reset the system. Apparently there's
+ * more magic to it than this!?!?
+ */
+#if 0
+ APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+ APUS_WRITE(APUS_REG_RESET,
+ REGRESET_PPCRESET|REGRESET_M68KRESET|
+ REGRESET_AMIGARESET|REGRESET_AUXRESET|
+ REGRESET_SCSIRESET);
+#endif
+ printk("\n**************************************\n");
+ printk("*** You can make a hard reset now! ***\n");
+ printk("**************************************\n");
+ for(;;);
+ break;
}
}
@@ -116,9 +187,23 @@ void machine_power_off(void)
switch (_machine) {
case _MACH_Pmac:
- cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
- for (;;)
- cuda_poll();
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ break;
+ case ADB_VIAPMU:
+ pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
+ 'M', 'A', 'T', 'T');
+ for (;;)
+ pmu_poll();
+ break;
+ default:
+ }
+ break;
+
case _MACH_chrp:
#if 0 /* RTAS doesn't seem to work on Longtrail.
For now, do it the same way as the PReP. */
@@ -126,9 +211,19 @@ void machine_power_off(void)
printk("RTAS system-reboot returned %d\n", err);
for (;;);
#endif
+
case _MACH_prep:
machine_restart(NULL);
+#ifdef CONFIG_APUS
+ case _MACH_apus:
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+ apm_set_power_state(APM_STATE_OFF);
+ for (;;);
+#endif
+#endif
}
+ for (;;)
+ ;
}
void machine_halt(void)
@@ -141,18 +236,90 @@ void machine_halt(void)
machine_power_off(); /* for now */
#endif
}
- else /* prep or chrp */
+ else /* prep, chrp or apus */
machine_restart(NULL);
}
+#ifdef CONFIG_BLK_DEV_IDE
void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
{
- if ( _machine == _MACH_Pmac )
+ switch (_machine) {
+ case _MACH_Pmac:
pmac_ide_init_hwif_ports(p,base,irq);
- else /* prep or chrp */
+ break;
+ case _MACH_chrp:
+ chrp_ide_init_hwif_ports(p,base,irq);
+ break;
+ case _MACH_prep:
prep_ide_init_hwif_ports(p,base,irq);
+ break;
+ }
+}
+#endif
+
+unsigned long cpu_temp(void)
+{
+ unsigned long i, temp, thrm1, dir;
+ int sanity;
+ /*
+ * setup thrm3 - need to give TAU at least 20us
+ * to do the compare so assume a 300MHz clock.
+ * We need 300*20 ticks then.
+ * -- Cort
+ */
+ asm("mtspr 1020, %1\n\t"
+ "mtspr 1021, %1\n\t"
+ "mtspr 1022, %0\n\t"::
+ "r" ( ((300*20)<<18) | THRM3_E), "r" (0) );
+
+#if 0
+ for ( i = 127 ; i >= 0 ; i-- )
+ {
+ asm("mtspr 1020, %0\n\t"::
+ "r" (THRM1_TID|THRM1_V|(i<<2)) );
+ /* check value */
+ while ( !( thrm1 & THRM1_TIV) )
+ asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );
+ if ( thrm1 & THRM1_TIN )
+ {
+ printk("tin set: %x tiv %x\n", thrm1,thrm1&THRM1_TIV);
+ goto out;
+ }
+
+ }
+#endif
+#if 0
+ i = 32; /* increment */
+ dir = 1; /* direction we're checking 0=up 1=down */
+ temp = 64; /* threshold checking against */
+ while ( i )
+ {
+ _set_THRM1((1<<29) | THRM1_V | (temp<<2) );
+ printk("checking %d in dir %d thrm set to %x/%x\n", temp,dir,
+ ( (1<<29) | THRM1_V | (temp<<2)),_get_THRM1());
+ /* check value */
+ sanity = 0x0fffffff;
+ while ( (!( thrm1 & THRM1_TIV)) && (sanity--) )
+ thrm1 = _get_THRM1();
+ /*asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );*/
+ if ( ! sanity || sanity==0xffffffff ) printk("no sanity\n");
+ /* temp is not in that direction */
+ if ( !(thrm1 & THRM1_TIN) )
+ {
+ printk("not in that dir thrm1 %x\n",thrm1);
+ if ( dir == 0 ) dir = 1;
+ else dir = 0;
+ }
+ if ( dir ) temp -= i;
+ else temp += i;
+ i /= 2;
+ }
+ asm("mtspr 1020, %0\n\t"
+ "mtspr 1022, %0\n\t" ::"r" (0) );
+#endif
+ return temp;
}
int get_cpuinfo(char *buffer)
@@ -160,9 +327,11 @@ int get_cpuinfo(char *buffer)
extern int pmac_get_cpuinfo(char *);
extern int chrp_get_cpuinfo(char *);
extern int prep_get_cpuinfo(char *);
+ extern int apus_get_cpuinfo(char *);
unsigned long len = 0;
unsigned long bogosum = 0;
unsigned long i;
+ unsigned long cr;
#ifdef __SMP__
extern unsigned long cpu_present_map;
extern struct cpuinfo_PPC cpu_data[NR_CPUS];
@@ -202,7 +371,18 @@ int get_cpuinfo(char *buffer)
len += sprintf(len+buffer, "603ev\n");
break;
case 8:
- len += sprintf(len+buffer, "750 (Arthur)\n");
+ len += sprintf(len+buffer,"750\n");
+ cr = _get_L2CR();
+ len += sprintf(len+buffer,"L2CR\t\t: %lx\n",cr);
+ if ( cr & (0x1<<1)) cr = 256;
+ else if ( cr & (0x2<<1)) cr = 512;
+ else if ( cr & (0x3<<1)) cr = 1024;
+ else cr = 0;
+ len += sprintf(len+buffer,"on-chip l2\t: "
+ "%ld KB (%s)\n",
+ cr,(_get_L2CR()&1) ? "on" : "off");
+ len += sprintf(len+buffer,"temperature \t: %lu C\n",
+ cpu_temp());
break;
case 9:
len += sprintf(len+buffer, "604e\n");
@@ -216,6 +396,7 @@ int get_cpuinfo(char *buffer)
break;
}
+
/*
* Assume here that all clock rates are the same in a
* smp system. -- Cort
@@ -290,6 +471,11 @@ int get_cpuinfo(char *buffer)
case _MACH_chrp:
len += chrp_get_cpuinfo(buffer+len);
break;
+#ifdef CONFIG_APUS
+ case _MACH_apus:
+ len += apus_get_cpuinfo(buffer+len);
+ break;
+#endif
}
return len;
}
@@ -302,43 +488,63 @@ __initfunc(unsigned long
identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7))
{
- extern unsigned long initrd_start, initrd_end;
extern setup_pci_ptrs(void);
- unsigned long boot_sdr1;
- ihandle prom_root;
- unsigned char type[16], model[16];
-
- asm("mfspr %0,25\n\t" :"=r" (boot_sdr1));
+#ifndef CONFIG_MBX8xx
- /*
- * if we have a sdr1 then we have openfirmware
- * and can ask it what machine we are (chrp/pmac/prep).
- * otherwise we're definitely prep. -- Cort
- */
- if ( !boot_sdr1 )
+#ifdef CONFIG_APUS
+ if ( r3 == 0x61707573 )
{
- /* we know for certain we're prep if no OF */
+ /* Parse bootinfo. The bootinfo is located right after
+ the kernel bss */
+ m68k_parse_bootinfo((const struct bi_record *)&_end);
+
have_of = 0;
- /* make a copy of residual data */
- if ( r3 )
- memcpy((void *)&res,(void *)(r3+KERNELBASE),
- sizeof(RESIDUAL));
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* Take care of initrd if we have one. Use data from
+ bootinfo to avoid the need to initialize PPC
+ registers when kernel is booted via a PPC reset. */
+ if ( m68k_ramdisk.addr ) {
+ initrd_start = (unsigned long) __va(m68k_ramdisk.addr);
+ initrd_end = (unsigned long)
+ __va(m68k_ramdisk.size + m68k_ramdisk.addr);
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ return 0;
+ }
+#endif
+
#ifndef CONFIG_MACH_SPECIFIC
+ /* prep boot loader tells us if we're prep or not */
+ if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
+ {
_machine = _MACH_prep;
-#endif /* CONFIG_MACH_SPECIFIC */
+ have_of = 0;
+ } else
+ {
+ /* need to ask OF if we're chrp or pmac */
+ extern unsigned char OF_type[16], OF_model[16];
+ prom_print(OF_type);
+ prom_print(OF_model);
+ if ( !strncmp("chrp", OF_type,4) )
+ {
+ _machine = _MACH_chrp;
+ }
+ else
+ {
+ /*if ( !strncmp("Power Macintosh", type,15) )*/
+ _machine = _MACH_Pmac;
+ }
+ _machine = _MACH_Pmac;
+
}
- else
+#endif /* CONFIG_MACH_SPECIFIC */
+
+ if ( have_of )
{
- /*
- * init prom here, then ask the openfirmware
- * what machine we are (prep/chrp/pmac). We don't use
- * OF on prep just yet. -- Cort
- */
-#ifndef CONFIG_PREP /* don't use OF on prep yet */
- have_of = 1;
/* prom_init has already been called from __start */
finish_device_tree();
-
/*
* If we were booted via quik, r3 points to the physical
* address of the command-line parameters.
@@ -356,7 +562,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
} else {
struct device_node *chosen;
char *p;
-
+
#ifdef CONFIG_BLK_DEV_INITRD
if (r3 - KERNELBASE < 0x800000
&& r4 != 0 && r4 != 0xdeadbeef) {
@@ -365,7 +571,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
}
#endif
- chosen = find_path_device("/chosen");
+ chosen = find_devices("chosen");
if (chosen != NULL) {
p = get_property(chosen, "bootargs", NULL);
if (p != NULL)
@@ -373,47 +579,18 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
}
}
cmd_line[sizeof(cmd_line) - 1] = 0;
-#endif /* CONFIG_PREP */
-
-#ifndef CONFIG_MACH_SPECIFIC
-#if 0
- prom_root = call_prom("finddevice", 1, 1, "/");
- call_prom("getprop", 4, 1, prom_root, "device_type", &type,
- (void *) sizeof(type));
- call_prom("getprop", 4, 1, prom_root, "model", &type,
- (void *) sizeof(model));
- if ( !strncmp("chrp", type,4) )
- {
- _machine = _MACH_chrp;
- }
- else
- {
- /*if ( !strncmp("Power Macintosh", type,15) )*/
- _machine = _MACH_Pmac;
- }
-#else
-
-#ifdef CONFIG_CHRP
- _machine = _MACH_chrp;
-#endif /* CONFIG_CHRP */
-#ifdef CONFIG_PMAC
- _machine = _MACH_Pmac;
-#endif /* CONFIG_PMAC */
-#ifdef CONFIG_PREP
- _machine = _MACH_Prep;
-#endif /* CONFIG_PREP */
-#endif /* #if */
-#endif /* CONFIG_MACH_SPECIFIC */
}
+#ifdef CONFIG_PCI
/* so that pmac/chrp can use pci to find its console -- Cort */
setup_pci_ptrs();
-
+#endif
+
switch (_machine)
{
case _MACH_Pmac:
#if !defined(CONFIG_MACH_SPECIFIC)
- isa_io_base = PMAC_ISA_IO_BASE;
+ /* isa_io_base gets set in pmac_find_bridges */
isa_mem_base = PMAC_ISA_MEM_BASE;
pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
ISA_DMA_THRESHOLD = ~0L;
@@ -422,6 +599,10 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
#endif /* ! CONFIG_MACH_SPECIFIC */
break;
case _MACH_prep:
+ /* make a copy of residual data */
+ if ( r3 )
+ memcpy((void *)&res,(void *)(r3+KERNELBASE),
+ sizeof(RESIDUAL));
#if !defined(CONFIG_MACH_SPECIFIC)
isa_io_base = PREP_ISA_IO_BASE;
isa_mem_base = PREP_ISA_MEM_BASE;
@@ -434,13 +615,12 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
if ( res.ResidualLength != 0 )
{
if ( !strncmp(res.VitalProductData.PrintableModel,"IBM",3) )
- _prep_type = 0x00;
+ _prep_type = _PREP_IBM;
else
- _prep_type = 0x01;
+ _prep_type = _PREP_Motorola;
}
else /* assume motorola if no residual (netboot?) */
_prep_type = _PREP_Motorola;
-
#ifdef CONFIG_BLK_DEV_RAM
/* take care of initrd if we have one */
if ( r4 )
@@ -457,7 +637,14 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
}
break;
case _MACH_chrp:
- /* LongTrail */
+#ifdef CONFIG_BLK_DEV_RAM
+ /* take care of initrd if we have one */
+ if ( r3 )
+ {
+ initrd_start = r3 + KERNELBASE;
+ initrd_end = r3+ r4 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_RAM */
#if !defined(CONFIG_MACH_SPECIFIC)
isa_io_base = CHRP_ISA_IO_BASE;
isa_mem_base = CHRP_ISA_MEM_BASE;
@@ -470,13 +657,33 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
default:
printk("Unknown machine type in identify_machine!\n");
}
- return 0;
-}
+#else /* CONFIG_MBX8xx */
+ extern setup_pci_ptrs(void);
-__initfunc(unsigned long
-bios32_init(unsigned long memory_start, unsigned long memory_end))
-{
- return memory_start;
+ if ( r3 )
+ memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+
+ setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_RAM
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_RAM */
+ /* take care of cmd line */
+ if ( r6 )
+ {
+
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+#endif /* CONFIG_MBX */
+
+ return 0;
}
__initfunc(void setup_arch(char **cmdline_p,
@@ -485,12 +692,18 @@ __initfunc(void setup_arch(char **cmdline_p,
extern void pmac_setup_arch(unsigned long *, unsigned long *);
extern void chrp_setup_arch(unsigned long *, unsigned long *);
extern void prep_setup_arch(unsigned long *, unsigned long *);
+ extern void apus_setup_arch(char **, unsigned long *, unsigned long *);
extern int panic_timeout;
extern char _etext[], _edata[];
extern char *klimit;
extern unsigned long find_available_memory(void);
extern unsigned long *end_of_DRAM;
+#ifdef CONFIG_XMON
+ extern void xmon_map_scc(void);
+ xmon_map_scc();
+#endif /* CONFIG_XMON */
+
/* reboot on panic */
panic_timeout = 180;
@@ -516,6 +729,12 @@ __initfunc(void setup_arch(char **cmdline_p,
case _MACH_chrp:
chrp_setup_arch(memory_start_p, memory_end_p);
break;
+#ifdef CONFIG_APUS
+ case _MACH_apus:
+ m68k_machtype = MACH_AMIGA;
+ apus_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+#endif
default:
printk("Unknown machine %d in setup_arch()\n", _machine);
}
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index ae6d3c5aa..1c977bb51 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -201,8 +201,13 @@ int sys_sigreturn(struct pt_regs *regs)
if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
/* Last stacked signal - restore registers */
sr = (struct sigregs *) sigctx.regs;
+#ifdef __SMP__
+ if ( regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
if (last_task_used_math == current)
giveup_fpu();
+#endif
if (copy_from_user(saved_regs, &sr->gp_regs,
sizeof(sr->gp_regs)))
goto badframe;
@@ -249,8 +254,13 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame,
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto badframe;
- if (last_task_used_math == current)
- giveup_fpu();
+#ifdef __SMP__
+ if ( regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
+ if (last_task_used_math == current)
+ giveup_fpu();
+#endif
if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
|| __copy_to_user(&frame->fp_regs, current->tss.fpr,
ELF_NFPREG * sizeof(double))
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 33d3a23b4..217e695f8 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -1,5 +1,5 @@
/*
- * $Id: smp.c,v 1.8 1998/01/06 06:44:57 cort Exp $
+ * $Id: smp.c,v 1.22 1998/04/10 01:53:34 cort Exp $
*
* Smp support for ppc.
*
@@ -30,22 +30,27 @@
#include <asm/init.h>
#include <asm/io.h>
+#include "time.h"
+
int smp_threads_ready = 0;
volatile int smp_commenced = 0;
int smp_num_cpus = 1;
unsigned long cpu_present_map = 0;
volatile int cpu_number_map[NR_CPUS];
volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+volatile int __cpu_logical_map[NR_CPUS];
static unsigned char boot_cpu_id = 0;
struct cpuinfo_PPC cpu_data[NR_CPUS];
-struct klock_info klock_info = { KLOCK_CLEAR, 0 };
+struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */
-volatile unsigned long hash_table_lock;
+volatile unsigned long ipi_count;
+
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
int start_secondary(void *);
-extern void init_IRQ(void);
extern int cpu_idle(void *unused);
void smp_boot_cpus(void)
@@ -56,49 +61,75 @@ void smp_boot_cpus(void)
struct task_struct *p;
printk("Entering SMP Mode...\n");
+
+ for (i = 0; i < NR_CPUS; i++) {
+ cpu_number_map[i] = -1;
+ prof_counter[i] = 1;
+ prof_multiplier[i] = 1;
+ }
+
cpu_present_map = 0;
for(i=0; i < NR_CPUS; i++)
- cpu_number_map[i] = -1;
+ __cpu_logical_map[i] = -1;
smp_store_cpu_info(boot_cpu_id);
active_kernel_processor = boot_cpu_id;
current->processor = boot_cpu_id;
-
cpu_present_map |= 1;
+ cpu_number_map[boot_cpu_id] = 0;
+ __cpu_logical_map[0] = boot_cpu_id;
+
+ if ( _machine != _MACH_Pmac )
+ {
+ printk("SMP not supported on this machine.\n");
+ return;
+ }
+
/* assume a 2nd processor for now */
cpu_present_map |= (1 << 1);
smp_num_cpus = 2;
- cpu_number_map[boot_cpu_id] = 0;
/* create a process for second processor */
kernel_thread(start_secondary, NULL, CLONE_PID);
- cpu_number_map[1] = 1;
p = task[1];
if ( !p )
panic("No idle task for secondary processor\n");
p->processor = 1;
current_set[1] = p;
+ /* need to flush here since secondary bat's aren't setup */
+ dcbf((volatile unsigned long *)&current_set[1]);
+
/* setup entry point of secondary processor */
*(volatile unsigned long *)(0xf2800000)
= (unsigned long)secondary_entry-KERNELBASE;
- /* interrupt secondary to begin executing code */
eieio();
- *(volatile unsigned long *)(0xf80000c0) = 0;
+ /* interrupt secondary to begin executing code */
+ *(volatile unsigned long *)(0xf80000c0) = 0L;
eieio();
/* wait to see if the secondary made a callin (is actually up) */
- for ( timeout = 0; timeout < 1500 ; timeout++ )
+ for ( timeout = 0; timeout < 15000 ; timeout++ )
+ {
+ if(cpu_callin_map[1])
+ break;
udelay(100);
+ }
if(cpu_callin_map[1]) {
cpu_number_map[1] = 1;
+ __cpu_logical_map[i] = 1;
printk("Processor 1 found.\n");
+
+#if 0 /* this sync's the decr's */
+ set_dec(decrementer_count);
+#endif
+ /* interrupt secondary to sync the time bases */
+ smp_message_pass(1,0xf0f0, 0, 0);
+ /* interrupt secondary to begin executing code */
+ /**(volatile unsigned long *)(0xf80000c0) = 0L;
+ eieio();*/
} else {
smp_num_cpus--;
printk("Processor %d is stuck.\n", 1);
}
-{
- extern unsigned long amhere;
- printk("amhere: %x\n", amhere);
-}
}
void smp_commence(void)
@@ -128,16 +159,15 @@ int start_secondary(void *unused)
void smp_callin(void)
{
printk("SMP %d: smp_callin()\n",current->processor);
- /*calibrate_delay();*/
smp_store_cpu_info(1);
-
- /* assume we're just the secondary processor for now */
- cpu_callin_map[1] = 1;
- dcbf(&cpu_callin_map[1]);
+ set_dec(decrementer_count);
current->mm->mmap->vm_page_prot = PAGE_SHARED;
current->mm->mmap->vm_start = PAGE_OFFSET;
current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+
+ /* assume we're just the secondary processor for now */
+ cpu_callin_map[1] = 1;
while(!smp_commenced)
barrier();
@@ -149,21 +179,120 @@ void smp_setup(char *str, int *ints)
printk("SMP %d: smp_setup()\n",current->processor);
}
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+void smp_local_timer_interrupt(struct pt_regs * regs)
{
- printk("SMP %d: sending smp message\n",current->processor);
-#if 0
- if ( smp_processor_id() == 0 )
+ int cpu = smp_processor_id();
+ extern void update_one_process(struct task_struct *,unsigned long,
+ unsigned long,unsigned long,int);
+
+ if (!--prof_counter[cpu]) {
+ int user=0,system=0;
+ struct task_struct * p = current;
+
+ /*
+ * After doing the above, we need to make like
+ * a normal interrupt - otherwise timer interrupts
+ * ignore the global interrupt lock, which is the
+ * WrongThing (tm) to do.
+ */
+
+ if (user_mode(regs))
+ user=1;
+ else
+ system=1;
+
+ if (p->pid) {
+ update_one_process(p, 1, user, system, cpu);
+
+ p->counter -= 1;
+ if (p->counter < 0) {
+ p->counter = 0;
+ need_resched = 1;
+ }
+ if (p->priority < DEF_PRIORITY) {
+ kstat.cpu_nice += user;
+ kstat.per_cpu_nice[cpu] += user;
+ } else {
+ kstat.cpu_user += user;
+ kstat.per_cpu_user[cpu] += user;
+ }
+
+ kstat.cpu_system += system;
+ kstat.per_cpu_system[cpu] += system;
+
+ }
+ prof_counter[cpu]=prof_multiplier[cpu];
+ }
+}
+
+/*
+ * Dirty hack to get smp message passing working.
+ * Right now it only works for stop cpu's but will be setup
+ * later for more general message passing.
+ *
+ * As it is now, if we're sending two message as the same time
+ * we have race conditions. I avoided doing locks here since
+ * all that works right now is the stop cpu message.
+ *
+ * -- Cort
+ */
+int smp_message[NR_CPUS];
+void smp_message_recv(void)
+{
+ int msg = smp_message[smp_processor_id()];
+
+ printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);
+
+ /* make sure msg is for us */
+ if ( msg == -1 ) return;
+printk("recv after msg check\n");
+ switch( msg )
{
- /* interrupt secondary */
- *(volatile unsigned long *)(0xf80000c0) = 0;
+ case MSG_STOP_CPU:
+ __cli();
+ while (1) ;
+ break;
+ case 0xf0f0: /* syncing time bases - just return */
+ break;
+ default:
+ printk("SMP %d: smp_message_recv(): unknown msg %d\n",
+ smp_processor_id(), msg);
+ break;
}
- else
+ /* reset message */
+ smp_message[smp_processor_id()] = -1;
+}
+
+spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ printk("SMP %d: sending smp message\n", current->processor);
+
+ spin_lock(&mesg_pass_lock);
+ if ( _machine != _MACH_Pmac )
+ return;
+
+#define OTHER (~smp_processor_id() & 1)
+
+ switch( target )
{
- /* interrupt primary */
- *(volatile unsigned long *)(0xf3019000);
+ case MSG_ALL:
+ smp_message[smp_processor_id()] = msg;
+ /* fall through */
+ case MSG_ALL_BUT_SELF:
+ smp_message[OTHER] = msg;
+ break;
+ default:
+ smp_message[target] = msg;
+ break;
}
-#endif
+ /* interrupt secondary processor */
+ /**(volatile unsigned long *)(0xf80000c0) = 0xffffffff;
+ eieio();*/
+ *(volatile unsigned long *)(0xf80000c0) = 0;
+ /* interrupt primary */
+ /**(volatile unsigned long *)(0xf3019000);*/
+ spin_unlock(&mesg_pass_lock);
}
int setup_profiling_timer(unsigned int multiplier)
diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c
new file mode 100644
index 000000000..dedf24806
--- /dev/null
+++ b/arch/ppc/kernel/softemu8xx.c
@@ -0,0 +1,96 @@
+/*
+ * Software emulation of some PPC instructions for the 8xx core.
+ *
+ * Copyright (C) 1998 Dan Malek (dmalek@jlc.net)
+ *
+ * Software floating emuation for the MPC8xx processor. I did this mostly
+ * because it was easier than trying to get the libraries compiled for
+ * software floating point. The goal is still to get the libraries done,
+ * but I lost patience and needed some hacks to at least get init and
+ * shells running. The first problem is the setjmp/longjmp that save
+ * and restore the floating point registers.
+ *
+ * For this emulation, our working registers are found on the register
+ * save area.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+/* Eventually we may need a look-up table, but this works for now.
+*/
+#define LFD 50
+#define LFDU 51
+#define STFD 54
+#define STFDU 55
+
+/*
+ * We return 0 on success, 1 on unimplemented instruction, and EFAULT
+ * if a load/store faulted.
+ */
+int
+Soft_emulate_8xx(struct pt_regs *regs)
+{
+ uint inst, instword;
+ uint flreg, idxreg, disp;
+ uint retval;
+ uint *ea, *ip;
+
+ retval = 0;
+
+ instword = *((uint *)regs->nip);
+ inst = instword >> 26;
+
+ flreg = (instword >> 21) & 0x1f;
+ idxreg = (instword >> 16) & 0x1f;
+ disp = instword & 0xffff;
+
+ ea = (uint *)(regs->gpr[idxreg] + disp);
+ ip = (uint *)&current->tss.fpr[flreg];
+
+ if (inst == LFD) {
+ if (copy_from_user(ip, ea, sizeof(double)))
+ retval = EFAULT;
+ }
+ else if (inst == LFDU) {
+
+ if (copy_from_user(ip, ea, sizeof(double)))
+ retval = EFAULT;
+ else
+ regs->gpr[idxreg] = (uint)ea;
+ }
+ else if (inst == STFD) {
+
+ if (copy_to_user(ea, ip, sizeof(double)))
+ retval = EFAULT;
+ }
+ else if (inst == STFDU) {
+
+ if (copy_to_user(ea, ip, sizeof(double)))
+ retval = EFAULT;
+ else
+ regs->gpr[idxreg] = (uint)ea;
+ }
+ else {
+ retval = 1;
+ }
+
+ if (retval == 0)
+ regs->nip += 4;
+ return(retval);
+}
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 319db15de..5a1063d4e 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,11 +1,25 @@
/*
- * $Id: time.c,v 1.17 1997/12/28 22:47:21 paulus Exp $
+ * $Id: time.c,v 1.28 1998/04/07 18:49:49 cort Exp $
* Common time routines among all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
* Paul Mackerras' version and mine for PReP and Pmac.
+ * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net).
+ *
+ * Since the MPC8xx has a programmable interrupt timer, I decided to
+ * use that rather than the decrementer. Two reasons: 1.) the clock
+ * frequency is low, causing 2.) a long wait in the timer interrupt
+ * while ((d = get_dec()) == dval)
+ * loop. The MPC8xx can be driven from a variety of input clocks,
+ * so a number of assumptions have been made here because the kernel
+ * parameter HZ is a constant. We assume (correctly, today :-) that
+ * the MPC8xx on the MBX board is driven from a 32.768 kHz crystal.
+ * This is then divided by 4, providing a 8192 Hz clock into the PIT.
+ * Since it is not possible to get a nice 100 Hz clock out of this, without
+ * creating a software PLL, I have set HZ to 128. -- Dan
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -22,12 +36,21 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/nvram.h>
+#include <asm/cache.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#endif
#include "time.h"
/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
int (*set_rtc_time)(unsigned long);
+void smp_local_timer_interrupt(struct pt_regs *);
+
/* keep track of when we need to update the rtc */
unsigned long last_rtc_update = 0;
@@ -48,6 +71,14 @@ unsigned count_period_den; /* count_period_num / count_period_den us */
void timer_interrupt(struct pt_regs * regs)
{
int dval, d;
+ unsigned long cpu = smp_processor_id();
+ /* save the HID0 in case dcache was off - see idle.c
+ * this hack should leave for a better solution -- Cort */
+ unsigned dcache_locked = unlock_dcache();
+
+if ( smp_processor_id() ) printk("SMP 1: timer intr\n");
+ hardirq_enter(cpu);
+
while ((dval = get_dec()) < 0) {
/*
* Wait for the decrementer to change, then jump
@@ -57,17 +88,49 @@ void timer_interrupt(struct pt_regs * regs)
while ((d = get_dec()) == dval)
;
set_dec(d + decrementer_count);
- do_timer(regs);
- /*
- * update the rtc when needed
- */
- if ( xtime.tv_sec > last_rtc_update + 660 )
- if (set_rtc_time(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ if ( !smp_processor_id() )
+ {
+ do_timer(regs);
+ /*
+ * update the rtc when needed
+ */
+ if ( xtime.tv_sec > last_rtc_update + 660 )
+ if (set_rtc_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
}
+#ifdef __SMP__
+ smp_local_timer_interrupt(regs);
+#endif
+
+ hardirq_exit(cpu);
+ /* restore the HID0 in case dcache was off - see idle.c
+ * this hack should leave for a better solution -- Cort */
+ lock_dcache(dcache_locked);
+}
+
+#ifdef CONFIG_MBX
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+mbx_set_rtc_time(unsigned long time)
+{
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+ return(0);
}
+#endif /* CONFIG_MBX */
/*
* This version of gettimeofday has microsecond resolution.
@@ -108,6 +171,7 @@ void do_settimeofday(struct timeval *tv)
void
time_init(void)
{
+#ifndef CONFIG_MBX
if ((_get_PVR() >> 16) == 1) {
/* 601 processor: dec counts down by 128 every 128ns */
decrementer_count = DECREMENTER_COUNT_601;
@@ -119,9 +183,10 @@ time_init(void)
case _MACH_Pmac:
/* can't call pmac_get_rtc_time() yet,
because via-cuda isn't initialized yet. */
- if ((_get_PVR() >> 16) != 1)
+ if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) )
pmac_calibrate_decr();
- set_rtc_time = pmac_set_rtc_time;
+ if ( !smp_processor_id() )
+ set_rtc_time = pmac_set_rtc_time;
break;
case _MACH_chrp:
chrp_time_init();
@@ -135,18 +200,63 @@ time_init(void)
prep_calibrate_decr();
set_rtc_time = prep_set_rtc_time;
break;
+/* ifdef APUS specific stuff until the merge is completed. -jskov */
+#ifdef CONFIG_APUS
+ case _MACH_apus:
+ {
+ xtime.tv_sec = apus_get_rtc_time();
+ apus_calibrate_decr();
+ set_rtc_time = apus_set_rtc_time;
+ break;
}
+#endif
+ }
+ xtime.tv_usec = 0;
+ set_dec(decrementer_count);
+#else
+ mbx_calibrate_decr();
+ set_rtc_time = mbx_set_rtc_time;
+
+ /* First, unlock all of the registers we are going to modify.
+ * To protect them from corruption during power down, registers
+ * that are maintained by keep alive power are "locked". To
+ * modify these registers we have to write the key value to
+ * the key location associated with the register.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+
+
+ /* Disable the RTC one second and alarm interrupts.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+ ~(RTCSC_SIE | RTCSC_ALE);
+
+ /* Enabling the decrementer also enables the timebase interrupts
+ * (or from the other point of view, to get decrementer interrupts
+ * we have to enable the timebase). The decrementer interrupt
+ * is wired into the vector table, nothing to do here for that.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+ ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+ (TBSCR_TBF | TBSCR_TBE));
+ if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+
+ /* Get time from the RTC.
+ */
+ xtime.tv_sec = ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
xtime.tv_usec = 0;
- /*
- * mark the rtc/on-chip timer as in sync
+#endif /* CONFIG_MBX */
+
+ /* mark the rtc/on-chip timer as in sync
* so we don't update right away
*/
last_rtc_update = xtime.tv_sec;
-
- set_dec(decrementer_count);
}
+#ifndef CONFIG_MBX
/*
* Uses the on-board timer to calibrate the on-chip decrementer register
* for prep systems. On the pmac the OF tells us what the frequency is
@@ -158,6 +268,27 @@ volatile int *done_ptr = &calibrate_done;
void prep_calibrate_decr(void)
{
unsigned long flags;
+
+ /* the Powerstack II's have trouble with the timer so
+ * we use a default value -- Cort
+ */
+ if ( (_prep_type == _PREP_Motorola) &&
+ ((inb(0x800) & 0xF0) & 0x40) )
+ {
+ unsigned long freq, divisor;
+ static unsigned long t2 = 0;
+
+ t2 = 998700000/60;
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ return;
+ }
+
save_flags(flags);
@@ -181,7 +312,7 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
{
unsigned long freq, divisor;
static unsigned long t1 = 0, t2 = 0;
-
+
if ( !t1 )
t1 = get_dec();
else if (!t2)
@@ -189,11 +320,6 @@ void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
t2 = get_dec();
t2 = t1-t2; /* decr's in 1/HZ */
t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
-if ( (t2>>20) > 100 )
-{
- printk("Decrementer frequency too high: %luMHz. Using 15MHz.\n",t2>>20);
- t2 = 998700000/60;
-}
freq = t2 * 60; /* try to make freq/1e6 an integer */
divisor = 60;
printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
@@ -205,6 +331,32 @@ if ( (t2>>20) > 100 )
}
}
+#else /* CONFIG_MBX */
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four. Currently, we only
+ * support the MBX, which is system clock divided by sixteen.
+ */
+void mbx_calibrate_decr(void)
+{
+ int freq, fp, divisor;
+
+ if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+ printk("WARNING: Wrong decrementer source clock.\n");
+
+ /* The manual says the frequency is in Hz, but it is really
+ * as MHz. The value 'fp' is the number of decrementer ticks
+ * per second.
+ */
+ /*fp = (mbx_board_info.bi_intfreq * 1000000) / 16;*/
+ freq = fp*60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+#endif /* CONFIG_MBX */
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
index 538ac7bb1..64a07250c 100644
--- a/arch/ppc/kernel/time.h
+++ b/arch/ppc/kernel/time.h
@@ -1,5 +1,5 @@
/*
- * $Id: time.h,v 1.7 1997/12/28 22:47:24 paulus Exp $
+ * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $
* Common time prototypes and such for all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -12,6 +12,7 @@
void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
void prep_calibrate_decr(void);
void pmac_calibrate_decr(void);
+extern void apus_calibrate_decr(void);
extern unsigned decrementer_count;
extern unsigned count_period_num;
extern unsigned count_period_den;
@@ -24,12 +25,16 @@ extern unsigned long last_rtc_update;
unsigned long prep_get_rtc_time(void);
unsigned long pmac_get_rtc_time(void);
unsigned long chrp_get_rtc_time(void);
+unsigned long apus_get_rtc_time(void);
int prep_set_rtc_time(unsigned long nowtime);
int pmac_set_rtc_time(unsigned long nowtime);
int chrp_set_rtc_time(unsigned long nowtime);
+int apus_set_rtc_time(unsigned long nowtime);
void pmac_read_rtc_time(void);
void chrp_calibrate_decr(void);
void chrp_time_init(void);
+int via_calibrate_decr(void);
+void mbx_calibrate_decr(void);
/* Accessor functions for the decrementer register. */
static __inline__ unsigned int get_dec(void)
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 7199dd5c1..c5c90b527 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -39,13 +39,31 @@ extern int fix_alignment(struct pt_regs *);
extern void bad_page_fault(struct pt_regs *, unsigned long);
#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *regs);
extern int xmon_bpt(struct pt_regs *regs);
extern int xmon_sstep(struct pt_regs *regs);
-extern void xmon(struct pt_regs *regs);
extern int xmon_iabr_match(struct pt_regs *regs);
+extern int xmon_dabr_match(struct pt_regs *regs);
extern void (*xmon_fault_handler)(struct pt_regs *regs);
#endif
+#ifdef CONFIG_XMON
+void (*debugger)(struct pt_regs *regs) = xmon;
+int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
+int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
+int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
+int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#ifdef CONFIG_KGDB
+void (*debugger)(struct pt_regs *regs);
+int (*debugger_bpt)(struct pt_regs *regs);
+int (*debugger_sstep)(struct pt_regs *regs);
+int (*debugger_iabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs);
+void (*debugger_fault_handler)(struct pt_regs *regs);
+#endif
+#endif
/*
* Trap & Exception support
*/
@@ -61,8 +79,8 @@ _exception(int signr, struct pt_regs *regs)
if (!user_mode(regs))
{
show_regs(regs);
-#ifdef CONFIG_XMON
- xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ debugger(regs);
#endif
print_backtrace((unsigned long *)regs->gpr[1]);
panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
@@ -75,9 +93,9 @@ MachineCheckException(struct pt_regs *regs)
{
if ( !user_mode(regs) )
{
-#ifdef CONFIG_XMON
- if (xmon_fault_handler) {
- xmon_fault_handler(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_fault_handler) {
+ debugger_fault_handler(regs);
return;
}
#endif
@@ -103,8 +121,8 @@ MachineCheckException(struct pt_regs *regs)
printk("Unknown values in msr\n");
}
show_regs(regs);
-#ifdef CONFIG_XMON
- xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ debugger(regs);
#endif
print_backtrace((unsigned long *)regs->gpr[1]);
panic("machine check");
@@ -123,8 +141,8 @@ UnknownException(struct pt_regs *regs)
void
InstructionBreakpoint(struct pt_regs *regs)
{
-#ifdef CONFIG_XMON
- if (xmon_iabr_match(regs))
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_iabr_match(regs))
return;
#endif
_exception(SIGTRAP, regs);
@@ -144,8 +162,8 @@ ProgramCheckException(struct pt_regs *regs)
_exception(SIGFPE, regs);
} else if (regs->msr & 0x20000) {
/* trap exception */
-#ifdef CONFIG_XMON
- if (xmon_bpt(regs))
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_bpt(regs))
return;
#endif
_exception(SIGTRAP, regs);
@@ -158,8 +176,8 @@ void
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
-#ifdef CONFIG_XMON
- if (xmon_sstep(regs))
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_sstep(regs))
return;
#endif
_exception(SIGTRAP, regs);
@@ -170,8 +188,13 @@ AlignmentException(struct pt_regs *regs)
{
int fixed;
+#ifdef __SMP__
+ if (regs->msr & MSR_FP )
+ smp_giveup_fpu(current);
+#else
if (last_task_used_math == current)
giveup_fpu();
+#endif
fixed = fix_alignment(regs);
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */
@@ -190,8 +213,8 @@ StackOverflow(struct pt_regs *regs)
{
printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
current, regs->gpr[1]);
-#ifdef CONFIG_XMON
- xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ debugger(regs);
#endif
show_regs(regs);
print_backtrace((unsigned long *)regs->gpr[1]);
@@ -205,3 +228,41 @@ trace_syscall(struct pt_regs *regs)
current, current->pid, regs->nip, regs->link, regs->gpr[0],
regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
}
+
+#ifdef CONFIG_8xx
+
+void
+SoftwareEmulation(struct pt_regs *regs)
+{
+ int errcode;
+ extern int Soft_emulate_8xx (struct pt_regs *regs);
+
+ if (user_mode(regs)) {
+#if 0
+ printk("(user mode)\n");
+ _exception(SIGTRAP, regs);
+#else
+ if (errcode = Soft_emulate_8xx(regs)) {
+printk("Software Emulation 0x%x: 0x%x ",
+ regs->nip, *((uint *)regs->nip));
+print_8xx_pte(current->mm, regs->nip);
+ if (errcode == EFAULT)
+ _exception(SIGBUS, regs);
+ else
+ _exception(SIGILL, regs);
+ }
+#endif
+ }
+ else {
+ printk("(kernel mode)\n");
+ panic("Kernel Mode Software Emulation");
+ }
+}
+#endif
+
+void
+TAUException(struct pt_regs *regs)
+{
+ printk("TAU trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
+}
diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c
index 5e2ceb889..55cc665d7 100644
--- a/arch/ppc/lib/locks.c
+++ b/arch/ppc/lib/locks.c
@@ -1,5 +1,5 @@
/*
- * $Id: locks.c,v 1.7 1998/01/06 06:44:59 cort Exp $
+ * $Id: locks.c,v 1.17 1998/03/26 22:19:38 cort Exp $
*
* Locks for smp ppc
*
@@ -9,53 +9,78 @@
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/delay.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/spinlock.h>
+#include <asm/io.h>
#define DEBUG_LOCKS 1
#undef INIT_STUCK
-#define INIT_STUCK 10000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock(%p) CPU#%d nip %08lx\n", lock, cpu, nip); stuck = INIT_STUCK; }
+#define INIT_STUCK 1000000
void _spin_lock(spinlock_t *lock)
{
- unsigned long val, nip = (unsigned long)__builtin_return_address(0);
int cpu = smp_processor_id();
+#ifdef DEBUG_LOCKS
int stuck = INIT_STUCK;
-
-again:
+#endif /* DEBUG_LOCKS */
/* try expensive atomic load/store to get lock */
- __asm__ __volatile__(
- "10: \n\t"
- "lwarx %0,0,%1 \n\t"
- "stwcx. %2,0,%1 \n\t"
- "bne- 10b \n\t"
- : "=r" (val)
- : "r" (&(lock->lock)), "r" ( (cpu&3)|(nip&~3L) ));
- if(val) {
+ while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) {
/* try cheap load until it's free */
while(lock->lock) {
- STUCK;
+#ifdef DEBUG_LOCKS
+ if(!--stuck)
+ {
+ printk("_spin_lock(%p) CPU#%d NIP %p"
+ " holder: cpu %ld pc %08lX\n",
+ lock, cpu, __builtin_return_address(0),
+ lock->owner_cpu,lock->owner_pc);
+ stuck = INIT_STUCK;
+ /* steal the lock */
+ /*xchg_u32((void *)&lock->lock,0);*/
+ }
+#endif /* DEBUG_LOCKS */
barrier();
}
- goto again;
}
+ lock->owner_pc = (unsigned long)__builtin_return_address(0);
+ lock->owner_cpu = cpu;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+ unsigned long result;
+
+ result = (unsigned long )xchg_u32((void *)&lock->lock,0xffffffff);
+ if ( !result )
+ {
+ lock->owner_cpu = smp_processor_id();
+ lock->owner_pc = (unsigned long)__builtin_return_address(0);
+ }
+ return (result == 0);
}
+
+
void _spin_unlock(spinlock_t *lp)
{
+#ifdef DEBUG_LOCKS
+ if ( !lp->lock )
+ panic("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp,
+ smp_processor_id(),current->comm,current->pid);
+ if ( lp->owner_cpu != smp_processor_id() )
+ panic("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
+ lp, smp_processor_id(), (int)lp->owner_cpu,
+ lp->owner_pc,lp->lock);
+#endif /* DEBUG_LOCKS */
+ lp->owner_pc = lp->owner_cpu = 0;
+ eieio();
lp->lock = 0;
+ eieio();
}
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("_read_lock(%p) CPU#%d\n", rw, cpu); stuck = INIT_STUCK; }
-
/*
* Just like x86, implement read-write locks as a 32-bit counter
* with the high bit (sign) being the "write" bit.
@@ -63,8 +88,10 @@ if(!--stuck) { printk("_read_lock(%p) CPU#%d\n", rw, cpu); stuck = INIT_STUCK; }
*/
void _read_lock(rwlock_t *rw)
{
+#ifdef DEBUG_LOCKS
unsigned long stuck = INIT_STUCK;
int cpu = smp_processor_id();
+#endif /* DEBUG_LOCKS */
again:
/* get our read lock in there */
@@ -76,7 +103,13 @@ again:
/* wait for the write lock to go away */
while ((signed long)((rw)->lock) < 0)
{
- STUCK;
+#ifdef DEBUG_LOCKS
+ if(!--stuck)
+ {
+ printk("_read_lock(%p) CPU#%d\n", rw, cpu);
+ stuck = INIT_STUCK;
+ }
+#endif /* DEBUG_LOCKS */
}
/* try to get the read lock again */
goto again;
@@ -87,33 +120,34 @@ void _read_unlock(rwlock_t *rw)
{
#ifdef DEBUG_LOCKS
if ( rw->lock == 0 )
- {
- if ( current)
printk("_read_unlock(): %s/%d (nip %08lX) lock %lx",
- current->comm,current->pid,current->tss.regs->nip,
+ current->comm,current->pid,current->tss.regs->nip,
rw->lock);
- else
- printk("no current\n");
- }
#endif /* DEBUG_LOCKS */
atomic_dec((atomic_t *) &(rw)->lock);
}
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock(%p) CPU#%d lock %lx)\n", rw, cpu,rw->lock); stuck = INIT_STUCK; }
-
void _write_lock(rwlock_t *rw)
{
+#ifdef DEBUG_LOCKS
unsigned long stuck = INIT_STUCK;
int cpu = smp_processor_id();
+#endif /* DEBUG_LOCKS */
again:
if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
{
while ( (rw)->lock & (1<<31) ) /* wait for write lock */
{
- STUCK;
+#ifdef DEBUG_LOCKS
+ if(!--stuck)
+ {
+ printk("write_lock(%p) CPU#%d lock %lx)\n",
+ rw, cpu,rw->lock);
+ stuck = INIT_STUCK;
+ }
+#endif /* DEBUG_LOCKS */
+ barrier();
}
goto again;
}
@@ -124,7 +158,15 @@ again:
clear_bit(31,&(rw)->lock);
while ( (rw)->lock & ~(1<<31) )
{
- STUCK;
+#ifdef DEBUG_LOCKS
+ if(!--stuck)
+ {
+ printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
+ rw, cpu,rw->lock);
+ stuck = INIT_STUCK;
+ }
+#endif /* DEBUG_LOCKS */
+ barrier();
}
goto again;
}
@@ -134,14 +176,9 @@ void _write_unlock(rwlock_t *rw)
{
#ifdef DEBUG_LOCKS
if ( !(rw->lock & (1<<31)) )
- {
- if ( current)
printk("_write_lock(): %s/%d (nip %08lX) lock %lx",
current->comm,current->pid,current->tss.regs->nip,
rw->lock);
- else
- printk("no current\n");
- }
#endif /* DEBUG_LOCKS */
clear_bit(31,&(rw)->lock);
}
@@ -149,6 +186,8 @@ void _write_unlock(rwlock_t *rw)
void __lock_kernel(struct task_struct *task)
{
#ifdef DEBUG_LOCKS
+ unsigned long stuck = INIT_STUCK;
+
if ( (signed long)(task->lock_depth) < 0 )
{
printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
@@ -156,20 +195,40 @@ void __lock_kernel(struct task_struct *task)
task->lock_depth);
}
#endif /* DEBUG_LOCKS */
+
+ if ( atomic_inc_return((atomic_t *) &task->lock_depth) != 1 )
+ return;
/* mine! */
- if ( atomic_inc_return((atomic_t *) &task->lock_depth) == 1 )
- klock_info.akp = smp_processor_id();
+ while ( xchg_u32( (void *)&klock_info.kernel_flag, KLOCK_HELD) )
+ {
+ /* try cheap load until it's free */
+ while(klock_info.kernel_flag) {
+#ifdef DEBUG_LOCKS
+ if(!--stuck)
+ {
+ printk("_lock_kernel() CPU#%d NIP %p\n",
+ smp_processor_id(),
+ __builtin_return_address(0));
+ stuck = INIT_STUCK;
+ }
+#endif /* DEBUG_LOCKS */
+ barrier();
+ }
+ }
+
+ klock_info.akp = smp_processor_id();
/* my kernel mode! mine!!! */
}
-
+
void __unlock_kernel(struct task_struct *task)
{
#ifdef DEBUG_LOCKS
- if ( task->lock_depth == 0 )
+ if ( (task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD) )
{
- printk("__unlock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
- task->comm,task->pid,task->tss.regs->nip,
- task->lock_depth);
+ printk("__unlock_kernel(): %s/%d (nip %08lX) "
+ "lock depth %x flags %lx\n",
+ task->comm,task->pid,task->tss.regs->nip,
+ task->lock_depth, klock_info.kernel_flag);
klock_info.akp = NO_PROC_ID;
klock_info.kernel_flag = 0;
return;
@@ -177,8 +236,8 @@ void __unlock_kernel(struct task_struct *task)
#endif /* DEBUG_LOCKS */
if ( atomic_dec_and_test((atomic_t *) &task->lock_depth) )
{
- klock_info.akp = NO_PROC_ID;
- klock_info.kernel_flag = 0;
+ klock_info.akp = NO_PROC_ID;
+ klock_info.kernel_flag = KLOCK_CLEAR;
}
}
@@ -192,4 +251,3 @@ void reacquire_kernel_lock(struct task_struct *task, int cpu,int depth)
__sti();
}
}
-
diff --git a/arch/ppc/mbx_defconfig b/arch/ppc/mbx_defconfig
new file mode 100644
index 000000000..e498b5249
--- /dev/null
+++ b/arch/ppc/mbx_defconfig
@@ -0,0 +1,196 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+CONFIG_8xx=y
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+# CONFIG_ALL_PPC is not set
+CONFIG_MBX=y
+CONFIG_MACH_SPECIFIC=y
+
+#
+# General setup
+#
+# CONFIG_EXPERIMENTAL is not set
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
+CONFIG_NET=y
+# CONFIG_SYSCTL is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PMAC_CONSOLE is not set
+# CONFIG_MAC_KEYBOARD is not set
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_XMON is not set
+CONFIG_VGA_CONSOLE=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# NEW devices (io_request, all ALPHA and dangerous)
+#
+# CONFIG_IO_REQUEST is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_RARP is not set
+CONFIG_IP_NOSR=y
+# CONFIG_SKB_LARGE is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_WAN_DRIVERS is not set
+# CONFIG_LAPBETHER is not set
+# CONFIG_X25_ASY is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_CDROM is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_PROC_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 8eaa49e92..9d0914979 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -35,11 +35,11 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_XMON
-extern void xmon(struct pt_regs *);
-extern void (*xmon_fault_handler)(struct pt_regs *);
-extern int xmon_dabr_match(struct pt_regs *);
-int xmon_kernel_faults = 0;
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+extern void (*debugger)(struct pt_regs *);
+extern void (*debugger_fault_handler)(struct pt_regs *);
+extern int (*debugger_dabr_match)(struct pt_regs *);
+int debugger_kernel_faults = 0;
#endif
unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */
@@ -72,14 +72,14 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
(regs->trap == 0x400)?"instr":"data"
);*/
-#ifdef CONFIG_XMON
- if (xmon_fault_handler && regs->trap == 0x300) {
- xmon_fault_handler(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_fault_handler && regs->trap == 0x300) {
+ debugger_fault_handler(regs);
return;
}
if (error_code & 0x00400000) {
/* DABR match */
- if (xmon_dabr_match(regs))
+ if (debugger_dabr_match(regs))
return;
}
#endif
@@ -90,9 +90,9 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
printk("page fault in interrupt handler, addr=%lx\n",
address);
show_regs(regs);
-#ifdef CONFIG_XMON
- if (xmon_kernel_faults)
- xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_kernel_faults)
+ debugger(regs);
#endif
}
}
@@ -112,11 +112,22 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
goto bad_area;
good_area:
+#ifdef CONFIG_6xx
if (error_code & 0x95700000)
/* an error such as lwarx to I/O controller space,
address matching DABR, eciwx, etc. */
+#endif /* CONFIG_6xx */
+#ifdef CONFIG_8xx
+ /* The MPC8xx seems to always set 0x80000000, which is
+ * "undefined". Of those that can be set, this is the only
+ * one which seems bad.
+ */
+ if (error_code & 0x10000000)
+ /* Guarded storage error. */
+#endif /* CONFIG_8xx */
goto bad_area;
+
/* a write */
if (error_code & 0x02000000) {
if (!(vma->vm_flags & VM_WRITE))
@@ -190,14 +201,47 @@ bad_page_fault(struct pt_regs *regs, unsigned long address)
/* kernel has accessed a bad area */
show_regs(regs);
print_backtrace( (unsigned long *)regs->gpr[1] );
-#ifdef CONFIG_XMON
- if (xmon_kernel_faults)
- xmon(regs);
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+ if (debugger_kernel_faults)
+ debugger(regs);
#endif
panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
regs->nip,regs->link,address,current->comm,current->pid);
}
+/*
+ * I need a va to pte function for the MPC8xx so I can set the cache
+ * attributes on individual pages used by the Communication Processor
+ * Module.
+ */
+pte_t *va_to_pte(struct task_struct *tsk, unsigned long address)
+{
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ dir = pgd_offset(tsk->mm, address & PAGE_MASK);
+ if (dir)
+ {
+ pmd = pmd_offset(dir, address & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, address & PAGE_MASK);
+ if (pte && pte_present(*pte))
+ {
+ return(pte);
+ }
+ } else
+ {
+ return (0);
+ }
+ } else
+ {
+ return (0);
+ }
+ return (0);
+}
+
unsigned long va_to_phys(unsigned long address)
{
pgd_t *dir;
@@ -226,6 +270,57 @@ unsigned long va_to_phys(unsigned long address)
return (0);
}
+void
+print_8xx_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t * pgd;
+ pmd_t * pmd;
+ pte_t * pte;
+
+ printk(" pte @ 0x%8lx: ", addr);
+ pgd = pgd_offset(mm, addr & PAGE_MASK);
+ if (pgd) {
+ pmd = pmd_offset(pgd, addr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd)) {
+ pte = pte_offset(pmd, addr & PAGE_MASK);
+ if (pte) {
+ printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
+ (long)pgd, (long)pte, (long)pte_val(*pte));
+ }
+ else {
+ printk("no pte\n");
+ }
+ }
+ else {
+ printk("no pmd\n");
+ }
+ }
+ else {
+ printk("no pgd\n");
+ }
+}
+
+int
+get_8xx_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t * pgd;
+ pmd_t * pmd;
+ pte_t * pte;
+ int retval = 0;
+
+ pgd = pgd_offset(mm, addr & PAGE_MASK);
+ if (pgd) {
+ pmd = pmd_offset(pgd, addr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd)) {
+ pte = pte_offset(pmd, addr & PAGE_MASK);
+ if (pte) {
+ retval = (int)pte_val(*pte);
+ }
+ }
+ }
+ return(retval);
+}
+
#if 0
/*
* Misc debugging functions. Please leave them here. -- Cort
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 273076d15..5967e29e6 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -7,6 +7,7 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
+ * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -31,6 +32,7 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/stddef.h>
+#include <linux/vmalloc.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
@@ -40,12 +42,27 @@
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h> /* for initrd_* */
#endif
+#ifdef CONFIG_8xx
+#include <asm/8xx_immap.h>
+#endif
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
-int prom_trashed;
-int next_mmu_context;
+#ifndef CONFIG_8xx
unsigned long _SDR1;
PTE *Hash, *Hash_end;
unsigned long Hash_size, Hash_mask;
+#endif /* CONFIG_8xx */
+
+/* ifdef APUS specific stuff until the merge is completed. -jskov */
+#ifdef CONFIG_APUS
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#endif
+
+int prom_trashed;
+int next_mmu_context;
unsigned long *end_of_DRAM;
int mem_init_done;
extern pgd_t swapper_pg_dir[];
@@ -55,10 +72,16 @@ extern char __init_begin, __init_end;
extern RESIDUAL res;
char *klimit = _end;
struct device_node *memory_node;
+unsigned long ioremap_base;
+unsigned long ioremap_bot;
+#ifndef __SMP__
+struct pgtable_cache_struct quicklists;
+#endif
-void *find_mem_piece(unsigned, unsigned);
-static void mapin_ram(void);
+#ifndef CONFIG_8xx
static void hash_init(void);
+#endif /* CONFIG_8xx */
+static void mapin_ram(void);
static void *MMU_get_page(void);
void map_page(struct task_struct *, unsigned long va,
unsigned long pa, int flags);
@@ -68,6 +91,38 @@ extern unsigned long *find_end_of_memory(void);
extern struct task_struct *current_set[NR_CPUS];
+#ifdef CONFIG_MBX
+/* This is a big hack that may not yet work correctly.
+ * The MBX8xx boards have a single DIMM socket for additional memory.
+ * Although it appears you can set magical locations in the serial
+ * EEPROM to get EPPC-Bug to configure this memory, there are no tools
+ * (i.e. commands) to make this easy. If you screw up, you will most
+ * likely end up with a board that will not boot until you find a
+ * way to program the EEPROM correctly. I decided to simply program
+ * the memory controller here to add the additional memory.
+ * The reason this may not work correctly is that depending upon the
+ * on-board and DIMM memory size, there may be holes in the physical
+ * address space. This is the case for me, I have a 4 MB local memory
+ * and a 32 MB DIMM.
+ * The DIMM is 64 bits wide, and we see it as two banks of 32 bit
+ * memory. The holes are caused by the requirement to map the
+ * memory on a natural alignment, that is a 16 MB bank must begin on
+ * a 16 MB boundary. The DIMM_SIZE below represents the size of the
+ * bank, which is the total size divided by two.
+ * Although I may not have all of this working, the intention is to
+ * mark all of the page maps in the "hole" as reserved, and adjust
+ * num_physpages accordingly. In the current implementation, this
+ * seems to work, but there are some assumptions about contiguous
+ * memory. The correct solution is to modify the memory allocators
+ * to know about holes, but that will have to wait for another day.
+ *
+ * define DIMM_8xx to enable this feature.
+ * define DIMM_SIZE to reflect the bank size (DIMM size divided by two).
+ */
+/*#define DIMM_8xx 1 */
+#define DIMM_SIZE (16 * 1024 * 1024)
+#endif /* CONFIG_MBX */
+
/*
* this tells the system to map all of ram with the segregs
* (i.e. page tables) instead of the bats.
@@ -77,6 +132,34 @@ extern struct task_struct *current_set[NR_CPUS];
/* optimization for 603 to load the tlb directly from the linux table */
#define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
+void __bad_pte(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ clear_page((unsigned long)pte);
+ pmd_val(*pmd) = (unsigned long)pte;
+ return pte + offset;
+ }
+ pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE;
+ return NULL;
+ }
+ free_page((unsigned long)pte);
+ if (pmd_bad(*pmd)) {
+ __bad_pte(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + offset;
+}
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
@@ -121,65 +204,32 @@ struct mem_pieces phys_mem;
struct mem_pieces phys_avail;
struct mem_pieces prom_mem;
-static void get_mem_prop(char *, struct mem_pieces *);
-static void sort_mem_pieces(struct mem_pieces *);
-static void coalesce_mem_pieces(struct mem_pieces *);
-static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+void *find_mem_piece(unsigned, unsigned);
static void print_mem_pieces(struct mem_pieces *);
-static void
-sort_mem_pieces(struct mem_pieces *mp)
-{
- unsigned long a, s;
- int i, j;
-
- for (i = 1; i < mp->n_regions; ++i) {
- a = mp->regions[i].address;
- s = mp->regions[i].size;
- for (j = i - 1; j >= 0; --j) {
- if (a >= mp->regions[j].address)
- break;
- mp->regions[j+1] = mp->regions[j];
- }
- mp->regions[j+1].address = a;
- mp->regions[j+1].size = s;
- }
-}
-
-static void
-coalesce_mem_pieces(struct mem_pieces *mp)
+/*
+ * Scan a region for a piece of a given size with the required alignment.
+ */
+void *
+find_mem_piece(unsigned size, unsigned align)
{
- unsigned long a, e;
- int i, j, d;
+ int i;
+ unsigned a, e;
+ struct mem_pieces *mp = &phys_avail;
- d = 0;
- for (i = 0; i < mp->n_regions; i = j) {
+ for (i = 0; i < mp->n_regions; ++i) {
a = mp->regions[i].address;
e = a + mp->regions[i].size;
- for (j = i + 1; j < mp->n_regions
- && mp->regions[j].address <= e; ++j)
- e = mp->regions[j].address + mp->regions[j].size;
- mp->regions[d].address = a;
- mp->regions[d].size = e - a;
- ++d;
+ a = (a + align - 1) & -align;
+ if (a + size <= e) {
+ remove_mem_piece(mp, a, size, 1);
+ return __va(a);
+ }
}
- mp->n_regions = d;
-}
-
-/*
- * Add some memory to an array of pieces
- */
-static void
-append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)
-{
- struct reg_property *rp;
-
- if (mp->n_regions >= MAX_MEM_REGIONS)
- return;
- rp = &mp->regions[mp->n_regions++];
- rp->address = start;
- rp->size = size;
+ printk("Couldn't find %u bytes at %u alignment\n", size, align);
+ abort();
+ return NULL;
}
/*
@@ -252,33 +302,73 @@ print_mem_pieces(struct mem_pieces *mp)
printk("\n");
}
-/*
- * Scan a region for a piece of a given size with the required alignment.
- */
-void *
-find_mem_piece(unsigned size, unsigned align)
+
+
+#ifndef CONFIG_8xx
+static void hash_init(void);
+static void get_mem_prop(char *, struct mem_pieces *);
+static void sort_mem_pieces(struct mem_pieces *);
+static void coalesce_mem_pieces(struct mem_pieces *);
+static void append_mem_piece(struct mem_pieces *, unsigned, unsigned);
+
+static void
+sort_mem_pieces(struct mem_pieces *mp)
{
- int i;
- unsigned a, e;
- struct mem_pieces *mp = &phys_avail;
+ unsigned long a, s;
+ int i, j;
- for (i = 0; i < mp->n_regions; ++i) {
+ for (i = 1; i < mp->n_regions; ++i) {
a = mp->regions[i].address;
- e = a + mp->regions[i].size;
- a = (a + align - 1) & -align;
- if (a + size <= e) {
- remove_mem_piece(mp, a, size, 1);
- return __va(a);
+ s = mp->regions[i].size;
+ for (j = i - 1; j >= 0; --j) {
+ if (a >= mp->regions[j].address)
+ break;
+ mp->regions[j+1] = mp->regions[j];
}
+ mp->regions[j+1].address = a;
+ mp->regions[j+1].size = s;
}
- printk("Couldn't find %u bytes at %u alignment\n", size, align);
- abort();
- return NULL;
+}
+
+static void
+coalesce_mem_pieces(struct mem_pieces *mp)
+{
+ unsigned long a, e;
+ int i, j, d;
+
+ d = 0;
+ for (i = 0; i < mp->n_regions; i = j) {
+ a = mp->regions[i].address;
+ e = a + mp->regions[i].size;
+ for (j = i + 1; j < mp->n_regions
+ && mp->regions[j].address <= e; ++j)
+ e = mp->regions[j].address + mp->regions[j].size;
+ mp->regions[d].address = a;
+ mp->regions[d].size = e - a;
+ ++d;
+ }
+ mp->n_regions = d;
+}
+
+/*
+ * Add some memory to an array of pieces
+ */
+static void
+append_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size)
+{
+ struct reg_property *rp;
+
+ if (mp->n_regions >= MAX_MEM_REGIONS)
+ return;
+ rp = &mp->regions[mp->n_regions++];
+ rp->address = start;
+ rp->size = size;
}
/*
* Read in a property describing some pieces of memory.
*/
+
static void
get_mem_prop(char *name, struct mem_pieces *mp)
{
@@ -365,6 +455,41 @@ unsigned long *pmac_find_end_of_memory(void)
return __va(total);
}
+#endif /* CONFIG_8xx */
+
+#ifdef CONFIG_APUS
+#define HARDWARE_MAPPED_SIZE (512*1024)
+unsigned long *apus_find_end_of_memory(void)
+{
+ unsigned long kstart, ksize;
+
+ /* Add the chunk that ADOS does not see. Removed again below. */
+ m68k_memory[0].size += HARDWARE_MAPPED_SIZE;
+
+ append_mem_piece(&phys_mem, m68k_memory[0].addr, m68k_memory[0].size);
+
+ phys_avail = phys_mem;
+ kstart = __pa(_stext);
+ ksize = PAGE_ALIGN(klimit - _stext);
+ remove_mem_piece(&phys_avail, kstart, ksize, 1);
+
+ /* Remove the upper HARDWARE_MAPPED_SIZE bytes where the address
+ * range 0xfff00000-0xfffx0000 is mapped to.
+ * We do it this way to ensure that the memory registered in the
+ * system has a power-of-two size.
+ */
+ remove_mem_piece(&phys_avail,
+ (m68k_memory[0].addr + m68k_memory[0].size
+ - HARDWARE_MAPPED_SIZE),
+ HARDWARE_MAPPED_SIZE, 1);
+
+ /* FIXME:APUS: Only handles one block of memory! Problem is
+ * that the VTOP/PTOV code in head.S would be a mess if it had
+ * to handle more than one block.
+ */
+ return __va(m68k_memory[0].addr + m68k_memory[0].size);
+}
+#endif
/*
* Find some memory for setup_arch to return.
@@ -381,6 +506,16 @@ unsigned long find_available_memory(void)
unsigned long start, end;
free = 0;
+ if (_machine == _MACH_mbx) {
+ /* Return the first, not the last region, because we
+ * may not yet have properly initialized the additonal
+ * memory DIMM.
+ */
+ a = PAGE_ALIGN(phys_avail.regions[0].address);
+ avail_start = (unsigned long) __va(a);
+ return avail_start;
+ }
+
for (i = 0; i < phys_avail.n_regions - 1; ++i) {
start = phys_avail.regions[i].address;
end = start + phys_avail.regions[i].size;
@@ -396,7 +531,7 @@ unsigned long find_available_memory(void)
void show_mem(void)
{
int i,free = 0,total = 0,reserved = 0;
- int shared = 0;
+ int shared = 0, cached = 0;
struct task_struct *p;
printk("Mem-info:\n");
@@ -407,6 +542,8 @@ void show_mem(void)
total++;
if (PageReserved(mem_map+i))
reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
else if (!atomic_read(&mem_map[i].count))
free++;
else
@@ -416,6 +553,8 @@ void show_mem(void)
printk("%d free pages\n",free);
printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared);
+ printk("%d pages swap cached\n",cached);
+ printk("%d pages in page table cache\n",(int)pgtable_cache_size);
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
@@ -487,6 +626,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
int codepages = 0;
int datapages = 0;
int initpages = 0;
+ extern unsigned int rtas_data, rtas_size;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
@@ -496,6 +636,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
+#ifndef CONFIG_8xx
remove_mem_piece(&phys_avail, __pa(avail_start),
start_mem - avail_start, 1);
@@ -520,7 +661,52 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
prom_trashed = 1;
-
+#else /* CONFIG_8xx */
+ /* When we get here, all of the page maps have been set up and
+ * Linux thinks we have contiguous memory. Since the MBX can
+ * have memory holes, we need to compensate for that here.
+ * The memory holes are currently pages marked reserved (all
+ * pages right now are marked reserved).
+ * All of the memory allocated by the kernel up to this point
+ * had to come from region 0.
+ */
+
+ /* First, unreserve all memory from the page following start_mem
+ * to the end of region 0.
+ */
+ for (addr = start_mem + PAGE_SIZE ;
+ addr < (ulong) __va(phys_mem.regions[0].size);
+ addr += PAGE_SIZE) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ }
+
+ /* Now add any additional regions to the system.
+ */
+ for (i = 1; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+ }
+ phys_avail.n_regions = 0; /* Nothing available, kernel owns */
+ /* Count up the size of the holes. We look for the space
+ * between the end of one region and the start of the next.
+ */
+ lim = 0;
+ for (i = 0; i < phys_mem.n_regions-1; ++i) {
+ a = (unsigned long) phys_mem.regions[i].address;
+ a += phys_mem.regions[i].size;
+ lim += phys_mem.regions[i+1].address - a;
+ }
+
+ /* It appears that num_physpages is only used for quota checking,
+ * when pages are locked down. We subtract the size of the holes
+ * from it now.
+ */
+ num_physpages -= lim/PAGE_SIZE;
+#endif /* CONFIG_8xx */
+
for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
if (PageReserved(mem_map + MAP_NR(addr))) {
if (addr < (ulong) etext)
@@ -537,7 +723,12 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
if (!initrd_start ||
addr < (initrd_start & PAGE_MASK) || addr >= initrd_end)
#endif /* CONFIG_BLK_DEV_INITRD */
- free_page(addr);
+#ifndef CONFIG_8xx
+ if ( !rtas_data ||
+ addr < (rtas_data & PAGE_MASK) ||
+ addr >= (rtas_data+rtas_size))
+#endif /* CONFIG_8xx */
+ free_page(addr);
}
printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
@@ -594,6 +785,7 @@ void si_meminfo(struct sysinfo *val)
return;
}
+#ifndef CONFIG_8xx
union ubat { /* BAT register values to be loaded */
BAT bat;
P601_BAT bat_601;
@@ -692,7 +884,7 @@ unsigned long *prep_find_end_of_memory(void)
return (__va(total));
}
-
+#endif /* CONFIG_8xx */
/*
* Map in all of physical memory starting at KERNELBASE.
@@ -702,8 +894,9 @@ unsigned long *prep_find_end_of_memory(void)
static void mapin_ram()
{
int i;
- unsigned long tot, bl, done;
unsigned long v, p, s, f;
+#ifndef CONFIG_8xx
+ unsigned long tot, mem_base, bl, done;
#ifndef MAP_RAM_WITH_SEGREGS
/* Set up BAT2 and if necessary BAT3 to cover RAM. */
@@ -711,15 +904,17 @@ static void mapin_ram()
for (bl = 128<<10; bl < 256<<20; bl <<= 1)
if (bl * 2 > tot)
break;
- setbat(2, KERNELBASE, 0, bl, RAM_PAGE);
- done = __pa(bat_addrs[2].limit) + 1;
+
+ mem_base = __pa(KERNELBASE);
+ setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
+ done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
if (done < tot) {
/* use BAT3 to cover a bit more */
tot -= done;
for (bl = 128<<10; bl < 256<<20; bl <<= 1)
if (bl * 2 > tot)
break;
- setbat(3, KERNELBASE+done, done, bl, RAM_PAGE);
+ setbat(3, KERNELBASE+done, mem_base+done, bl, RAM_PAGE);
}
#endif
@@ -734,6 +929,27 @@ static void mapin_ram()
/* On the powerpc, no user access
forces R/W kernel access */
f |= _PAGE_USER;
+#else /* CONFIG_8xx */
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ v = (ulong)__va(phys_mem.regions[i].address);
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ /* On the MPC8xx, we want the page shared so we
+ * don't get ASID compares on kernel space.
+ */
+ f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
+
+ /* I don't really need the rest of this code, but
+ * I grabbed it because I think the line:
+ * f |= _PAGE_USER
+ * is incorrect. It needs to be set to bits we
+ * don't define to cause a kernel read-only. On
+ * the MPC8xx, the PAGE_DIRTY takes care of that
+ * for us (along with the RW software state).
+ */
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+#endif /* CONFIG_8xx */
map_page(&init_task, v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
@@ -741,6 +957,7 @@ static void mapin_ram()
}
}
+#ifndef CONFIG_8xx
/*
* Initialize the hash table and patch the instructions in head.S.
*/
@@ -820,7 +1037,7 @@ static void hash_init(void)
Hash_end = 0;
}
-
+#endif /* CONFIG_8xx */
/*
* Do very early mm setup such as finding the size of memory
@@ -832,13 +1049,19 @@ static void hash_init(void)
void
MMU_init(void)
{
+#ifndef CONFIG_8xx
if (have_of)
end_of_DRAM = pmac_find_end_of_memory();
+#ifdef CONFIG_APUS
+ else if (_machine == _MACH_apus )
+ end_of_DRAM = apus_find_end_of_memory();
+#endif
else /* prep */
end_of_DRAM = prep_find_end_of_memory();
hash_init();
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
+ ioremap_base = 0xf8000000;
/* Map in all of RAM starting at KERNELBASE */
mapin_ram();
@@ -856,16 +1079,40 @@ MMU_init(void)
IO_PAGE + ((_prep_type == _PREP_IBM)? _PAGE_USER: 0));
break;
case _MACH_chrp:
- setbat(0, 0xc0000000, 0xc0000000, 0x10000000, IO_PAGE);
- setbat(1, 0xf8000000, 0xf8000000, 0x20000, IO_PAGE);
- setbat(3, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+ setbat(0, 0xf8000000, 0xf8000000, 0x20000, IO_PAGE);
break;
case _MACH_Pmac:
setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE);
- /* this is used to cover registers used by smp boards -- Cort */
- setbat(3, 0xf8000000, 0xf8000000, 0x100000, IO_PAGE);
+ ioremap_base = 0xf0000000;
break;
+#ifdef CONFIG_APUS
+ case _MACH_apus:
+ /* Map Cyberstorm PPC registers. */
+ /* FIXME:APUS: Performance penalty here. Restrict it
+ * to the Cyberstorm registers.
+ */
+ setbat(0, 0xfff00000, 0xfff00000, 0x00080000, IO_PAGE);
+ /* Map chip and ZorroII memory */
+ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE);
+ break;
+#endif
}
+ ioremap_bot = ioremap_base;
+#else /* CONFIG_8xx */
+
+ /* Map in all of RAM starting at KERNELBASE */
+ mapin_ram();
+
+ /* Now map in some of the I/O space that is generically needed
+ * or shared with multiple devices.
+ * All of this fits into the same 4Mbyte region, so it only
+ * requires one page table page.
+ */
+ ioremap(NVRAM_ADDR, NVRAM_SIZE);
+ ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE);
+ ioremap(MBX_IMAP_ADDR, MBX_IMAP_SIZE);
+ ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
+#endif /* CONFIG_8xx */
}
static void *
@@ -887,27 +1134,98 @@ MMU_get_page()
void *
ioremap(unsigned long addr, unsigned long size)
{
- unsigned long p, end = addr + size;
+ return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+
+void *
+__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+{
+ unsigned long p, v, i;
+
+ /*
+ * Choose an address to map it to.
+ * Once the vmalloc system is running, we use it.
+ * Before then, we map addresses >= ioremap_base
+ * virt == phys; for addresses below this we use
+ * space going down from ioremap_base (ioremap_bot
+ * records where we're up to).
+ *
+ * We should also look out for a frame buffer and
+ * map it with a free BAT register, if there is one.
+ */
+ p = addr & PAGE_MASK;
+ size = PAGE_ALIGN(addr + size) - p;
+ if (size == 0)
+ return NULL;
- for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
- map_page(&init_task, p, p,
- pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
- return (void *) addr;
+ if (mem_init_done) {
+ struct vm_struct *area;
+ area = get_vm_area(size);
+ if (area == 0)
+ return NULL;
+ v = VMALLOC_VMADDR(area->addr);
+ } else {
+ if (p >= ioremap_base)
+ v = p;
+ else
+ v = (ioremap_bot -= size);
+ }
+
+ flags |= pgprot_val(PAGE_KERNEL);
+ if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
+ flags |= _PAGE_GUARDED;
+ for (i = 0; i < size; i += PAGE_SIZE)
+ map_page(&init_task, v+i, p+i, flags);
+
+ return (void *) (v + (addr & ~PAGE_MASK));
}
-void iounmap(unsigned long *addr)
+void iounmap(void *addr)
{
/* XXX todo */
}
+unsigned long iopa(unsigned long addr)
+{
+ unsigned long idx;
+ pmd_t *pd;
+ pte_t *pg;
+#ifndef CONFIG_8xx
+ int b;
+#endif
+ idx = addr & ~PAGE_MASK;
+ addr = addr & PAGE_MASK;
+
+#ifndef CONFIG_8xx
+ /* Check the BATs */
+ for (b = 0; b < 4; ++b)
+ if (addr >= bat_addrs[b].start && addr <= bat_addrs[b].limit)
+ return bat_addrs[b].phys | idx;
+#endif /* CONFIG_8xx */
+ /* Do we have a page table? */
+ if (init_task.mm->pgd == NULL)
+ return 0;
+
+ /* Use upper 10 bits of addr to index the first level map */
+ pd = (pmd_t *) (init_task.mm->pgd + (addr >> PGDIR_SHIFT));
+ if (pmd_none(*pd))
+ return 0;
+
+ /* Use middle 10 bits of addr to index the second-level map */
+ pg = pte_offset(pd, addr);
+ return (pte_val(*pg) & PAGE_MASK) | idx;
+}
+
void
map_page(struct task_struct *tsk, unsigned long va,
unsigned long pa, int flags)
{
pmd_t *pd;
pte_t *pg;
+#ifndef CONFIG_8xx
int b;
-
+#endif
+
if (tsk->mm->pgd == NULL) {
/* Allocate upper level page map */
tsk->mm->pgd = (pgd_t *) MMU_get_page();
@@ -915,6 +1233,7 @@ map_page(struct task_struct *tsk, unsigned long va,
/* Use upper 10 bits of VA to index the first level map */
pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
if (pmd_none(*pd)) {
+#ifndef CONFIG_8xx
/*
* Need to allocate second-level table, but first
* check whether this address is already mapped by
@@ -927,14 +1246,16 @@ map_page(struct task_struct *tsk, unsigned long va,
return;
}
}
+#endif /* CONFIG_8xx */
pg = (pte_t *) MMU_get_page();
pmd_val(*pd) = (unsigned long) pg;
}
/* Use middle 10 bits of VA to index the second-level map */
pg = pte_offset(pd, va);
set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
- /*flush_hash_page(va >> 28, va);*/
+#ifndef CONFIG_8xx
flush_hash_page(0, va);
+#endif
}
/*
@@ -957,11 +1278,14 @@ map_page(struct task_struct *tsk, unsigned long va,
void
local_flush_tlb_all(void)
{
+#ifndef CONFIG_8xx
memset(Hash, 0, Hash_size);
_tlbia();
+#else
+ asm volatile ("tlbia" : : );
+#endif
}
-
/*
* Flush all the (user) entries for the address space described
* by mm. We can't rely on mm->mmap describing all the entries
@@ -970,33 +1294,43 @@ local_flush_tlb_all(void)
void
local_flush_tlb_mm(struct mm_struct *mm)
{
+#ifndef CONFIG_8xx
mm->context = NO_CONTEXT;
if (mm == current->mm) {
get_mmu_context(current);
/* done by get_mmu_context() now -- Cort */
/*set_context(current->mm->context);*/
}
+#else
+ asm volatile ("tlbia" : : );
+#endif
}
void
local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
{
+#ifndef CONFIG_8xx
if (vmaddr < TASK_SIZE)
flush_hash_page(vma->vm_mm->context, vmaddr);
else
flush_hash_page(0, vmaddr);
+#else
+ asm volatile ("tlbia" : : );
+#endif
}
-/* for each page addr in the range, call MMU_invalidate_page()
- if the range is very large and the hash table is small it might be faster to
- do a search of the hash table and just invalidate pages that are in the range
- but that's for study later.
- -- Cort
- */
+/*
+ * for each page addr in the range, call MMU_invalidate_page()
+ * if the range is very large and the hash table is small it might be
+ * faster to do a search of the hash table and just invalidate pages
+ * that are in the range but that's for study later.
+ * -- Cort
+ */
void
local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
+#ifndef CONFIG_8xx
start &= PAGE_MASK;
if (end - start > 20 * PAGE_SIZE)
@@ -1009,6 +1343,9 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e
{
flush_hash_page(mm->context, start);
}
+#else
+ asm volatile ("tlbia" : : );
+#endif
}
/*
@@ -1020,6 +1357,7 @@ local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long e
void
mmu_context_overflow(void)
{
+#ifndef CONFIG_8xx
struct task_struct *tsk;
printk(KERN_DEBUG "mmu_context_overflow\n");
@@ -1034,6 +1372,12 @@ mmu_context_overflow(void)
/* make sure current always has a context */
current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
set_context(current->mm->context);
+#else
+ /* We set the value to -1 because it is pre-incremented before
+ * before use.
+ */
+ next_mmu_context = -1;
+#endif
}
#if 0
@@ -1090,3 +1434,69 @@ void local_flush_cache_range(struct mm_struct *mm, unsigned long start,
}
#endif
+#ifdef CONFIG_MBX
+/*
+ * This is a big hack right now, but it may turn into something real
+ * someday.
+ *
+ * For the MBX860 (at this time anyway), there is nothing to initialize
+ * associated the the PROM. Rather than include all of the prom.c
+ * functions in the image just to get prom_init, all we really need right
+ * now is the initialization of the physical memory region.
+ */
+void
+set_mbx_memory(void)
+{
+ unsigned long kstart, ksize;
+ bd_t *binfo;
+#ifdef DIMM_8xx
+ volatile memctl8xx_t *mcp;
+#endif
+
+ binfo = (bd_t *)&res;
+
+ /* The MBX can have up to three memory regions, the on-board
+ * DRAM plus two more banks of DIMM socket memory. The DIMM is
+ * 64 bits, seen from the processor as two 32 bit banks.
+ * The on-board DRAM is reflected in the board information
+ * structure, and is either 4 Mbytes or 16 Mbytes.
+ * I think there is a way to program the serial EEPROM information
+ * so EPPC-Bug will initialize this memory, but I have not
+ * done that and it may not be a wise thing to do. If you
+ * remove the DIMM without reprogramming the EEPROM, bad things
+ * could happen since EPPC-Bug tries to use the upper 128K of
+ * memory.
+ */
+ phys_mem.n_regions = 1;
+ phys_mem.regions[0].address = 0;
+ phys_mem.regions[0].size = binfo->bi_memsize;
+ end_of_DRAM = __va(binfo->bi_memsize);
+
+#ifdef DIMM_8xx
+ /* This is a big hack. It assumes my 32 Mbyte DIMM in a 40 MHz
+ * MPC860. Don't do this (or change this) if you are running
+ * something else.
+ */
+ mcp = (memctl8xx_t *)(&(((immap_t *)MBX_IMAP_ADDR)->im_memctl));
+
+ mcp->memc_or2 = (~(DIMM_SIZE-1) | 0x00000400);
+ mcp->memc_br2 = DIMM_SIZE | 0x00000081;
+ mcp->memc_or3 = (~((2*DIMM_SIZE)-1) | 0x00000400);
+ mcp->memc_br3 = 2*DIMM_SIZE | 0x00000081;
+
+
+ phys_mem.regions[phys_mem.n_regions].address = DIMM_SIZE;
+ phys_mem.regions[phys_mem.n_regions++].size = DIMM_SIZE;
+ phys_mem.regions[phys_mem.n_regions].address = 2 * DIMM_SIZE;
+ phys_mem.regions[phys_mem.n_regions++].size = DIMM_SIZE;
+
+ end_of_DRAM = __va(3 * DIMM_SIZE);
+#endif
+
+ phys_avail = phys_mem;
+
+ kstart = __pa(_stext); /* should be 0 */
+ ksize = PAGE_ALIGN(_end - _stext);
+ remove_mem_piece(&phys_avail, kstart, ksize, 0);
+}
+#endif
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
index 529b33138..8cf7eb8a6 100644
--- a/arch/ppc/pmac_defconfig
+++ b/arch/ppc/pmac_defconfig
@@ -1,5 +1,5 @@
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
#
@@ -7,11 +7,12 @@
#
CONFIG_PPC=y
CONFIG_NATIVE=y
+CONFIG_PPC6XX=y
+# CONFIG_PPC8XX is not set
CONFIG_MACH_SPECIFIC=y
CONFIG_PMAC=y
# CONFIG_PREP is not set
# CONFIG_CHRP is not set
-CONFIG_COMMON=y
#
# General setup
@@ -19,8 +20,9 @@ CONFIG_COMMON=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+CONFIG_KERNELD=y
CONFIG_PCI=y
+CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
@@ -28,14 +30,20 @@ CONFIG_SYSVIPC=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
CONFIG_BINFMT_MISC=m
-CONFIG_BINFMT_JAVA=m
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_ABSTRACT_CONSOLE is not set
CONFIG_PMAC_CONSOLE=y
CONFIG_MAC_KEYBOARD=y
CONFIG_MAC_FLOPPY=y
+CONFIG_MACMOUSE=y
CONFIG_PROC_DEVICETREE=y
# CONFIG_XMON is not set
+CONFIG_CONTROL_VIDEO=y
+CONFIG_PLATINUM_VIDEO=y
+CONFIG_VALKYRIE_VIDEO=y
CONFIG_ATY_VIDEO=y
CONFIG_IMSTT_VIDEO=y
+CONFIG_CHIPS_VIDEO=y
#
# Plug and Play support
@@ -47,6 +55,10 @@ CONFIG_IMSTT_VIDEO=y
#
# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_BLK_DEV_IDECD=y
@@ -55,14 +67,20 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=m
+# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -77,6 +95,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
CONFIG_NET_ALIAS=y
+# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -85,37 +104,56 @@ CONFIG_IP_MULTICAST=y
# CONFIG_IP_ACCT is not set
# CONFIG_IP_MASQUERADE is not set
# CONFIG_IP_ROUTER is not set
-CONFIG_NET_IPIP=m
+# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
CONFIG_INET_RARP=y
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
+
+#
+#
+#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
#
# SCSI support
#
CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
#
# SCSI low-level drivers
@@ -124,7 +162,12 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
+CONFIG_SCSI_AIC7XXX=m
+# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set
+# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_PAGE_ENABLE is not set
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
@@ -134,12 +177,16 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_SEAGATE is not set
@@ -158,27 +205,47 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
# CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
CONFIG_NET_ETHERNET=y
CONFIG_MACE=y
-CONFIG_DEC_ELCP=m
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=m
+CONFIG_DEC_ELCP=m
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
# CONFIG_PLIP is not set
CONFIG_PPP=m
-# CONFIG_NET_RADIO is not set
+
+#
+# CCP compressors for PPP are only built as modules.
+#
# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
# ISDN subsystem
#
# CONFIG_ISDN is not set
@@ -187,28 +254,68 @@ CONFIG_PPP=m
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
#
# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
#
# Filesystems
#
# CONFIG_QUOTA is not set
-CONFIG_MINIX_FS=m
+# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
CONFIG_ISO9660_FS=y
-# CONFIG_NLS is not set
+# CONFIG_JOLIET is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=m
# CONFIG_ROMFS_FS is not set
CONFIG_AUTOFS_FS=y
# CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
#
# Character devices
@@ -217,20 +324,25 @@ CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_SOFTCURSOR is not set
CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_PRINTER is not set
# CONFIG_MOUSE is not set
# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
# CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_BT848 is not set
CONFIG_NVRAM=y
# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
#
# Sound
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
index 147fa3005..a323e652e 100644
--- a/arch/ppc/prep_defconfig
+++ b/arch/ppc/prep_defconfig
@@ -6,12 +6,14 @@
# Platform support
#
CONFIG_PPC=y
-CONFIG_NATIVE=y
-CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
+# CONFIG_8xx is not set
# CONFIG_PMAC is not set
CONFIG_PREP=y
# CONFIG_CHRP is not set
-CONFIG_COMMON=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_MBX is not set
+CONFIG_MACH_SPECIFIC=y
#
# General setup
@@ -19,20 +21,25 @@ CONFIG_COMMON=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
+CONFIG_KERNELD=y
CONFIG_PCI=y
+# CONFIG_PCI_QUIRKS is not set
# CONFIG_PCI_OPTIMIZE is not set
+CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
-# CONFIG_SYSCTL is not set
+CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PARPORT is not set
+# CONFIG_ABSTRACT_CONSOLE is not set
# CONFIG_PMAC_CONSOLE is not set
# CONFIG_MAC_KEYBOARD is not set
# CONFIG_MAC_FLOPPY is not set
+# CONFIG_MACMOUSE is not set
# CONFIG_PROC_DEVICETREE is not set
# CONFIG_XMON is not set
CONFIG_VGA_CONSOLE=y
@@ -55,14 +62,16 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -77,32 +86,34 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ACCT is not set
-# CONFIG_IP_MASQUERADE is not set
+CONFIG_IP_ACCT=y
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_ALIAS is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
CONFIG_INET_RARP=y
# CONFIG_IP_NOSR is not set
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
# CONFIG_NET_SCHED is not set
+# CONFIG_NET_PROFILE is not set
#
# SCSI support
@@ -115,6 +126,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y
# CONFIG_CHR_DEV_SG is not set
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
#
# SCSI low-level drivers
@@ -133,6 +145,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y
# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
@@ -143,8 +156,10 @@ CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
CONFIG_SCSI_NCR53C8XX_SYNC=5
# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
-# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_SEAGATE is not set
@@ -152,6 +167,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=5
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_MESH is not set
# CONFIG_SCSI_MAC53C94 is not set
@@ -162,12 +178,13 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
# CONFIG_EQUALIZER is not set
-# CONFIG_ETHERTAP is not set
CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_LANCE=y
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
CONFIG_PCNET32=y
@@ -184,14 +201,18 @@ CONFIG_DE4X5=y
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
-CONFIG_PPP=m
-# CONFIG_NET_RADIO is not set
+CONFIG_PPP=y
# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
# ISDN subsystem
#
# CONFIG_ISDN is not set
@@ -200,6 +221,7 @@ CONFIG_PPP=m
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
#
# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
#
# Filesystems
@@ -208,29 +230,59 @@ CONFIG_PPP=m
# CONFIG_MINIX_FS is not set
CONFIG_EXT2_FS=y
CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
+CONFIG_JOLIET=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=y
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
# CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
+# CONFIG_ADFS_FS is not set
# CONFIG_MAC_PARTITION is not set
+CONFIG_NLS=y
#
# Native Language Support
#
-# CONFIG_NLS is not set
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
#
# Character devices
@@ -239,14 +291,9 @@ CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_SOFTCURSOR is not set
CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_PRINTER is not set
CONFIG_MOUSE=y
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
@@ -256,14 +303,18 @@ CONFIG_PSMOUSE=y
# CONFIG_PC110_PAD is not set
# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
# CONFIG_VIDEO_DEV is not set
-# CONFIG_VIDEO_BT848 is not set
# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
#
# Sound