diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
commit | 012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch) | |
tree | 87efc733f9b164e8c85c0336f92c8fb7eff6d183 /arch/ppc | |
parent | 625a1589d3d6464b5d90b8a0918789e3afffd220 (diff) |
Merge with Linux 2.4.0-test9. Please check DECstation, I had a number
of rejects to fixup while integrating Linus patches. I also found
that this kernel will only boot SMP on Origin; the UP kernel freeze
soon after bootup with SCSI timeout messages. I commit this anyway
since I found that the last CVS versions had the same problem.
Diffstat (limited to 'arch/ppc')
66 files changed, 4829 insertions, 1671 deletions
diff --git a/arch/ppc/8260_io/Config.in b/arch/ppc/8260_io/Config.in index 8cdd8c615..4db16a068 100644 --- a/arch/ppc/8260_io/Config.in +++ b/arch/ppc/8260_io/Config.in @@ -11,12 +11,15 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then bool 'Ethernet on SCC2' CONFIG_SCC2_ENET fi fi - bool 'FCC Ethernet' CONFIG_FCC_ENET - if [ "$CONFIG_FCC_ENET" = "y" ]; then - bool 'Ethernet on FCC1' CONFIG_FCC1_ENET - if [ "$CONFIG_FCC1_ENET" != "y" ]; then - bool 'Ethernet on FCC2' CONFIG_FCC2_ENET - fi +# +# CONFIG_FEC_ENET is only used to get netdevices to call our init +# function. Any combination of FCC1,2,3 are supported. +# + bool 'FCC Ethernet' CONFIG_FEC_ENET + if [ "$CONFIG_FEC_ENET" = "y" ]; then + bool 'Ethernet on FCC1' CONFIG_FCC1_ENET + bool 'Ethernet on FCC2' CONFIG_FCC2_ENET + bool 'Ethernet on FCC3' CONFIG_FCC3_ENET fi endmenu fi diff --git a/arch/ppc/8260_io/Makefile b/arch/ppc/8260_io/Makefile index 240a85628..8de47b144 100644 --- a/arch/ppc/8260_io/Makefile +++ b/arch/ppc/8260_io/Makefile @@ -10,8 +10,8 @@ O_TARGET := 8260_io.a O_OBJS = commproc.o uart.o -ifdef CONFIG_FCC_ENET -O_OBJS += fcc.o +ifdef CONFIG_FEC_ENET +O_OBJS += fcc_enet.o endif ifdef CONFIG_SCC_ENET O_OBJS += enet.o diff --git a/arch/ppc/8260_io/commproc.c b/arch/ppc/8260_io/commproc.c index 8642fa420..b7c13b167 100644 --- a/arch/ppc/8260_io/commproc.c +++ b/arch/ppc/8260_io/commproc.c @@ -69,17 +69,27 @@ m8260_cpm_reset(void) cpmp = (cpm8260_t *)commproc; } -/* Allocate some memory from the dual ported ram. We may want to - * enforce alignment restrictions, but right now everyone is a good - * citizen. +/* Allocate some memory from the dual ported ram. + * To help protocols with object alignment restrictions, we do that + * if they ask. */ uint -m8260_cpm_dpalloc(uint size) +m8260_cpm_dpalloc(uint size, uint align) { uint retloc; + uint align_mask, off; + uint savebase; - if ((dp_alloc_base + size) >= dp_alloc_top) + align_mask = align - 1; + savebase = dp_alloc_base; + + if ((off = (dp_alloc_base & align_mask)) != 0) + dp_alloc_base += (align - off); + + if ((dp_alloc_base + size) >= dp_alloc_top) { + dp_alloc_base = savebase; return(CPM_DP_NOSPACE); + } retloc = dp_alloc_base; dp_alloc_base += size; @@ -91,12 +101,22 @@ m8260_cpm_dpalloc(uint size) * UART "fifos" and the like. */ uint -m8260_cpm_hostalloc(uint size) +m8260_cpm_hostalloc(uint size, uint align) { uint retloc; + uint align_mask, off; + uint savebase; - if ((host_buffer + size) >= host_end) + align_mask = align - 1; + savebase = host_buffer; + + if ((off = (host_buffer & align_mask)) != 0) + host_buffer += (align - off); + + if ((host_buffer + size) >= host_end) { + host_buffer = savebase; return(0); + } retloc = host_buffer; host_buffer += size; diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c index 4c8c672fd..e1ff3c092 100644 --- a/arch/ppc/8260_io/enet.c +++ b/arch/ppc/8260_io/enet.c @@ -466,8 +466,11 @@ for (;;) { cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. - */ - skb = dev_alloc_skb(pkt_len); + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -475,10 +478,10 @@ for (;;) { } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } @@ -549,10 +552,10 @@ static void set_multicast_list(struct net_device *dev) /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->sccp->scc_pmsr |= SCC_PMSR_PRO; + cep->sccp->scc_pmsr |= SCC_PSMR_PRO; } else { - cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO; + cep->sccp->scc_pmsr &= ~SCC_PSMR_PRO; if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the @@ -678,11 +681,11 @@ int __init scc_enet_init(void) * These are relative offsets in the DP ram address space. * Initialize base addresses for the buffer descriptors. */ - i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE); + i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); ep->sen_genscc.scc_rbase = i; cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; - i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE); + i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); ep->sen_genscc.scc_tbase = i; cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; @@ -816,7 +819,7 @@ int __init scc_enet_init(void) /* 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_NIB22); + sccp->scc_pmsr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c new file mode 100644 index 000000000..da3991ae3 --- /dev/null +++ b/arch/ppc/8260_io/fcc_enet.c @@ -0,0 +1,1601 @@ +/* + * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * This version of the driver is a combination of the 8xx fec and + * 8260 SCC Ethernet drivers. People seem to be choosing common I/O + * configurations, so this driver will work on the EST8260 boards and + * others yet to be announced. + * + * 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/config.h> +#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/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> + +#include <asm/immap_8260.h> +#include <asm/pgtable.h> +#include <asm/mpc8260.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include <asm/cpm_8260.h> + +/* The transmitter timeout + */ +#define TX_TIMEOUT (2*HZ) + +/* 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 FCC_ENET_RX_PAGES 16 +#define FCC_ENET_RX_FRSIZE 2048 +#define FCC_ENET_RX_FRPPG (PAGE_SIZE / FCC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES) +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ + +/* The FCC stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 + +/* Maximum input DMA size. Must be a should(?) be a multiple of 4. +*/ +#define PKT_MAXDMA_SIZE 1520 + +/* Maximum input buffer size. Must be a multiple of 32. +*/ +#define PKT_MAXBLR_SIZE 1536 + +static int fcc_enet_open(struct net_device *dev); +static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int fcc_enet_rx(struct net_device *dev); +static void fcc_enet_mii(struct net_device *dev); +static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static int fcc_enet_close(struct net_device *dev); +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void restart_fcc(struct net_device *dev); + +/* These will be configurable for the FCC choice. + * Multiple ports can be configured. There is little choice among the + * I/O pins to the PHY, except the clocks. We will need some board + * dependent clock selection. + * Why in the hell did I put these inside #ifdef's? I dunno, maybe to + * help show what pins are used for each device. + */ + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL ((uint)0x00000001) +#define PA1_CRS ((uint)0x00000002) +#define PA1_TXER ((uint)0x00000004) +#define PA1_TXEN ((uint)0x00000008) +#define PA1_RXDV ((uint)0x00000010) +#define PA1_RXER ((uint)0x00000020) +#define PA1_TXDAT ((uint)0x00003c00) +#define PA1_RXDAT ((uint)0x0003c000) +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + +/* CLK12 is receive, CLK11 is transmit. These are board specific. +*/ +#define PC_F1RXCLK ((uint)0x00000800) +#define PC_F1TXCLK ((uint)0x00000400) +#define CMX1_CLK_ROUTE ((uint)0x3e000000) +#define CMX1_CLK_MASK ((uint)0xff000000) + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER ((uint)0x00000001) +#define PB2_RXDV ((uint)0x00000002) +#define PB2_TXEN ((uint)0x00000004) +#define PB2_RXER ((uint)0x00000008) +#define PB2_COL ((uint)0x00000010) +#define PB2_CRS ((uint)0x00000020) +#define PB2_TXDAT ((uint)0x000003c0) +#define PB2_RXDAT ((uint)0x00003c00) +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + +/* CLK13 is receive, CLK14 is transmit. These are board dependent. +*/ +#define PC_F2RXCLK ((uint)0x00001000) +#define PC_F2TXCLK ((uint)0x00002000) +#define CMX2_CLK_ROUTE ((uint)0x00250000) +#define CMX2_CLK_MASK ((uint)0x00ff0000) + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV ((uint)0x00004000) +#define PB3_RXER ((uint)0x00008000) +#define PB3_TXER ((uint)0x00010000) +#define PB3_TXEN ((uint)0x00020000) +#define PB3_COL ((uint)0x00040000) +#define PB3_CRS ((uint)0x00080000) +#define PB3_TXDAT ((uint)0x0f000000) +#define PB3_RXDAT ((uint)0x00f00000) +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 (0) +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) + +/* CLK15 is receive, CLK16 is transmit. These are board dependent. +*/ +#define PC_F3RXCLK ((uint)0x00004000) +#define PC_F3TXCLK ((uint)0x00008000) +#define CMX3_CLK_ROUTE ((uint)0x00003700) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +/* MII status/control serial interface. +*/ +#define PC_MDIO ((uint)0x00400000) +#define PC_MDCK ((uint)0x00200000) + +/* A table of information for supporting FCCs. This does two things. + * First, we know how many FCCs we have and they are always externally + * numbered from zero. Second, it holds control register and I/O + * information that could be different among board designs. + */ +typedef struct fcc_info { + uint fc_fccnum; + uint fc_cpmblock; + uint fc_cpmpage; + uint fc_proff; + uint fc_interrupt; + uint fc_trxclocks; + uint fc_clockroute; + uint fc_clockmask; + uint fc_mdio; + uint fc_mdck; +} fcc_info_t; + +static fcc_info_t fcc_ports[] = { +#ifdef CONFIG_FCC1_ENET + { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1, + (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +#ifdef CONFIG_FCC2_ENET + { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2, + (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +#ifdef CONFIG_FCC3_ENET + { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3, + (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +}; + +/* The FCC 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 fcc_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. */ + volatile fcc_t *fccp; + volatile fcc_enet_t *ep; + struct net_device_stats stats; + uint tx_full; + spinlock_t lock; + uint phy_address; + uint phy_type; + uint phy_duplex; + fcc_info_t *fip; +}; + +static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile immap_t *immap); +static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev); +static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, + volatile immap_t *immap); +static void init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile immap_t *immap); + +/* MII processing. We keep this as simple as possible. Requests are + * placed on the list (if there is room). When the request is finished + * by the MII, an optional function may be called. + */ +typedef struct mii_list { + uint mii_regval; + void (*mii_func)(uint val, struct net_device *dev); + struct mii_list *mii_next; +} mii_list_t; + +#define NMII 20 +mii_list_t mii_cmds[NMII]; +mii_list_t *mii_free; +mii_list_t *mii_head; +mii_list_t *mii_tail; + +static int phyaddr; +static uint phytype; + +static int mii_queue(int request, void (*func)(uint, struct net_device *)); +static void mii_startup_cmds(void); +static uint mii_send_receive(fcc_info_t *fip, uint cmd); + +/* Make MII read/write commands for the FCC. +*/ + +#define mk_mii_phyaddr(ADDR) (0x60020000 | ((ADDR) << 23) | (2 << 18)) + +#define mk_mii_read(REG) (0x60020000 | ((phyaddr << 23) | \ + (REG & 0x1f) << 18)) + +#define mk_mii_write(REG, VAL) (0x50020000 | ((phyaddr << 23) | \ + (REG & 0x1f) << 18) | \ + (VAL & 0xffff)) + + +static int +fcc_enet_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; /* Always succeed */ +} + +static int +fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + volatile cbd_t *bdp; + + + /* 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 cep->tx_full should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + 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; + + spin_lock_irq(&cep->lock); + + /* 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); + +#if 0 + /* Errata says don't do this. + */ + cep->fccp->fcc_ftodr = 0x8000; +#endif + 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++; + + if (bdp->cbd_sc & BD_ENET_TX_READY) { + netif_stop_queue(dev); + cep->tx_full = 1; + } + + cep->cur_tx = (cbd_t *)bdp; + + spin_unlock_irq(&cep->lock); + + return 0; +} + + +static void +fcc_enet_timeout(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + 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 %p%s cur_rx %p.\n", + cep->cur_tx, cep->tx_full ? " (full)" : "", + cep->cur_rx); + bdp = cep->tx_bd_base; + printk(" Tx @base %p :\n", bdp); + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp = cep->rx_bd_base; + printk(" Rx @base %p :\n", bdp); + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + } +#endif + if (!cep->tx_full) + netif_wake_queue(dev); +} + +/* The interrupt handler. + */ +static void +fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + volatile struct fcc_enet_private *cep; + volatile cbd_t *bdp; + ushort int_events; + int must_restart; + + cep = (struct fcc_enet_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->fccp->fcc_fcce; + cep->fccp->fcc_fcce = int_events; + must_restart = 0; + + /* Handle receive event in its own function. + */ + if (int_events & FCC_ENET_RXF) + fcc_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 :-). + */ + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + */ + if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { + spin_lock(&cep->lock); + bdp = cep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { + if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) + break; + + 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++; + + + /* 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; + cep->stats.tx_errors++; + } + + cep->stats.tx_packets++; + + /* 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_irq(cep->tx_skbuff[cep->skb_dirty]); + 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) { + cep->tx_full = 0; + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + } + + cep->dirty_tx = (cbd_t *)bdp; + } + + if (must_restart) { + volatile cpm8260_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(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, + 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + spin_unlock(&cep->lock); + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. + */ + if (int_events & FCC_ENET_BSY) { + cep->stats.rx_dropped++; + } + 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 +fcc_enet_rx(struct net_device *dev) +{ + struct fcc_enet_private *cep; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + + cep = (struct fcc_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. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); + + 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-4); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len-4, 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 +fcc_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + netif_stop_queue(dev); + + return 0; +} + +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + return &cep->stats; +} + +/* The MII is simulated from the 8xx FEC implementation. The FCC + * is not responsible for the MII control/status interface. + */ +static void +fcc_enet_mii(struct net_device *dev) +{ + struct fcc_enet_private *fep; + mii_list_t *mip; + uint mii_reg; + + fep = (struct fcc_enet_private *)dev->priv; +#if 0 + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + mii_reg = ep->fec_mii_data; +#endif + + if ((mip = mii_head) == NULL) { + printk("MII and no head!\n"); + return; + } + + if (mip->mii_func != NULL) + (*(mip->mii_func))(mii_reg, dev); + + mii_head = mip->mii_next; + mip->mii_next = mii_free; + mii_free = mip; + +#if 0 + if ((mip = mii_head) != NULL) + ep->fec_mii_data = mip->mii_regval; +#endif +} + +static int +mii_queue(int regval, void (*func)(uint, struct net_device *)) +{ + unsigned long flags; + mii_list_t *mip; + int retval; + + retval = 0; + + save_flags(flags); + cli(); + + if ((mip = mii_free) != NULL) { + mii_free = mip->mii_next; + mip->mii_regval = regval; + mip->mii_func = func; + mip->mii_next = NULL; + if (mii_head) { + mii_tail->mii_next = mip; + mii_tail = mip; + } + else { + mii_head = mii_tail = mip; +#if 0 + (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval; +#endif + } + } + else { + retval = 1; + } + + restore_flags(flags); + + return(retval); +} + +static volatile uint full_duplex; + +static void +mii_status(uint mii_reg, struct net_device *dev) +{ + volatile uint prev_duplex; + + if (((mii_reg >> 18) & 0x1f) == 1) { + /* status register. + */ + printk("fec: "); + if (mii_reg & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_reg & 0x0010) + printk(",remote fault"); + if (mii_reg & 0x0020) + printk(",auto complete"); + printk("\n"); + } + if (((mii_reg >> 18) & 0x1f) == 0x14) { + /* Extended chip status register. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_reg & 0x0800) + printk("100 Mbps"); + else + printk("10 Mbps"); + + if (mii_reg & 0x1000) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } +#if 0 + if (prev_duplex != full_duplex) + restart_fec(dev); +#endif + } + if (((mii_reg >> 18) & 0x1f) == 31) { + /* QS6612 PHY Control/Status. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + + mii_reg = (mii_reg >> 2) & 7; + + if (mii_reg & 1) + printk("10 Mbps"); + else + printk("100 Mbps"); + + if (mii_reg > 4) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + +#if 0 + if (prev_duplex != full_duplex) + restart_fec(dev); +#endif + } +} + +static uint phyno; + +static void +mii_discover_phy3(uint mii_reg, struct net_device *dev) +{ + phytype <<= 16; + phytype |= (mii_reg & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", phyno, phytype); + mii_startup_cmds(); +} + +static void +mii_discover_phy(uint mii_reg, struct net_device *dev) +{ + if (phyno < 32) { + if ((phytype = (mii_reg & 0xffff)) != 0xffff) { + phyaddr = phyno; + mii_queue(mk_mii_read(3), mii_discover_phy3); + } + else { + phyno++; + mii_queue(mk_mii_phyaddr(phyno), mii_discover_phy); + } + } + else { + printk("FEC: No PHY device found.\n"); + } +} + +static void +mii_discover_phy_poll(fcc_info_t *fip) +{ + uint rv; + int i; + + for (i=0; i<32; i++) { + rv = mii_send_receive(fip, mk_mii_phyaddr(i)); + if ((phytype = (rv & 0xffff)) != 0xffff) { + phyaddr = i; + rv = mii_send_receive(fip, mk_mii_read(3)); + phytype <<= 16; + phytype |= (rv & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", phyaddr, phytype); + } + } +} + +static void +mii_startup_cmds(void) +{ + +#if 1 + /* Level One PHY. + */ + + /* Read status registers to clear any pending interrupt. + */ + mii_queue(mk_mii_read(1), mii_status); + mii_queue(mk_mii_read(18), mii_status); + + /* Read extended chip status register. + */ + mii_queue(mk_mii_read(0x14), mii_status); + + /* Set default operation of 100-TX....for some reason + * some of these bits are set on power up, which is wrong. + */ + mii_queue(mk_mii_write(0x13, 0), NULL); + + /* Enable Link status change interrupts. + */ + mii_queue(mk_mii_write(0x11, 0x0002), NULL); + + /* Don't advertize Full duplex. + mii_queue(mk_mii_write(0x04, 0x0021), NULL); + */ +#endif + +} + +/* This supports the mii_link interrupt below. + * We should get called three times. Once for register 1, once for + * register 18, and once for register 20. + */ +static uint mii_saved_reg1; + +static void +mii_relink(uint mii_reg, struct net_device *dev) +{ + volatile uint prev_duplex; + unsigned long flags; + + if (((mii_reg >> 18) & 0x1f) == 1) { + /* Just save the status register and get out. + */ + mii_saved_reg1 = mii_reg; + return; + } + if (((mii_reg >> 18) & 0x1f) == 18) { + /* Not much here, but has to be read to clear the + * interrupt condition. + */ + if ((mii_reg & 0x8000) == 0) + printk("fec: re-link and no IRQ?\n"); + if ((mii_reg & 0x4000) == 0) + printk("fec: no PHY power?\n"); + } + if (((mii_reg >> 18) & 0x1f) == 20) { + /* Extended chip status register. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + if (mii_reg & 0x0800) + printk(", 100 Mbps"); + else + printk(", 10 Mbps"); + + if (mii_reg & 0x1000) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + if (prev_duplex != full_duplex) { + save_flags(flags); + cli(); +#if 0 + restart_fec(dev); +#endif + restore_flags(flags); + } + } + if (((mii_reg >> 18) & 0x1f) == 31) { + /* QS6612 PHY Control/Status. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + mii_reg = (mii_reg >> 2) & 7; + + if (mii_reg & 1) + printk(", 10 Mbps"); + else + printk(", 100 Mbps"); + + if (mii_reg > 4) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + +#if 0 + if (prev_duplex != full_duplex) { + save_flags(flags); + cli(); + restart_fec(dev); + restore_flags(flags); + } +#endif + } +} + +/* 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 net_device *dev) +{ + struct fcc_enet_private *cep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile fcc_enet_t *ep; + int i, j; + + cep = (struct fcc_enet_private *)dev->priv; + +return; + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)dev->base_addr; + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO; + } else { + + cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->fen_gaddrh = 0xffffffff; + ep->fen_gaddrl = 0xffffffff; + } + else { + /* Clear filter and add the addresses in the list. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 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->fen_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(cep->fip->fc_cpmpage, + cep->fip->fc_cpmblock, 0x0c, + CPM_CR_SET_GADDR) | CPM_CR_FLG; + udelay(10); + while (cpmp->cp_cpcr & CPM_CR_FLG); + } + } + } +} + +/* Initialize the CPM Ethernet on FCC. + */ +int __init fec_enet_init(void) +{ + struct net_device *dev; + struct fcc_enet_private *cep; + fcc_info_t *fip; + int i, np; + volatile immap_t *immap; + volatile iop8260_t *io; + + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + io = &immap->im_ioport; + + np = sizeof(fcc_ports) / sizeof(fcc_info_t); + fip = fcc_ports; + + while (np-- > 0) { + + /* Allocate some private information. + */ + cep = (struct fcc_enet_private *) + kmalloc(sizeof(*cep), GFP_KERNEL); + __clear_user(cep,sizeof(*cep)); + spin_lock_init(&cep->lock); + cep->fip = fip; + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + dev->priv = cep; + + init_fcc_shutdown(fip, cep, immap); + init_fcc_ioports(fip, io, immap); + init_fcc_param(fip, dev, immap); + + dev->base_addr = (unsigned long)(cep->ep); + + /* The CPM Ethernet specific entries in the device + * structure. + */ + dev->open = fcc_enet_open; + dev->hard_start_xmit = fcc_enet_start_xmit; + dev->tx_timeout = fcc_enet_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = fcc_enet_close; + dev->get_stats = fcc_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + init_fcc_startup(fip, dev); + + printk("%s: FCC ENET Version 0.2, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + /* This is just a hack for now that works only on the EST + * board, or anything else that has MDIO/CK configured. + * It is mainly to test the MII software clocking. + */ + mii_discover_phy_poll(fip); + + fip++; + } + + return 0; +} + +/* Make sure the device is shut down during initialization. +*/ +static void __init +init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile immap_t *immap) +{ + volatile fcc_enet_t *ep; + volatile fcc_t *fccp; + + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]); + + /* And another to the FCC register area. + */ + fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]); + cep->fccp = fccp; /* Keep the pointers handy */ + cep->ep = ep; + + /* Disable receive and transmit in case someone left it running. + */ + fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* Initialize the I/O pins for the FCC Ethernet. +*/ +static void __init +init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, + volatile immap_t *immap) +{ + + /* FCC1 pins are on port A/C. FCC2/3 are port B/C. + */ + if (fip->fc_proff == PROFF_FCC1) { + /* Configure port A and C pins for FCC1 Ethernet. + */ + io->iop_pdira &= ~PA1_DIRA0; + io->iop_pdira |= PA1_DIRA1; + io->iop_psora &= ~PA1_PSORA0; + io->iop_psora |= PA1_PSORA1; + io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1); + } + if (fip->fc_proff == PROFF_FCC2) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB2_DIRB0; + io->iop_pdirb |= PB2_DIRB1; + io->iop_psorb &= ~PB2_PSORB0; + io->iop_psorb |= PB2_PSORB1; + io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1); + } + if (fip->fc_proff == PROFF_FCC3) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB3_DIRB0; + io->iop_pdirb |= PB3_DIRB1; + io->iop_psorb &= ~PB3_PSORB0; + io->iop_psorb |= PB3_PSORB1; + io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1); + } + + /* Port C has clocks...... + */ + io->iop_psorc &= ~(fip->fc_trxclocks); + io->iop_pdirc &= ~(fip->fc_trxclocks); + io->iop_pparc |= fip->fc_trxclocks; + + /* ....and the MII serial clock/data. + */ + io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_podrc |= fip->fc_mdio; + io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck); + + /* Configure Serial Interface clock routing. + * First, clear all FCC bits to zero, + * then set the ones we want. + */ + immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask); + immap->im_cpmux.cmx_fcr |= fip->fc_clockroute; +} + +static void __init +init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile immap_t *immap) +{ + unsigned char *eap; + unsigned long mem_addr; + bd_t *bd; + int i, j; + struct fcc_enet_private *cep; + volatile fcc_enet_t *ep; + volatile cbd_t *bdp; + volatile cpm8260_t *cp; + + cep = (struct fcc_enet_private *)(dev->priv); + ep = cep->ep; + cp = cpmp; + + bd = (bd_t *)__res; + + /* Zero the whole thing.....I must have missed some individually. + * It works when I do this. + */ + memset((char *)ep, 0, sizeof(fcc_enet_t)); + + /* 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. + */ +#if 0 + /* I really want to do this, but for some reason it doesn't + * work with the data cache enabled, so I allocate from the + * main memory instead. + */ + i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i]; + cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; + + i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i]; + cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; +#else + cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base); + cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base); +#endif + + cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; + cep->cur_rx = cep->rx_bd_base; + + ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + + /* Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; + + /* Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. + */ + mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128); + ep->fen_genfcc.fcc_riptr = mem_addr; + ep->fen_genfcc.fcc_tiptr = mem_addr+32; + ep->fen_padptr = mem_addr+64; + memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32); + + ep->fen_genfcc.fcc_rbptr = 0; + ep->fen_genfcc.fcc_tbptr = 0; + ep->fen_genfcc.fcc_rcrc = 0; + ep->fen_genfcc.fcc_tcrc = 0; + ep->fen_genfcc.fcc_res1 = 0; + ep->fen_genfcc.fcc_res2 = 0; + + ep->fen_camptr = 0; /* CAM isn't used in this driver */ + + /* Set CRC preset and mask. + */ + ep->fen_cmask = 0xdebb20e3; + ep->fen_cpres = 0xffffffff; + + ep->fen_crcec = 0; /* CRC Error counter */ + ep->fen_alec = 0; /* alignment error counter */ + ep->fen_disfc = 0; /* discard frame counter */ + ep->fen_retlim = 15; /* Retry limit threshold */ + ep->fen_pper = 0; /* Normal persistence */ + + /* Clear hash filter tables. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + ep->fen_iaddrh = 0; + ep->fen_iaddrl = 0; + + /* Clear the Out-of-sequence TxBD. + */ + ep->fen_tfcstat = 0; + ep->fen_tfclen = 0; + ep->fen_tfcptr = 0; + + ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ + + /* Set Ethernet station address. + * + * This is supplied in the board information structure, so we + * copy that into the controller. + * So, far we have only been given one Ethernet address. We make + * it unique by setting a few bits in the upper byte of the + * non-static part of the address. + */ + eap = (unsigned char *)&(ep->fen_paddrh); + for (i=5; i>=0; i--) { + if (i == 3) { + dev->dev_addr[i] = bd->bi_enetaddr[i]; + dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum)); + *eap++ = dev->dev_addr[i]; + } + else { + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; + } + } + + ep->fen_taddrh = 0; + ep->fen_taddrm = 0; + ep->fen_taddrl = 0; + + ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */ + ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */ + + /* Clear stat counters, in case we ever enable RMON. + */ + ep->fen_octc = 0; + ep->fen_colc = 0; + ep->fen_broc = 0; + ep->fen_mulc = 0; + ep->fen_uspc = 0; + ep->fen_frgc = 0; + ep->fen_ospc = 0; + ep->fen_jbrc = 0; + ep->fen_p64c = 0; + ep->fen_p65c = 0; + ep->fen_p128c = 0; + ep->fen_p256c = 0; + ep->fen_p512c = 0; + ep->fen_p1024c = 0; + + ep->fen_rfthr = 0; /* Suggested by manual */ + ep->fen_rfcnt = 0; + ep->fen_cftype = 0; + + /* 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_datlen = 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<FCC_ENET_RX_PAGES; i++) { + + /* Allocate a page. + */ + mem_addr = __get_free_page(GFP_KERNEL); + + /* Initialize the BD for every fragment in the page. + */ + for (j=0; j<FCC_ENET_RX_FRPPG; j++) { + bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FCC_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(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + cep->skb_cur = cep->skb_dirty = 0; +} + +/* Let 'er rip. +*/ +static void __init +init_fcc_startup(fcc_info_t *fip, struct net_device *dev) +{ + volatile fcc_t *fccp; + struct fcc_enet_private *cep; + + cep = (struct fcc_enet_private *)(dev->priv); + fccp = cep->fccp; + + fccp->fcc_fcce = 0xffff; /* Clear any pending events */ + + /* Enable interrupts for transmit error, complete frame + * received, and any transmit buffer we have also set the + * interrupt flag. + */ + fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); + + /* Install our interrupt handler. + */ + if (request_8xxirq(fip->fc_interrupt, fcc_enet_interrupt, 0, + "fenet", dev) < 0) + printk("Can't get FCC IRQ %d\n", fip->fc_interrupt); + + /* Set GFMR to enable Ethernet operating mode. + */ + fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); + + /* Set sync/delimiters. + */ + fccp->fcc_fdsr = 0xd555; + + /* Set protocol specific processing mode for Ethernet. + * This has to be adjusted for Full Duplex operation after we can + * determine how to detect that. + */ + fccp->fcc_fpsmr = FCC_PSMR_ENCRC; + + /* And last, enable the transmit and receive processing. + */ + fccp->fcc_gfmr |= (FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* MII command/status interface. + * I'm not going to describe all of the details. You can find the + * protocol definition in many other places, including the data sheet + * of most PHY parts. + * I wonder what "they" were thinking (maybe weren't) when they leave + * the I2C in the CPM but I have to toggle these bits...... + */ +static uint +mii_send_receive(fcc_info_t *fip, uint cmd) +{ + unsigned long flags; + uint retval; + int read_op, i; + volatile immap_t *immap; + volatile iop8260_t *io; + + immap = (immap_t *)IMAP_ADDR; + io = &immap->im_ioport; + + /* When we get here, both clock and data are high, outputs. + * Output is open drain. + * Data transitions on high->low clock, is valid on low->high clock. + * Spec says edge transitions no closer than 160 nSec, minimum clock + * cycle 400 nSec. I could only manage about 500 nSec edges with + * an XOR loop, so I won't worry about delays yet. + * I disable interrupts during bit flipping to ensure atomic + * updates of the registers. I do lots of interrupt disable/enable + * to ensure we don't hang out too long with interrupts disabled. + */ + + /* First, crank out 32 1-bits as preamble. + * This is 64 transitions to clock the bits, with clock/data + * left high. + */ + save_flags(flags); + cli(); + for (i=0; i<64; i++) { + io->iop_pdatc ^= fip->fc_mdck; + udelay(0); + } + restore_flags(flags); + + read_op = ((cmd & 0xf0000000) == 0x60000000); + + /* We return the command word on a write op, or the command portion + * plus the new data on a read op. This is what the 8xx FEC does, + * and it allows the functions to simply look at the returned value + * and know the PHY/register as well. + */ + if (read_op) + retval = cmd; + else + retval = (cmd >> 16); + + /* Clock out the first 16 MS bits of the command. + */ + save_flags(flags); + cli(); + for (i=0; i<16; i++) { + io->iop_pdatc &= ~(fip->fc_mdck); + if (cmd & 0x80000000) + io->iop_pdatc |= fip->fc_mdio; + else + io->iop_pdatc &= ~(fip->fc_mdio); + cmd <<= 1; + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + } + + /* Do the turn-around. If read op, we make the IO and input. + * If write op, do the 1/0 thing. + */ + io->iop_pdatc &= ~(fip->fc_mdck); + if (read_op) + io->iop_pdirc &= ~(fip->fc_mdio); + else + io->iop_pdatc |= fip->fc_mdio; + io->iop_pdatc |= fip->fc_mdck; + + /* I do this mainly to get just a little delay. + */ + restore_flags(flags); + save_flags(flags); + cli(); + io->iop_pdatc &= ~(fip->fc_mdck); + io->iop_pdirc &= ~(fip->fc_mdio); + io->iop_pdatc |= fip->fc_mdck; + + restore_flags(flags); + save_flags(flags); + cli(); + + /* For read, clock in 16 bits. For write, clock out + * rest of command. + */ + if (read_op) { + io->iop_pdatc &= ~(fip->fc_mdck); + udelay(0); + for (i=0; i<16; i++) { + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + retval <<= 1; + if (io->iop_pdatc & fip->fc_mdio) + retval |= 1; + io->iop_pdatc &= ~(fip->fc_mdck); + udelay(0); + } + } + else { + for (i=0; i<16; i++) { + io->iop_pdatc &= ~(fip->fc_mdck); + if (cmd & 0x80000000) + io->iop_pdatc |= fip->fc_mdio; + else + io->iop_pdatc &= ~(fip->fc_mdio); + cmd <<= 1; + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + } + io->iop_pdatc &= ~(fip->fc_mdck); + } + restore_flags(flags); + + /* Some diagrams show two 1 bits for "idle". I don't know if + * this is really necessary or if it was just to indicate nothing + * is going to happen for a while. + * Make the data pin an output, set the data high, and clock it. + */ + save_flags(flags); + cli(); + io->iop_pdatc |= fip->fc_mdio; + io->iop_pdirc |= fip->fc_mdio; + for (i=0; i<3; i++) + io->iop_pdatc ^= fip->fc_mdck; + restore_flags(flags); + + /* We exit with the same conditions as entry. + */ + return(retval); +} diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c index caa5ca8b0..97c4cb880 100644 --- a/arch/ppc/8260_io/uart.c +++ b/arch/ppc/8260_io/uart.c @@ -977,8 +977,7 @@ static int rs_8xx_write(struct tty_struct * tty, int from_user, } if (from_user) { - if (c != - copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { + if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { if (!ret) ret = -EFAULT; break; @@ -2396,10 +2395,10 @@ int __init rs_8xx_init(void) io->iop_pdird &= ~0x00800000; io->iop_psord &= ~0x00c00000; #if USE_SMC2 - io->iop_ppara |= 0x01800000; - io->iop_pdira |= 0x00800000; - io->iop_pdira &= ~0x01000000; - io->iop_psora &= ~0x01800000; + io->iop_ppara |= 0x00c00000; + io->iop_pdira |= 0x00400000; + io->iop_pdira &= ~0x00800000; + io->iop_psora &= ~0x00c00000; #endif /* Configure SCC2 and SCC3. Be careful about the fine print. @@ -2473,11 +2472,11 @@ int __init rs_8xx_init(void) * descriptors from dual port ram, and a character * buffer area from host mem. */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); + mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -2506,11 +2505,11 @@ int __init rs_8xx_init(void) sup->scc_genscc.scc_rbase = dp_addr; } - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); + mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -2716,11 +2715,11 @@ static int __init serial_console_setup(struct console *co, char *options) /* Allocate space for two buffer descriptors in the DP ram. */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2, 8); /* Allocate space for two 2 byte FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(4); + mem_addr = m8260_cpm_hostalloc(4, 1); /* Set the physical address of the host memory buffers in * the buffer descriptors. diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index 730453bbb..b77cf32da 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -484,8 +484,11 @@ for (;;) { cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. - */ - skb = dev_alloc_skb(pkt_len); + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -493,10 +496,10 @@ for (;;) { } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index f69d0dfbd..45f10b635 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -669,18 +669,21 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { #endif /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. */ - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); fep->stats.rx_dropped++; } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c index a78f8aa41..0073527a7 100644 --- a/arch/ppc/amiga/time.c +++ b/arch/ppc/amiga/time.c @@ -11,10 +11,6 @@ #include <linux/timex.h> -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec); - unsigned long m68k_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; @@ -37,38 +33,6 @@ int m68k_set_rtc_time(unsigned long nowtime) return -1; } -/* 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 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - - void apus_heartbeat (void) { #ifdef CONFIG_HEARTBEAT diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile index 48750982e..f7ea3a3fa 100644 --- a/arch/ppc/chrpboot/Makefile +++ b/arch/ppc/chrpboot/Makefile @@ -67,11 +67,13 @@ initrd.o: ramdisk.image.gz piggyback zImage: $(OBJS) no_initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) - ./addnote $@ + cp $@ $@.rs6k + ./addnote $@.rs6k zImage.initrd: $(OBJS) initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) - ./addnote $@ + cp $@ $@.rs6k + ./addnote $@.rs6k else znetboot: diff --git a/arch/ppc/chrpboot/addnote.c b/arch/ppc/chrpboot/addnote.c index 5f0934f6e..b2374df7c 100644 --- a/arch/ppc/chrpboot/addnote.c +++ b/arch/ppc/chrpboot/addnote.c @@ -22,12 +22,23 @@ char arch[] = "PowerPC"; #define N_DESCR 6 unsigned int descr[N_DESCR] = { +#if 1 + /* values for IBM RS/6000 machines */ 0xffffffff, /* real-mode = true */ 0x00c00000, /* real-base, i.e. where we expect OF to be */ 0xffffffff, /* real-size */ 0xffffffff, /* virt-base */ 0xffffffff, /* virt-size */ 0x4000, /* load-base */ +#else + /* values for longtrail CHRP */ + 0, /* real-mode = false */ + 0xffffffff, /* real-base */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x00600000, /* load-base */ +#endif }; unsigned char buf[512]; @@ -63,7 +74,7 @@ unsigned char buf[512]; unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; -main(int ac, char **av) +int main(int ac, char **av) { int fd, n, i; int ph, ps, np; diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile index 23afda4a8..494026e42 100644 --- a/arch/ppc/coffboot/Makefile +++ b/arch/ppc/coffboot/Makefile @@ -8,7 +8,7 @@ HOSTCFLAGS = -O -I$(TOPDIR)/include CFLAGS = $(CPPFLAGS) -O -fno-builtin OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x00400000 +CHRP_LD_ARGS = -Ttext 0x01000000 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o diff --git a/arch/ppc/coffboot/chrpmain.c b/arch/ppc/coffboot/chrpmain.c index 4d994d17e..08b238b16 100644 --- a/arch/ppc/coffboot/chrpmain.c +++ b/arch/ppc/coffboot/chrpmain.c @@ -22,13 +22,18 @@ void stop_imac_usb(void); #define get_16be(x) (*(unsigned short *)(x)) #define get_32be(x) (*(unsigned *)(x)) -#define RAM_START 0x00000000 -#define RAM_END (8<<20) +#define RAM_END (16 << 20) #define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) char *avail_ram; -char *end_avail; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; extern char _end[]; extern char image_data[]; @@ -60,29 +65,30 @@ boot(int a1, int a2, void *prom) im = image_data; len = image_len; /* claim 3MB starting at PROG_START */ - claim(PROG_START, 3 << 20, 0); + claim(PROG_START, PROG_SIZE, 0); dst = (void *) PROG_START; if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim 512kB for scratch space */ - avail_ram = (char *) claim(0, 512 << 10, 0x10); - end_avail = avail_ram + (512 << 10); - printf("avail_ram = %x\n", avail_ram); + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 3 << 20, im, &len); + gunzip(dst, PROG_SIZE, im, &len); printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); } else { memmove(dst, im, len); } flush_cache(dst, len); - stop_imac_ethernet(); - stop_imac_usb(); make_bi_recs((unsigned long) dst + len); sa = (unsigned long)PROG_START; printf("start address = 0x%x\n", sa); - (*(void (*)())sa)(0, 0, prom, a1, a2); + (*(void (*)())sa)(a1, a2, prom); printf("returned?\n"); @@ -122,6 +128,7 @@ void make_bi_recs(unsigned long addr) rec = (struct bi_record *)((unsigned long)rec + rec->size); } +#if 0 #define eieio() asm volatile("eieio"); void stop_imac_ethernet(void) @@ -172,14 +179,35 @@ void stop_imac_usb(void) *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ eieio(); } +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; void *zalloc(void *x, unsigned items, unsigned size) { - void *p = avail_ram; + void *p; + struct memchunk **mpp, *mp; size *= items; size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; if (avail_ram > end_avail) { printf("oops... out of memory\n"); pause(); @@ -189,6 +217,17 @@ void *zalloc(void *x, unsigned items, unsigned size) void zfree(void *x, void *addr, unsigned nb) { + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; } #define HEAD_CRC 2 diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 950118eb2..0a217d4c9 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -88,11 +88,15 @@ fi if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then bool 'Math emulation' CONFIG_MATH_EMULATION fi + endmenu mainmenu_option next_comment comment 'General setup' +bool 'High memory support (experimental)' CONFIG_HIGHMEM +bool 'Mac-on-Linux support' CONFIG_MOL + define_bool CONFIG_ISA n define_bool CONFIG_SBUS n @@ -140,20 +144,6 @@ if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC fi - bool 'Power management support for PowerBooks' CONFIG_PMAC_PBOOK - bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY - tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL - if [ "$CONFIG_MAC_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE - fi - bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB - if [ "$CONFIG_ADB" = "y" ]; then - bool ' Include CUDA ADB driver' CONFIG_ADB_CUDA - bool ' Include MacIO ADB driver' CONFIG_ADB_MACIO - bool ' Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU - bool 'Support for ADB keyboard' CONFIG_ADB_KEYBOARD - bool 'Support for ADB mouse' CONFIG_ADBMOUSE - fi tristate 'Support for /dev/rtc' CONFIG_PPC_RTC bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -192,7 +182,7 @@ endmenu source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in -#source drivers.new/Config.in +source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then source net/Config.in @@ -262,6 +252,43 @@ comment 'Console drivers' source drivers/video/Config.in endmenu +source drivers/input/Config.in + +mainmenu_option next_comment +comment 'Macintosh device drivers' + +if [ "$CONFIG_ALL_PPC" = "y" ]; then + # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU + bool 'Support for CUDA based PowerMacs' CONFIG_ADB_CUDA + bool 'Support for PMU based PowerMacs' CONFIG_ADB_PMU + if [ "$CONFIG_ADB_PMU" = "y" ]; then + bool ' Power management support for PowerBooks' CONFIG_PMAC_PBOOK + # made a separate option since backlight may end up beeing used + # on non-powerbook machines (but only on PMU based ones AFAIK) + bool ' Backlight control for LCD screens' CONFIG_PMAC_BACKLIGHT + fi + bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY + tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL + if [ "$CONFIG_MAC_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + fi + bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB + if [ "$CONFIG_ADB" = "y" ]; then + bool ' Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO + fi +fi +if [ "$CONFIG_ADB" = "y" ]; then + dep_bool ' Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT + if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then + define_bool CONFIG_MAC_HID y + bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES + bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN + else + bool ' Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD + fi +fi +endmenu + source drivers/char/Config.in source drivers/media/Config.in @@ -287,7 +314,6 @@ source arch/ppc/8260_io/Config.in fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index 68e49c148..a9ae80db0 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -9,12 +9,20 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y @@ -25,15 +33,9 @@ CONFIG_ALL_PPC=y CONFIG_ALTIVEC=y # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set CONFIG_PCI=y @@ -44,8 +46,8 @@ CONFIG_SYSVIPC=y CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -57,21 +59,18 @@ CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_ADBMOUSE=y +CONFIG_PPC_RTC=y CONFIG_PROC_DEVICETREE=y CONFIG_BOOTX_TEXT=y # CONFIG_MOTOROLA_HOTSWAP is not set # CONFIG_CMDLINE_BOOL is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -90,8 +89,11 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -109,22 +111,24 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP 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_INET_ECN is not set CONFIG_SYN_COOKIES=y -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -145,26 +149,42 @@ CONFIG_IDE=y # IDE, ATA and ATAPI Block devices # 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_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -173,37 +193,40 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set +CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set -# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -211,6 +234,10 @@ CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -296,6 +323,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -327,8 +355,9 @@ CONFIG_DE4X5=y # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set # CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -347,11 +376,13 @@ CONFIG_DE4X5=y # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_DEFLATE=y # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -404,12 +435,13 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y @@ -420,6 +452,7 @@ CONFIG_FB_MATROX_G100=y CONFIG_FB_ATY=y CONFIG_FB_ATY128=y CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -437,6 +470,32 @@ CONFIG_FONT_SUN12x22=y # CONFIG_FONT_ACORN_8x8 is not set # +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_HID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y + +# # Character devices # CONFIG_VT=y @@ -459,7 +518,6 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -469,19 +527,19 @@ CONFIG_PSMOUSE=y # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -490,26 +548,31 @@ CONFIG_NVRAM=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y +# CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -519,7 +582,8 @@ CONFIG_ISO9660_FS=y # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set @@ -571,12 +635,14 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -593,6 +659,10 @@ CONFIG_NLS=y # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -605,6 +675,7 @@ CONFIG_NLS=y # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Sound @@ -614,6 +685,7 @@ CONFIG_DMASOUND_AWACS=y CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -622,6 +694,7 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -647,24 +720,39 @@ CONFIG_SOUND_CS4232=m # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # CONFIG_USB=y CONFIG_USB_DEBUG=y -# CONFIG_USB_DEVICEFS is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -679,15 +767,13 @@ CONFIG_USB_OHCI=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# USB Human Interface Devices (HID) +# CONFIG_USB_HID=y # CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set # # Kernel hacking @@ -695,4 +781,3 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y - diff --git a/arch/ppc/configs/est8260_defconfig b/arch/ppc/configs/est8260_defconfig index 972820d21..d317c8517 100644 --- a/arch/ppc/configs/est8260_defconfig +++ b/arch/ppc/configs/est8260_defconfig @@ -9,12 +9,18 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +# CONFIG_MODULES is not set + +# # Platform support # CONFIG_PPC=y # CONFIG_6xx is not set # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set CONFIG_8260=y # CONFIG_8xx is not set CONFIG_6xx=y @@ -29,13 +35,9 @@ CONFIG_EST8260=y CONFIG_MACH_SPECIFIC=y # -# Loadable module support -# -# CONFIG_MODULES is not set - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set # CONFIG_PCI is not set @@ -56,15 +58,17 @@ CONFIG_KERNEL_ELF=y # CONFIG_PARPORT is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set -# CONFIG_PMAC_PBOOK is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADB is not set +# CONFIG_PPC_RTC is not set # CONFIG_PROC_DEVICETREE is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_MOTOROLA_HOTSWAP is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -84,8 +88,10 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -105,17 +111,11 @@ CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP 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_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -126,9 +126,9 @@ CONFIG_SKB_LARGE=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -164,6 +164,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -245,6 +246,15 @@ CONFIG_NET_ETHERNET=y # CONFIG_FB is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# +# Macintosh device drivers +# + +# # Character devices # # CONFIG_VT is not set @@ -269,19 +279,19 @@ CONFIG_UNIX98_PTY_COUNT=256 # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -290,9 +300,13 @@ CONFIG_UNIX98_PTY_COUNT=256 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -310,6 +324,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set @@ -369,6 +384,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set @@ -382,7 +398,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y -# CONFIG_FCC_ENET is not set +# CONFIG_FEC_ENET is not set # # USB support diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig index e141e8f54..522bd5d5d 100644 --- a/arch/ppc/configs/gemini_defconfig +++ b/arch/ppc/configs/gemini_defconfig @@ -14,14 +14,12 @@ CONFIG_EXPERIMENTAL=y CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set -# CONFIG_82xx is not set +# CONFIG_PPC64 is not set +# CONFIG_8260 is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set # CONFIG_ALL_PPC is not set CONFIG_GEMINI=y +# CONFIG_EST8260 is not set # CONFIG_APUS is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -37,7 +35,8 @@ CONFIG_KMOD=y # # General setup # -# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_SBUS is not set CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y @@ -47,8 +46,12 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# # CONFIG_PARPORT is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set @@ -57,7 +60,6 @@ CONFIG_KERNEL_ELF=y # CONFIG_MAC_SERIAL is not set # CONFIG_ADB is not set # CONFIG_PROC_DEVICETREE is not set -# CONFIG_TOTALMP is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_MOTOROLA_HOTSWAP is not set @@ -70,22 +72,16 @@ CONFIG_KERNEL_ELF=y # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# Additional Block Devices # -# CONFIG_BLK_DEV_HD_ONLY is not set -# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -138,6 +134,13 @@ CONFIG_SKB_LARGE=y # CONFIG_NET_SCHED is not set # +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# # SCSI support # CONFIG_SCSI=y @@ -148,7 +151,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set -CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 @@ -171,7 +173,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -184,43 +185,22 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_NCR53C7xx_sync is not set +# CONFIG_SCSI_NCR53C7xx_FAST is not set +# CONFIG_SCSI_NCR53C7xx_DISCONNECT 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_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 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 is not set # CONFIG_SCSI_MAC53C94 is not set -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set # # Network device support @@ -232,6 +212,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -249,12 +230,10 @@ CONFIG_NCR885E=y # 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_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # @@ -274,7 +253,7 @@ CONFIG_NCR885E=y # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -292,6 +271,11 @@ CONFIG_NCR885E=y # CONFIG_HAMRADIO is not set # +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -361,12 +345,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_AGP is not set # -# USB support -# -# CONFIG_USB is not set - -# -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set @@ -378,12 +357,14 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set @@ -397,6 +378,7 @@ CONFIG_EXT2_FS=y # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -416,6 +398,11 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOUND is not set # +# USB support +# +# CONFIG_USB is not set + +# # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set diff --git a/arch/ppc/configs/rpxcllf_defconfig b/arch/ppc/configs/rpxcllf_defconfig index 9aaa80530..4dda3d93f 100644 --- a/arch/ppc/configs/rpxcllf_defconfig +++ b/arch/ppc/configs/rpxcllf_defconfig @@ -9,18 +9,27 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +# CONFIG_MODULES is not set + +# # Platform support # CONFIG_PPC=y # CONFIG_6xx is not set # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set CONFIG_8xx=y CONFIG_SERIAL_CONSOLE=y # CONFIG_RPXLITE is not set CONFIG_RPXCLASSIC=y # CONFIG_BSEIP is not set +# CONFIG_TQM8xxL is not set +# CONFIG_TQM860L is not set +# CONFIG_TQM860 is not set # CONFIG_MBX is not set # CONFIG_WINCEPT is not set # CONFIG_ALL_PPC is not set @@ -29,13 +38,9 @@ CONFIG_MACH_SPECIFIC=y CONFIG_MATH_EMULATION=y # -# Loadable module support -# -# CONFIG_MODULES is not set - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set # CONFIG_PCI is not set @@ -56,6 +61,11 @@ CONFIG_KERNEL_ELF=y # CONFIG_PARPORT is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -75,8 +85,10 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -96,17 +108,11 @@ CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP 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_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -117,9 +123,9 @@ CONFIG_SKB_LARGE=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -155,6 +161,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -236,6 +243,15 @@ CONFIG_NET_ETHERNET=y # CONFIG_FB is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# +# Macintosh device drivers +# + +# # Character devices # # CONFIG_VT is not set @@ -260,19 +276,19 @@ CONFIG_UNIX98_PTY_COUNT=256 # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -281,9 +297,13 @@ CONFIG_UNIX98_PTY_COUNT=256 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -301,6 +321,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set @@ -360,6 +381,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set @@ -374,7 +396,9 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y CONFIG_FEC_ENET=y +CONFIG_ENET_BIG_BUFFERS=y CONFIG_8xxSMC2=y +# CONFIG_8xx_ALTSMC2 is not set CONFIG_8xxSCC=y # diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index e1854fad6..9b3d88212 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -9,12 +9,20 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y @@ -25,15 +33,9 @@ CONFIG_ALL_PPC=y CONFIG_ALTIVEC=y # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set CONFIG_PCI=y @@ -44,8 +46,8 @@ CONFIG_SYSVIPC=y CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -57,21 +59,18 @@ CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_ADBMOUSE=y +CONFIG_PPC_RTC=y CONFIG_PROC_DEVICETREE=y CONFIG_BOOTX_TEXT=y # CONFIG_MOTOROLA_HOTSWAP is not set # CONFIG_CMDLINE_BOOL is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -90,8 +89,11 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -109,22 +111,24 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP 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_INET_ECN is not set CONFIG_SYN_COOKIES=y -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -145,26 +149,42 @@ CONFIG_IDE=y # IDE, ATA and ATAPI Block devices # 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_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -173,37 +193,40 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set +CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set -# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -211,6 +234,10 @@ CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -296,6 +323,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -327,8 +355,9 @@ CONFIG_DE4X5=y # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set # CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -347,11 +376,13 @@ CONFIG_DE4X5=y # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_DEFLATE=y # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -404,12 +435,13 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y @@ -420,6 +452,7 @@ CONFIG_FB_MATROX_G100=y CONFIG_FB_ATY=y CONFIG_FB_ATY128=y CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -437,6 +470,32 @@ CONFIG_FONT_SUN12x22=y # CONFIG_FONT_ACORN_8x8 is not set # +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_HID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y + +# # Character devices # CONFIG_VT=y @@ -459,7 +518,6 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -469,19 +527,19 @@ CONFIG_PSMOUSE=y # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -490,26 +548,31 @@ CONFIG_NVRAM=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y +# CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -519,7 +582,7 @@ CONFIG_ISO9660_FS=y # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set +CONFIG_DEVFS_FS=y # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y @@ -572,12 +635,14 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -594,6 +659,10 @@ CONFIG_NLS=y # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -606,6 +675,7 @@ CONFIG_NLS=y # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Sound @@ -615,6 +685,7 @@ CONFIG_DMASOUND_AWACS=y CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -623,6 +694,7 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -648,24 +720,39 @@ CONFIG_SOUND_CS4232=m # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # CONFIG_USB=y CONFIG_USB_DEBUG=y -# CONFIG_USB_DEVICEFS is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -680,15 +767,18 @@ CONFIG_USB_OHCI=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# USB Human Interface Devices (HID) +# CONFIG_USB_HID=y # CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set + +# +# Mac-on-Linux (MOL) support +# +# CONFIG_MOL is not set # # Kernel hacking diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 0369ad800..a539083bd 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -99,8 +99,10 @@ endif ifeq ($(CONFIG_ALL_PPC),y) O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \ chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \ - prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o \ - pmac_backlight.o + prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o + ifeq ($(CONFIG_PMAC_BACKLIGHT),y) + O_OBJS += pmac_backlight.o + endif OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index b93bd8193..d75663be5 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -304,7 +304,7 @@ __apus void apus_calibrate_decr(void) { #ifdef CONFIG_APUS - int freq, divisor; + unsigned long freq; /* This algorithm for determining the bus speed was contributed by Ralph Schmidt. */ @@ -335,8 +335,8 @@ void apus_calibrate_decr(void) bus_speed = 60; freq = 15000000; } else if ((bus_speed >= 63) && (bus_speed < 69)) { - bus_speed = 66; - freq = 16500000; + bus_speed = 67; + freq = 16666667; } else { printk ("APUS: Unable to determine bus speed (%d). " "Defaulting to 50MHz", bus_speed); @@ -375,12 +375,10 @@ void apus_calibrate_decr(void) } - freq *= 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; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); __bus_speed = bus_speed; __speed_test_failed = speed_test_failed; diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index c43296c42..43b678861 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -284,13 +284,38 @@ hydra_init(void) return 1; } +#ifdef CONFIG_POWER4 +static void +power4_fixup_dev(struct pci_dev *dev) +{ + int i; + unsigned long offset; + + for (i = 0; i < 6; ++i) { + if (dev->resource[i].start == 0) + continue; + offset = pci_address_offset(dev->bus->number, + dev->resource[i].flags); + if (offset) { + dev->resource[i].start += offset; + dev->resource[i].end += offset; + printk("device %x.%x[%d] now [%lx..%lx]\n", + dev->bus->number, dev->devfn, i, + dev->resource[i].start, + dev->resource[i].end); + } + /* zap the 2nd function of the winbond chip */ + if (dev->resource[i].flags & IORESOURCE_IO + && dev->bus->number == 0 && dev->devfn == 0x81) + dev->resource[i].flags &= ~IORESOURCE_IO; + } +} +#endif /* CONFIG_POWER4 */ + void __init chrp_pcibios_fixup(void) { struct pci_dev *dev; -#ifdef CONFIG_POWER4 - int i; -#endif int *brp; struct device_node *np; extern struct pci_ops generic_pci_ops; @@ -316,10 +341,8 @@ chrp_pcibios_fixup(void) /* PCI interrupts are controlled by the OpenPIC */ pci_for_each_dev(dev) { np = find_pci_device_OFnode(dev->bus->number, dev->devfn); - if ( (np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) + if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) dev->irq = np->intrs[0].line; - if ( dev->irq ) - dev->irq = openpic_to_irq( dev->irq ); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { @@ -337,25 +360,7 @@ chrp_pcibios_fixup(void) dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } #ifdef CONFIG_POWER4 - for (i = 0; i < 6; ++i) { - unsigned long offset; - if (dev->resource[i].start == 0) - continue; - offset = pci_address_offset(dev->bus->number, - dev->resource[i].flags); - if (offset) { - dev->resource[i].start += offset; - dev->resource[i].end += offset; - printk("device %x.%x[%d] now [%lx..%lx]\n", - dev->bus->number, dev->devfn, i, - dev->resource[i].start, - dev->resource[i].end); - } - /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - } + power4_fixup_dev(dev); #else if (dev->bus->number > 0 && python_busnr > 0) dev->resource[0].start += dev->bus->number*0x01000000; @@ -363,6 +368,40 @@ chrp_pcibios_fixup(void) } } +static struct { + /* parent is iomem */ + struct resource ram, pci_mem, isa_mem, pci_io, pci_cfg, rom_exp, flash; + /* parent is isa_mem */ + struct resource nvram; +} gg2_resources = { + ram: { "RAM", 0x00000000, 0xbfffffff, IORESOURCE_MEM }, + pci_mem: { "GG2 PCI mem", 0xc0000000, 0xf6ffffff, IORESOURCE_MEM }, + isa_mem: { "GG2 ISA mem", 0xf7000000, 0xf7ffffff }, + pci_io: { "GG2 PCI I/O", 0xf8000000, 0xf8ffffff }, + pci_cfg: { "GG2 PCI cfg", 0xfec00000, 0xfec7ffff }, + rom_exp: { "ROM exp", 0xff000000, 0xff7fffff, }, + flash: { "Flash ROM", 0xfff80000, 0xffffffff }, + nvram: { "NVRAM", 0xf70e0000, 0xf70e7fff }, +}; + +static void __init gg2_pcibios_fixup(void) +{ + int i; + extern unsigned long *end_of_DRAM; + + chrp_pcibios_fixup(); + gg2_resources.ram.end = (unsigned long)end_of_DRAM-PAGE_OFFSET; + for (i = 0; i < 7; i++) + request_resource(&iomem_resource, + &((struct resource *)&gg2_resources)[i]); + request_resource(&gg2_resources.isa_mem, &gg2_resources.nvram); +} + +static void __init gg2_pcibios_fixup_bus(struct pci_bus *bus) +{ + bus->resource[1] = &gg2_resources.pci_mem; +} + decl_config_access_method(grackle); decl_config_access_method(indirect); decl_config_access_method(rtas); @@ -372,6 +411,7 @@ chrp_setup_pci_ptrs(void) { struct device_node *py; + ppc_md.pcibios_fixup = chrp_pcibios_fixup; #ifdef CONFIG_POWER4 set_config_access_method(rtas); pci_dram_offset = 0; @@ -428,16 +468,17 @@ chrp_setup_pci_ptrs(void) } else { + /* LongTrail */ pci_dram_offset = 0; isa_mem_base = 0xf7000000; isa_io_base = 0xf8000000; set_config_access_method(gg2); + ppc_md.pcibios_fixup = gg2_pcibios_fixup; + ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; } } } #endif /* CONFIG_POWER4 */ - - ppc_md.pcibios_fixup = chrp_pcibios_fixup; } #ifdef CONFIG_PPC64BRIDGE diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 8d6649231..ccc6621de 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -62,11 +62,13 @@ extern volatile unsigned char *chrp_int_ack_special; unsigned long chrp_get_rtc_time(void); int chrp_set_rtc_time(unsigned long nowtime); void chrp_calibrate_decr(void); -void chrp_time_init(void); +long chrp_time_init(void); void chrp_setup_pci_ptrs(void); -extern void chrp_progress(char *, unsigned short); void chrp_event_scan(void); +void rtas_display_progress(char *, unsigned short); +void rtas_indicator_progress(char *, unsigned short); +void bootx_text_progress(char *, unsigned short); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); @@ -91,6 +93,8 @@ extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; extern unsigned long loops_per_sec; +extern int bootx_text_mapped; +static int max_width; unsigned long empty_zero_page[1024]; @@ -252,13 +256,6 @@ chrp_setup_arch(void) #endif ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ printk("Boot arguments: %s\n", cmd_line); - - 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"); #ifndef CONFIG_PPC64BRIDGE /* PCI bridge config space access area - @@ -446,11 +443,43 @@ void __init chrp_init_IRQ(void) void __init chrp_init2(void) { +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) + struct device_node *kbd; +#endif #ifdef CONFIG_NVRAM pmac_nvram_init(); #endif + + 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"); + if (ppc_md.progress) ppc_md.progress(" Have fun! ", 0x7777); + +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) + if (kbd->parent && kbd->parent->type + && strcmp(kbd->parent->type, "adb") == 0) + break; + if (kbd) { + ppc_md.kbd_setkeycode = mackbd_setkeycode; + ppc_md.kbd_getkeycode = mackbd_getkeycode; + ppc_md.kbd_translate = mackbd_translate; + ppc_md.kbd_unexpected_up = mackbd_unexpected_up; + ppc_md.kbd_leds = mackbd_leds; + ppc_md.kbd_init_hw = mackbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif /* CONFIG_MAGIC_SYSRQ */ + } +#endif /* CONFIG_VT && CONFIG_ADB_KEYBOARD */ } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) @@ -598,40 +627,40 @@ void __init ppc_md.calibrate_decr = chrp_calibrate_decr; #ifdef CONFIG_VT -#ifdef CONFIG_MAC_KEYBOARD - if (adb_driver == NULL) - { -#endif /* CONFIG_MAC_KEYBOAD */ - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; - SYSRQ_KEY = 0x54; -#endif /* CONFIG_MAGIC_SYSRQ */ -#ifdef CONFIG_MAC_KEYBOARD - } - else - { - ppc_md.kbd_setkeycode = mackbd_setkeycode; - ppc_md.kbd_getkeycode = mackbd_getkeycode; - ppc_md.kbd_translate = mackbd_translate; - ppc_md.kbd_unexpected_up = mackbd_unexpected_up; - ppc_md.kbd_leds = mackbd_leds; - ppc_md.kbd_init_hw = mackbd_init_hw; + /* these are adjusted in chrp_init2 if we have an ADB keyboard */ + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; - SYSRQ_KEY = 0x69; + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif /* CONFIG_MAGIC_SYSRQ */ - } -#endif /* CONFIG_MAC_KEYBOARD */ #endif /* CONFIG_VT */ - if ( rtas_data ) - ppc_md.progress = chrp_progress; - + + if (rtas_data) { + struct device_node *rtas; + unsigned int *p; + + rtas = find_devices("rtas"); + if (rtas != NULL) { + if (get_property(rtas, "display-character", NULL)) { + ppc_md.progress = rtas_display_progress; + p = (unsigned int *) get_property + (rtas, "ibm,display-line-length", NULL); + if (p) + max_width = *p; + } else if (get_property(rtas, "set-indicator", NULL)) + ppc_md.progress = rtas_indicator_progress; + } + } +#ifdef CONFIG_BOOTX_TEXT + if (ppc_md.progress == NULL && bootx_text_mapped) + ppc_md.progress = bootx_text_progress; +#endif + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = chrp_ide_insw; ppc_ide_md.outsw = chrp_ide_outsw; @@ -653,30 +682,13 @@ void __init } void __chrp -chrp_progress(char *s, unsigned short hex) +rtas_display_progress(char *s, unsigned short hex) { - extern unsigned int rtas_data; - int max_width, width; - struct device_node *root; + int width; char *os = s; - unsigned long *p; - if ( (root = find_path_device("/rtas")) && - (p = (unsigned long *)get_property(root, - "ibm,display-line-length", - NULL)) ) - max_width = *p; - else - max_width = 0x10; - - if ( (_machine != _MACH_chrp) || !rtas_data ) - return; if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) - { - /* assume no display-character RTAS method - use hex display */ - call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); return; - } width = max_width; while ( *os ) @@ -696,3 +708,17 @@ chrp_progress(char *s, unsigned short hex) call_rtas( "display-character", 1, 1, NULL, ' ' ); } +void __chrp +rtas_indicator_progress(char *s, unsigned short hex) +{ + call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); +} + +#ifdef CONFIG_BOOTX_TEXT +void +bootx_text_progress(char *s, unsigned short hex) +{ + prom_print(s); + prom_print("\n"); +} +#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c index 54b4a76bb..67325c685 100644 --- a/arch/ppc/kernel/chrp_time.c +++ b/arch/ppc/kernel/chrp_time.c @@ -15,6 +15,7 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/interrupt.h> +#include <linux/time.h> #include <linux/timex.h> #include <linux/kernel_stat.h> #include <linux/mc146818rtc.h> @@ -32,18 +33,20 @@ static int nvram_as1 = NVRAM_AS1; static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -void __init chrp_time_init(void) +long __init chrp_time_init(void) { struct device_node *rtcs; int base; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); if (rtcs == NULL || rtcs->addrs == NULL) - return; + return 0; base = rtcs->addrs[0].address; nvram_as1 = 0; nvram_as0 = base; nvram_data = base + 1; + + return 0; } int __chrp chrp_cmos_clock_read(int addr) @@ -115,28 +118,34 @@ int __chrp chrp_set_rtc_time(unsigned long nowtime) unsigned long __chrp chrp_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; + int uip, i; /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); sec = chrp_cmos_clock_read(RTC_SECONDS); min = chrp_cmos_clock_read(RTC_MINUTES); hour = chrp_cmos_clock_read(RTC_HOURS); day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); mon = chrp_cmos_clock_read(RTC_MONTH); year = chrp_cmos_clock_read(RTC_YEAR); - } while (sec != chrp_cmos_clock_read(RTC_SECONDS)); + uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); @@ -155,8 +164,7 @@ unsigned long __chrp chrp_get_rtc_time(void) void __init chrp_calibrate_decr(void) { struct device_node *cpu; - int *fp, divisor; - unsigned long freq; + unsigned int freq, *fp; if (via_calibrate_decr()) return; @@ -168,15 +176,13 @@ void __init chrp_calibrate_decr(void) freq = 16666000; /* hardcoded default */ cpu = find_type_devices("cpu"); if (cpu != 0) { - fp = (int *) get_property(cpu, "timebase-frequency", NULL); + fp = (unsigned int *) + get_property(cpu, "timebase-frequency", NULL); if (fp != 0) freq = *fp; } - freq *= 30; - divisor = 30; - printk("time_init: decrementer frequency = %lu/%d (%ld MHz)\n", freq, - divisor, (freq/divisor)>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index d40a54cf1..627cd7a2a 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -30,6 +30,7 @@ #include <linux/errno.h> #include <linux/sys.h> #include <linux/config.h> +#include "mol.h" #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -85,7 +86,7 @@ _GLOBAL(DoSyscall) beq- 10f cmpi 0,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */ beq- 16f - lwz r10,TASK_FLAGS(r2) + lwz r10,TASK_PTRACE(r2) andi. r10,r10,PT_TRACESYS bne- 50f cmpli 0,r0,NR_syscalls @@ -241,6 +242,13 @@ _GLOBAL(_switch) /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */ lwz r9,PGDIR(r4) /* cache the page table root */ tophys(r9,r9) /* convert to phys addr */ +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + li r5, 0x3980 + stw r5, 8(r6) + lwz r5, 8(r6) +#endif mtspr M_TWB,r9 /* Update MMU base address */ tlbia SYNC @@ -349,21 +357,18 @@ ret_to_user_hook: beq+ restore li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD + MOL_HOOK_MMU(8,r8) bl do_signal .globl do_signal_ret do_signal_ret: -restore: - lwz r3,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r3 - mtlr r0 +restore: lwz r3,_XER(r1) mtspr XER,r3 - REST_10GPRS(3, r1) - REST_10GPRS(13, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - + REST_10GPRS(9,r1) + REST_10GPRS(19,r1) + REST_2GPRS(29,r1) + REST_GPR(31,r1) + /* make sure we hard disable here, even if rtl is active, to protect * SRR[01] and SPRG2 -- Cort */ @@ -376,12 +381,28 @@ restore: lwz r0,_MSR(r1) andi. r0,r0,MSR_PR beq+ 1f +#ifdef CONFIG_ALTIVEC + mfpvr r8 /* check if we are on a G4 */ + srwi r8,r8,16 + cmpwi r8,PVR_7400@h + bne 2f + lwz r0,THREAD+THREAD_VRSAVE(r2) + mtspr SPRN_VRSAVE,r0 /* if so, restore VRSAVE reg */ +2: +#endif /* CONFIG_ALTIVEC */ addi r0,r1,INT_FRAME_SIZE /* size of frame */ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ - tophys(r2,r1) - CLR_TOP32(r2) - mtspr SPRG2,r2 /* phys exception stack pointer */ + tophys(r8,r1) + CLR_TOP32(r8) + MOL_HOOK_MMU(9, r4) /* mod. r0,r2-r7, lr, ctr */ + mtspr SPRG2,r8 /* phys exception stack pointer */ 1: + lwz r3,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r3 + mtlr r0 + REST_4GPRS(3, r1) + REST_2GPRS(7, r1) lwz r0,_MSR(r1) FIX_SRR1(r0,r2) mtspr SRR1,r0 diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index 4b63d5dc0..57599917a 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -24,6 +24,8 @@ #include <asm/errno.h> #include <asm/ohare.h> #include <asm/heathrow.h> +#include <asm/keylargo.h> +#include <asm/uninorth.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/feature.h> @@ -34,6 +36,20 @@ #define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) +/* Keylargo reg. access. */ +#define KL_FCR(r) (keylargo_base + ((r) >> 2)) +#define KL_IN(r) (in_le32(KL_FCR(r))) +#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v))) +#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v))) +#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v))) + +/* Uni-N reg. access. Note that Uni-N regs are big endian */ +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + typedef struct feature_bit { int reg; /* reg. offset from mac-io base */ unsigned int polarity; /* 0 = normal, 1 = inverse */ @@ -74,11 +90,45 @@ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_Airport_reset */ }; -/* Those bits are from a PowerBook. It's possible that desktop machines - * based on heathrow need a different definition or some bits removed +/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed + * the SCC related bits and init them once. They have proven to occasionally cause + * problems with the desktop units. */ static fbit feature_bits_heathrow[] = { {0x38,0,0}, /* FEATURE_null */ + {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,0}, /* FEATURE_Serial_enable */ + {0x38,0,0}, /* FEATURE_Serial_IO_A */ + {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,0}, /* FEATURE_Mediabay_reset */ + {0x38,1,0}, /* FEATURE_Mediabay_power */ + {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ + {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ + {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ + {0x38,1,0}, /* FEATURE_Modem_power */ + {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,1,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ + {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ +}; + +/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet). + * Heathrow-based desktop macs (Beige G3s) are _not_ handled here + */ +static fbit feature_bits_wallstreet[] = { + {0x38,0,0}, /* FEATURE_null */ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ @@ -145,32 +195,32 @@ static fbit feature_bits_paddington[] = { */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ - {0x38,0,0x00000054}, /* FEATURE_Serial_enable */ - {0x38,0,0}, /* FEATURE_Serial_IO_A */ - {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */ + {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */ + {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ {0x3c,0,0}, /* FEATURE_IDE0_enable */ - {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */ + {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ - {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */ + {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x40,1,0x02000000}, /* FEATURE_Modem_power */ + {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */ - {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */ + {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ + {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ - {0x40,1,0x08000000}, /* FEATURE_Airport_reset */ + {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; /* definition of a feature controller object */ @@ -190,6 +240,8 @@ feature_lookup_controller(struct device_node *device); static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); static void heathrow_wakeup(struct feature_controller* ctrler); +static void keylargo_init(void); +static void uninorth_init(void); static void core99_prepare_for_sleep(struct feature_controller* ctrler); static void core99_wake_up(struct feature_controller* ctrler); @@ -228,8 +280,15 @@ feature_init(void) } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + } else if (machine_is_compatible("AAPL,PowerBook1998")) { + feature_add_controller(np, feature_bits_wallstreet); } else { - feature_add_controller(np, feature_bits_heathrow); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_heathrow); + if (ctrler) + out_le32(FREG(ctrler,HEATHROW_FEATURE_REG), + in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS); + } np = np->next; } @@ -249,14 +308,17 @@ feature_init(void) np = find_devices("uni-n"); if (np && np->n_addrs > 0) { uninorth_base = ioremap(np->addrs[0].address, 0x1000); - rev = (u32 *)get_property(np, "device-rev", NULL); - if (rev) - uninorth_rev = *rev; + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); } if (uninorth_base && keylargo_base) printk("Uni-N revision: %d, KeyLargo revision: %d\n", uninorth_rev, keylargo_rev); + if (uninorth_base) + uninorth_init(); + if (keylargo_base) + keylargo_init(); + if (controller_count) printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); @@ -440,14 +502,21 @@ feature_set_gmac_power(struct device_node* device, int power) if (!uninorth_base) return; if (power) - out_le32(uninorth_base + 0x20/4, - in_le32(uninorth_base + 0x20/4) | 0x02000000); + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); else - out_le32(uninorth_base + 0x20/4, - in_le32(uninorth_base + 0x20/4) & ~0x02000000); + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); udelay(20); } +void +feature_set_gmac_phy_reset(struct device_node* device, int reset) +{ + if (!keylargo_base) + return; + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); +} + /* Pass the node of the correct controller, please */ void feature_set_usb_power(struct device_node* device, int power) @@ -460,6 +529,53 @@ feature_set_firewire_power(struct device_node* device, int power) { } +/* Initialize the Core99 UniNorth host bridge and memory controller + */ +static void +uninorth_init(void) +{ + struct device_node* gmac; + unsigned long actrl; + + /* Set the arbitrer QAck delay according to what Apple does + */ + actrl = in_be32(UN_REG(UNI_N_ARB_CTRL)) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) + << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + + /* + * Turns OFF the gmac clock. The gmac driver will turn + * it back ON when the interface is enabled. This save + * power on portables. + * + * Note: We could also try to turn OFF the PHY. Since this + * has to be done by both the gmac driver and this code, + * I'll probably end-up moving some of this out of the + * modular gmac driver into a non-modular stub containing + * some basic PHY management and power management stuffs + */ + gmac = find_devices("ethernet"); + + while(gmac) { + if (device_is_compatible(gmac, "gmac")) + break; + gmac = gmac->next; + } + if (gmac) + feature_set_gmac_power(gmac, 0); +} + +/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure + * OpenPIC is enabled + */ +static void +keylargo_init(void) +{ + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); +} + +#ifdef CONFIG_PMAC_PBOOK void feature_prepare_for_sleep(void) { @@ -506,27 +622,28 @@ feature_wake_up(void) } } -static u32 save_fcr0; -//static u32 save_fcr1; -//static u32 save_fcr2; +static u32 save_fcr[5]; static u32 save_mbcr; static void heathrow_prepare_for_sleep(struct feature_controller* ctrler) { save_mbcr = in_le32(FREG(ctrler, 0x34)); - save_fcr0 = in_le32(FREG(ctrler, 0x38)); + save_fcr[0] = in_le32(FREG(ctrler, 0x38)); + save_fcr[1] = in_le32(FREG(ctrler, 0x3c)); - out_le32(FREG(ctrler, 0x38), save_fcr0 & ~HRW_IOBUS_ENABLE); + out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE); } static void heathrow_wakeup(struct feature_controller* ctrler) { - out_le32(FREG(ctrler, 0x38), save_fcr0); + out_le32(FREG(ctrler, 0x38), save_fcr[0]); + out_le32(FREG(ctrler, 0x3c), save_fcr[1]); out_le32(FREG(ctrler, 0x34), save_mbcr); - - out_le32(FREG(ctrler, 0x38), save_fcr0 | HRW_IOBUS_ENABLE); + mdelay(1); + out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE); + mdelay(1); } static void @@ -540,4 +657,4 @@ core99_wake_up(struct feature_controller* ctrler) { /* Not yet implemented */ } - +#endif /* CONFIG_PMAC_PBOOK */ diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c index 7be4675c2..a01ff9eca 100644 --- a/arch/ppc/kernel/gemini_setup.c +++ b/arch/ppc/kernel/gemini_setup.c @@ -15,6 +15,7 @@ #include <linux/errno.h> #include <linux/reboot.h> #include <linux/pci.h> +#include <linux/time.h> #include <linux/kdev_t.h> #include <linux/types.h> #include <linux/major.h> @@ -335,7 +336,7 @@ void __init gemini_init_IRQ(void) #define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) /* ensure that the RTC is up and running */ -void __init gemini_time_init(void) +long __init gemini_time_init(void) { unsigned char reg; @@ -346,6 +347,7 @@ void __init gemini_time_init(void) gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); } + return 0; } #undef DEBUG_RTC diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S index be86a1503..1129dd40e 100644 --- a/arch/ppc/kernel/hashtable.S +++ b/arch/ppc/kernel/hashtable.S @@ -27,6 +27,7 @@ #include <asm/processor.h> #include <asm/page.h> #include <linux/config.h> +#include "mol.h" /* * Load a PTE into the hash table, if possible. @@ -593,6 +594,11 @@ _GLOBAL(flush_hash_segments) * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) +#ifdef CONFIG_MOL + mflr r10 + MOL_HOOK_MMU(10, r6) + mtlr r10 +#endif lis r6,Hash@ha lwz r6,Hash@l(r6) /* hash table base */ cmpwi 0,r6,0 /* hash table in use? */ diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 067581f5d..5d26e2917 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -31,6 +31,7 @@ #include <asm/page.h> #include <linux/config.h> #include <asm/mmu.h> +#include "mol.h" #ifdef CONFIG_APUS #include <asm/amigappc.h> @@ -78,7 +79,7 @@ CACHELINE_WORDS = 32 mtspr DBAT##n##L,RB; \ 1: #endif /* CONFIG_PPC64BRIDGE */ - + .text .globl _stext _stext: @@ -162,8 +163,8 @@ __start: /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ -__after_prom_start: bl mmu_off +__after_mmu_off: bl clear_bats bl flush_tlbs #endif @@ -202,15 +203,7 @@ __after_prom_start: 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 relocate_kernel - lis r3,KERNELBASE@h /* if so, are we */ - cmpw 0,r4,r3 /* already running at KERNELBASE? */ bne relocate_kernel -2: #endif /* CONFIG_APUS */ /* * we now have the 1st 16M of ram mapped with the bats. @@ -300,6 +293,17 @@ label: \ .long hdlr; \ .long ret_from_except +#define STD_MOL_EXCEPTION(n, label, hdlr, hook) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + MOL_HOOK(hook); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,MSR_KERNEL; \ + bl transfer_to_handler; \ + .long hdlr; \ + .long ret_from_except + /* System reset */ #ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ #ifdef CONFIG_GEMINI @@ -324,6 +328,7 @@ DataAccessCont: DataAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ + MOL_HOOK(0) mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -366,6 +371,7 @@ InstructionAccessCont: InstructionAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ + MOL_HOOK(1) andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ @@ -430,6 +436,7 @@ Alignment: . = 0x700 ProgramCheck: EXCEPTION_PROLOG + MOL_HOOK(2) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ @@ -441,6 +448,7 @@ ProgramCheck: . = 0x800 FPUnavailable: EXCEPTION_PROLOG + MOL_HOOK_RESTORE(3) bne load_up_fpu /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -450,6 +458,7 @@ FPUnavailable: . = 0x900 Decrementer: EXCEPTION_PROLOG + MOL_HOOK(4) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler @@ -473,12 +482,9 @@ SystemCall: .long ret_from_except /* Single step - not used on 601 */ - STD_EXCEPTION(0xd00, SingleStep, SingleStepException) - + STD_MOL_EXCEPTION(0xd00, SingleStep, SingleStepException, 5) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) -#ifndef CONFIG_ALTIVEC - STD_EXCEPTION(0xf00, Trap_0f, UnknownException) -#else + /* * The Altivec unavailable trap is at 0x0f20. Foo. * We effectively remap it to 0x3000. @@ -493,15 +499,20 @@ trap_0f_cont: .long ret_from_except . = 0xf20 +#ifdef CONFIG_ALTIVEC b AltiVecUnavailable -#endif /* CONFIG_ALTIVEC */ - +#endif +Trap_0f: + EXCEPTION_PROLOG + b trap_0f_cont + /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. */ . = 0x1000 InstructionTLBMiss: + MOL_HOOK_TLBMISS( 14 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -568,6 +579,7 @@ InstructionAddressInvalid: */ . = 0x1100 DataLoadTLBMiss: + MOL_HOOK_TLBMISS( 15 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -633,6 +645,7 @@ DataAddressInvalid: */ . = 0x1200 DataStoreTLBMiss: + MOL_HOOK_TLBMISS( 16 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -674,7 +687,7 @@ DataStoreTLBMiss: mtcrf 0x80,r3 rfi - STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) + STD_MOL_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, 11) STD_EXCEPTION(0x1400, SMI, SMIException) STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -687,7 +700,7 @@ DataStoreTLBMiss: STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) - STD_EXCEPTION(0x2000, RunMode, RunModeException) + STD_MOL_EXCEPTION(0x2000, RunMode, RunModeException, 5) STD_EXCEPTION(0x2100, Trap_21, UnknownException) STD_EXCEPTION(0x2200, Trap_22, UnknownException) STD_EXCEPTION(0x2300, Trap_23, UnknownException) @@ -709,16 +722,12 @@ DataStoreTLBMiss: #ifdef CONFIG_ALTIVEC AltiVecUnavailable: EXCEPTION_PROLOG + MOL_HOOK_RESTORE(12) bne load_up_altivec /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ .long KernelAltiVec .long ret_from_except - -/* here are the bits of trap 0xf00 which got displaced */ -Trap_0f: - EXCEPTION_PROLOG - b trap_0f_cont #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_PPC64BRIDGE @@ -753,6 +762,14 @@ transfer_to_handler: beq 2f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) +#ifdef CONFIG_ALTIVEC + mfpvr r24 /* check if we are on a G4 */ + srwi r24,r24,16 + cmpwi r24,PVR_7400@h + bne 2f + mfspr r22,SPRN_VRSAVE /* if so, save vrsave register value */ + stw r22,THREAD_VRSAVE(r23) +#endif /* CONFIG_ALTIVEC */ 2: addi r2,r23,-THREAD /* set r2 to current */ tovirt(r2,r2) mflr r23 @@ -771,6 +788,7 @@ transfer_to_handler: lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ FIX_SRR1(r20,r22) + MOL_HOOK(6) mtspr SRR0,r24 mtspr SRR1,r20 mtlr r23 @@ -981,6 +999,11 @@ KernelAltiVec: .globl giveup_altivec giveup_altivec: +#ifdef CONFIG_MOL + mflr r4 + MOL_HOOK_MMU(13, r5) + mtlr r4 +#endif mfmsr r5 oris r5,r5,MSR_VEC@h SYNC @@ -1017,6 +1040,11 @@ giveup_altivec: */ .globl giveup_fpu giveup_fpu: +#ifdef CONFIG_MOL + mflr r4 + MOL_HOOK_MMU(7, r5) + mtlr r4 +#endif mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1048,19 +1076,10 @@ giveup_fpu: * the kernel image to physical address 0. */ relocate_kernel: -#if 0 /* Is this still needed ? I don't think so. It breaks new - * boot-with-mmu-off stuff - */ - lis r9,0x426f /* if booted from BootX, don't */ - addi r9,r9,0x6f58 /* translate source addr */ - cmpw r31,r9 /* (we have to on chrp) */ - beq 7f - rlwinm r4,r4,0,8,31 /* translate source address */ - add r4,r4,r3 /* to region mapped with BATs */ -#endif -7: addis r9,r26,klimit@ha /* fetch klimit */ + addis r9,r26,klimit@ha /* fetch klimit */ lwz r25,klimit@l(r9) addis r25,r25,-KERNELBASE@h + li r3,0 /* Destination base address */ li r6,0 /* Destination offset */ li r5,0x4000 /* # bytes of memory to copy */ bl copy_and_flush /* copy the first 0x4000 bytes */ @@ -1307,7 +1326,7 @@ enable_caches: mfspr r9,PVR rlwinm r9,r9,16,16,31 cmpi 0,r9,1 - beq 4f /* not needed for 601 */ + beq 6f /* not needed for 601 */ mfspr r11,HID0 andi. r0,r11,HID0_DCE ori r11,r11,HID0_ICE|HID0_DCE @@ -1323,26 +1342,33 @@ enable_caches: isync cmpi 0,r9,4 /* check for 604 */ cmpi 1,r9,9 /* or 604e */ - cmpi 2,r9,10 /* or mach5 */ + cmpi 2,r9,10 /* or mach5 / 604r */ cmpi 3,r9,8 /* check for 750 (G3) */ cmpi 4,r9,12 /* or 7400 (G4) */ cror 2,2,6 cror 2,2,10 bne 4f - ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ + ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e|r], enable */ bne 2,5f - ori r11,r11,HID0_BTCD + ori r11,r11,HID0_BTCD /* superscalar exec & br history tbl */ b 5f 4: cror 14,14,18 bne 3,6f - /* We should add ABE here if we want to use Store Gathering - * and other nifty bridge features + /* for G3/G4: + * enable Store Gathering (SGE), Address Brodcast (ABE), + * Branch History Table (BHTE), Branch Target ICache (BTIC) */ - ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC /* for g3/g4, enable */ + ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ + li r3,HID0_SPD + andc r11,r11,r3 /* clear SPD: enable speculative */ li r3,0 - mtspr ICTC,r3 -5: mtspr HID0,r11 /* superscalar exec & br history tbl */ + mtspr ICTC,r3 /* Instruction Cache Throttling off */ +5: isync + mtspr HID0,r11 + sync + isync 6: blr /* @@ -1548,12 +1574,11 @@ flush_tlbs: blr mmu_off: - addi r4, r3, __after_prom_start - _start + addi r4, r3, __after_mmu_off - _start mfmsr r3 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ beqlr - ori r3,r3,MSR_DR|MSR_IR - xori r3,r3,MSR_DR|MSR_IR + andc r3,r3,r0 mtspr SRR0,r4 mtspr SRR1,r3 sync @@ -1617,23 +1642,19 @@ setup_disp_bat: mflr r8 bl reloc_offset mtlr r8 - lis r8, disp_BATL@h - ori r8, r8, disp_BATL@l - add r8, r3, r8 - lwz r8, 0(r8) - lis r11, disp_BATU@h - ori r11, r11, disp_BATU@l - add r11, r3, r11 - lwz r11, 0(r11) - mtspr IBAT3L,r8 - mtspr IBAT3U,r11 + addis r8,r3,disp_BAT@ha + addi r8,r8,disp_BAT@l + lwz r11,0(r8) + lwz r8,4(r8) mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpi 0,r9,1 beq 1f mtspr DBAT3L,r8 mtspr DBAT3U,r11 -1: + blr +1: mtspr IBAT3L,r8 + mtspr IBAT3U,r11 blr #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ @@ -1649,18 +1670,43 @@ setup_disp_bat: */ .globl m8260_gorom m8260_gorom: - li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SRR0,r6 - mtspr SRR1,r5 - rfi + mfmsr r0 + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + sync + mtmsr r0 + sync + mfspr r11, HID0 + lis r10, 0 + ori r10,r10,HID0_ICE|HID0_DCE + andc r11, r11, r10 + mtspr HID0, r11 + isync + li r5, MSR_ + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SRR0,r6 + mtspr SRR1,r5 + isync + sync + rfi 2: - mtlr r4 - blr + mtlr r4 + blr +#endif + +#ifdef CONFIG_MOL +/* + * Mac-on-linux hook_table. Don't put this in the data section - + * the base address must be within the first 32KB of RAM. + */ + .globl mol_interface +mol_interface: + .long MOL_INTERFACE_VERSION + .fill 24,4,0 /* space for 24 hooks */ #endif + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index a35f6e2a1..40579ce63 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -874,6 +874,13 @@ start_here: lis r6, swapper_pg_dir@h tophys(r6,r6) ori r6, r6, swapper_pg_dir@l +#ifdef CONFIG_8xx_CPU6 + lis r4, cpu6_errata_word@h + ori r4, r4, cpu6_errata_word@l + li r3, 0x3980 + stw r3, 12(r4) + lwz r3, 12(r4) +#endif mtspr M_TWB, r6 lis r4,2f@h ori r4,r4,2f@l @@ -940,9 +947,23 @@ start_here: * ASID compare register with the new "context". */ _GLOBAL(set_context) +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + tophys (r4, r4) + li r7, 0x3980 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr M_TWB, r4 /* Update MMU base address */ + li r7, 0x3380 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr M_CASID, r3 /* Update context */ +#else mtspr M_CASID,r3 /* Update context */ tophys (r4, r4) mtspr M_TWB, r4 /* and pgd */ +#endif tlbia SYNC blr @@ -966,6 +987,24 @@ m8xx_gorom: 2: mtlr r4 blr + +#ifdef CONFIG_8xx_CPU6 +/* It's here because it is unique to the 8xx. + * It is important we get called with interrupts disabled. I used to + * do that, but it appears that all code that calls this already had + * interrupt disabled. + */ + .globl set_dec_cpu6 +set_dec_cpu6: + lis r7, cpu6_errata_word@h + ori r7, r7, cpu6_errata_word@l + li r4, 0x2c00 + stw r4, 8(r7) + lwz r4, 8(r7) + mtspr 22, r3 /* Update Decrementer */ + SYNC + blr +#endif /* * We put a few things here that have to be page-aligned. @@ -991,3 +1030,9 @@ swapper_pg_dir: cmd_line: .space 512 +#ifdef CONFIG_8xx_CPU6 + .globl cpu6_errata_word +cpu6_errata_word: + .space 16 +#endif + diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index d29f7bd20..a363a0e34 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -286,6 +286,7 @@ void power_save(void) case 6: /* 603e */ case 7: /* 603ev */ case 8: /* 750 */ + case 12: /* 7400 */ save_flags(msr); __cli(); if (!current->need_resched) { diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 64ef4b4dc..eef89f352 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -137,17 +137,21 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) if (!handler) { /* Free */ - for (p = &irq_desc[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; + p = &irq_desc[irq].action; + while ((action = *p) != NULL && action->dev_id != dev_id) + p = &action->next; + if (action == NULL) + return -ENOENT; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (irq_desc[irq].action == NULL) + disable_irq(irq); + restore_flags(flags); + irq_kfree(action); + return 0; } action = (struct irqaction *) @@ -300,7 +304,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) } } -asmlinkage int do_IRQ(struct pt_regs *regs, int isfake) +int do_IRQ(struct pt_regs *regs, int isfake) { int cpu = smp_processor_id(); int irq; diff --git a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c index 891b0ca44..6e006a867 100644 --- a/arch/ppc/kernel/m8260_setup.c +++ b/arch/ppc/kernel/m8260_setup.c @@ -112,11 +112,10 @@ void __init m8260_calibrate_decr(void) bd_t *binfo = (bd_t *)__res; int freq, divisor; - freq = (binfo->bi_intfreq * 1000000); - divisor = 16; - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + freq = (binfo->bi_busfreq * 1000000); + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); } /* The 8260 has an internal 1-second timer update register that @@ -143,8 +142,20 @@ void m8260_restart(char *cmd) { extern void m8260_gorom(bd_t *bi, uint addr); + uint startaddr; - m8260_gorom(NULL, 0xff000100); + /* Most boot roms have a warmstart as the second instruction + * of the reset vector. If that doesn't work for you, change this + * or the reboot program to send a proper address. + */ + startaddr = 0xff000104; + + if (cmd != NULL) { + if (!strncmp(cmd, "startaddr=", 10)) + startaddr = simple_strtoul(&cmd[10], NULL, 0); + } + + m8260_gorom((uint)__pa(__res), startaddr); } void diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c index a00a8c452..7dc408a13 100644 --- a/arch/ppc/kernel/m8xx_setup.c +++ b/arch/ppc/kernel/m8xx_setup.c @@ -135,6 +135,13 @@ abort(void) machine_restart(NULL); } +/* A place holder for time base interrupts, if they are ever enabled. +*/ +void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) +{ + printk("timebase_interrupt()\n"); +} + /* The decrementer counts at the system (internal) clock frequency divided by * sixteen, or external oscillator divided by four. We force the processor * to use system clock divided by sixteen. @@ -160,35 +167,14 @@ void __init m8xx_calibrate_decr(void) 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; -} - -/* A place holder for time base interrupts, if they are ever enabled. -*/ -void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) -{ - printk("timebase_interrupt()\n"); -} - -/* 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 -m8xx_set_rtc_time(unsigned long time) -{ - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; - return(0); -} - -unsigned long __init -m8xx_get_rtc_time(void) -{ - /* First, unlock all of the registers we are going to modify. + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); + + /* Perform some more timer/timebase initialization. This used + * to be done elsewhere, but other changes caused it to get + * called more than once....that is a bad thing. + * + * 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 @@ -219,9 +205,27 @@ m8xx_get_rtc_time(void) ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr = ((mk_int_int_mask(DEC_INTERRUPT) << 8) | (TBSCR_TBF | TBSCR_TBE)); + if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) panic("Could not allocate timer IRQ!"); +} +/* 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 +m8xx_set_rtc_time(unsigned long time) +{ + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; + return(0); +} + +unsigned long __init +m8xx_get_rtc_time(void) +{ /* Get time from the RTC. */ return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc)); diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 081dda7f3..e3826293b 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -24,12 +24,15 @@ #if defined(CONFIG_4xx) || defined(CONFIG_8xx) #define CACHE_LINE_SIZE 16 #define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 #elif !defined(CONFIG_PPC64BRIDGE) #define CACHE_LINE_SIZE 32 #define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 #else #define CACHE_LINE_SIZE 128 #define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 #endif /* CONFIG_4xx || CONFIG_8xx */ .text @@ -339,7 +342,15 @@ _GLOBAL(__flush_icache_page) _GLOBAL(clear_page) li r0,4096/CACHE_LINE_SIZE mtctr r0 +#ifdef CONFIG_8xx + li r4, 0 +1: stw r4, 0(r3) + stw r4, 4(r3) + stw r4, 8(r3) + stw r4, 12(r3) +#else 1: dcbz 0,r3 +#endif addi r3,r3,CACHE_LINE_SIZE bdnz 1b blr @@ -361,12 +372,31 @@ _GLOBAL(clear_page) stwu r9,16(r3) _GLOBAL(copy_page) - li r0,4096/CACHE_LINE_SIZE - mtctr r0 addi r3,r3,-4 addi r4,r4,-4 li r5,4 -1: dcbz r5,r3 + +#ifndef CONFIG_8xx +#if MAX_COPY_PREFETCH > 1 + li r0,MAX_COPY_PREFETCH + li r11,4 + mtctr r0 +11: dcbt r11,r4 + addi r11,r11,CACHE_LINE_SIZE + bdnz 11b +#else /* MAX_COPY_PREFETCH == 1 */ + dcbt r5,r4 + li r11,CACHE_LINE_SIZE+4 +#endif /* MAX_COPY_PREFETCH */ +#endif /* CONFIG_8xx */ + + li r0,4096/CACHE_LINE_SIZE + mtctr r0 +1: +#ifndef CONFIG_8xx + dcbt r11,r4 + dcbz r5,r3 +#endif COPY_16_BYTES #if CACHE_LINE_SIZE >= 32 COPY_16_BYTES @@ -484,7 +514,7 @@ _GLOBAL(atomic_dec_and_test) stwcx. r5,0,r3 /* Update with new value */ bne- 10b /* Retry if "reservation" (i.e. lock) lost */ cntlzw r3,r5 - srwi r3,r3,5 + srwi r3,r3,5 blr #endif /* 0 */ _GLOBAL(atomic_clear_mask) @@ -629,48 +659,59 @@ _GLOBAL(_outsl_ns) blr /* - * Extended precision shifts + * Extended precision shifts. + * + * Updated to be valid for shift counts from 0 to 63 inclusive. + * -- Gabriel * * R3/R4 has 64 bit value * R5 has shift count * result in R3/R4 * - * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ - * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000 - * lshrdi3: XXXYYY/ZZZAAA -> 000XXX/YYYZZZ + * ashrdi3: arithmetic right shift (sign propagation) + * lshrdi3: logical right shift + * ashldi3: left shift */ _GLOBAL(__ashrdi3) - li r6,32 - sub r6,r6,r5 - slw r7,r3,r6 /* isolate YYY */ - srw r4,r4,r5 /* isolate ZZZ */ - or r4,r4,r7 /* YYYZZZ */ - sraw r3,r3,r5 /* SSSXXX */ + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 + sraw r7,r3,r7 # t2 = MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 + sraw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 blr _GLOBAL(__ashldi3) - li r6,32 - sub r6,r6,r5 - srw r7,r4,r6 /* isolate ZZZ */ - slw r4,r4,r5 /* AAA000 */ - slw r3,r3,r5 /* YYY--- */ - or r3,r3,r7 /* YYYZZZ */ + subfic r6,r5,32 + slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count + addi r7,r5,32 # could be xori, or addi with -32 + srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) + slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) + or r3,r3,r6 # MSW |= t1 + slw r4,r4,r5 # LSW = LSW << count + or r3,r3,r7 # MSW |= t2 blr _GLOBAL(__lshrdi3) - li r6,32 - sub r6,r6,r5 - slw r7,r3,r6 /* isolate YYY */ - srw r4,r4,r5 /* isolate ZZZ */ - or r4,r4,r7 /* YYYZZZ */ - srw r3,r3,r5 /* 000XXX */ + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + srw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 blr _GLOBAL(abs) - cmpi 0,r3,0 - bge 10f - neg r3,r3 -10: blr + srawi r4,r3,31 + xor r3,r3,r4 + sub r3,r3,r4 + blr _GLOBAL(_get_SP) mr r3,r1 /* Close enough */ @@ -1217,6 +1258,6 @@ _GLOBAL(sys_call_table) .long sys_pciconfig_iobase /* 200 */ .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ .long sys_getdents64 /* 202 */ - .rept NR_syscalls-201 + .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr diff --git a/arch/ppc/kernel/mol.h b/arch/ppc/kernel/mol.h new file mode 100644 index 000000000..6105867e1 --- /dev/null +++ b/arch/ppc/kernel/mol.h @@ -0,0 +1,68 @@ +/* + * arch/ppc/kernel/mol.h + * + * <mol.h> + * + * Mac-on-Linux hook macros + * <http://www.maconlinux.org> + * + * Copyright (C) 2000 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _PPC_KERNEL_MOL +#define _PPC_KERNEL_MOL + +#include <linux/config.h> + +#ifdef CONFIG_MOL +#define MOL_INTERFACE_VERSION 3 + +#define MOL_HOOK(hook_num) \ + lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ + cmpwi cr1,r0,0; \ + beq+ cr1,777f; \ + mtctr r0; \ + bctrl; \ +777: lwz r0,GPR0(r21) + +#define MOL_HOOK_RESTORE(hook_num) \ + mfcr r2; \ + MOL_HOOK(hook_num); \ + mtcrf 0x80,r2; \ + lwz r2,_CTR(r21); \ + mtctr r2; \ + lwz r2,GPR2(r21) + +#define MOL_HOOK_MMU(hook_num, scr) \ + lis scr,(mol_interface + 4 * hook_num + 4)@ha; \ + lwz scr,(mol_interface + 4 * hook_num + 4)@l(scr); \ + cmpwi cr1,scr,0; \ + beq+ cr1,778f; \ + mtctr scr; \ + bctrl; \ +778: + +#define MOL_HOOK_TLBMISS(hook_num) \ + lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ + cmpwi r0,0; \ + beq+ 779f; \ + mflr r3; \ + mtlr r0; \ + blrl; \ + mtlr r3; \ +779: + +#else +#define MOL_HOOK(num) +#define MOL_HOOK_RESTORE(num) +#define MOL_HOOK_MMU(num, scr) +#define MOL_HOOK_TLBMISS(num) +#endif + + +#endif /* _PPC_KERNEL_MOL */ diff --git a/arch/ppc/kernel/oak_setup.c b/arch/ppc/kernel/oak_setup.c index 09e6e6e6f..ef5a7a0fe 100644 --- a/arch/ppc/kernel/oak_setup.c +++ b/arch/ppc/kernel/oak_setup.c @@ -231,10 +231,11 @@ oak_halt(void) /* * Document me. */ -void __init +long __init oak_time_init(void) { /* XXX - Implement me */ + return 0; } /* diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index 416137934..5ca365b1c 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -100,7 +100,7 @@ struct hw_interrupt_type open_pic = { #ifdef CONFIG_SMP void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { - smp_message_recv(cpl-OPENPIC_VEC_IPI); + smp_message_recv(cpl-OPENPIC_VEC_IPI, regs); } #endif /* CONFIG_SMP */ @@ -262,11 +262,11 @@ void __init openpic_init(int main_pic) int j, pri; pri = strcmp(np->name, "programmer-switch") ? 2 : 7; for (j=0;j<np->n_intrs;j++) { - openpic_initirq( np->intrs[j].line, - pri, - np->intrs[j].line, - 0, - np->intrs[j].sense); + openpic_initirq(np->intrs[j].line, + pri, + np->intrs[j].line, + 0, + np->intrs[j].sense); if (np->intrs[j].sense) irq_desc[np->intrs[j].line].status = IRQ_LEVEL; } diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 6233e5f9b..84faa0e1d 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -25,7 +25,13 @@ #include "pci.h" -static void __init pcibios_claim_resources(struct list_head *); +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; @@ -70,59 +76,280 @@ struct pci_ops generic_pci_ops = generic_pcibios_write_dword }; -void __init pcibios_init(void) -{ - printk("PCI: Probing PCI hardware\n"); - pci_scan_bus(0, &generic_pci_ops, NULL); - if (ppc_md.pcibios_fixup) - ppc_md.pcibios_fixup(); - pcibios_claim_resources(&pci_root_buses); -} -void __init -pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) { - ranges->io_start -= bus->resource[0]->start; - ranges->io_end -= bus->resource[0]->start; - ranges->mem_start -= bus->resource[1]->start; - ranges->mem_end -= bus->resource[1]->start; + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } } -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +void +pcibios_align_resource(void *data, struct resource *res, unsigned long size) { - return start; + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } } -static void __init pcibios_claim_resources(struct list_head *bus_list) + +/* + * Handle resources of PCI devices. If the world were perfect, we could + * just allocate all the resource regions and do nothing more. It isn't. + * On the other hand, we cannot just re-allocate all devices, as it would + * require us to know lots of host bridge internals. So we attempt to + * keep as much of the original configuration as possible, but tweak it + * when it's found to be wrong. + * + * Known BIOS problems we have to work around: + * - I/O or memory regions not configured + * - regions configured, but not enabled in the command register + * - bogus I/O addresses above 64K used + * - expansion ROMs left enabled (this may sound harmless, but given + * the fact the PCI specs explicitly allow address decoders to be + * shared between expansion ROMs and other resource regions, it's + * at least dangerous) + * + * Our solution: + * (1) Allocate resources for all buses behind PCI-to-PCI bridges. + * This gives us fixed barriers on where we can allocate. + * (2) Allocate resources for all enabled devices. If there is + * a collision, just mark the resource as unallocated. Also + * disable expansion ROMs during this step. + * (3) Try to allocate resources for disabled devices. If the + * resources were assigned correctly, everything goes well, + * if they weren't, they won't disturb allocation of other + * resources. + * (4) Assign new addresses to resources which were either + * not configured at all or misconfigured. If explicitly + * requested by the user, configure expansion ROM address + * as well. + */ + +static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { - struct list_head *ln, *dn; + struct list_head *ln; struct pci_bus *bus; struct pci_dev *dev; int idx; + struct resource *r, *pr; + /* Depth-First Search on bus tree */ for (ln=bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); - for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) { - dev = pci_dev_b(dn); - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) - { - struct resource *r = &dev->resource[idx]; - struct resource *pr; + if ((dev = bus->self)) { + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + r = &dev->resource[idx]; if (!r->start) continue; pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) - { - printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); - /* We probably should disable the region, shouldn't we? */ + printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name); + } + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +static void __init pcibios_allocate_resources(int pass) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r, *pr; + + pci_for_each_dev(dev) { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (r->parent) /* Already allocated */ + continue; + if (!r->start) /* Address not assigned at all */ + continue; + if (r->end == 0xffffffff) { + /* LongTrail OF quirk: unassigned */ + DBG("PCI: Resource %08lx-%08lx was unassigned\n", r->start, r->end); + r->end -= r->start; + r->start = 0; + continue; + } + + if (r->flags & IORESOURCE_IO) + disabled = !(command & PCI_COMMAND_IO); + else + disabled = !(command & PCI_COMMAND_MEMORY); + if (pass == disabled) { + DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", + r->start, r->end, r->flags, disabled, pass); + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name); + /* We'll assign a new address later */ + r->end -= r->start; + r->start = 0; } } } - pcibios_claim_resources(&bus->children); + if (!pass) { + r = &dev->resource[PCI_ROM_RESOURCE]; + if (r->flags & PCI_ROM_ADDRESS_ENABLE) { + /* Turn the ROM off, leave the resource region, but keep it unregistered. */ + u32 reg; + DBG("PCI: Switching off ROM of %s\n", dev->slot_name); + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, dev->rom_base_reg, ®); + pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); + } + } + } +} + +static void __init pcibios_assign_resources(void) +{ + struct pci_dev *dev; + int idx; + struct resource *r; + + pci_for_each_dev(dev) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) + continue; + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end) + pci_assign_resource(dev, idx); + } + + if (0) { /* don't assign ROMs */ + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pci_assign_resource(dev, PCI_ROM_RESOURCE); + } } } + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + + +void __init pcibios_init(void) +{ + printk("PCI: Probing PCI hardware\n"); + pci_scan_bus(0, &generic_pci_ops, NULL); + if (ppc_md.pcibios_fixup) + ppc_md.pcibios_fixup(); + pcibios_allocate_bus_resources(&pci_root_buses); + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); + pcibios_assign_resources(); +} + +void __init +pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; +} + void __init pcibios_fixup_bus(struct pci_bus *bus) { if ( ppc_md.pcibios_fixup_bus ) @@ -134,21 +361,7 @@ char __init *pcibios_setup(char *str) return str; } -/* the next two are stolen from the alpha port... */ -void __init -pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) -{ - unsigned long where, size; - u32 reg; - - where = PCI_BASE_ADDRESS_0 + (resource * 4); - size = res->end - res->start; - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); -} - +/* the next one is stolen from the alpha port... */ void __init pcibios_update_irq(struct pci_dev *dev, int irq) { @@ -156,11 +369,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq) /* XXX FIXME - update OF device tree node interrupt property */ } -void __init -pcibios_align_resource(void *data, struct resource *res, unsigned long size) -{ -} - int pcibios_enable_device(struct pci_dev *dev) { u16 cmd, old_cmd; @@ -188,114 +396,26 @@ int pcibios_enable_device(struct pci_dev *dev) return 0; } -/* - * Those syscalls are derived from the Alpha versions, they - * allow userland apps to retreive the per-device iobase and - * mem-base. They also provide wrapper for userland to do - * config space accesses. - * The "host_number" returns the number of the Uni-N sub bridge - */ - -asmlinkage int -sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, buf); - break; - case 2: - err = pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, (unsigned short *)buf); - break; - case 4: - err = pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, (unsigned int *)buf); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -asmlinkage int -sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = get_user(ubyte, buf); - if (err) - break; - err = pcibios_write_config_byte(bus, dfn, off, ubyte); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 2: - err = get_user(ushort, (unsigned short *)buf); - if (err) - break; - err = pcibios_write_config_word(bus, dfn, off, ushort); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 4: - err = get_user(uint, (unsigned int *)buf); - if (err) - break; - err = pcibios_write_config_dword(bus, dfn, off, uint); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - void * -pci_dev_io_base(unsigned char bus, unsigned char devfn) +pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) { - /* Defaults to old way */ - if (!ppc_md.pci_dev_io_base) - return pci_io_base(bus); - return ppc_md.pci_dev_io_base(bus, devfn); + if (!ppc_md.pci_dev_io_base) { + /* Please, someone fix this for non-pmac machines, we + * need either the virtual or physical PCI IO base + */ + return 0; + } + return ppc_md.pci_dev_io_base(bus, devfn, physical); } void * pci_dev_mem_base(unsigned char bus, unsigned char devfn) { /* Default memory base is 0 (1:1 mapping) */ - if (!ppc_md.pci_dev_mem_base) + if (!ppc_md.pci_dev_mem_base) { + /* Please, someone fix this for non-pmac machines.*/ return 0; + } return ppc_md.pci_dev_mem_base(bus, devfn); } @@ -318,15 +438,20 @@ pci_dev_root_bridge(unsigned char bus, unsigned char devfn) asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) { + long result = -EOPNOTSUPP; + switch (which) { case IOBASE_BRIDGE_NUMBER: return (long)pci_dev_root_bridge(bus, devfn); case IOBASE_MEMORY: return (long)pci_dev_mem_base(bus, devfn); case IOBASE_IO: - return (long)pci_dev_io_base(bus, devfn); + result = (long)pci_dev_io_base(bus, devfn, 1); + if (result == 0) + result = -EOPNOTSUPP; + break; } - return -EOPNOTSUPP; + return result; } diff --git a/arch/ppc/kernel/pmac_backlight.c b/arch/ppc/kernel/pmac_backlight.c index 8c6244632..30ad5f416 100644 --- a/arch/ppc/kernel/pmac_backlight.c +++ b/arch/ppc/kernel/pmac_backlight.c @@ -41,16 +41,16 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c #ifdef CONFIG_ADB_PMU /* Special case for the old PowerBook since I can't test on it */ - if ((machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500") - || machine_is_compatible("AAPL,PowerBook1998") - || machine_is_compatible("AAPL,PowerBook1999")) - && !strcmp(type, "pmu")) + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) valid = 1; - else #endif - { - if (bk_node) - prop = get_property(bk_node, "backlight-control", NULL); + if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); if (prop && !strncmp(prop, type, strlen(type))) valid = 1; } @@ -70,8 +70,6 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c } #ifdef CONFIG_ADB_PMU - backlight_autosave = machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500"); if (backlight_autosave) { struct adb_request req; pmu_request(&req, NULL, 2, 0xd9, 0); diff --git a/arch/ppc/kernel/pmac_nvram.c b/arch/ppc/kernel/pmac_nvram.c index d8de113ec..1c4c1eea1 100644 --- a/arch/ppc/kernel/pmac_nvram.c +++ b/arch/ppc/kernel/pmac_nvram.c @@ -312,17 +312,18 @@ pmac_nvram_update(void) __openfirmware unsigned char nvram_read_byte(int addr) { - struct adb_request req; - switch (nvram_naddrs) { #ifdef CONFIG_ADB_PMU - case -1: + case -1: { + struct adb_request req; + if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, (addr >> 8) & 0xff, addr & 0xff)) break; while (!req.complete) pmu_poll(); return req.reply[1]; + } #endif case 1: if (is_core_99) @@ -339,17 +340,18 @@ unsigned char nvram_read_byte(int addr) __openfirmware void nvram_write_byte(unsigned char val, int addr) { - struct adb_request req; - switch (nvram_naddrs) { #ifdef CONFIG_ADB_PMU - case -1: + case -1: { + struct adb_request req; + if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, (addr >> 8) & 0xff, addr & 0xff, val)) break; while (!req.complete) pmu_poll(); break; + } #endif case 1: if (is_core_99) { diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index ced029722..8f7b3d7c2 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -35,6 +35,7 @@ struct uninorth_data { volatile unsigned int* cfg_addr; volatile unsigned int* cfg_data; void* iobase; + unsigned long iobase_phys; }; static struct uninorth_data uninorth_bridges[3]; @@ -133,15 +134,20 @@ pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn) __pmac void * -pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn) +pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) { - int bridge; - if (uninorth_count == 0) - return pci_io_base(bus); - bridge = pmac_pci_dev_root_bridge(bus, devfn); - if (bridge == -1) - return pci_io_base(bus); - return uninorth_bridges[bridge].iobase; + int bridge = -1; + if (uninorth_count != 0) + bridge = pmac_pci_dev_root_bridge(bus, devfn); + if (bridge == -1) { + struct bridge_data *bp; + + if (bus > max_bus || (bp = bridges[bus]) == 0) + return 0; + return physical ? (void *) bp->io_base_phys : bp->io_base; + } + return physical ? (void *) uninorth_bridges[bridge].iobase_phys + : uninorth_bridges[bridge].iobase; } __pmac @@ -649,7 +655,9 @@ static void __init add_bridges(struct device_node *dev) uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000); uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000); uninorth_bridges[i].node = dev; - uninorth_bridges[i].iobase = (void *)addr->address; + uninorth_bridges[i].iobase_phys = addr->address; + /* is 0x10000 enough for io space ? */ + uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000); /* XXX This is the bridge with the PCI expansion bus. This is also the * address of the bus that will receive type 1 config accesses and io * accesses. Appears to be correct for iMac DV and G4 Sawtooth too. @@ -667,14 +675,15 @@ static void __init add_bridges(struct device_node *dev) if (device_is_compatible(dev, "uni-north")) { bp->cfg_addr = 0; bp->cfg_data = 0; - /* is 0x10000 enough for io space ? */ - bp->io_base = (void *)ioremap(addr->address, 0x10000); + bp->io_base = uninorth_bridges[uninorth_count-1].iobase; + bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ bp->cfg_addr = (volatile unsigned int *) ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); + bp->io_base_phys = 0xfe000000; bp->io_base = (void *) ioremap(0xfe000000, 0x20000); if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(bp, 1); @@ -687,6 +696,7 @@ static void __init add_bridges(struct device_node *dev) ioremap(addr->address + 0x800000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); + bp->io_base_phys = addr->address; bp->io_base = (void *) ioremap(addr->address, 0x10000); } if (isa_io_base == 0) diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index e0e654305..efd767482 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -204,17 +204,12 @@ pmac_get_irq(struct pt_regs *regs) unsigned long bits = 0; #ifdef CONFIG_SMP - void pmac_smp_message_recv(void); + void pmac_smp_message_recv(struct pt_regs *); /* IPI's are a hack on the powersurge -- Cort */ if ( smp_processor_id() != 0 ) { -#ifdef CONFIG_XMON - static int xmon_2nd; - if (xmon_2nd) - xmon(regs); -#endif - pmac_smp_message_recv(); + pmac_smp_message_recv(regs); return -2; /* ignore, already handled */ } #endif /* CONFIG_SMP */ diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 658d7c226..b5bf03abc 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -68,7 +68,7 @@ #undef SHOW_GATWICK_IRQS -extern void pmac_time_init(void); +extern long pmac_time_init(void); extern unsigned long pmac_get_rtc_time(void); extern int pmac_set_rtc_time(unsigned long nowtime); extern void pmac_read_rtc_time(void); @@ -77,24 +77,29 @@ extern void pmac_setup_pci_ptrs(void); extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char mackbd_unexpected_up(unsigned char keycode); +extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +extern int mackbd_unexpected_up(unsigned char keycode); extern void mackbd_leds(unsigned char leds); -extern void mackbd_init_hw(void); +extern void __init mackbd_init_hw(void); +extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mac_hid_kbd_unexpected_up(unsigned char keycode); +extern void mac_hid_init_hw(void); #ifdef CONFIG_MAGIC_SYSRQ -unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mac_hid_kbd_sysrq_xlate[128]; +extern unsigned char pckbd_sysrq_xlate[128]; +extern unsigned char mackbd_sysrq_xlate[128]; #endif /* CONFIG_MAGIC_SYSRQ */ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); +extern int keyboard_sends_linux_keycodes; extern void pmac_nvram_update(void); -extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn); +extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical); extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn); extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn); @@ -115,7 +120,6 @@ extern int pmac_newworld; extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); static void init_p2pbridge(void); -static void init_uninorth(void); #ifdef CONFIG_BOOTX_TEXT void pmac_progress(char *s, unsigned short hex); #endif @@ -276,7 +280,6 @@ pmac_setup_arch(void) pmac_find_bridges(); init_p2pbridge(); - init_uninorth(); /* Checks "l2cr-value" property in the registry */ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) { @@ -372,31 +375,6 @@ static void __init ohare_init(void) } } -static void __init -init_uninorth(void) -{ - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs - */ - struct device_node* gmac = find_devices("ethernet"); - - while(gmac) { - if (device_is_compatible(gmac, "gmac")) - break; - gmac = gmac->next; - } - if (gmac) - feature_set_gmac_power(gmac, 0); -} - extern char *bootpath; extern char *bootdevice; void *boot_host; @@ -404,14 +382,15 @@ int boot_target; int boot_part; kdev_t boot_dev; -extern void via_pmu_start(void); - void __init pmac_init2(void) { #ifdef CONFIG_ADB_PMU via_pmu_start(); #endif +#ifdef CONFIG_ADB_CUDA + via_cuda_start(); +#endif #ifdef CONFIG_PMAC_PBOOK media_bay_init(); #endif @@ -683,7 +662,26 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.pci_dev_mem_base = pmac_pci_dev_mem_base; ppc_md.pci_dev_root_bridge = pmac_pci_dev_root_bridge; -#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) +#ifdef CONFIG_VT +#ifdef CONFIG_INPUT_ADBHID + ppc_md.kbd_init_hw = mac_hid_init_hw; + ppc_md.kbd_translate = mac_hid_kbd_translate; + ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up; + ppc_md.kbd_setkeycode = 0; + ppc_md.kbd_getkeycode = 0; +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; + } else +#endif /* CONFIG_MAC_ADBKEYCODES */ + { + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; + } +#endif /* CONFIG_MAGIC_SYSRQ */ +#elif defined(CONFIG_ADB_KEYBOARD) ppc_md.kbd_setkeycode = mackbd_setkeycode; ppc_md.kbd_getkeycode = mackbd_getkeycode; ppc_md.kbd_translate = mackbd_translate; @@ -691,10 +689,11 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; + ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; SYSRQ_KEY = 0x69; -#endif -#endif +#endif /* CONFIG_MAGIC_SYSRQ */ +#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */ +#endif /* CONFIG_VT */ #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) ppc_ide_md.insw = pmac_ide_insw; diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index 9eb326bf9..00b6302a7 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -25,7 +25,7 @@ #include <asm/io.h> #include <asm/pgtable.h> #include <asm/machdep.h> - +#include <asm/hardirq.h> #include <asm/time.h> #include <asm/nvram.h> @@ -58,7 +58,7 @@ extern rwlock_t xtime_lock; extern struct timezone sys_tz; __init -void pmac_time_init(void) +long pmac_time_init(void) { #ifdef CONFIG_NVRAM s32 delta = 0; @@ -72,17 +72,18 @@ void pmac_time_init(void) dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, dst ? "on" : "off"); - sys_tz.tz_minuteswest = -delta/60; - /* I _suppose_ this is 0:off, 1:on */ - sys_tz.tz_dsttime = dst; + return delta; +#else + return 0; #endif } __pmac unsigned long pmac_get_rtc_time(void) { -#ifdef CONFIG_ADB +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; + unsigned long now; #endif /* Get the time from the RTC */ @@ -96,8 +97,9 @@ unsigned long pmac_get_rtc_time(void) 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; + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + return now - RTC_OFFSET; #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: @@ -108,21 +110,25 @@ unsigned long pmac_get_rtc_time(void) 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; + now = (req.reply[1] << 24) + (req.reply[2] << 16) + + (req.reply[3] << 8) + req.reply[4]; + return now - RTC_OFFSET; #endif /* CONFIG_ADB_PMU */ default: - return 0; } + return 0; } int pmac_set_rtc_time(unsigned long nowtime) { +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; +#endif - nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60; + nowtime += RTC_OFFSET; switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) @@ -133,16 +139,19 @@ int pmac_set_rtc_time(unsigned long nowtime) printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", req.reply_len); return 1; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) return 0; while (!req.complete) pmu_poll(); - if (req.reply_len != 5) + if (req.reply_len != 0) printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", req.reply_len); return 1; +#endif /* CONFIG_ADB_PMU */ default: return 0; } @@ -186,12 +195,11 @@ int __init via_calibrate_decr(void) ; dend = get_dec(); - decrementer_count = (dstart - dend) / 6; - count_period_num = 60; - count_period_den = decrementer_count * 6 * HZ / 100000; + tb_ticks_per_jiffy = (dstart - dend) / 6; + tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); - printk(KERN_INFO "via_calibrate_decr: decrementer_count = %u (%u ticks)\n", - decrementer_count, dstart - dend); + printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", + tb_ticks_per_jiffy, dstart - dend); return 1; } @@ -214,8 +222,11 @@ static int time_sleep_notify(struct pmu_sleep_notifier *self, int when) case PBOOK_WAKE: write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = pmac_get_rtc_time() + time_diff; + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + so use get_tbl, not native */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); xtime.tv_usec = 0; - set_dec(decrementer_count); last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); break; @@ -236,7 +247,7 @@ static struct pmu_sleep_notifier time_sleep_notifier = { void __init pmac_calibrate_decr(void) { struct device_node *cpu; - int freq, *fp, divisor; + unsigned int freq, *fp; #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&time_sleep_notifier); @@ -252,15 +263,13 @@ void __init pmac_calibrate_decr(void) cpu = find_type_devices("cpu"); if (cpu == 0) panic("can't find cpu node in time_init"); - fp = (int *) get_property(cpu, "timebase-frequency", NULL); + fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); if (fp == 0) panic("can't get cpu timebase frequency"); - 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; + freq = *fp; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c index 7a673fb70..1b865ef96 100644 --- a/arch/ppc/kernel/ppc-stub.c +++ b/arch/ppc/kernel/ppc-stub.c @@ -122,9 +122,9 @@ void breakinst(void); static char remcomInBuffer[BUFMAX]; static char remcomOutBuffer[BUFMAX]; -static int initialized = 0; -static int kgdb_active = 0; -static int kgdb_started = 0; +static int initialized; +static int kgdb_active; +static int kgdb_started; static u_int fault_jmp_buf[100]; static int kdebug; diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 1317359e7..9240431e6 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -37,6 +37,7 @@ #include <asm/hw_irq.h> #include <asm/nvram.h> #include <asm/mmu_context.h> +#include <asm/backlight.h> #ifdef CONFIG_SMP #include <asm/smplock.h> #endif /* CONFIG_SMP */ @@ -184,6 +185,10 @@ EXPORT_SYMBOL(giveup_fpu); EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +#ifdef CONFIG_ALTIVEC +EXPORT_SYMBOL(last_task_used_altivec); +EXPORT_SYMBOL(giveup_altivec); +#endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SMP EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); @@ -204,26 +209,34 @@ EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB -/* - * This could be more fine-grained, but for now assume if we have - * ADB we have it all -- Cort - */ EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_register); +EXPORT_SYMBOL(adb_unregister); +EXPORT_SYMBOL(adb_poll); +EXPORT_SYMBOL(adb_try_handler_change); +#endif /* CONFIG_ADB */ +#ifdef CONFIG_ADB_CUDA EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); +#endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); #endif /* CONFIG_ADB_PMU */ -#endif /* CONFIG_ADB */ #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); -#endif CONFIG_PMAC_PBOOK +#endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_PMAC_BACKLIGHT +EXPORT_SYMBOL(get_backlight_level); +EXPORT_SYMBOL(set_backlight_level); +#endif /* CONFIG_PMAC_BACKLIGHT */ #if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL_NOVERS(sys_ctrler); +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL_NOVERS(have_of); +#endif /* CONFIG_MACH_SPECIFIC */ EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -253,10 +266,7 @@ EXPORT_SYMBOL(nvram_write_byte); EXPORT_SYMBOL(pmac_xpram_read); EXPORT_SYMBOL(pmac_xpram_write); #endif /* CONFIG_NVRAM */ -#ifdef CONFIG_PPC_RTC -EXPORT_SYMBOL(mktime); EXPORT_SYMBOL(to_tm); -#endif EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(__ashldi3); @@ -280,7 +290,7 @@ EXPORT_SYMBOL(do_IRQ_intercept); EXPORT_SYMBOL(irq_desc); void ppc_irq_dispatch_handler(struct pt_regs *, int); EXPORT_SYMBOL(ppc_irq_dispatch_handler); -EXPORT_SYMBOL(decrementer_count); +EXPORT_SYMBOL(tb_ticks_per_jiffy); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); EXPORT_SYMBOL(console_lock); @@ -310,3 +320,17 @@ EXPORT_SYMBOL(do_softirq); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(mmu_context_overflow); + +#ifdef CONFIG_MOL +extern ulong mol_interface[]; +extern PTE *Hash; +extern unsigned long Hash_mask; +extern void (*ret_from_except)(void); +extern struct task_struct *last_task_used_altivec; +EXPORT_SYMBOL_NOVERS(mol_interface); +EXPORT_SYMBOL(Hash); +EXPORT_SYMBOL(Hash_mask); +EXPORT_SYMBOL(handle_mm_fault); +EXPORT_SYMBOL(last_task_used_math); +EXPORT_SYMBOL(ret_from_except); +#endif /* CONFIG_MOL */ diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index a09b4cf81..d72e74735 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -365,14 +365,13 @@ prep_setup_arch(void) */ void __init prep_res_calibrate_decr(void) { - int freq, divisor; + unsigned long freq, divisor=4; freq = res->VitalProductData.ProcessorBusHz; - divisor = 4; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + (freq/divisor)/1000000, (freq/divisor)%1000000); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); } /* @@ -381,32 +380,30 @@ void __init prep_res_calibrate_decr(void) * but on prep we have to figure it out. * -- Cort */ -int calibrate_done = 0; -volatile int *done_ptr = &calibrate_done; +/* Done with 3 interrupts: the first one primes the cache and the + * 2 following ones measure the interval. The precision of the method + * is still doubtful due to the short interval sampled. + */ +static __initdata volatile int calibrate_steps = 3; +static __initdata unsigned tbstamp; void __init 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) - { - t2 = get_dec(); - t2 = t1-t2; /* decr's in 1/HZ */ - t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ - 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; - *done_ptr = 1; + unsigned long t, freq; + int step=--calibrate_steps; + + t = get_tbl(); + if (step > 0) { + tbstamp = t; + } else { + freq = (t - tbstamp)*HZ; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } } @@ -428,17 +425,43 @@ void __init prep_calibrate_decr(void) if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) panic("Could not allocate timer IRQ!"); __sti(); - while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */ + while ( calibrate_steps ) /* nothing */; /* wait for calibrate */ restore_flags(flags); free_irq( 0, NULL); } -/* We use the NVRAM RTC to time a second to calibrate the decrementer. */ +static long __init mk48t59_init(void) { + unsigned char tmp; + + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); + if (tmp & MK48T59_RTC_CB_STOP) { + printk("Warning: RTC was stopped, date will be wrong.\n"); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, + tmp & ~MK48T59_RTC_CB_STOP); + /* Low frequency crystal oscillators may take a very long + * time to startup and stabilize. For now just ignore the + * the issue, but attempting to calibrate the decrementer + * from the RTC just after this wakeup is likely to be very + * inaccurate. Firmware should not allow to load + * the OS with the clock stopped anyway... + */ + } + /* Ensure that the clock registers are updated */ + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp); + return 0; +} + +/* We use the NVRAM RTC to time a second to calibrate the decrementer, + * the RTC registers have just been set up in the right state by the + * preceding routine. + */ void __init mk48t59_calibrate_decr(void) { - unsigned long freq, divisor; - unsigned long t1, t2; + unsigned long freq; + unsigned long t1; unsigned char save_control; long i; unsigned char sec; @@ -458,29 +481,31 @@ void __init mk48t59_calibrate_decr(void) /* Read the seconds value to see when it changes. */ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + /* Actually this is bad for precision, we should have a loop in + * which we only read the seconds counter. nvram_read_val writes + * the address bytes on every call and this takes a lot of time. + * Perhaps an nvram_wait_change method returning a time + * stamp with a loop count as parameter would be the solution. + */ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ + t1 = get_tbl(); if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t1 = get_dec(); sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */ + freq = get_tbl()-t1; if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t2 = t1 - get_dec(); - - 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; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } void __prep @@ -788,6 +813,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, { ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; + ppc_md.time_init = mk48t59_init; } else { @@ -808,6 +834,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; ppc_md.calibrate_decr = mk48t59_calibrate_decr; + ppc_md.time_init = mk48t59_init; } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c index 7274dfd0b..78634c6e2 100644 --- a/arch/ppc/kernel/prep_time.c +++ b/arch/ppc/kernel/prep_time.c @@ -15,6 +15,7 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/interrupt.h> +#include <linux/time.h> #include <linux/timex.h> #include <linux/kernel_stat.h> #include <linux/init.h> @@ -99,28 +100,34 @@ __prep unsigned long mc146818_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; + int uip, i; /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = CMOS_READ(RTC_FREQ_SELECT); sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); day = CMOS_READ(RTC_DAY_OF_MONTH); mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); + uip |= CMOS_READ(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -177,29 +184,12 @@ unsigned long mk48t59_get_rtc_time(void) { unsigned char save_control; unsigned int year, mon, day, hour, min, sec; - int i; - /* Make sure the time is not stopped. */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); - - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, - (save_control & (~MK48T59_RTC_CB_STOP))); - - /* Now make sure the read bit is off so the value will change. */ + /* Simple: freeze the clock, read it and allow updates again */ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); save_control &= ~MK48T59_RTC_CA_READ; ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - /* Read the seconds value to see when it changes. */ - sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); - - /* Wait until the seconds value changes, then read the value. */ - for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ - if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { - break; - } - } - /* Set the register to read the value. */ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, (save_control | MK48T59_RTC_CA_READ)); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 7bc5cb82f..27adc9958 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -234,7 +234,6 @@ _switch_to(struct task_struct *prev, struct task_struct *new, prev->thread.vrsave ) giveup_altivec(prev); #endif /* CONFIG_ALTIVEC */ - prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* CONFIG_SMP */ /* Avoid the trap. On smp this this never happens since @@ -266,7 +265,7 @@ void show_regs(struct pt_regs * regs) last_task_used_altivec); #ifdef CONFIG_SMP - printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); + printk(" CPU: %d", current->processor); #endif /* CONFIG_SMP */ printk("\n"); @@ -315,6 +314,7 @@ release_thread(struct task_struct *t) */ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, struct task_struct * p, struct pt_regs * regs) { unsigned long msr; @@ -378,9 +378,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, childregs->msr &= ~MSR_VEC; #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_SMP - p->last_processor = NO_PROC_ID; -#endif /* CONFIG_SMP */ return 0; } @@ -440,13 +437,13 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) current->thread.fpscr = 0; } -asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +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); + res = do_fork(clone_flags, regs->gpr[1], regs, 0); #ifdef CONFIG_SMP /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. @@ -459,13 +456,13 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, return res; } -asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { int res; - res = do_fork(SIGCHLD, regs->gpr[1], regs); + res = do_fork(SIGCHLD, regs->gpr[1], regs, 0); #ifdef CONFIG_SMP /* When we clone the idle task we keep the same pid but * the return value of 0 for both causes problems. @@ -477,15 +474,15 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, return res; } -asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); } -asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) +int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs *regs) { int error; char * filename; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 1d661fa71..5494f2f52 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -140,8 +140,7 @@ static long g_loc_Y = 0; static long g_max_loc_X = 0; static long g_max_loc_Y = 0; -unsigned long disp_BATL = 0; -unsigned long disp_BATU = 0; +unsigned long disp_BAT[2] = {0, 0}; #define cmapsz (16*256) @@ -276,8 +275,7 @@ prom_print(const char *msg) prom_drawstring(msg); #endif return; - } - + } for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) @@ -362,7 +360,7 @@ prom_hold_cpus(unsigned long mem) /* copy the holding pattern code to someplace safe (0) */ /* the holding pattern is now within the first 0x100 bytes of the kernel image -- paulus */ - memcpy((void *)0, KERNELBASE + offset, 0x100); + memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100); flush_icache_range(0, 0x100); /* look for cpus */ @@ -556,6 +554,54 @@ prom_alloc_htab(void) } #endif /* CONFIG_PPC64BRIDGE */ +static __init void +prom_instantiate_rtas(void) +{ + ihandle prom_rtas; + unsigned int i; + struct prom_args prom_args; + unsigned long offset = reloc_offset(); + + prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); + if (prom_rtas == (void *) -1) + return; + + RELOC(rtas_size) = 0; + call_prom(RELOC("getprop"), 4, 1, prom_rtas, + RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); + prom_print(RELOC("instantiating rtas")); + if (RELOC(rtas_size) == 0) { + RELOC(rtas_data) = 0; + } else { + /* + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. + */ + RELOC(rtas_data) = 6 << 20; + prom_print(RELOC(" at ")); + prom_print_hex(RELOC(rtas_data)); + } + + prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); + prom_print(RELOC("...")); + prom_args.service = RELOC("call-method"); + prom_args.nargs = 3; + 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); + RELOC(prom)(&prom_args); + i = 0; + if (prom_args.args[3] == 0) + i = (unsigned int)prom_args.args[4]; + RELOC(rtas_entry) = i; + if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) + prom_print(RELOC(" failed\n")); + else + prom_print(RELOC(" done\n")); +} + /* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. @@ -566,7 +612,7 @@ prom_init(int r3, int r4, prom_entry pp) { int chrp = 0; unsigned long mem; - ihandle prom_rtas, prom_mmu, prom_op; + ihandle prom_mmu, prom_op; unsigned long offset = reloc_offset(); int l; char *p, *d; @@ -650,47 +696,7 @@ prom_init(int r3, int r4, prom_entry pp) mem = ALIGN(mem + strlen(d) + 1); } - prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); - if (prom_rtas != (void *) -1) { - int i, nargs; - struct prom_args prom_args; - - RELOC(rtas_size) = 0; - call_prom(RELOC("getprop"), 4, 1, prom_rtas, - RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); - prom_print(RELOC("instantiating rtas")); - if (RELOC(rtas_size) == 0) { - RELOC(rtas_data) = 0; - } else { - /* - * Ask OF for some space for RTAS. - * Actually OF has bugs so we just arbitrarily - * use memory at the 6MB point. - */ - RELOC(rtas_data) = 6 << 20; - prom_print(RELOC(" at ")); - prom_print_hex(RELOC(rtas_data)); - } - prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); - prom_print(RELOC("...")); - 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); - RELOC(prom)(&prom_args); - if (prom_args.args[nargs] != 0) - i = 0; - else - i = (int)prom_args.args[nargs+1]; - RELOC(rtas_entry) = i; - if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) - prom_print(RELOC(" failed\n")); - else - prom_print(RELOC(" done\n")); - } + prom_instantiate_rtas(); #ifdef CONFIG_PPC64BRIDGE /* @@ -737,7 +743,7 @@ prom_init(int r3, int r4, prom_entry pp) /* We assume the phys. address size is 3 cells */ if (prom_args.args[nargs] != 0) - prom_print(RELOC(" (translate failed) ")); + prom_print(RELOC(" (translate failed)\n")); else phys = (unsigned long)prom_args.args[nargs+3]; } @@ -752,8 +758,6 @@ prom_init(int r3, int r4, prom_entry pp) if (prom_version >= 3) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); - offset = reloc_offset(); - phys = offset + KERNELBASE; } #ifdef CONFIG_BOOTX_TEXT @@ -769,7 +773,9 @@ prom_init(int r3, int r4, prom_entry pp) } #endif - prom_print(RELOC("returning from prom_init\n")); + prom_print(RELOC("returning ")); + prom_print_hex(phys); + prom_print(RELOC(" from prom_init\n")); RELOC(prom_stdout) = 0; return phys; } @@ -836,9 +842,8 @@ prom_welcome(boot_infos_t* bi, unsigned long phys) } /* Calc BAT values for mapping the display and store them - * in disp_BATH and disp_BATL. Those values are then used - * from head.S to map the display during identify_machine() - * and MMU_Init() + * in disp_BAT. Those values are then used from head.S to map + * the display during identify_machine() and MMU_Init() * * For now, the display is mapped in place (1:1). This should * be changed if the display physical address overlaps @@ -862,13 +867,13 @@ prepare_disp_BAT(void) if ((_get_PVR() >> 16) != 1) { /* 603, 604, G3, G4, ... */ addr &= 0xFF000000UL; - RELOC(disp_BATU) = addr | (BL_16M<<2) | 2; - RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + RELOC(disp_BAT[0]) = addr | (BL_16M<<2) | 2; + RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ addr &= 0xFF800000UL; - RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; - RELOC(disp_BATL) = addr | BL_8M | 0x40; + RELOC(disp_BAT[0]) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + RELOC(disp_BAT[1]) = addr | BL_8M | 0x40; } bi->logicalDisplayBase = bi->dispDeviceBase; } @@ -1003,34 +1008,52 @@ setup_disp_fake_bi(ihandle dp) unsigned address; boot_infos_t* bi; unsigned long offset = reloc_offset(); - - prom_print(RELOC("Initializing fake screen\n")); - - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), - &width, sizeof(width)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), - &height, sizeof(height)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), - &depth, sizeof(depth)); + struct pci_reg_property addrs[8]; + int i, naddrs; + char name[32]; + char *getprop = RELOC("getprop"); + + prom_print(RELOC("Initializing fake screen: ")); + + memset(name, 0, sizeof(name)); + call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_print(name); + prom_print(RELOC("\n")); + call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width)); + call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height)); + call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), + call_prom(getprop, 4, 1, dp, RELOC("linebytes"), &pitch, sizeof(pitch)); - address = 0; - if (pitch == 1) { - address = 0xfa000000; + if (pitch == 1) pitch = 0x1000; /* for strange IBM display */ - } - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), + address = 0; + call_prom(getprop, 4, 1, dp, RELOC("address"), &address, sizeof(address)); if (address == 0) { - prom_print(RELOC("Failed to get address\n")); - return; + /* look for an assigned address with a size of >= 1MB */ + naddrs = (int) call_prom(getprop, 4, 1, dp, + RELOC("assigned-addresses"), + addrs, sizeof(addrs)); + naddrs /= sizeof(struct pci_reg_property); + for (i = 0; i < naddrs; ++i) { + if (addrs[i].size_lo >= (1 << 20)) { + address = addrs[i].addr.a_lo; + /* use the BE aperture if possible */ + if (addrs[i].size_lo >= (16 << 20)) + address += (8 << 20); + break; + } + } + if (address == 0) { + prom_print(RELOC("Failed to get address\n")); + return; + } } -#if 0 /* kludge for valkyrie */ - if (strcmp(dp->name, "valkyrie") == 0) - address += 0x1000; -#endif + if (strcmp(name, RELOC("valkyrie")) == 0) + address += 0x1000; RELOC(disp_bi) = &fake_bi; bi = PTRRELOC((&fake_bi)); @@ -1334,11 +1357,19 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start) */ if (get_property(node, "interrupt-controller", &l)) { int i,j; + int cvt_irq; + + /* XXX on chrp, offset interrupt numbers for the + 8259 by 0, those for the openpic by 16 */ + cvt_irq = _machine == _MACH_chrp + && get_property(node, "interrupt-parent", NULL) == 0; np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = ipsize / isize; mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *interrupts++; + if (cvt_irq) + np->intrs[i].line = openpic_to_irq(np->intrs[i].line); np->intrs[i].sense = 0; if (isize > 1) np->intrs[i].sense = *interrupts++; @@ -2072,7 +2103,6 @@ abort() * changes. */ -__init void map_bootx_text(void) { @@ -2083,7 +2113,10 @@ map_bootx_text(void) offset = ((unsigned long) disp_bi->dispDeviceBase) - base; size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset + disp_bi->dispDeviceRect[0]; - disp_bi->logicalDisplayBase = ioremap(base, size) + offset; + disp_bi->logicalDisplayBase = ioremap(base, size); + if (disp_bi->logicalDisplayBase == 0) + return; + disp_bi->logicalDisplayBase += offset; bootx_text_mapped = 1; } @@ -2102,6 +2135,35 @@ calc_base(boot_infos_t *bi, int x, int y) return base; } +/* Adjust the display to a new resolution */ +void +bootx_update_display(unsigned long phys, int width, int height, + int depth, int pitch) +{ + if (disp_bi == 0) + return; + /* check it's the same frame buffer (within 16MB) */ + if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xff000000) + return; + + disp_bi->dispDeviceBase = (__u8 *) phys; + disp_bi->dispDeviceRect[0] = 0; + disp_bi->dispDeviceRect[1] = 0; + disp_bi->dispDeviceRect[2] = width; + disp_bi->dispDeviceRect[3] = height; + disp_bi->dispDeviceDepth = depth; + disp_bi->dispDeviceRowBytes = pitch; + if (bootx_text_mapped) { + iounmap(disp_bi->logicalDisplayBase); + bootx_text_mapped = 0; + } + map_bootx_text(); + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; +} + __pmac static void clearscreen(void) @@ -2162,6 +2224,9 @@ scrollscreen(void) (bi->dispDeviceDepth >> 3)) >> 2; int i,j; +#ifdef CONFIG_ADB_PMU + pmu_suspend(); /* PMU will not shut us down ! */ +#endif for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; @@ -2178,6 +2243,9 @@ scrollscreen(void) *(dst_ptr++) = 0; dst += (bi->dispDeviceRowBytes >> 2); } +#ifdef CONFIG_ADB_PMU + pmu_resume(); /* PMU will not shut us down ! */ +#endif } #endif /* ndef NO_SCROLL */ diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 67387cca0..6bafa57c1 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -35,6 +35,8 @@ #include <asm/bootx.h> #include <asm/machdep.h> #include <asm/feature.h> +#include <asm/uaccess.h> + #ifdef CONFIG_OAK #include "oak_setup.h" #endif /* CONFIG_OAK */ @@ -655,16 +657,18 @@ int parse_bootinfo(void) } /* Checks "l2cr=xxxx" command-line option */ -void ppc_setup_l2cr(char *str, int *ints) +int ppc_setup_l2cr(char *str) { if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) ) { unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); - _set_L2CR(0); - _set_L2CR(val); + _set_L2CR(0); /* force invalidate by disable cache */ + _set_L2CR(val); /* and enable it */ } + return 1; } +__setup("l2cr=", ppc_setup_l2cr); void __init ppc_init(void) { @@ -683,6 +687,9 @@ void __init setup_arch(char **cmdline_p) extern char *klimit; extern void do_init_bootmem(void); + /* so udelay does something sensible, assume <= 1000 bogomips */ + loops_per_sec = 500000000; + #ifdef CONFIG_ALL_PPC feature_init(); #endif @@ -737,6 +744,7 @@ void __init setup_arch(char **cmdline_p) if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); + sort_exception_table(); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 79847fa0d..dd3d1ae1b 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -154,7 +154,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, } -asmlinkage int +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) { struct pt_regs *regs = (struct pt_regs *) &uss; @@ -232,7 +232,7 @@ struct rt_sigframe * Each of these things must be a multiple of 16 bytes in size. * */ -asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe *rt_sf; struct sigcontext_struct sigctx; @@ -301,7 +301,6 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) return ret; badframe: - lock_kernel(); do_exit(SIGSEGV); } @@ -351,7 +350,6 @@ badframe: printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -418,7 +416,6 @@ int sys_sigreturn(struct pt_regs *regs) return ret; badframe: - lock_kernel(); do_exit(SIGSEGV); } @@ -460,7 +457,6 @@ badframe: printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -541,7 +537,6 @@ badframe: regs, frame, *newspp); printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -645,8 +640,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* FALLTHRU */ default: - lock_kernel(); - sigaddset(¤t->signal, signr); + sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; do_exit(exit_code); @@ -663,6 +657,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); + break; } if (regs->trap == 0x0C00 /* System Call! */ && diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 8cb68c6b2..0a66d6c6b 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -62,72 +62,62 @@ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; int start_secondary(void *); extern int cpu_idle(void *unused); u_int openpic_read(volatile u_int *addr); +void smp_call_function_interrupt(void); +void smp_message_pass(int target, int msg, unsigned long data, int wait); +/* register for interrupting the primary processor on the powersurge */ +/* N.B. this is actually the ethernet ROM! */ +#define PSURGE_PRI_INTR 0xf3019000 /* register for interrupting the secondary processor on the powersurge */ -#define PSURGE_INTR ((volatile unsigned *)0xf80000c0) +#define PSURGE_SEC_INTR 0xf80000c0 +/* register for storing the start address for the secondary processor */ +#define PSURGE_START 0xf2800000 +/* virtual addresses for the above */ +volatile u32 *psurge_pri_intr; +volatile u32 *psurge_sec_intr; +volatile u32 *psurge_start; + +/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. */ +#define PPC_MSG_CALL_FUNCTION 0 +#define PPC_MSG_RESCHEDULE 1 +#define PPC_MSG_INVALIDATE_TLB 2 +#define PPC_MSG_XMON_BREAK 3 + +static inline void set_tb(unsigned int upper, unsigned int lower) +{ + mtspr(SPRN_TBWU, upper); + mtspr(SPRN_TBWL, lower); +} void smp_local_timer_interrupt(struct pt_regs * regs) { 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; - current->need_resched = 1; - } - if (p->nice > 0) { - 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; - - } + if (!--prof_counter[cpu]) { + update_process_times(user_mode(regs)); prof_counter[cpu]=prof_multiplier[cpu]; } } -void smp_message_recv(int msg) +void smp_message_recv(int msg, struct pt_regs *regs) { ipi_count++; - switch( msg ) - { - case MSG_STOP_CPU: - __cli(); - while (1) ; + switch( msg ) { + case PPC_MSG_CALL_FUNCTION: + smp_call_function_interrupt(); break; - case MSG_RESCHEDULE: + case PPC_MSG_RESCHEDULE: current->need_resched = 1; break; - case MSG_INVALIDATE_TLB: + case PPC_MSG_INVALIDATE_TLB: _tlbia(); - case 0xf0f0: /* pmac syncing time bases - just return */ break; +#ifdef CONFIG_XMON + case PPC_MSG_XMON_BREAK: + xmon(regs); + break; +#endif /* CONFIG_XMON */ default: printk("SMP %d: smp_message_recv(): unknown msg %d\n", smp_processor_id(), msg); @@ -142,25 +132,38 @@ void smp_message_recv(int msg) * smp_message[]. * * This is because don't have several IPI's on the PowerSurge even though - * we do on the chrp. It would be nice to use actual IPI's such as with openpic - * rather than this. + * we do on the chrp. It would be nice to use actual IPI's such as with + * openpic rather than this. * -- Cort */ int pmac_smp_message[NR_CPUS]; -void pmac_smp_message_recv(void) +void pmac_smp_message_recv(struct pt_regs *regs) { - int msg = pmac_smp_message[smp_processor_id()]; - + int cpu = smp_processor_id(); + int msg; + /* clear interrupt */ - out_be32(PSURGE_INTR, ~0); - - /* make sure msg is for us */ - if ( msg == -1 ) return; + if (cpu == 1) + out_be32(psurge_sec_intr, ~0); + + if (smp_num_cpus < 2) + return; + + /* make sure there is a message there */ + msg = pmac_smp_message[cpu]; + if (msg == 0) + return; - smp_message_recv(msg); - /* reset message */ - pmac_smp_message[smp_processor_id()] = -1; + pmac_smp_message[cpu] = 0; + + smp_message_recv(msg - 1, regs); +} + +void +pmac_primary_intr(int irq, void *d, struct pt_regs *regs) +{ + pmac_smp_message_recv(regs); } /* @@ -171,7 +174,7 @@ void pmac_smp_message_recv(void) void smp_send_tlb_invalidate(int cpu) { if ( (_get_PVR()>>16) == 8 ) - smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0); + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0); } void smp_send_reschedule(int cpu) @@ -187,18 +190,135 @@ void smp_send_reschedule(int cpu) */ /* This is only used if `cpu' is running an idle task, so it will reschedule itself anyway... */ - smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); + smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0); +} + +#ifdef CONFIG_XMON +void smp_send_xmon_break(int cpu) +{ + smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0); +} +#endif /* CONFIG_XMON */ + +static void stop_this_cpu(void *dummy) +{ + __cli(); + while (1) + ; } void smp_send_stop(void) { - smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0); + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; +} + +/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + * Stolen from the i386 version. + */ +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; + +static volatile struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} *call_data = NULL; + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) +/* + * [SUMMARY] Run a function on all other CPUs. + * <func> The function to run. This must be fast and non-blocking. + * <info> An arbitrary pointer to pass to the function. + * <nonatomic> currently unused. + * <wait> If true, wait (atomically) until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute <<func>> or are or have executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +{ + struct call_data_struct data; + int ret = -1, cpus = smp_num_cpus-1; + int timeout; + + if (!cpus) + return 0; + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + /* Send a message to all other CPUs and wait for them to respond */ + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0); + + /* Wait for response */ + timeout = 1000000; + while (atomic_read(&data.started) != cpus) { + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", + smp_processor_id(), atomic_read(&data.started)); + goto out; + } + barrier(); + udelay(1); + } + + if (wait) { + timeout = 1000000; + while (atomic_read(&data.finished) != cpus) { + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", + smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); + goto out; + } + barrier(); + udelay(1); + } + } + ret = 0; + + out: + spin_unlock_bh(&call_lock); + return ret; +} + +void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function + */ + atomic_inc(&call_data->started); + /* + * At this point the info structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) + atomic_inc(&call_data->finished); } void smp_message_pass(int target, int msg, unsigned long data, int wait) { - int i; - if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) ) return; @@ -212,31 +332,29 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) * the recipient won't know the message was destined * for it. -- Cort */ - for ( i = 0; i <= smp_num_cpus ; i++ ) - pmac_smp_message[i] = -1; - switch( target ) - { - case MSG_ALL: - pmac_smp_message[smp_processor_id()] = msg; - /* fall through */ - case MSG_ALL_BUT_SELF: - for ( i = 0 ; i < smp_num_cpus ; i++ ) - if ( i != smp_processor_id () ) - pmac_smp_message[i] = msg; - break; - default: - pmac_smp_message[target] = msg; - break; + if (smp_processor_id() == 0) { + /* primary cpu */ + if (target == 1 || target == MSG_ALL_BUT_SELF + || target == MSG_ALL) { + pmac_smp_message[1] = msg + 1; + /* interrupt secondary processor */ + out_be32(psurge_sec_intr, ~0); + out_be32(psurge_sec_intr, 0); + } + } else { + /* secondary cpu */ + if (target == 0 || target == MSG_ALL_BUT_SELF + || target == MSG_ALL) { + pmac_smp_message[0] = msg + 1; + /* interrupt primary processor */ + in_be32(psurge_pri_intr); + } + } + if (target == smp_processor_id() || target == MSG_ALL) { + /* sending a message to ourself */ + /* XXX maybe we shouldn't do this if ints are off */ + smp_message_recv(msg, NULL); } - /* interrupt secondary processor */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); - /* - * Assume for now that the secondary doesn't send - * IPI's -- Cort - */ - /* interrupt primary */ - /**(volatile unsigned long *)(0xf3019000);*/ break; case _MACH_chrp: case _MACH_prep: @@ -261,7 +379,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) #else /* CONFIG_POWER4 */ /* for now, only do reschedule messages since we only have one IPI */ - if (msg != MSG_RESCHEDULE) + if (msg != PPC_MSG_RESCHEDULE) break; for (i = 0; i < smp_num_cpus; ++i) { if (target == MSG_ALL || target == i @@ -319,7 +437,10 @@ void __init smp_boot_cpus(void) { case _MACH_Pmac: /* assume powersurge board - 2 processors -- Cort */ - cpu_nr = 2; + cpu_nr = 2; + psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); + psurge_sec_intr = ioremap(PSURGE_SEC_INTR, 4); + psurge_start = ioremap(PSURGE_START, 4); break; case _MACH_chrp: if (OpenPIC) @@ -347,7 +468,7 @@ void __init smp_boot_cpus(void) /* create a process for the processor */ /* we don't care about the values in regs since we'll never reschedule the forked task. */ - if (do_fork(CLONE_VM|CLONE_PID, 0, ®s) < 0) + if (do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0) < 0) panic("failed fork for CPU %d", i); p = init_task.prev_task; if (!p) @@ -370,13 +491,11 @@ void __init smp_boot_cpus(void) { case _MACH_Pmac: /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) = - (unsigned long)__secondary_start_psurge-KERNELBASE; - eieio(); + out_be32(psurge_start, __pa(__secondary_start_psurge)); /* interrupt secondary to begin executing code */ - out_be32(PSURGE_INTR, ~0); + out_be32(psurge_sec_intr, ~0); udelay(1); - out_be32(PSURGE_INTR, 0); + out_be32(psurge_sec_intr, 0); break; case _MACH_chrp: *(unsigned long *)KERNELBASE = i; @@ -399,9 +518,6 @@ void __init smp_boot_cpus(void) if ( cpu_callin_map[i] ) { printk("Processor %d found.\n", i); - /* this sync's the decr's -- Cort */ - if ( _machine == _MACH_Pmac ) - set_dec(decrementer_count); smp_num_cpus++; } else { printk("Processor %d is stuck.\n", i); @@ -415,9 +531,25 @@ void __init smp_boot_cpus(void) { /* reset the entry point so if we get another intr we won't * try to startup again */ - *(volatile unsigned long *)(0xf2800000) = 0x100; - /* send interrupt to other processors to start decr's on all cpus */ - smp_message_pass(1,0xf0f0, 0, 0); + out_be32(psurge_start, 0x100); + if (request_irq(30, pmac_primary_intr, 0, "primary IPI", 0)) + printk(KERN_ERR "Couldn't get primary IPI interrupt"); + /* + * The decrementers of both cpus are frozen at this point + * until we give the secondary cpu another interrupt. + * We set them both to decrementer_count and then send + * the interrupt. This should get the decrementers + * synchronized. + * -- paulus. + */ + set_dec(tb_ticks_per_jiffy); + if ((_get_PVR() >> 16) != 1) { + set_tb(0, 0); /* set timebase if not 601 */ + last_jiffy_stamp(0) = 0; + } + out_be32(psurge_sec_intr, ~0); + udelay(1); + out_be32(psurge_sec_intr, 0); } } @@ -447,8 +579,11 @@ int __init start_secondary(void *unused) void __init smp_callin(void) { smp_store_cpu_info(current->processor); - set_dec(decrementer_count); - + set_dec(tb_ticks_per_jiffy); + if (_machine == _MACH_Pmac && (_get_PVR() >> 16) != 1) { + set_tb(0, 0); /* set timebase if not 601 */ + last_jiffy_stamp(current->processor) = 0; + } init_idle(); cpu_callin_map[current->processor] = 1; diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 314c1240c..d0fee4344 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -45,7 +45,7 @@ check_bugs(void) { } -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) +int sys_ioperm(unsigned long from, unsigned long num, int on) { printk(KERN_ERR "sys_ioperm()\n"); return -EIO; @@ -74,7 +74,7 @@ int sys_modify_ldt(int a1, int a2, int a3, int a4) * * This is really horribly ugly. */ -asmlinkage int +int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { int version, ret; @@ -172,7 +172,7 @@ sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage int sys_pipe(int *fildes) +int sys_pipe(int *fildes) { int fd[2]; int error; @@ -185,19 +185,19 @@ asmlinkage int sys_pipe(int *fildes) return error; } -asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) +unsigned long sys_mmap(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) { struct file * file = NULL; int ret = -EBADF; + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { if (!(file = fget(fd))) goto out; } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); down(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, offset); up(¤t->mm->mmap_sem); @@ -207,7 +207,7 @@ out: return ret; } -extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); /* * Due to some executables calling the wrong select we sometimes @@ -215,7 +215,7 @@ extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timev * (a single ptr to them all args passed) then calls * sys_select() with the appropriate args. -- Cort */ -asmlinkage int +int ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { if ( (unsigned long)n >= 4096 ) @@ -232,14 +232,14 @@ ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) return sys_select(n, inp, outp, exp, tvp); } -asmlinkage int sys_pause(void) +int sys_pause(void) { current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND; } -asmlinkage int sys_uname(struct old_utsname * name) +int sys_uname(struct old_utsname * name) { int err = -EFAULT; @@ -250,7 +250,7 @@ asmlinkage int sys_uname(struct old_utsname * name) return err; } -asmlinkage int sys_olduname(struct oldold_utsname * name) +int sys_olduname(struct oldold_utsname * name) { int error; diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index aff4838b3..f71c8cbbf 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -6,6 +6,27 @@ * Paul Mackerras' version and mine for PReP and Pmac. * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net). * + * First round of bugfixes by Gabriel Paubert (paubert@iram.es) + * to make clock more stable (2.4.0-test5). The only thing + * that this code assumes is that the timebases have been synchronized + * by firmware on SMP and are never stopped (never do sleep + * on SMP then, nap and doze are OK). + * + * TODO (not necessarily in this file): + * - improve precision and reproducibility of timebase frequency + * measurement at boot time. + * - get rid of xtime_lock for gettimeofday (generic kernel problem + * to be implemented on all architectures for SMP scalability and + * eventually implementing gettimeofday without entering the kernel). + * - put all time/clock related variables in a single structure + * to minimize number of cache lines touched by gettimeofday() + * - for astronomical applications: add a new function to get + * non ambiguous timestamps even around leap seconds. This needs + * a new timestamp format and a good name. + * + * + * The following comment is partially obsolete (at least the long wait + * is no more a valid reason): * 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 @@ -49,18 +70,32 @@ void smp_local_timer_interrupt(struct pt_regs *); /* keep track of when we need to update the rtc */ -time_t last_rtc_update = 0; +time_t last_rtc_update; extern rwlock_t xtime_lock; /* The decrementer counts down by 128 every 128ns on a 601. */ #define DECREMENTER_COUNT_601 (1000000000 / HZ) -#define COUNT_PERIOD_NUM_601 1 -#define COUNT_PERIOD_DEN_601 1000 -unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ -unsigned count_period_num; /* 1 decrementer count equals */ -unsigned count_period_den; /* count_period_num / count_period_den us */ -unsigned long last_tb; +unsigned tb_ticks_per_jiffy; +unsigned tb_to_us; +unsigned tb_last_stamp; + +extern unsigned long wall_jiffies; + +static long time_offset; + +/* Timer interrupt helper function */ +static inline int tb_delta(unsigned *jiffy_stamp) { + int delta; + if (__USE_RTC()) { + delta = get_rtcl(); + if (delta < *jiffy_stamp) *jiffy_stamp -= 1000000000; + delta -= *jiffy_stamp; + } else { + delta = get_tbl() - *jiffy_stamp; + } + return delta; +} /* * timer_interrupt - gets called when the decrementer overflows, @@ -69,88 +104,56 @@ unsigned long last_tb; */ int timer_interrupt(struct pt_regs * regs) { - int dval, d; -#if 0 - unsigned long flags; -#endif + int next_dec; unsigned long cpu = smp_processor_id(); - + unsigned jiffy_stamp = last_jiffy_stamp(cpu); + hardirq_enter(cpu); -#ifdef CONFIG_SMP - { - unsigned int loops = 100000000; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* CONFIG_SMP */ - dval = get_dec(); - /* - * Wait for the decrementer to change, then jump - * in and add decrementer_count to its value - * (quickly, before it changes again!) - */ - while ((d = get_dec()) == dval) - ; - asm volatile("mftb %0" : "=r" (last_tb) ); - /* - * Don't play catchup between the call to time_init() - * and sti() in init/main.c. - * - * This also means if we're delayed for > HZ - * we lose those ticks. If we're delayed for > HZ - * then we have something wrong anyway, though. - * - * -- Cort - */ - if ( d < (-1*decrementer_count) ) - d = 0; - set_dec(d + decrementer_count); - if ( !smp_processor_id() ) - { + do { + jiffy_stamp += tb_ticks_per_jiffy; + if (smp_processor_id()) continue; + /* We are in an interrupt, no need to save/restore flags */ + write_lock(&xtime_lock); + tb_last_stamp = jiffy_stamp; do_timer(regs); -#if 0 - /* -- BenH -- I'm removing this for now since it can cause various - * troubles with local-time RTCs. Now that we have a - * /dev/rtc that uses ppc_md.set_rtc_time() on mac, it - * should be possible to program the RTC from userland - * in all cases. - */ + /* - * update the rtc when needed + * update the rtc when needed, this should be performed on the + * right fraction of a second. Half or full second ? + * Full second works on mk48t59 clocks, others need testing. + * Note that this update is basically only used through + * the adjtimex system calls. Setting the HW clock in + * any other way is a /dev/rtc and userland business. + * This is still wrong by -0.5/+1.5 jiffies because of the + * timer interrupt resolution and possible delay, but here we + * hit a quantization limit which can only be solved by higher + * resolution timers and decoupling time management from timer + * interrupts. This is also wrong on the clocks + * which require being written at the half second boundary. + * We should have an rtc call that only sets the minutes and + * seconds like on Intel to avoid problems with non UTC clocks. */ - read_lock_irqsave(&xtime_lock, flags); - if ( (time_status & STA_UNSYNC) && - ((xtime.tv_sec > last_rtc_update + 60) || - (xtime.tv_sec < last_rtc_update)) ) - { - if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; + if ( (time_status & STA_UNSYNC) == 0 && + xtime.tv_sec - last_rtc_update >= 659 && + abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ && + jiffies - wall_jiffies == 1) { + if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0) + last_rtc_update = xtime.tv_sec+1; else - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec; + /* Try again one minute later */ + last_rtc_update += 60; } - read_unlock_irqrestore(&xtime_lock, flags); -#endif - } + write_unlock(&xtime_lock); + } while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0); + set_dec(next_dec); + last_jiffy_stamp(cpu) = jiffy_stamp; + #ifdef CONFIG_SMP smp_local_timer_interrupt(regs); #endif - if ( ppc_md.heartbeat && !ppc_md.heartbeat_count--) + if (ppc_md.heartbeat && !ppc_md.heartbeat_count--) ppc_md.heartbeat(); hardirq_exit(cpu); @@ -162,106 +165,138 @@ int timer_interrupt(struct pt_regs * regs) */ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, diff; + unsigned long flags; + unsigned delta, lost_ticks, usec, sec; - save_flags(flags); - cli(); read_lock_irqsave(&xtime_lock, flags); - *tv = xtime; + sec = xtime.tv_sec; + usec = xtime.tv_usec; + delta = tb_ticks_since(tb_last_stamp); +#ifdef CONFIG_SMP + /* As long as timebases are not in sync, gettimeofday can only + * have jiffy resolution on SMP. + */ + if (_machine != _MACH_Pmac) + delta = 0; +#endif /* CONFIG_SMP */ + lost_ticks = jiffies - wall_jiffies; read_unlock_irqrestore(&xtime_lock, flags); - /* XXX we don't seem to have the decrementers synced properly yet */ -#ifndef CONFIG_SMP - asm volatile("mftb %0" : "=r" (diff) ); - diff -= last_tb; - tv->tv_usec += diff * count_period_num / count_period_den; - tv->tv_sec += tv->tv_usec / 1000000; - tv->tv_usec = tv->tv_usec % 1000000; -#endif - - restore_flags(flags); + + usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta); + while (usec > 1000000) { + sec++; + usec -= 1000000; + } + tv->tv_sec = sec; + tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) { unsigned long flags; - int frac_tick; - - last_rtc_update = 0; /* so the rtc gets updated soon */ - - frac_tick = tv->tv_usec % (1000000 / HZ); - save_flags(flags); - cli(); + int tb_delta, new_usec, new_sec; + write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = tv->tv_sec; - xtime.tv_usec = tv->tv_usec - frac_tick; - write_unlock_irqrestore(&xtime_lock, flags); - set_dec(frac_tick * count_period_den / count_period_num); + /* Updating the RTC is not the job of this code. If the time is + * stepped under NTP, the RTC will be update after STA_UNSYNC + * is cleared. Tool like clock/hwclock either copy the RTC + * to the system time, in which case there is no point in writing + * to the RTC again, or write to the RTC but then they don't call + * settimeofday to perform this operation. Note also that + * we don't touch the decrementer since: + * a) it would lose timer interrupt synchronization on SMP + * (if it is working one day) + * b) it could make one jiffy spuriously shorter or longer + * which would introduce another source of uncertainty potentially + * harmful to relatively short timers. + */ + + /* This works perfectly on SMP only if the tb are in sync but + * guarantees an error < 1 jiffy even if they are off by eons, + * still reasonable when gettimeofday resolution is 1 jiffy. + */ + tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id())); + tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; + new_sec = tv->tv_sec; + new_usec = tv->tv_usec - mulhwu(tb_to_us, tb_delta); + while (new_usec <0) { + new_sec--; + new_usec += 1000000; + } + xtime.tv_usec = new_usec; + xtime.tv_sec = new_sec; + + /* In case of a large backwards jump in time with NTP, we want the + * clock to be updated as soon as the PLL is again in lock. + */ + last_rtc_update = new_sec - 658; + time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - restore_flags(flags); + write_unlock_irqrestore(&xtime_lock, flags); } void __init time_init(void) { + time_t sec, old_sec; + unsigned old_stamp, stamp, elapsed; + /* This function is only called on the boot processor */ unsigned long flags; + if (ppc_md.time_init != NULL) - { - ppc_md.time_init(); - } + time_offset = ppc_md.time_init(); - if ((_get_PVR() >> 16) == 1) { + if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ - decrementer_count = DECREMENTER_COUNT_601; - count_period_num = COUNT_PERIOD_NUM_601; - count_period_den = COUNT_PERIOD_DEN_601; - } else if (!smp_processor_id()) { + tb_ticks_per_jiffy = DECREMENTER_COUNT_601; + /* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */ + tb_to_us = 0x418937; + } else { ppc_md.calibrate_decr(); } + /* Now that the decrementer is calibrated, it can be used in case the + * clock is stuck, but the fact that we have to handle the 601 + * makes things more complex. Repeatedly read the RTC until the + * next second boundary to try to achieve some precision... + */ + stamp = get_native_tbl(); + sec = ppc_md.get_rtc_time(); + elapsed = 0; + do { + old_stamp = stamp; + old_sec = sec; + stamp = get_native_tbl(); + if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000; + elapsed += stamp - old_stamp; + sec = ppc_md.get_rtc_time(); + } while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy); + if (sec==old_sec) { + printk("Warning: real time clock seems stuck!\n"); + } write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = ppc_md.get_rtc_time(); + xtime.tv_sec = sec; + last_jiffy_stamp(0) = tb_last_stamp = stamp; xtime.tv_usec = 0; + /* No update now, we just read the time from the RTC ! */ + last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); + /* Not exact, but the timer interrupt takes care of this */ + set_dec(tb_ticks_per_jiffy); - set_dec(decrementer_count); - /* allow setting the time right away */ - last_rtc_update = 0; -} - -/* 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 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ + /* If platform provided a timezone (pmac), we correct the time + * using do_sys_settimeofday() which in turn calls warp_clock() + */ + if (time_offset) { + struct timezone tz; + tz.tz_minuteswest = -time_offset / 60; + tz.tz_dsttime = 0; + do_sys_settimeofday(NULL, &tz); + } } #define TICK_SIZE tick @@ -354,3 +389,31 @@ void to_tm(int tim, struct rtc_time * tm) */ GregorianDay(tm); } + +/* Auxiliary function to compute scaling factors */ +/* Actually the choice of a timebase running at 1/4 the of the bus + * frequency giving resolution of a few tens of nanoseconds is quite nice. + * It makes this computation very precise (27-28 bits typically) which + * is optimistic considering the stability of most processor clock + * oscillators and the precision with which the timebase frequency + * is measured but does not harm. + */ +unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { + unsigned mlt=0, tmp, err; + /* No concern for performance, it's done once: use a stupid + * but safe and compact method to find the multiplier. + */ + for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { + if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; + } + /* We might still be off by 1 for the best approximation. + * A side effect of this is that if outscale is too large + * the returned value will be zero. + * Many corner cases have been checked and seem to work, + * some might have been forgotten in the test however. + */ + err = inscale*(mlt+1); + if (err <= inscale/2) mlt++; + return mlt; +} + diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 0701f7118..3b7473dda 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -87,45 +87,76 @@ _exception(int signr, struct pt_regs *regs) void MachineCheckException(struct pt_regs *regs) { - if ( !user_mode(regs) ) - { -#if defined(CONFIG_8xx) && defined(CONFIG_PCI) - /* the qspan pci read routines can cause machine checks -- Cort */ - bad_page_fault(regs, regs->dar); +#ifdef CONFIG_ALL_PPC + unsigned long fixup; +#endif /* CONFIG_ALL_PPC */ + + if (user_mode(regs)) { + _exception(SIGSEGV, regs); return; + } + +#if defined(CONFIG_8xx) && defined(CONFIG_PCI) + /* the qspan pci read routines can cause machine checks -- Cort */ + bad_page_fault(regs, regs->dar); + return; #endif #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - if (debugger_fault_handler) { - debugger_fault_handler(regs); - return; - } + if (debugger_fault_handler) { + debugger_fault_handler(regs); + return; + } #endif - printk("Machine check in kernel mode.\n"); - printk("Caused by (from SRR1=%lx): ", regs->msr); - switch (regs->msr & 0xF0000) { - case 0x80000: - printk("Machine check signal\n"); - break; - case 0x40000: - printk("Transfer error ack signal\n"); - break; - case 0x20000: - printk("Data parity error signal\n"); - break; - case 0x10000: - printk("Address parity error signal\n"); - break; - default: - printk("Unknown values in msr\n"); + +#ifdef CONFIG_ALL_PPC + /* + * I/O accesses can cause machine checks on powermacs. + * Check if the NIP corresponds to the address of a sync + * instruction for which there is an entry in the exception + * table. + */ + if (regs->msr & (0x80000 | 0x40000) + && (fixup = search_exception_table(regs->nip)) != 0) { + /* + * Check that it's a sync instruction. + * As the address is in the exception table + * we should be able to read the instr there. + */ + if (*(unsigned int *)regs->nip == 0x7c0004ac) { + unsigned int lsi = ((unsigned int *)regs->nip)[-1]; + int rb = (lsi >> 11) & 0x1f; + printk(KERN_DEBUG "%s bad port %lx at %lx\n", + (lsi & 0x100)? "OUT to": "IN from", + regs->gpr[rb] - _IO_BASE, regs->nip); + regs->nip = fixup; + return; } - show_regs(regs); + } +#endif /* CONFIG_ALL_PPC */ + printk("Machine check in kernel mode.\n"); + printk("Caused by (from SRR1=%lx): ", regs->msr); + switch (regs->msr & 0xF0000) { + case 0x80000: + printk("Machine check signal\n"); + break; + case 0x40000: + printk("Transfer error ack signal\n"); + break; + case 0x20000: + printk("Data parity error signal\n"); + break; + case 0x10000: + printk("Address parity error signal\n"); + break; + default: + printk("Unknown values in msr\n"); + } + show_regs(regs); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - debugger(regs); + debugger(regs); #endif - print_backtrace((unsigned long *)regs->gpr[1]); - panic("machine check"); - } - _exception(SIGSEGV, regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); } void @@ -166,6 +197,46 @@ RunModeException(struct pt_regs *regs) _exception(SIGTRAP, regs); } +/* Illegal instruction emulation support. Originally written to + * provide the PVR to user applications using the mfspr rd, PVR. + * Return non-zero if we can't emulate, or EFAULT if the associated + * memory access caused an access fault. Return zero on success. + * + * There are a couple of ways to do this, either "decode" the instruction + * or directly match lots of bits. In this case, matching lots of + * bits is faster and easier. + * + */ +#define INST_MFSPR_PVR 0x7c1f42a6 +#define INST_MFSPR_PVR_MASK 0xfc1fffff + +static int +emulate_instruction(struct pt_regs *regs) +{ + uint instword; + uint rd; + uint retval; + + retval = EFAULT; + + if (!user_mode(regs)) + return retval; + + if (get_user(instword, (uint *)(regs->nip))) + return retval; + + /* Emulate the mfspr rD, PVR. + */ + if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = _get_PVR(); + retval = 0; + } + if (retval == 0) + regs->nip += 4; + return(retval); +} + void ProgramCheckException(struct pt_regs *regs) { @@ -193,7 +264,14 @@ ProgramCheckException(struct pt_regs *regs) #endif _exception(SIGTRAP, regs); } else { - _exception(SIGILL, regs); + /* Try to emulate it if we should. */ + int errcode; + if ((errcode = emulate_instruction(regs))) { + if (errcode == EFAULT) + _exception(SIGBUS, regs); + else + _exception(SIGILL, regs); + } } #endif } diff --git a/arch/ppc/kernel/walnut_setup.c b/arch/ppc/kernel/walnut_setup.c index 768c36a94..e48a3e61a 100644 --- a/arch/ppc/kernel/walnut_setup.c +++ b/arch/ppc/kernel/walnut_setup.c @@ -226,10 +226,11 @@ walnut_halt(void) /* * Document me. */ -void __init +long __init walnut_time_init(void) { /* XXX - Implement me */ + return 0; } /* diff --git a/arch/ppc/kernel/xics.c b/arch/ppc/kernel/xics.c index a9772821b..2b277f952 100644 --- a/arch/ppc/kernel/xics.c +++ b/arch/ppc/kernel/xics.c @@ -166,7 +166,7 @@ xics_get_irq(struct pt_regs *regs) void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) { qirr_info(smp_processor_id()) = 0xff; - smp_message_recv(MSG_RESCHEDULE); + smp_message_recv(MSG_RESCHEDULE, regs); } void xics_cause_IPI(int cpu) diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 1c4f1f78e..a922b4361 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -9,13 +9,74 @@ * 2 of the License, or (at your option) any later version. */ #include "../kernel/ppc_asm.tmpl" +#include <linux/config.h> #include <asm/processor.h> #include <asm/errno.h> -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 +#if defined(CONFIG_4xx) || defined(CONFIG_8xx) +#define CACHE_LINE_SIZE 16 +#define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 +#elif !defined(CONFIG_PPC64BRIDGE) +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 +#else +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 +#endif /* CONFIG_4xx || CONFIG_8xx */ + +#define COPY_16_BYTES \ + lwz r7,4(r4); \ + lwz r8,8(r4); \ + lwz r9,12(r4); \ + lwzu r10,16(r4); \ + stw r7,4(r6); \ + stw r8,8(r6); \ + stw r9,12(r6); \ + stwu r10,16(r6) + +#define COPY_16_BYTES_WITHEX(n) \ +8 ## n ## 0: \ + lwz r7,4(r4); \ +8 ## n ## 1: \ + lwz r8,8(r4); \ +8 ## n ## 2: \ + lwz r9,12(r4); \ +8 ## n ## 3: \ + lwzu r10,16(r4); \ +8 ## n ## 4: \ + stw r7,4(r6); \ +8 ## n ## 5: \ + stw r8,8(r6); \ +8 ## n ## 6: \ + stw r9,12(r6); \ +8 ## n ## 7: \ + stwu r10,16(r6) + +#define COPY_16_BYTES_EXCODE(n) \ +9 ## n ## 0: \ + addi r5,r5,-(16 * n); \ + b 104f; \ +9 ## n ## 1: \ + addi r5,r5,-(16 * n); \ + b 105f; \ +.section __ex_table,"a"; \ + .align 2; \ + .long 8 ## n ## 0b,9 ## n ## 0b; \ + .long 8 ## n ## 1b,9 ## n ## 0b; \ + .long 8 ## n ## 2b,9 ## n ## 0b; \ + .long 8 ## n ## 3b,9 ## n ## 0b; \ + .long 8 ## n ## 4b,9 ## n ## 1b; \ + .long 8 ## n ## 5b,9 ## n ## 1b; \ + .long 8 ## n ## 6b,9 ## n ## 1b; \ + .long 8 ## n ## 7b,9 ## n ## 1b; \ +.text + +CACHELINE_BYTES = CACHE_LINE_SIZE +LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE +CACHELINE_MASK = (CACHE_LINE_SIZE-1) .globl strcpy strcpy: @@ -105,7 +166,14 @@ cacheable_memzero: bdnz 4b 3: mtctr r9 li r7,4 +#if !defined(CONFIG_8xx) 10: dcbz r7,r6 +#else +10: stw r4, 4(r6) + stw r4, 8(r6) + stw r4, 12(r6) + stw r4, 16(r6) +#endif addi r6,r6,CACHELINE_BYTES bdnz 10b clrlwi r5,r8,32-LG_CACHELINE_BYTES @@ -202,23 +270,24 @@ cacheable_memcpy: li r11,4 mtctr r0 beq 63f -53: dcbz r11,r6 - lwz r7,4(r4) - lwz r8,8(r4) - lwz r9,12(r4) - lwzu r10,16(r4) - stw r7,4(r6) - stw r8,8(r6) - stw r9,12(r6) - stwu r10,16(r6) - lwz r7,4(r4) - lwz r8,8(r4) - lwz r9,12(r4) - lwzu r10,16(r4) - stw r7,4(r6) - stw r8,8(r6) - stw r9,12(r6) - stwu r10,16(r6) +53: +#if !defined(CONFIG_8xx) + dcbz r11,r6 +#endif + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif bdnz 53b 63: srwi. r0,r5,2 @@ -380,25 +449,59 @@ __copy_tofrom_user: 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ clrlwi r5,r5,32-LG_CACHELINE_BYTES li r11,4 - mtctr r0 beq 63f -53: dcbz r11,r6 -10: lwz r7,4(r4) -11: lwz r8,8(r4) -12: lwz r9,12(r4) -13: lwzu r10,16(r4) -14: stw r7,4(r6) -15: stw r8,8(r6) -16: stw r9,12(r6) -17: stwu r10,16(r6) -20: lwz r7,4(r4) -21: lwz r8,8(r4) -22: lwz r9,12(r4) -23: lwzu r10,16(r4) -24: stw r7,4(r6) -25: stw r8,8(r6) -26: stw r9,12(r6) -27: stwu r10,16(r6) + +#if !defined(CONFIG_8xx) + /* Here we decide how far ahead to prefetch the source */ +#if MAX_COPY_PREFETCH > 1 + /* Heuristically, for large transfers we prefetch + MAX_COPY_PREFETCH cachelines ahead. For small transfers + we prefetch 1 cacheline ahead. */ + cmpwi r0,MAX_COPY_PREFETCH + li r7,1 + li r3,4 + ble 111f + li r7,MAX_COPY_PREFETCH +111: mtctr r7 +112: dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES + bdnz 112b +#else /* MAX_COPY_PREFETCH == 1 */ + li r3,CACHELINE_BYTES + 4 + dcbt r11,r4 +#endif /* MAX_COPY_PREFETCH */ +#endif /* CONFIG_8xx */ + + mtctr r0 +53: +#if !defined(CONFIG_8xx) + dcbt r3,r4 + dcbz r11,r6 +#endif +/* had to move these to keep extable in order */ + .section __ex_table,"a" + .align 2 + .long 70b,100f + .long 71b,101f + .long 72b,102f + .long 73b,103f + .long 53b,105f + .text +/* the main body of the cacheline loop */ + COPY_16_BYTES_WITHEX(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_WITHEX(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_WITHEX(2) + COPY_16_BYTES_WITHEX(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_WITHEX(4) + COPY_16_BYTES_WITHEX(5) + COPY_16_BYTES_WITHEX(6) + COPY_16_BYTES_WITHEX(7) +#endif +#endif +#endif bdnz 53b 63: srwi. r0,r5,2 @@ -434,15 +537,31 @@ __copy_tofrom_user: 103: li r4,1 91: li r3,2 b 99f -/* read fault in 2nd half of cacheline loop */ -106: addi r5,r5,-16 -/* read fault in 1st half of cacheline loop */ + +/* + * this stuff handles faults in the cacheline loop and branches to either + * 104f (if in read part) or 105f (if in write part), after updating r5 + */ + COPY_16_BYTES_EXCODE(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_EXCODE(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_EXCODE(2) + COPY_16_BYTES_EXCODE(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_EXCODE(4) + COPY_16_BYTES_EXCODE(5) + COPY_16_BYTES_EXCODE(6) + COPY_16_BYTES_EXCODE(7) +#endif +#endif +#endif + +/* read fault in cacheline loop */ 104: li r4,0 b 92f -/* write fault in 2nd half of cacheline loop */ -107: addi r5,r5,-16 /* fault on dcbz (effectively a write fault) */ -/* or write fault in 1st half of cacheline loop */ +/* or write fault in cacheline loop */ 105: li r4,1 92: li r3,LG_CACHELINE_BYTES b 99f @@ -485,36 +604,15 @@ __copy_tofrom_user: bdnz 114b 120: blr -.section __ex_table,"a" + .section __ex_table,"a" .align 2 - .long 70b,100b - .long 71b,101b - .long 72b,102b - .long 73b,103b - .long 53b,105b - .long 10b,104b - .long 11b,104b - .long 12b,104b - .long 13b,104b - .long 14b,105b - .long 15b,105b - .long 16b,105b - .long 17b,105b - .long 20b,106b - .long 21b,106b - .long 22b,106b - .long 23b,106b - .long 24b,107b - .long 25b,107b - .long 26b,107b - .long 27b,107b .long 30b,108b .long 31b,109b .long 40b,110b .long 41b,111b .long 112b,120b .long 114b,120b -.text + .text .globl __clear_user __clear_user: @@ -546,12 +644,13 @@ __clear_user: blr 99: li r3,-EFAULT blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 11b,99b .long 1b,99b .long 8b,99b -.text + .text .globl __strncpy_from_user __strncpy_from_user: @@ -570,10 +669,11 @@ __strncpy_from_user: blr 99: li r3,-EFAULT blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 1b,99b -.text + .text /* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ .globl __strnlen_user @@ -596,6 +696,7 @@ __strnlen_user: blr 99: li r3,0 /* bad address, return 0 */ blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 1b,99b diff --git a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c index 60563122d..ac400b8c6 100644 --- a/arch/ppc/mbxboot/misc.c +++ b/arch/ppc/mbxboot/misc.c @@ -269,6 +269,11 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, b */ #ifdef CONFIG_MBX cmd_line = (char *)(load_addr - 0x10000); + + /* To be like everyone else, we need one too, although this + * board information is passed from the boot rom. + */ + bp->bi_baudrate = 9600; #else cmd_line = (char *)(0x200000); #endif diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c index dc57bf868..f43bfaff4 100644 --- a/arch/ppc/mm/extable.c +++ b/arch/ppc/mm/extable.c @@ -4,11 +4,47 @@ * from linux/arch/i386/mm/extable.c */ +#include <linux/config.h> #include <linux/module.h> #include <asm/uaccess.h> -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of segments + * such as the prep, pmac, chrp, etc. segments as well as the init + * segment and the main kernel text segment. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void +sort_exception_table(void) +{ + sort_ex_table(__start___ex_table, __stop___ex_table); +} static inline unsigned long search_one_table(const struct exception_table_entry *first, @@ -36,25 +72,21 @@ search_exception_table(unsigned long addr) { unsigned long ret; -#if 1 /*ndef CONFIG_MODULES*/ +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); if (ret) return ret; #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; - read_lock(&modlist_lock); for (mp = module_list; mp != NULL; mp = mp->next) { if (mp->ex_table_start == NULL) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); - if (ret) { - read_unlock(&modlist_lock); + if (ret) return ret; - } } - read_unlock(&modlist_lock); #endif return 0; diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 0b551c803..b6da2cdfc 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -67,7 +67,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, #if defined(CONFIG_4xx) int is_write = error_code & ESR_DST; #else - int is_write = error_code & 0x02000000; + int is_write = 0; /* * Fortunately the bit assignments in SRR1 for an instruction @@ -77,6 +77,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, */ if (regs->trap == 0x400) error_code &= 0x48200000; + else + is_write = error_code & 0x02000000; #endif /* CONFIG_4xx */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 67257c50b..be7d1f063 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -36,6 +36,7 @@ #include <linux/delay.h> #include <linux/openpic.h> #include <linux/bootmem.h> +#include <linux/highmem.h> #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> /* for initrd_* */ #endif @@ -69,15 +70,20 @@ #include "4xx_tlb.h" #endif +#define MAX_LOW_MEM (640 << 20) + #define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) int prom_trashed; atomic_t next_mmu_context; unsigned long *end_of_DRAM; +unsigned long total_memory; +unsigned long total_lowmem; int mem_init_done; int init_bootmem_done; int boot_mapsize; unsigned long totalram_pages = 0; +unsigned long totalhigh_pages = 0; extern pgd_t swapper_pg_dir[]; extern char _start[], _end[]; extern char etext[], _stext[]; @@ -98,22 +104,26 @@ extern unsigned int rtas_data, rtas_size; #ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif +#ifdef CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; +#endif void MMU_init(void); static void *MMU_get_page(void); -unsigned long *prep_find_end_of_memory(void); -unsigned long *pmac_find_end_of_memory(void); -unsigned long *apus_find_end_of_memory(void); -unsigned long *gemini_find_end_of_memory(void); -extern unsigned long *find_end_of_memory(void); +unsigned long prep_find_end_of_memory(void); +unsigned long pmac_find_end_of_memory(void); +unsigned long apus_find_end_of_memory(void); +unsigned long gemini_find_end_of_memory(void); +extern unsigned long find_end_of_memory(void); #ifdef CONFIG_8xx -unsigned long *m8xx_find_end_of_memory(void); +unsigned long m8xx_find_end_of_memory(void); #endif /* CONFIG_8xx */ #ifdef CONFIG_4xx -unsigned long *oak_find_end_of_memory(void); +unsigned long oak_find_end_of_memory(void); #endif #ifdef CONFIG_8260 -unsigned long *m8260_find_end_of_memory(void); +unsigned long m8260_find_end_of_memory(void); #endif /* CONFIG_8260 */ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); @@ -269,6 +279,7 @@ void show_mem(void) int i,free = 0,total = 0,reserved = 0; int shared = 0, cached = 0; struct task_struct *p; + int highmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -276,6 +287,8 @@ void show_mem(void) i = max_mapnr; while (i-- > 0) { total++; + if (PageHighMem(mem_map+i)) + highmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -286,6 +299,7 @@ void show_mem(void) shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); + printk("%d pages of HIGHMEM\n", highmem); printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); @@ -354,6 +368,8 @@ void si_meminfo(struct sysinfo *val) continue; val->sharedram += atomic_read(&mem_map[i].count) - 1; } + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; } @@ -443,7 +459,8 @@ out: void iounmap(void *addr) { - /* XXX todo */ + if (addr > high_memory && (unsigned long) addr < ioremap_bot) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); } unsigned long iopa(unsigned long addr) @@ -476,7 +493,7 @@ map_page(unsigned long va, unsigned long pa, int flags) { pmd_t *pd, oldpd; pte_t *pg; - + /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); oldpd = *pd; @@ -516,6 +533,7 @@ local_flush_tlb_all(void) flush_hash_segments(0xd, 0xffffff); #else __clear_user(Hash, Hash_size); + _tlbia(); #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif /* CONFIG_SMP */ @@ -610,6 +628,13 @@ mmu_context_overflow(void) } #endif /* CONFIG_8xx */ +void flush_page_to_ram(struct page *page) +{ + unsigned long vaddr = kmap(page); + __flush_page_to_ram(vaddr); + kunmap(page); +} + #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); @@ -722,7 +747,7 @@ static void __init mapin_ram(void) if (align && align < max_size) max_size = align; - tot = (unsigned long)end_of_DRAM - KERNELBASE; + tot = total_lowmem; for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > tot) break; @@ -745,6 +770,8 @@ static void __init mapin_ram(void) for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); p = phys_mem.regions[i].address; + if (p >= total_lowmem) + break; 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. @@ -766,6 +793,8 @@ static void __init mapin_ram(void) map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; + if (p >= total_lowmem) + break; } } } @@ -788,77 +817,42 @@ static void __init *MMU_get_page(void) return p; } -void __init free_initmem(void) +static void free_sec(unsigned long start, unsigned long end, const char *name) { - unsigned long a; - unsigned long num_freed_pages = 0, num_prep_pages = 0, - num_pmac_pages = 0, num_openfirmware_pages = 0, - num_apus_pages = 0, num_chrp_pages = 0; -#define FREESEC(START,END,CNT) do { \ - a = (unsigned long)(&START); \ - for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ - clear_bit(PG_reserved, &virt_to_page(a)->flags); \ - set_page_count(virt_to_page(a), 1); \ - free_page(a); \ - CNT++; \ - } \ -} while (0) - - FREESEC(__init_begin,__init_end,num_freed_pages); - switch (_machine) - { - case _MACH_Pmac: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_chrp: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - break; - case _MACH_prep: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_mbx: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_apus: - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_gemini: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - } + unsigned long cnt = 0; - if ( !have_of ) - FREESEC( __openfirmware_begin, __openfirmware_end, - num_openfirmware_pages ); - - printk ("Freeing unused kernel memory: %ldk init", - PGTOKB(num_freed_pages)); - - if ( num_prep_pages ) - printk(" %ldk prep", PGTOKB(num_prep_pages)); - if ( num_chrp_pages ) - printk(" %ldk chrp", PGTOKB(num_chrp_pages)); - if ( num_pmac_pages ) - printk(" %ldk pmac", PGTOKB(num_pmac_pages)); - if ( num_openfirmware_pages ) - printk(" %ldk open firmware", PGTOKB(num_openfirmware_pages)); - if ( num_apus_pages ) - printk(" %ldk apus", PGTOKB(num_apus_pages)); - printk("\n"); + while (start < end) { + clear_bit(PG_reserved, &virt_to_page(start)->flags); + set_page_count(virt_to_page(start), 1); + free_page(start); + cnt++; + start += PAGE_SIZE; + } + if (cnt) + printk(" %ldk %s", PGTOKB(cnt), name); +} + +void free_initmem(void) +{ +#define FREESEC(TYPE) \ + free_sec((unsigned long)(&__ ## TYPE ## _begin), \ + (unsigned long)(&__ ## TYPE ## _end), \ + #TYPE); + + printk ("Freeing unused kernel memory:"); + FREESEC(init); + if (_machine != _MACH_Pmac) + FREESEC(pmac); + if (_machine != _MACH_chrp) + FREESEC(chrp); + if (_machine != _MACH_prep) + FREESEC(prep); + if (_machine != _MACH_apus) + FREESEC(apus); + if (!have_of) + FREESEC(openfirmware); + printk("\n"); +#undef FREESEC } #ifdef CONFIG_BLK_DEV_INITRD @@ -909,7 +903,8 @@ MMU_init(void) * at KERNELBASE. */ - end_of_DRAM = oak_find_end_of_memory(); + total_memory = total_lowmem = oak_find_end_of_memory(); + end_of_DRAM = __va(total_memory); mapin_ram(); /* @@ -939,23 +934,33 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); #ifndef CONFIG_8xx if (have_of) - end_of_DRAM = pmac_find_end_of_memory(); + total_memory = pmac_find_end_of_memory(); #ifdef CONFIG_APUS else if (_machine == _MACH_apus ) - end_of_DRAM = apus_find_end_of_memory(); + total_memory = apus_find_end_of_memory(); #endif #ifdef CONFIG_GEMINI else if ( _machine == _MACH_gemini ) - end_of_DRAM = gemini_find_end_of_memory(); + total_memory = gemini_find_end_of_memory(); #endif /* CONFIG_GEMINI */ #if defined(CONFIG_8260) else - end_of_DRAM = m8260_find_end_of_memory(); + total_memory = m8260_find_end_of_memory(); #else else /* prep */ - end_of_DRAM = prep_find_end_of_memory(); + total_memory = prep_find_end_of_memory(); #endif + total_lowmem = total_memory; +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); + if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifndef CONFIG_PPC64BRIDGE @@ -995,7 +1000,7 @@ void __init MMU_init(void) #endif break; case _MACH_Pmac: - ioremap_base = 0xf8000000; + ioremap_base = 0xfe000000; break; case _MACH_apus: /* Map PPC exception vectors. */ @@ -1022,7 +1027,15 @@ void __init MMU_init(void) #endif /* CONFIG_POWER4 */ #else /* CONFIG_8xx */ - end_of_DRAM = m8xx_find_end_of_memory(); + total_memory = total_lowmem = m8xx_find_end_of_memory(); +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); @@ -1055,7 +1068,7 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT /* Must be done last, or ppc_md.progress will die */ - if (_machine == _MACH_Pmac) + if (_machine == _MACH_Pmac || _machine == _MACH_chrp) map_bootx_text(); #endif } @@ -1092,7 +1105,7 @@ void __init do_init_bootmem(void) start = PAGE_ALIGN(start); boot_mapsize = init_bootmem(start >> PAGE_SHIFT, - __pa(end_of_DRAM) >> PAGE_SHIFT); + total_lowmem >> PAGE_SHIFT); /* remove the bootmem bitmap from the available memory */ mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); @@ -1105,47 +1118,6 @@ void __init do_init_bootmem(void) init_bootmem_done = 1; } -#if 0 -/* - * Find some memory for setup_arch to return. - * We use the largest chunk of available memory as the area - * that setup_arch returns, making sure that there are at - * least 32 pages unused before this for MMU_get_page to use. - */ -unsigned long __init find_available_memory(void) -{ - int i, rn; - unsigned long a, free; - unsigned long start, end; - - 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; - } - - rn = 0; - for (i = 1; i < phys_avail.n_regions; ++i) - if (phys_avail.regions[i].size > phys_avail.regions[rn].size) - rn = i; - free = 0; - for (i = 0; i < rn; ++i) { - start = phys_avail.regions[i].address; - end = start + phys_avail.regions[i].size; - free += (end & PAGE_MASK) - PAGE_ALIGN(start); - } - a = PAGE_ALIGN(phys_avail.regions[rn].address); - if (free < 32 * PAGE_SIZE) - a += 32 * PAGE_SIZE - free; - avail_start = (unsigned long) __va(a); - return avail_start; -} -#endif /* 0 */ - /* * paging_init() sets up the page tables - in fact we've already done this. */ @@ -1153,6 +1125,14 @@ void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], i; +#ifdef CONFIG_HIGHMEM + map_page(PKMAP_BASE, 0, 0); /* XXX gross */ + pkmap_page_table = pte_offset(pmd_offset(pgd_offset_k(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ + kmap_pte = pte_offset(pmd_offset(pgd_offset_k(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_prot = PAGE_KERNEL; +#endif /* CONFIG_HIGHMEM */ + /* * Grab some memory for bad_page and bad_pagetable to use. */ @@ -1162,9 +1142,14 @@ void __init paging_init(void) /* * All pages are DMA-able so we put them all in the DMA zone. */ - zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT; + zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; for (i = 1; i < MAX_NR_ZONES; i++) zones_size[i] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + free_area_init(zones_size); } @@ -1176,7 +1161,17 @@ void __init mem_init(void) int codepages = 0; int datapages = 0; int initpages = 0; +#ifdef CONFIG_HIGHMEM + unsigned long highmem_mapnr; + + highmem_mapnr = total_lowmem >> PAGE_SHIFT; + highmem_start_page = mem_map + highmem_mapnr; + max_mapnr = total_memory >> PAGE_SHIFT; + totalram_pages += max_mapnr - highmem_mapnr; +#else max_mapnr = max_low_pfn; +#endif /* CONFIG_HIGHMEM */ + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1217,11 +1212,28 @@ void __init mem_init(void) datapages++; } - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", +#ifdef CONFIG_HIGHMEM + { + unsigned long pfn; + + for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { + struct page *page = mem_map + pfn; + + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; + } +#endif /* CONFIG_HIGHMEM */ + + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n", (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long) end_of_DRAM); + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); mem_init_done = 1; } @@ -1234,7 +1246,7 @@ void __init mem_init(void) * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ -unsigned long __init *pmac_find_end_of_memory(void) +unsigned long __init pmac_find_end_of_memory(void) { unsigned long a, total; unsigned long ram_limit = 0xe0000000 - KERNELBASE; @@ -1279,7 +1291,7 @@ unsigned long __init *pmac_find_end_of_memory(void) set_phys_avail(&phys_mem); - return __va(total); + return total; } #endif /* CONFIG_ALL_PPC */ @@ -1290,7 +1302,7 @@ unsigned long __init *pmac_find_end_of_memory(void) * this will likely stay separate from the pmac. * -- Cort */ -unsigned long __init *prep_find_end_of_memory(void) +unsigned long __init prep_find_end_of_memory(void) { unsigned long total; total = res->TotalMemory; @@ -1308,15 +1320,15 @@ unsigned long __init *prep_find_end_of_memory(void) mem_pieces_append(&phys_mem, 0, total); set_phys_avail(&phys_mem); - return (__va(total)); + return (total); } #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_GEMINI) -unsigned long __init *gemini_find_end_of_memory(void) +unsigned long __init gemini_find_end_of_memory(void) { - unsigned long total, *ret; + unsigned long total; unsigned char reg; reg = readb(GEMINI_MEMCFG); @@ -1327,9 +1339,8 @@ unsigned long __init *gemini_find_end_of_memory(void) phys_mem.regions[0].size = total; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* defined(CONFIG_GEMINI) */ @@ -1337,10 +1348,9 @@ unsigned long __init *gemini_find_end_of_memory(void) /* * Same hack as 8xx. */ -unsigned long __init *m8260_find_end_of_memory(void) +unsigned long __init m8260_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1349,15 +1359,14 @@ unsigned long __init *m8260_find_end_of_memory(void) phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* CONFIG_8260 */ #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init *apus_find_end_of_memory(void) +unsigned long __init apus_find_end_of_memory(void) { int shadow = 0; @@ -1421,7 +1430,7 @@ unsigned long __init *apus_find_end_of_memory(void) the PowerUP board. Other system memory is horrible slow in comparison. The user can use other memory for swapping using the z2ram device. */ - return __va(memory[0].addr + memory[0].size); + return memory[0].addr + memory[0].size; } #endif /* CONFIG_APUS */ @@ -1484,7 +1493,7 @@ static void __init hash_init(void) /* Find some memory for the hash table. */ if ( Hash_size ) { Hash = mem_pieces_find(Hash_size, Hash_size); - /*__clear_user(Hash, Hash_size);*/ + cacheable_memzero(Hash, Hash_size); } else Hash = 0; #endif /* CONFIG_PPC64BRIDGE */ @@ -1544,10 +1553,9 @@ static void __init hash_init(void) * functions in the image just to get prom_init, all we really need right * now is the initialization of the physical memory region. */ -unsigned long __init *m8xx_find_end_of_memory(void) +unsigned long __init m8xx_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1555,12 +1563,9 @@ unsigned long __init *m8xx_find_end_of_memory(void) phys_mem.regions[0].address = 0; phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address+ - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].address + phys_mem.regions[0].size; } #endif /* !CONFIG_4xx && !CONFIG_8xx */ @@ -1569,7 +1574,7 @@ unsigned long __init *m8xx_find_end_of_memory(void) * Return the virtual address representing the top of physical RAM * on the Oak board. */ -unsigned long __init * +unsigned long __init oak_find_end_of_memory(void) { extern unsigned char __res[]; @@ -1580,12 +1585,9 @@ oak_find_end_of_memory(void) phys_mem.regions[0].address = 0; phys_mem.regions[0].size = bip->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address + - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return (ret); + return (phys_mem.regions[0].address + phys_mem.regions[0].size); } #endif diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index a816f0b9d..499c5b6c8 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -8,6 +8,7 @@ #include <asm/page.h> #include <linux/adb.h> #include <linux/pmu.h> +#include <linux/cuda.h> #include <linux/kernel.h> #include <asm/prom.h> #include <asm/bootx.h> @@ -67,6 +68,12 @@ xmon_map_scc(void) use_screen = 1; } #endif +#ifdef CONFIG_ADB_CUDA + if (!via_modem && disp_bi ) { + prom_drawstring("xmon uses screen and keyboard\n"); + use_screen = 1; + } +#endif #endif #ifdef CHRP_ESCC @@ -100,6 +107,10 @@ xmon_map_scc(void) /* should already be mapped by the kernel boot */ sccc = (volatile unsigned char *) (isa_io_base + 0x3fd); sccd = (volatile unsigned char *) (isa_io_base + 0x3f8); + if (xmon_use_sccb) { + sccc -= 0x100; + sccd -= 0x100; + } TXRDY = 0x20; RXRDY = 1; } @@ -109,6 +120,19 @@ static int scc_initialized = 0; void xmon_init_scc(void); extern void pmu_poll(void); +extern void cuda_poll(void); + +static inline void do_poll_adb(void) +{ +#ifdef CONFIG_ADB_PMU + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll(); +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB_CUDA + if (sys_ctrler == SYS_CTRLER_CUDA) + cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ +} int xmon_write(void *handle, void *ptr, int nb) @@ -128,12 +152,8 @@ xmon_write(void *handle, void *ptr, int nb) xmon_init_scc(); ct = 0; for (i = 0; i < nb; ++i) { - while ((*sccc & TXRDY) == 0) { -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ - } + while ((*sccc & TXRDY) == 0) + do_poll_adb(); c = p[i]; if (c == '\n' && !ct) { c = '\r'; @@ -189,9 +209,7 @@ xmon_get_adb_key(void) prom_drawchar('\b'); t = 200000; } -#ifdef CONFIG_ADB_PMU - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); } while (xmon_adb_keycode == -1); k = xmon_adb_keycode; if (on) @@ -230,14 +248,9 @@ xmon_read(void *handle, void *ptr, int nb) xmon_init_scc(); for (i = 0; i < nb; ++i) { while ((*sccc & RXRDY) == 0) -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#else - ; -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); buf_access(); - *p++ = *sccd; + *p++ = *sccd; } return i; } @@ -246,10 +259,7 @@ int xmon_read_poll(void) { if ((*sccc & RXRDY) == 0) { -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); return -1; } buf_access(); @@ -491,3 +501,19 @@ xmon_fgets(char *str, int nb, void *f) *p = 0; return str; } + +void +xmon_enter(void) +{ +#ifdef CONFIG_ADB_PMU + pmu_suspend(); +#endif +} + +void +xmon_leave(void) +{ +#ifdef CONFIG_ADB_PMU + pmu_resume(); +#endif +} diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 75160d9b8..49c3be834 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -6,15 +6,23 @@ #include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> +#include <linux/smp.h> #include <asm/ptrace.h> #include <asm/string.h> #include <asm/prom.h> +#include <asm/bitops.h> #include "nonstdio.h" #include "privinst.h" #define scanhex xmon_scanhex #define skipbl xmon_skipbl +#ifdef CONFIG_SMP +static unsigned long cpus_in_xmon = 0; +static unsigned long got_xmon = 0; +static volatile int take_xmon = -1; +#endif /* CONFIG_SMP */ + static unsigned adrs; static int size = 1; static unsigned ndump = 64; @@ -84,6 +92,9 @@ static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); static void bpt_cmds(void); static void cacheflush(void); +#ifdef CONFIG_SMP +static void cpu_cmd(void); +#endif /* CONFIG_SMP */ #if 0 /* Makes compile with -Wall */ static char *pretty_print_addr(unsigned long addr); static char *lookup_name(unsigned long addr); @@ -96,8 +107,18 @@ extern int putchar(int ch); extern int setjmp(u_int *); extern void longjmp(u_int *, int); +extern void xmon_enter(void); +extern void xmon_leave(void); + #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) +#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'f') \ + || ('A' <= (c) && (c) <= 'F')) +#define isalnum(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'z') \ + || ('A' <= (c) && (c) <= 'Z')) + static char *help_string = "\ Commands:\n\ d dump bytes\n\ @@ -117,10 +138,12 @@ Commands:\n\ x exit monitor\n\ "; -static int xmon_trace; +static int xmon_trace[NR_CPUS]; #define SSTEP 1 /* stepping because of 's' command */ #define BRSTEP 2 /* stepping over breakpoint */ +static struct pt_regs *xmon_regs[NR_CPUS]; + void xmon(struct pt_regs *excp) { @@ -143,27 +166,52 @@ xmon(struct pt_regs *excp) msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ - remove_bpts(); + xmon_regs[smp_processor_id()] = excp; + xmon_enter(); excprint(excp); +#ifdef CONFIG_SMP + if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) + for (;;) + ; + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; + } + } + /* + * XXX: breakpoints are removed while any cpu is in xmon + */ +#endif /* CONFIG_SMP */ + remove_bpts(); cmd = cmds(excp); if (cmd == 's') { - xmon_trace = SSTEP; + xmon_trace[smp_processor_id()] = SSTEP; excp->msr |= 0x400; } else if (at_breakpoint(excp->nip)) { - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; excp->msr |= 0x400; } else { - xmon_trace = 0; + xmon_trace[smp_processor_id()] = 0; insert_bpts(); } + xmon_leave(); + xmon_regs[smp_processor_id()] = 0; +#ifdef CONFIG_SMP + clear_bit(0, &got_xmon); + clear_bit(smp_processor_id(), &cpus_in_xmon); +#endif /* CONFIG_SMP */ set_msr(msr); /* restore interrupt enable */ } void xmon_irq(int irq, void *d, struct pt_regs *regs) { + unsigned long flags; + save_flags(flags);cli(); printf("Keyboard interrupt\n"); xmon(regs); + restore_flags(flags); } int @@ -178,7 +226,7 @@ xmon_bpt(struct pt_regs *regs) --bp->count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); @@ -189,10 +237,10 @@ xmon_bpt(struct pt_regs *regs) int xmon_sstep(struct pt_regs *regs) { - if (!xmon_trace) + if (!xmon_trace[smp_processor_id()]) return 0; - if (xmon_trace == BRSTEP) { - xmon_trace = 0; + if (xmon_trace[smp_processor_id()] == BRSTEP) { + xmon_trace[smp_processor_id()] = 0; insert_bpts(); } else { xmon(regs); @@ -207,7 +255,7 @@ xmon_dabr_match(struct pt_regs *regs) --dabr.count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { dabr.instr = regs->nip; @@ -223,7 +271,7 @@ xmon_iabr_match(struct pt_regs *regs) --iabr.count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); @@ -264,6 +312,7 @@ insert_bpts() bp->address); bp->enabled = 0; } + store_inst((void *) bp->address); } #if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) if (dabr.enabled) @@ -293,6 +342,7 @@ remove_bpts() && mwrite(bp->address, &bp->instr, 4) != 4) printf("Couldn't remove breakpoint at %x\n", bp->address); + store_inst((void *) bp->address); } } @@ -306,6 +356,9 @@ cmds(struct pt_regs *excp) last_cmd = NULL; for(;;) { +#ifdef CONFIG_SMP + printf("%d:", smp_processor_id()); +#endif /* CONFIG_SMP */ printf("mon> "); fflush(stdout); flush_input(); @@ -383,12 +436,67 @@ cmds(struct pt_regs *excp) case 'b': bpt_cmds(); break; - case 'c': + case 'C': csum(); break; +#ifdef CONFIG_SMP + case 'c': + cpu_cmd(); + break; +#endif /* CONFIG_SMP */ + } + } +} + +#ifdef CONFIG_SMP +static void cpu_cmd(void) +{ + unsigned cpu; + int timeout; + int cmd; + + cmd = inchar(); + if (cmd == 'i') { + /* interrupt other cpu(s) */ + cpu = MSG_ALL_BUT_SELF; + scanhex(&cpu); + smp_send_xmon_break(cpu); + return; + } + termch = cmd; + if (!scanhex(&cpu)) { + /* print cpus waiting or in xmon */ + printf("cpus stopped:"); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (test_bit(cpu, &cpus_in_xmon)) { + printf(" %d", cpu); + if (cpu == smp_processor_id()) + printf("*", cpu); + } + } + printf("\n"); + return; + } + /* try to switch to cpu specified */ + take_xmon = cpu; + timeout = 10000000; + while (take_xmon >= 0) { + if (--timeout == 0) { + /* yes there's a race here */ + take_xmon = -1; + printf("cpu %u didn't take control\n", cpu); + return; + } + } + /* now have to wait to be given control back */ + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; } } } +#endif /* CONFIG_SMP */ static unsigned short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, @@ -551,6 +659,8 @@ backtrace(struct pt_regs *excp) extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; extern char ret_from_except; + printf("backtrace:\n"); + if (excp != NULL) sp = excp->gpr[1]; else @@ -592,6 +702,9 @@ getsp() void excprint(struct pt_regs *fp) { +#ifdef CONFIG_SMP + printf("cpu %d: ", smp_processor_id()); +#endif /* CONFIG_SMP */ printf("vector: %x at pc = %x", fp->trap, fp->nip); printf(", lr = %x, msr = %x, sp = %x [%x]\n", @@ -1163,9 +1276,6 @@ bsesc() return c; } -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) void dump() { @@ -1402,6 +1512,16 @@ skipbl() return c; } +#define N_PTREGS 44 +static char *regnames[N_PTREGS] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq", + "trap", "dar", "dsisr", "res" +}; + int scanhex(vp) unsigned *vp; @@ -1410,6 +1530,36 @@ unsigned *vp; unsigned v; c = skipbl(); + if (c == '%') { + /* parse register name */ + char regname[8]; + int i; + + for (i = 0; i < sizeof(regname) - 1; ++i) { + c = inchar(); + if (!isalnum(c)) { + termch = c; + break; + } + regname[i] = c; + } + regname[i] = 0; + for (i = 0; i < N_PTREGS; ++i) { + if (strcmp(regnames[i], regname) == 0) { + unsigned *rp = (unsigned *) + xmon_regs[smp_processor_id()]; + if (rp == NULL) { + printf("regs not available\n"); + return 0; + } + *vp = rp[i]; + return 1; + } + } + printf("invalid register name '%%%s'\n", regname); + return 0; + } + d = hexdigit(c); if( d == EOF ){ termch = c; |