From a3c57c1be7587f0d8d2fb6f77fe3746e3f4b5d19 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:27:30 -0500 Subject: [PATCH] Import 2.3.20pre1 --- Documentation/devices.tex | 14 +- Documentation/devices.txt | 8 +- Documentation/kbuild/config-language.txt | 68 +- Documentation/kernel-parameters.txt | 6 +- Documentation/networking/ray_cs.txt | 151 + Documentation/nmi_watchdog.txt | 33 + Documentation/parport.txt | 2 +- MAINTAINERS | 5 + Makefile | 2 +- arch/alpha/kernel/core_apecs.c | 1 - arch/alpha/kernel/core_cia.c | 1 - arch/alpha/kernel/core_lca.c | 1 - arch/alpha/kernel/core_mcpcia.c | 1 - arch/alpha/kernel/core_polaris.c | 1 - arch/alpha/kernel/core_pyxis.c | 1 - arch/alpha/kernel/core_t2.c | 1 - arch/alpha/kernel/core_tsunami.c | 1 - arch/alpha/kernel/pci.c | 8 +- arch/alpha/kernel/setup.c | 1 - arch/alpha/kernel/sys_dp264.c | 1 - arch/alpha/kernel/sys_rawhide.c | 1 - arch/alpha/kernel/sys_sio.c | 1 - arch/arm/config.in | 214 +- arch/i386/boot/setup.S | 33 +- arch/i386/defconfig | 1 + arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/bios32.c | 628 ++- arch/i386/kernel/entry.S | 9 +- arch/i386/kernel/head.S | 9 + arch/i386/kernel/i386_ksyms.c | 2 + arch/i386/kernel/i8259.c | 244 +- arch/i386/kernel/io_apic.c | 513 ++- arch/i386/kernel/irq.c | 84 +- arch/i386/kernel/smp.c | 2195 +++-------- arch/i386/kernel/smpboot.c | 1650 ++++++++ arch/i386/kernel/time.c | 2 +- arch/i386/kernel/traps.c | 126 +- arch/m68k/config.in | 544 +-- arch/mips/config.in | 308 +- arch/mips/kernel/pci.c | 1 - arch/mips/sni/pci.c | 1 - arch/mips/sni/setup.c | 1 - arch/ppc/8xx_io/Config.in | 16 + arch/ppc/8xx_io/Makefile | 9 +- arch/ppc/8xx_io/commproc.c | 39 +- arch/ppc/8xx_io/commproc.h | 131 + arch/ppc/8xx_io/enet.c | 87 +- arch/ppc/8xx_io/fec.c | 81 +- arch/ppc/8xx_io/uart.c | 111 +- arch/ppc/Makefile | 6 +- arch/ppc/amiga/Makefile | 4 + arch/ppc/amiga/amiints.c | 146 +- arch/ppc/amiga/bootinfo.c | 13 +- arch/ppc/amiga/chipram.c | 176 +- arch/ppc/amiga/config.c | 49 +- arch/ppc/amiga/ints.c | 22 +- arch/ppc/amiga/pcmcia.c | 1 + arch/ppc/amiga/time.c | 6 +- arch/ppc/boot/Makefile | 11 +- arch/ppc/common_defconfig | 105 +- arch/ppc/config.in | 80 +- arch/ppc/defconfig | 105 +- arch/ppc/gemini_defconfig | 79 +- arch/ppc/kernel/Makefile | 59 +- arch/ppc/kernel/apus_setup.c | 610 ++- arch/ppc/kernel/chrp_pci.c | 3 +- arch/ppc/kernel/chrp_setup.c | 90 +- arch/ppc/kernel/entry.S | 3 +- arch/ppc/kernel/feature.c | 20 +- arch/ppc/kernel/gemini_pci.c | 1 - arch/ppc/kernel/gemini_setup.c | 7 +- arch/ppc/kernel/head.S | 36 +- arch/ppc/kernel/head_8xx.S | 37 +- arch/ppc/kernel/i8259.c | 1 - arch/ppc/kernel/idle.c | 4 +- arch/ppc/kernel/indirect_pci.c | 12 +- arch/ppc/kernel/irq.c | 43 +- arch/ppc/kernel/local_irq.h | 21 +- arch/ppc/kernel/m8xx_setup.c | 521 +++ arch/ppc/kernel/misc.S | 174 +- arch/ppc/kernel/open_pic.c | 12 +- arch/ppc/kernel/pci.c | 11 +- arch/ppc/kernel/pmac_pic.c | 113 +- arch/ppc/kernel/pmac_pic.h | 7 +- arch/ppc/kernel/pmac_setup.c | 60 +- arch/ppc/kernel/pmac_support.c | 8 +- arch/ppc/kernel/pmac_time.c | 33 +- arch/ppc/kernel/ppc8xx_pic.c | 173 +- arch/ppc/kernel/ppc8xx_pic.h | 12 + arch/ppc/kernel/ppc_htab.c | 76 +- arch/ppc/kernel/ppc_ksyms.c | 48 +- arch/ppc/kernel/prep_nvram.c | 14 +- arch/ppc/kernel/prep_pci.c | 8 +- arch/ppc/kernel/prep_setup.c | 47 +- arch/ppc/kernel/process.c | 6 +- arch/ppc/kernel/prom.c | 149 +- arch/ppc/kernel/qspan_pci.c | 379 ++ arch/ppc/kernel/residual.c | 5 +- arch/ppc/kernel/setup.c | 132 +- arch/ppc/kernel/sleep.S | 264 ++ arch/ppc/kernel/smp.c | 18 +- arch/ppc/kernel/traps.c | 12 +- arch/ppc/lib/locks.c | 2 +- arch/ppc/mbxboot/Makefile | 42 +- arch/ppc/mbxboot/embed_config.c | 207 + arch/ppc/mbxboot/head.S | 219 +- arch/ppc/mbxboot/iic.c | 250 ++ arch/ppc/mbxboot/m8xx_tty.c | 253 ++ arch/ppc/mbxboot/misc.c | 339 +- arch/ppc/mbxboot/pci.c | 251 ++ arch/ppc/mbxboot/qspan_pci.c | 267 ++ arch/ppc/mm/fault.c | 32 - arch/ppc/mm/init.c | 132 +- arch/ppc/vmlinux.lds | 8 + arch/ppc/xmon/start.c | 106 +- arch/sparc64/config.in | 10 +- arch/sparc64/defconfig | 7 +- arch/sparc64/kernel/pci.c | 5 - drivers/atm/Config.in | 74 +- drivers/char/defkeymap.c | 3 +- drivers/char/mem.c | 4 +- drivers/char/pms.c | 28 +- drivers/macintosh/Makefile | 40 +- drivers/macintosh/adb.c | 144 +- drivers/macintosh/mac_keyb.c | 40 +- drivers/macintosh/macio-adb.c | 39 +- drivers/macintosh/macserial.c | 53 +- drivers/macintosh/macserial.h | 1 + drivers/macintosh/mediabay.c | 102 +- drivers/macintosh/via-cuda.c | 149 +- drivers/macintosh/via-pmu.c | 668 +++- drivers/misc/Config.in | 9 +- drivers/misc/Makefile | 4 - drivers/misc/acpi.c | 59 + drivers/misc/piix4_acpi.c | 214 - drivers/net/pcmcia/ray_cs.c | 372 +- drivers/net/pcmcia/ray_cs.h | 9 +- drivers/net/pcmcia/rayctl.h | 19 +- drivers/parport/ieee1284.c | 10 +- drivers/parport/ieee1284_ops.c | 15 +- drivers/parport/init.c | 2 + drivers/parport/parport_pc.c | 132 +- drivers/pci/Makefile | 6 +- drivers/pci/pci.c | 93 +- drivers/pci/quirks.c | 4 +- drivers/pci/setup.c | 10 +- drivers/scsi/ChangeLog.ncr53c8xx | 30 + drivers/scsi/ChangeLog.sym53c8xx | 129 + drivers/scsi/Makefile | 19 + drivers/scsi/README.aic7xxx | 24 +- drivers/scsi/README.ncr53c8xx | 416 +- drivers/scsi/aic7xxx.c | 272 +- drivers/scsi/hosts.c | 7 + drivers/scsi/ncr53c8xx.c | 412 +- drivers/scsi/sg.c | 121 +- drivers/scsi/sim710.c | 1605 ++++++++ drivers/scsi/sim710.h | 845 ++++ drivers/scsi/sim710.scr | 554 +++ drivers/scsi/sim710_d.h | 2360 +++++++++++ drivers/scsi/sim710_u.h | 67 + drivers/scsi/sym53c8xx.c | 4601 ++++++++++++++-------- drivers/scsi/sym53c8xx.h | 2 +- drivers/scsi/sym53c8xx_defs.h | 401 +- drivers/usb/Config.in | 58 +- drivers/usb/Makefile | 9 + drivers/usb/README.ohci | 12 + drivers/usb/README.serial | 35 + drivers/usb/acm.c | 235 +- drivers/usb/audio.c | 3473 +++++++++++++++- drivers/usb/audio.h | 116 + drivers/usb/cpia.c | 1216 +++--- drivers/usb/cpia.h | 90 +- drivers/usb/ezusb.c | 157 +- drivers/usb/ezusb.h | 25 +- drivers/usb/hp_scanner.c | 4 +- drivers/usb/hub.c | 10 +- drivers/usb/inits.h | 1 + drivers/usb/keyboard.c | 2 +- drivers/usb/keymap.c | 4 +- drivers/usb/maps/usb.map | 16 +- drivers/usb/mouse.c | 2 +- drivers/usb/ohci-debug.c | 5 +- drivers/usb/ohci-hcd.c | 10 +- drivers/usb/ohci-hcd.h | 2 +- drivers/usb/ohci.c | 350 +- drivers/usb/ohci.h | 43 +- drivers/usb/printer.c | 21 +- drivers/usb/proc_usb.c | 217 +- drivers/usb/serial.c | 691 ++++ drivers/usb/uhci.c | 71 +- drivers/usb/uhci.h | 4 + drivers/usb/usb-core.c | 9 +- drivers/usb/usb.c | 41 +- drivers/usb/usb.h | 39 +- drivers/usb/usb_scsi.c | 24 +- drivers/usb/uss720.c | 25 +- fs/Config.in | 3 + fs/dcache.c | 78 +- fs/dquot.c | 3 +- fs/inode.c | 431 +- fs/isofs/inode.c | 15 +- fs/ncpfs/Config.in | 20 +- fs/ncpfs/dir.c | 700 ++-- fs/ncpfs/file.c | 3 +- fs/ncpfs/inode.c | 117 +- fs/ncpfs/ioctl.c | 157 +- fs/ncpfs/ncplib_kernel.c | 21 +- fs/ncpfs/ncplib_kernel.h | 47 +- fs/ncpfs/ncpsign_kernel.h | 1 - fs/ncpfs/sock.c | 2 - fs/nfsd/nfsfh.c | 4 +- fs/open.c | 11 +- fs/sysv/inode.c | 25 +- fs/udf/inode.c | 2 +- include/asm-i386/apic.h | 267 +- include/asm-i386/hw_irq.h | 44 +- include/asm-i386/irq.h | 2 +- include/asm-i386/msr.h | 2 + include/asm-i386/processor.h | 3 + include/asm-i386/smp.h | 49 +- include/asm-ppc/adb.h | 100 - include/asm-ppc/adb_mouse.h | 23 - include/asm-ppc/amigahw.h | 14 + include/asm-ppc/amigappc.h | 16 +- include/asm-ppc/amigayle.h | 2 +- include/asm-ppc/amipcmcia.h | 2 +- include/asm-ppc/bootx.h | 133 +- include/asm-ppc/bseip.h | 41 + include/asm-ppc/cuda.h | 38 - include/asm-ppc/feature.h | 2 + include/asm-ppc/ide.h | 4 + include/asm-ppc/init.h | 2 +- include/asm-ppc/io.h | 10 +- include/asm-ppc/irq.h | 71 +- include/asm-ppc/irq_control.h | 112 +- include/asm-ppc/keyboard.h | 7 +- include/asm-ppc/linux_logo.h | 9 - include/asm-ppc/machdep.h | 21 +- include/asm-ppc/mbx.h | 30 +- include/asm-ppc/mpc8xx.h | 71 + include/asm-ppc/ohare.h | 2 + include/asm-ppc/pgtable.h | 33 +- include/asm-ppc/pmu.h | 97 - include/asm-ppc/processor.h | 33 +- include/asm-ppc/prom.h | 4 +- include/asm-ppc/rpxclassic.h | 67 + include/asm-ppc/rpxlite.h | 67 + include/asm-ppc/serial.h | 16 +- include/asm-ppc/shmparam.h | 2 +- include/asm-ppc/smp.h | 1 - include/asm-ppc/spinlock.h | 19 +- include/asm-ppc/system.h | 7 +- include/linux/acpi.h | 14 +- include/linux/dcache.h | 11 +- include/linux/fs.h | 5 +- include/linux/msg.h | 40 +- include/linux/ncp.h | 25 - include/linux/ncp_fs.h | 84 +- include/linux/ncp_fs_i.h | 33 +- include/linux/ncp_fs_sb.h | 18 +- include/linux/ncp_mount.h | 2 - include/linux/ncp_no.h | 19 + include/linux/netfilter.h | 3 +- include/linux/netfilter_ipv4.h | 6 + include/linux/parport_pc.h | 69 +- include/linux/pci.h | 1127 +----- include/linux/pci_ids.h | 1095 +++++ include/linux/prctl.h | 3 + include/linux/proc_fs.h | 1 + include/linux/sched.h | 2 + include/linux/smp.h | 2 +- include/linux/sunrpc/xprt.h | 4 +- include/scsi/sg.h | 21 +- init/main.c | 10 - ipc/msg.c | 959 +++-- kernel/sys.c | 11 + kernel/sysctl.c | 2 - mm/filemap.c | 2 +- mm/vmscan.c | 10 +- net/802/fc.c | 5 +- net/core/netfilter.c | 3 - net/sunrpc/xprt.c | 61 +- 282 files changed, 29836 insertions(+), 11571 deletions(-) create mode 100644 Documentation/networking/ray_cs.txt create mode 100644 Documentation/nmi_watchdog.txt create mode 100644 arch/i386/kernel/smpboot.c create mode 100644 arch/ppc/8xx_io/Config.in create mode 100644 arch/ppc/amiga/pcmcia.c create mode 100644 arch/ppc/kernel/m8xx_setup.c create mode 100644 arch/ppc/kernel/qspan_pci.c create mode 100644 arch/ppc/kernel/sleep.S create mode 100644 arch/ppc/mbxboot/embed_config.c create mode 100644 arch/ppc/mbxboot/iic.c create mode 100644 arch/ppc/mbxboot/m8xx_tty.c create mode 100644 arch/ppc/mbxboot/pci.c create mode 100644 arch/ppc/mbxboot/qspan_pci.c delete mode 100644 drivers/misc/piix4_acpi.c create mode 100644 drivers/scsi/sim710.c create mode 100644 drivers/scsi/sim710.h create mode 100644 drivers/scsi/sim710.scr create mode 100644 drivers/scsi/sim710_d.h create mode 100644 drivers/scsi/sim710_u.h create mode 100644 drivers/usb/README.serial create mode 100644 drivers/usb/audio.h create mode 100644 drivers/usb/serial.c delete mode 100644 include/asm-ppc/adb.h delete mode 100644 include/asm-ppc/adb_mouse.h create mode 100644 include/asm-ppc/bseip.h delete mode 100644 include/asm-ppc/cuda.h create mode 100644 include/asm-ppc/mpc8xx.h delete mode 100644 include/asm-ppc/pmu.h create mode 100644 include/asm-ppc/rpxclassic.h create mode 100644 include/asm-ppc/rpxlite.h create mode 100644 include/linux/ncp_no.h create mode 100644 include/linux/pci_ids.h diff --git a/Documentation/devices.tex b/Documentation/devices.tex index d4e10e7f7b59..03533ac8ed97 100644 --- a/Documentation/devices.tex +++ b/Documentation/devices.tex @@ -254,11 +254,13 @@ Your cooperation is appreciated. \major{86}{}{char }{SCSI media changer} \major{87}{}{char }{Sony Control-A1 stereo control bus} \major{88}{}{char }{COMX synchronous serial card} -\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface} -\major{89}{}{char }{I$^2$C bus interface} \major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} +\major{89}{}{char }{I$^2$C bus interface} +\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface} \major{90}{}{char }{Memory Technology Device (RAM, ROM, Flash)} +\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface} \major{91}{}{char }{CAN-Bus controller} +\major{ }{}{block}{Tenth IDE hard disk/CD-ROM interface} \major{92}{}{char }{Reserved for ith Kommunikationstechnik MIC ISDN card} \major{93}{}{char }{IBM Smart Capture Card frame grabber} \major{94}{}{char }{miroVIDEO DC10/30 capture/playback device} @@ -1748,7 +1750,7 @@ on {\url http://home.pages.de/~videotext/\/}. \end{devicelist} \begin{devicelist} -\major{ }{}{block}{Sixth IDE hard disk/CD-ROM interface} +\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} \minor{0}{/dev/hdm}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdn}{Slave: whole disk (or CD-ROM)} \end{devicelist} @@ -1765,7 +1767,7 @@ major number 3). \end{devicelist} \begin{devicelist} -\major{ }{}{block}{Seventh IDE hard disk/CD-ROM interface} +\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface} \minor{0}{/dev/hdo}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdp}{Slave: whole disk (or CD-ROM)} \end{devicelist} @@ -1784,7 +1786,7 @@ major number 3). \end{devicelist} \begin{devicelist} -\major{ }{}{block}{Eighth IDE hard disk/CD-ROM interface} +\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface} \minor{0}{/dev/hdq}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdr}{Slave: whole disk (or CD-ROM)} \end{devicelist} @@ -1801,7 +1803,7 @@ major number 3). \end{devicelist} \begin{devicelist} -\major{ }{}{block}{Ninth IDE hard disk/CD-ROM interface} +\major{ }{}{block}{Tenth IDE hard disk/CD-ROM interface} \minor{0}{/dev/hds}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdt}{Slave: whole disk (or CD-ROM)} \end{devicelist} diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 9f911d1fc174..13a48d06cfb0 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -1215,7 +1215,7 @@ Your cooperation is appreciated. 1 = /dev/comx1 COMX channel 1 ... - block Sixth IDE hard disk/CD-ROM interface + block Seventh IDE hard disk/CD-ROM interface 0 = /dev/hdm Master: whole disk (or CD-ROM) 64 = /dev/hdn Slave: whole disk (or CD-ROM) @@ -1227,7 +1227,7 @@ Your cooperation is appreciated. 1 = /dev/i2c1 Second I2C adapter ... - block Seventh IDE hard disk/CD-ROM interface + block Eighth IDE hard disk/CD-ROM interface 0 = /dev/hdo Master: whole disk (or CD-ROM) 64 = /dev/hdp Slave: whole disk (or CD-ROM) @@ -1241,7 +1241,7 @@ Your cooperation is appreciated. 30 = /dev/mtd15 16th MTD (rw) 31 = /dev/mtdr15 16th MTD (ro) - block Eighth IDE hard disk/CD-ROM interface + block Ninth IDE hard disk/CD-ROM interface 0 = /dev/hdq Master: whole disk (or CD-ROM) 64 = /dev/hdr Slave: whole disk (or CD-ROM) @@ -1253,7 +1253,7 @@ Your cooperation is appreciated. 1 = /dev/can1 Second CAN-Bus controller ... - block Ninth IDE hard disk/CD-ROM interface + block Tenth IDE hard disk/CD-ROM interface 0 = /dev/hds Master: whole disk (or CD-ROM) 64 = /dev/hdt Slave: whole disk (or CD-ROM) diff --git a/Documentation/kbuild/config-language.txt b/Documentation/kbuild/config-language.txt index 079f0c751328..dce6086f97de 100644 --- a/Documentation/kbuild/config-language.txt +++ b/Documentation/kbuild/config-language.txt @@ -1,5 +1,5 @@ Config Language Specification -21 January 1999 +28 September 1999 Michael Elizabeth Chastain, @@ -82,7 +82,10 @@ Here are the basic grammar elements. double-quoted string. If the word is unquoted or double quoted, then $-substition will be performed on the word. - A /symbol/ is a single unquoted word. + A /symbol/ is a single unquoted word. A symbol must have a name of + the form CONFIG_*. scripts/mkdep.c relies on this convention in order + to generate dependencies on individual CONFIG_* symbols instead of + making one massive dependency on include/linux/autoconf.h. A /dep/ is a dependency. Syntactically, it is a /word/. At run time, a /dep/ must evaluate to "y", "m", "n", or "". @@ -355,8 +358,8 @@ This verb assigns the value of /word/ to /symbol/. Any hexadecimal number is a legal value. Configure: implemented -Menuconfig: not implemented -Xconfig: not implemented +Menuconfig: implemented +Xconfig: implemented mconfig: implemented Example: @@ -377,8 +380,8 @@ This verb assigns /symbol/ the value /word/. Any decimal number is a legal value. Configure: implemented -Menuconfig: not implemented -Xconfig: not implemented +Menuconfig: implemented +Xconfig: implemented mconfig: implemented Example: @@ -394,8 +397,8 @@ This verb assigns the value of /word/ to /symbol/. Legal input values are any ASCII string, except for the characters '"' and '\\'. Configure: implemented -Menuconfig: not implemented -Xconfig: not implemented +Menuconfig: implemented +Xconfig: implemented mconfig: implemented Example @@ -414,9 +417,9 @@ As soon as this verb is implemented in all interpreters, please use it instead of define_bool to define tristate values. This aids in static type checking. -Configure: not implemented -Menuconfig: not implemented -Xconfig: not implemented +Configure: implemented +Menuconfig: implemented +Xconfig: implemented mconfig: implemented Example: @@ -433,22 +436,27 @@ Example: This verb evaluates all of the dependencies in the dependency list. Any dependency which has a value of "y" does not restrict the input -range. Any dependency which has a value of "n", or which has some -other value, restricts the input range to "n". +range. Any dependency which has an empty value is ignored. +Any dependency which has a value of "n", or which has some other value, +restricts the input range to "n". Quoting dependencies is not allowed. +Using dependencies with an empty value possible is not recommended. If the input range is restricted to the single choice "n", dep_bool silently assigns "n" to /symbol/. If the input range has more than one choice, dep_bool displays /prompt/ to the user, accepts a value from the user, and assigns that value to /symbol/. -Configure: not implemented -Menuconfig: not implemented -XConfig: not implemented +Configure: implemented +Menuconfig: implemented +XConfig: implemented mconfig: implemented # not from the corpus dep_bool 'RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_PCI +Known bugs: +- Xconfig does not write "# foo is not set" to .config (as well as + "#unset foo" to autoconf.h) if command is disabled by its dependencies. === dep_hex /prompt/ /symbol/ /word/ /dep/ ... @@ -464,13 +472,15 @@ mconfig: not implemented -=== dep_tristate /prompt/ /symbol /dep/ ... +=== dep_tristate /prompt/ /symbol/ /dep/ ... This verb evaluates all of the dependencies in the dependency list. -Any dependency which as a value of "y" does not restrict the input range. +Any dependency which has a value of "y" does not restrict the input range. Any dependency which has a value of "m" restricts the input range to -"m" or "n". Any dependency which has a value of "n", or which has some -other value, restricts the input range to "n". +"m" or "n". Any dependency which has an empty value is ignored. +Any dependency which has a value of "n", or which has some other value, +restricts the input range to "n". Quoting dependencies is not allowed. +Using dependencies with an empty value possible is not recommended. If the input range is restricted to the single choice "n", dep_tristate silently assigns "n" to /symbol/. If the input range has more than @@ -478,10 +488,13 @@ one choice, dep_tristate displays /prompt/ to the user, accepts a value from the user, and assigns that value to /symbol/. Configure: implemented -Menuconfig: implemented (but silently ignores dependencies after the first) -Xconfig: implemented (but silently ignores dependencies after the first) +Menuconfig: implemented +Xconfig: implemented mconfig: implemented +Known bugs: +- Xconfig does not write "# foo is not set" to .config (as well as + "#unset foo" to autoconf.h) if command is disabled by its dependencies. === unset /symbol/ ... @@ -492,7 +505,7 @@ up deeper problems with variable semantics in a random-execution language. Configure: implemented Menuconfig: implemented -Xconfig: not implemented +Xconfig: implemented (with bugs) mconfig: implemented @@ -570,14 +583,9 @@ Menuconfig: implemented XConfig: implemented, with bugs mconfig: implemented -Xconfig has several known bugs, and probably some unknown bugs too: - -- In a comparison, if the left-hand atom is a variable and that variable - is from a choice list, the right-hand atom must be "y". +Xconfig has some known bugs, and probably some unknown bugs too: -- In a comparison, if the right-hand atom is a variable and that variable - is from a choice list, you lose. tkparse will throw a segmentation - violation, silently generate bizarre TCL code, or something else. +- literals with an empty "" value are not properly handled. - tkparse gives the wrong precedence to -o, -a, and !. Don't use both -o and -a in an expression. Don't use ! at all. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 02f1310e7fda..dc57ee65150c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -266,9 +266,11 @@ or parport=0xBBB[,IRQ[,DMA]] to use any IRQ/DMA settings detected IRQ/DMA settings because of possible conflicts). You can specify the base address, IRQ, and DMA settings; IRQ - and DMA should be numbers or 'auto' + and DMA should be numbers, or 'auto' (for using detected settings on that - particular port). Parallel ports are + particular port), or 'nofifo' (to + avoid using a FIFO even if it is + detected). Parallel ports are assigned in the order they are specified on the command line, starting with parport0. diff --git a/Documentation/networking/ray_cs.txt b/Documentation/networking/ray_cs.txt new file mode 100644 index 000000000000..b1def00bc4a3 --- /dev/null +++ b/Documentation/networking/ray_cs.txt @@ -0,0 +1,151 @@ +September 21, 1999 + +Copyright (c) 1998 Corey Thomas (corey@world.std.com) + +This file is the documentation for the Raylink Wireless LAN card driver for +Linux. The Raylink wireless LAN card is a PCMCIA card which provides IEEE +802.11 compatible wireless network connectivity at 1 and 2 megabits/second. +See http://www.raytheon.com/micro/raylink/ for more information on the Raylink +card. This driver is in early development and does have bugs. See the known +bugs and limitations at the end of this document for more information. +This driver also works with WebGear's Aviator 2.4 and Aviator Pro +wireless LAN cards. + +As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel +source. My web page for the development of ray_cs is at +http://world.std.com/~corey/raylink.html and I can be emailed at +corey@world.std.com + +The kernel driver is based on ray_cs-1.62.tgz + +The driver at my web page is intended to be used as an add on to +David Hinds pcmcia package. All the command line parameters are +available when compiled as a module. When built into the kernel, only +the essid= string parameter is available via the kernel command line. +This will change after the method of sorting out parameters for all +the PCMCIA drivers is agreed upon. If you must have a built in driver +with nondefault parameters, they can be edited in +/usr/src/linux/drivers/net/pcmcia/ray_cs.c. Searching for MODULE_PARM +will find them all. + +Information on card services is available at: + ftp://hyper.stanford.edu/pub/pcmcia/doc + http://hyper.stanford.edu/HyperNews/get/pcmcia/home.html + + +Card services user programs are still required for PCMCIA devices. +pcmcia-cs-3.1.1 or greater is required for the kernel version of +the driver. + +Currently, ray_cs is not part of David Hinds card services package, +so the following magic is required. + +At the end of the /etc/pcmcia/config.opts file, add the line: +source ./ray_cs.opts +This will make card services read the ray_cs.opts file +when starting. Create the file /etc/pcmcia/ray_cs.opts containing the +following: + +#### start of /etc/pcmcia/ray_cs.opts ################### +# Configuration options for Raylink Wireless LAN PCMCIA card +device "ray_cs" + class "network" module "misc/ray_cs" + +card "RayLink PC Card WLAN Adapter" + manfid 0x01a6, 0x0000 + bind "ray_cs" + +module "misc/ray_cs" opts "" +#### end of /etc/pcmcia/ray_cs.opts ##################### + + +To join an existing network with +different parameters, contact the network administrator for the +configuration information, and edit /etc/pcmcia/ray_cs.opts. +Add the parameters below between the empty quotes. + +Parameters for ray_cs driver which may be specified in ray_cs.opts: + +bc integer 0 = normal mode (802.11 timing) + 1 = slow down inter frame timing to allow + operation with older breezecom access + points. + +beacon_period integer beacon period in Kilo-microseconds + legal values = must be integer multiple + of hop dwell + default = 256 + +country integer 1 = USA (default) + 2 = Europe + 3 = Japan + 4 = Korea + 5 = Spain + 6 = France + 7 = Israel + 8 = Australia + +essid string ESS ID - network name to join + string with maximum length of 32 chars + default value = "ADHOC_ESSID" + +hop_dwell integer hop dwell time in Kilo-microseconds + legal values = 16,32,64,128(default),256 + +irq_mask integer linux standard 16 bit value 1bit/IRQ + lsb is IRQ 0, bit 1 is IRQ 1 etc. + Used to restrict choice of IRQ's to use. + Recommended method for controlling + interrupts is in /etc/pcmcia/config.opts + +net_type integer 0 (default) = adhoc network, + 1 = infrastructure + +phy_addr string string containing new MAC address in + hex, must start with x eg + x00008f123456 + +psm integer 0 = continuously active + 1 = power save mode (not useful yet) + +pc_debug integer (0-5) larger values for more verbose + logging. Replaces ray_debug. + +ray_debug integer Replaced with pc_debug + +ray_mem_speed integer defaults to 500 + +sniffer integer 0 = not sniffer (default) + 1 = sniffer which can be used to record all + network traffic using tcpdump or similar, + but no normal network use is allowed. + +translate integer 0 = no translation (encapsulate frames) + 1 = translation (RFC1042/802.1) + + +More on sniffer mode: + +tcpdump does not understand 802.11 headers, so it can't +interpret the contents, but it can record to a file. This is only +useful for debugging 802.11 lowlevel protocols that are not visible to +linux. If you want to watch ftp xfers, or do similar things, you +don't need to use sniffer mode. Also, some packet types are never +sent up by the card, so you will never see them (ack, rts, cts, probe +etc.) There is a simple program (showcap) included in the ray_cs +package which parses the 802.11 headers. + +Known Problems and missing features + + Does not work with non x86 + + Does not work with SMP + + Support for defragmenting frames is not yet debugged, and in + fact is known to not work. I have never encountered a net set + up to fragment, but still, it should be fixed. + + The ioctl support is incomplete. The hardware address cannot be set + using ifconfig yet. If a different hardware address is needed, it may + be set using the phy_addr parameter in ray_cs.opts. This requires + a card insertion to take effect. diff --git a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt new file mode 100644 index 000000000000..feb78559effa --- /dev/null +++ b/Documentation/nmi_watchdog.txt @@ -0,0 +1,33 @@ + +Is your SMP system locking up unpredictably? No keyboard activity, just +a frustrating complete hard lockup? Do you want to help us debugging +such lockups? If all yes then this document is definitely for you. + +on Intel SMP hardware there is a feature that enables us to generate +'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get +executed even if the system is otherwise locked up hard) This can be +used to debug hard kernel lockups. By executing periodic NMI interrupts, +the kernel can monitor wether any CPU has locked up, and print out +debugging messages if so. You can enable/disable the NMI watchdog at boot +time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant +lilo.conf entry: + + append="nmi_watchdog=1" + +A 'lockup' is the following scenario: if any CPU in the system does not +execute the period local timer interrupt for more than 5 seconds, then +the NMI handler generates an oops and kills the process. This +'controlled crash' (and the resulting kernel messages) can be used to +debug the lockup. Thus whenever the lockup happens, wait 5 seconds and +the oops will show up automatically. If the kernel produces no messages +then the system has crashed so hard (eg. hardware-wise) that either it +cannot even accept NMI interrupts, or the crash has made the kernel +unable to print messages. + +NOTE: currently the NMI-oopser is enabled unconditionally on x86 SMP +boxes. + +[ feel free to send bug reports, suggestions and patches to + Ingo Molnar or the Linux SMP mailing + list at ] + diff --git a/Documentation/parport.txt b/Documentation/parport.txt index 152e3f3cfea7..c932216df82a 100644 --- a/Documentation/parport.txt +++ b/Documentation/parport.txt @@ -67,7 +67,7 @@ If you compile the parport code into the kernel, then you can use kernel boot parameters to get the same effect. Add something like the following to your LILO command line: - parport=0x3bc parport=0x378,7 parport=0x278,auto + parport=0x3bc parport=0x378,7 parport=0x278,auto,nofifo You can have many `parport=...' statements, one for each port you want to add. Adding `parport=0' to the kernel command-line will disable diff --git a/MAINTAINERS b/MAINTAINERS index 6532b058ed92..1005b7fd708f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -434,6 +434,11 @@ M: Gadi Oxman L: linux-kernel@vger.rutgers.edu S: Maintained +INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT +P: Ingo Molnar +M: mingo@redhat.com +S: Maintained + IP MASQUERADING: P: Juanjo Ciarlante M: jjciarla@raiz.uncu.edu.ar diff --git a/Makefile b/Makefile index 63936e2617b0..39e92a6a0cd4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 19 +SUBLEVEL = 20 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c index 46378b7620ce..6a402a3e1d94 100644 --- a/arch/alpha/kernel/core_apecs.c +++ b/arch/alpha/kernel/core_apecs.c @@ -18,7 +18,6 @@ #include #include #include -#include #define __EXTERN_INLINE inline #include diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index 5821db09dd80..4e773862b15f 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -19,7 +19,6 @@ #include #include -#include #define __EXTERN_INLINE inline #include diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c index 13172b708405..8b87f8afaebd 100644 --- a/arch/alpha/kernel/core_lca.c +++ b/arch/alpha/kernel/core_lca.c @@ -17,7 +17,6 @@ #include #include #include -#include #define __EXTERN_INLINE inline #include diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index ac86d5255a2e..1222556d3490 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -15,7 +15,6 @@ #include #include -#include #include #define __EXTERN_INLINE inline diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c index 39ae36f8e795..a6b1a70c759a 100644 --- a/arch/alpha/kernel/core_polaris.c +++ b/arch/alpha/kernel/core_polaris.c @@ -12,7 +12,6 @@ #include #include -#include #define __EXTERN_INLINE inline #include diff --git a/arch/alpha/kernel/core_pyxis.c b/arch/alpha/kernel/core_pyxis.c index 88a3e37c9f76..4f9dd9a81cc5 100644 --- a/arch/alpha/kernel/core_pyxis.c +++ b/arch/alpha/kernel/core_pyxis.c @@ -14,7 +14,6 @@ #include #include -#include #define __EXTERN_INLINE inline #include diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c index 43103f8ebc18..6028e4e5816b 100644 --- a/arch/alpha/kernel/core_t2.c +++ b/arch/alpha/kernel/core_t2.c @@ -17,7 +17,6 @@ #include #include -#include #define __EXTERN_INLINE #include diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index c0d7c867d283..b27298bd5679 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -14,7 +14,6 @@ #include #include -#include #include #define __EXTERN_INLINE inline diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index a81ba409304c..39d6b759fe3b 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "proto.h" @@ -81,6 +80,13 @@ pcibios_assign_special(void) for (dev = pci_devices; dev; dev = dev->next) { if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE) continue; + /* Resource 1 of IDE controller is the address of HD_CMD + register which actually occupies a single byte (0x3f6 + for ide0) in reported 0x3f4-3f7 range. We have to fix + that to avoid resource conflict with AT-style floppy + controller. */ + dev->resource[1].start += 2; + dev->resource[1].end = dev->resource[1].start; for (i = 0; i < PCI_NUM_RESOURCES; i++) { if (dev->resource[i].flags) pci_claim_resource(dev, i); diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 47a86c9fe4b5..9bb21671cafc 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -40,7 +40,6 @@ #include #include #include -#include #include "proto.h" #include "pci_impl.h" diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index a5806275fc98..9959aad332c5 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c index 1b5e1c3cf6c1..4561c4046810 100644 --- a/arch/alpha/kernel/sys_rawhide.c +++ b/arch/alpha/kernel/sys_rawhide.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c index 8e7fdb85fe73..a6575de9c3f7 100644 --- a/arch/alpha/kernel/sys_sio.c +++ b/arch/alpha/kernel/sys_sio.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "proto.h" #include "irq_impl.h" diff --git a/arch/arm/config.in b/arch/arm/config.in index e9783461cf3c..52f69bcd8e8e 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -6,6 +6,11 @@ mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_ARM y +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + mainmenu_option next_comment comment 'System and processor type' @@ -17,24 +22,24 @@ choice 'ARM system type' \ FootBridge-based CONFIG_FOOTBRIDGE" RiscPC if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE - if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then - define_bool CONFIG_ADDIN_FOOTBRIDGE n - else - define_bool CONFIG_ADDIN_FOOTBRIDGE y - fi + bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE + if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then + define_bool CONFIG_ADDIN_FOOTBRIDGE n + else + define_bool CONFIG_ADDIN_FOOTBRIDGE y + fi fi if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then - bool ' Include support for Intel EBSA285' CONFIG_ARCH_EBSA285 - bool ' Include support for Chalice CATS boards' CONFIG_CATS - bool ' Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER + bool ' Include support for Intel EBSA285' CONFIG_ARCH_EBSA285 + bool ' Include support for Chalice CATS boards' CONFIG_CATS + bool ' Include support for Corel NetWinder' CONFIG_ARCH_NETWINDER fi if [ "$CONFIG_ADDIN_FOOTBRIDGE" = "y" ]; then - # If we get any other footbridge-based plug-in boards, then - # add your architecture options here - define_bool CONFIG_ARCH_CO285 y + # If we get any other footbridge-based plug-in boards, then + # add your architecture options here + define_bool CONFIG_ARCH_CO285 y fi # @@ -44,9 +49,9 @@ fi if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then - define_bool CONFIG_ARCH_ACORN y + define_bool CONFIG_ARCH_ACORN y else - define_bool CONFIG_ARCH_ACORN n + define_bool CONFIG_ARCH_ACORN n fi # @@ -56,33 +61,33 @@ fi # if [ "$CONFIG_ARCH_ARC" = "y" -o \ "$CONFIG_ARCH_A5K" = "y" ]; then - define_bool CONFIG_CPU_32 n - define_bool CONFIG_CPU_26 y + define_bool CONFIG_CPU_32 n + define_bool CONFIG_CPU_26 y - # - # Select memory size - # - bool '2MB physical memory' CONFIG_PAGESIZE_16 + # + # Select memory size + # + bool '2MB physical memory' CONFIG_PAGESIZE_16 else - define_bool CONFIG_CPU_32 y - define_bool CONFIG_CPU_26 n - - # - # Select CPU and optimisation dependent on architecture - # - if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ - "$CONFIG_FOOTBRIDGE" = "y" -o \ - "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then - define_bool CONFIG_CPU_32v4 y - define_bool CONFIG_CPU_SA110 y - else - if [ "$CONFIG_ARCH_RPC" = "y" ]; then - define_bool CONFIG_CPU_32v3 y - bool 'Support ARM610' CONFIG_CPU_ARM6 - bool 'Support ARM710' CONFIG_CPU_ARM7 - bool 'Support StrongARM110' CONFIG_CPU_SA110 - fi - fi + define_bool CONFIG_CPU_32 y + define_bool CONFIG_CPU_26 n + + # + # Select CPU and optimisation dependent on architecture + # + if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ + "$CONFIG_FOOTBRIDGE" = "y" -o \ + "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then + define_bool CONFIG_CPU_32v4 y + define_bool CONFIG_CPU_SA110 y + else + if [ "$CONFIG_ARCH_RPC" = "y" ]; then + define_bool CONFIG_CPU_32v3 y + bool 'Support ARM610' CONFIG_CPU_ARM6 + bool 'Support ARM710' CONFIG_CPU_ARM7 + bool 'Support StrongARM110' CONFIG_CPU_SA110 + fi + fi fi # @@ -90,7 +95,7 @@ fi # if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then - define_bool CONFIG_PCI y + define_bool CONFIG_PCI y fi # @@ -98,18 +103,15 @@ fi # if [ "$CONFIG_CATS" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" ]; then - define_bool CONFIG_ISA_DMA y + define_bool CONFIG_ISA_DMA y else - define_bool CONFIG_ISA_DMA n + define_bool CONFIG_ISA_DMA n fi endmenu -mainmenu_option next_comment -comment 'Code maturity level options' -bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL -if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then - bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP +if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" -a "$CONFIG_EXPERIMENTAL" ]; then + bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP fi #bool 'Split text into discardable sections' CONFIG_TEXT_SECTIONS endmenu @@ -118,8 +120,8 @@ mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD fi endmenu @@ -134,41 +136,41 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_CPU_32" = "y" ]; then - tristate 'RISC OS personality' CONFIG_ARTHUR + tristate 'RISC OS personality' CONFIG_ARTHUR fi tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then - if [ "$CONFIG_ARCH_ARC" = "y" ]; then - dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT - fi - dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT -# If exactly one hardware type is selected then parport will optimise away -# support for loading any others. Defeat this if the user is keen. - if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then - if [ "$CONFIG_PARPORT_PC" != "n" -o "$CONFIG_PARPORT_ARC" != "n" ]; then - bool ' Support foreign hardware' CONFIG_PARPORT_OTHER - fi - fi + if [ "$CONFIG_ARCH_ARC" = "y" ]; then + dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT + fi + dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + # If exactly one hardware type is selected then parport will optimise away + # support for loading any others. Defeat this if the user is keen. + if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then + if [ "$CONFIG_PARPORT_PC" != "n" -o "$CONFIG_PARPORT_ARC" != "n" ]; then + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + fi + fi fi if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_CATS" = "y" ]; then - string 'Initial kernel command string' CONFIG_CMDLINE + string 'Initial kernel command string' CONFIG_CMDLINE fi if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_EBSA285" = "y" -o \ "$CONFIG_ARCH_CO285" = "y" ]; then - bool 'Timer and CPU usage LEDs' CONFIG_LEDS - if [ "$CONFIG_LEDS" = "y" ]; then - if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ - "$CONFIG_ARCH_EBSA285" = "y" -o \ - "$CONFIG_ARCH_CO285" = "y" ]; then - bool ' Timer LED' CONFIG_LEDS_TIMER - bool ' CPU usage LED' CONFIG_LEDS_CPU - fi - fi + bool 'Timer and CPU usage LEDs' CONFIG_LEDS + if [ "$CONFIG_LEDS" = "y" ]; then + if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ + "$CONFIG_ARCH_EBSA285" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" ]; then + bool ' Timer LED' CONFIG_LEDS_TIMER + bool ' CPU usage LED' CONFIG_LEDS_CPU + fi + fi fi endmenu @@ -179,48 +181,48 @@ source drivers/pnp/Config.in source drivers/block/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - source drivers/acorn/block/Config.in + source drivers/acorn/block/Config.in fi source drivers/char/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - if [ "$CONFIG_MOUSE" = "y" ]; then - if [ "$CONFIG_ARCH_RPC" != "y" ]; then - define_bool CONFIG_KBDMOUSE y - else - define_bool CONFIG_RPCMOUSE y - fi - fi + if [ "$CONFIG_MOUSE" = "y" ]; then + if [ "$CONFIG_ARCH_RPC" != "y" ]; then + define_bool CONFIG_KBDMOUSE y + else + define_bool CONFIG_RPCMOUSE y + fi + fi fi source drivers/usb/Config.in if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then - bool 'VGA text console' CONFIG_VGA_CONSOLE - fi - bool 'Support Frame buffer devices' CONFIG_FB - source drivers/video/Config.in - endmenu + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then + bool 'VGA text console' CONFIG_VGA_CONSOLE + fi + bool 'Support Frame buffer devices' CONFIG_FB + source drivers/video/Config.in + endmenu fi if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in + source net/Config.in - source net/ax25/Config.in + source net/ax25/Config.in - source net/irda/Config.in + source net/irda/Config.in - mainmenu_option next_comment - comment 'Network device support' + mainmenu_option next_comment + comment 'Network device support' - bool 'Network device support?' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - source drivers/net/Config.in - fi - endmenu + bool 'Network device support?' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + fi + endmenu fi # mainmenu_option next_comment @@ -238,19 +240,19 @@ comment 'SCSI support' tristate 'SCSI support?' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then - source drivers/scsi/Config.in + source drivers/scsi/Config.in fi endmenu if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_PCI" = "y" ]; then - mainmenu_option next_comment - comment 'Sound' - - tristate 'Sound support' CONFIG_SOUND - if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in - fi - endmenu + mainmenu_option next_comment + comment 'Sound' + + tristate 'Sound support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in + fi + endmenu fi source fs/Config.in diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 70cfc07243ee..5a4ecee12b83 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -641,36 +641,9 @@ a20_wait: out #0xf1,al call delay -! well, that went ok, I hope. Now we have to reprogram the interrupts :-( -! we put them right after the intel-reserved hardware interrupts, at -! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really -! messed this up with the original PC, and they haven't been able to -! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, -! which is used for the internal hardware interrupts as well. We just -! have to reprogram the 8259's, and it isn't fun. - - mov al,#0x11 ! initialization sequence - out #0x20,al ! send it to 8259A-1 - call delay - out #0xA0,al ! and to 8259A-2 - call delay - mov al,#0x20 ! start of hardware int's (0x20) - out #0x21,al - call delay - mov al,#0x28 ! start of hardware int's 2 (0x28) - out #0xA1,al - call delay - mov al,#0x04 ! 8259-1 is master - out #0x21,al - call delay - mov al,#0x02 ! 8259-2 is slave - out #0xA1,al - call delay - mov al,#0x01 ! 8086 mode for both - out #0x21,al - call delay - out #0xA1,al - call delay +! well, that went ok, I hope. Now we mask all interrupts - the rest +! is done in init_IRQ(). + mov al,#0xFF ! mask off all interrupts for now out #0xA1,al call delay diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 606a516305c8..bf0e611d8633 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -360,6 +360,7 @@ CONFIG_82C710_MOUSE=y # # Misc devices # +CONFIG_ACPI=y # # Filesystems diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 875f52d5a801..e4cad464f5c7 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -43,7 +43,7 @@ else endif ifdef CONFIG_SMP -O_OBJS += smp.o trampoline.o +O_OBJS += smp.o smpboot.o trampoline.o endif ifdef CONFIG_X86_IO_APIC diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index f0c63c93807d..cee8e7fcd8ca 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -77,6 +77,9 @@ * Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj] * * August 1999 : New resource management and configuration access stuff. [mj] + * + * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges. + * Based on ideas by Chris Frantz and David Hinds. [mj] */ #include @@ -89,6 +92,7 @@ #include #include #include +#include #include #include @@ -112,9 +116,37 @@ #define PCI_NO_CHECKS 0x400 #define PCI_NO_PEER_FIXUP 0x800 #define PCI_ASSIGN_ROMS 0x1000 +#define PCI_NO_IRQ_SCAN 0x2000 static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; +/* + * IRQ routing table provided by the BIOS + */ + +struct irq_info { + u8 bus, devfn; /* Bus, device and function */ + struct { + u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ + u16 bitmap; /* Available IRQs */ + } __attribute__((packed)) irq[4]; + u8 slot; /* Slot number, 0=onboard */ + u8 rfu; +} __attribute__((packed)); + +struct irq_routing_table { + u32 signature; /* PIRQ_SIGNATURE should be here */ + u16 version; /* PIRQ_VERSION */ + u16 size; /* Table size in bytes */ + u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + u32 miniport_data; /* Crap */ + u8 rfu[11]; + u8 checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[0]; +} __attribute__((packed)); + /* * Direct access to PCI hardware... */ @@ -347,6 +379,8 @@ static struct pci_ops * __init pci_check_direct(void) #define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b #define PCIBIOS_WRITE_CONFIG_WORD 0xb10c #define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d +#define PCIBIOS_GET_ROUTING_OPTIONS 0xb10e +#define PCIBIOS_SET_PCI_HW_INT 0xb10f /* BIOS32 signature: "_32_" */ #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) @@ -489,31 +523,6 @@ static int __init check_pcibios(void) return 0; } -#if 0 /* Not used */ - -static int pci_bios_find_class (unsigned int class_code, unsigned short index, - unsigned char *bus, unsigned char *device_fn) -{ - unsigned long bx; - unsigned long ret; - - __asm__ ("lcall (%%edi)\n\t" - "jc 1f\n\t" - "xor %%ah, %%ah\n" - "1:" - : "=b" (bx), - "=a" (ret) - : "1" (PCIBIOS_FIND_PCI_CLASS_CODE), - "c" (class_code), - "S" ((int) index), - "D" (&pci_indirect)); - *bus = (bx >> 8) & 0xff; - *device_fn = bx & 0xff; - return (int) (ret & 0xff00) >> 8; -} - -#endif - static int __init pci_bios_find_device (unsigned short vendor, unsigned short device_id, unsigned short index, unsigned char *bus, unsigned char *device_fn) { @@ -757,85 +766,126 @@ static void __init pcibios_sort(void) *last = NULL; } -#endif - /* - * Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it. + * Ask BIOS for IRQ Routing Table */ -static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx) +struct irq_routing_options { + u16 size; + struct irq_info *table; + u16 segment; +} __attribute__((packed)); + +static unsigned long pcibios_irq_page __initdata = 0; + +static inline void __init pcibios_free_irq_routing_table(void) { - unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx; - struct resource *r = &dev->resource[idx]; - unsigned int size = r->end - r->start + 1; + if (pcibios_irq_page) + free_page(pcibios_irq_page); +} - if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || - (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - /* - * In case the BIOS didn't assign an address 0--3 to an IDE - * controller, we don't try to fix it as it means "use default - * addresses" at least with several broken chips and the IDE - * driver needs the original settings to recognize which devices - * correspond to the primary controller. - * - * We don't assign VGA I/O ranges as well. - */ - return; - } - /* - * We need to avoid collisions with `mirrored' VGA ports and other strange - * ISA hardware, so we always want the addresses kilobyte aligned. - */ - if (!size || size > 256) { - printk(KERN_ERR "PCI: Cannot assign I/O space to device %s, %d bytes are too much.\n", dev->name, size); - return; - } else { - u32 try; +static struct irq_routing_table * __init pcibios_get_irq_routing_table(void) +{ + struct irq_routing_options opt; + struct irq_routing_table *rt; + int ret, map; - r->start = 0; - r->end = size - 1; - if (pci_assign_resource(dev, idx)) { - printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name); - return; - } - printk("PCI: Assigned I/O space %04lx-%04lx to device %s\n", r->start, r->end, dev->name); - pci_read_config_dword(dev, reg, &try); - if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) { - r->start = 0; - pci_write_config_dword(dev, reg, 0); - printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try); - } + if (pci_probe & PCI_NO_IRQ_SCAN) + return NULL; + pcibios_irq_page = __get_free_page(GFP_KERNEL); + if (!pcibios_irq_page) + return 0; + rt = (void *) pcibios_irq_page; + opt.table = rt->slots; + opt.size = PAGE_SIZE - sizeof(struct irq_routing_table); + opt.segment = __KERNEL_DS; + + DBG("PCI: Fetching IRQ routing table... "); + __asm__("push %%es\n\t" + "push %%ds\n\t" + "pop %%es\n\t" + "lcall (%%esi)\n\t" + "pop %%es\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=a" (ret), + "=b" (map) + : "0" (PCIBIOS_GET_ROUTING_OPTIONS), + "1" (0), + "D" ((long) &opt), + "S" (&pci_indirect)); + DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); + if (ret & 0xff00) { + printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff); + return 0; } + + memset(rt, 0, sizeof(struct irq_routing_table)); + rt->size = opt.size + sizeof(struct irq_routing_table); + printk("PCI: Using BIOS Interrupt Routing Table\n"); + return rt; } +#endif + /* - * Assign address to expansion ROM. This is a highly experimental feature - * and you must enable it by "pci=rom". It's even not guaranteed to work - * with all cards since the PCI specs allow address decoders to be shared - * between the ROM space and one of the standard regions (sigh!). + * Assign new address to PCI resource. We hope our resource information + * is complete. On the PC, we don't re-assign resources unless we are + * forced to do so. + * + * Expects start=0, end=size-1, flags=resource type. */ -static void __init pcibios_fixup_rom_addr(struct pci_dev *dev) + +static int __init pcibios_assign_resource(struct pci_dev *dev, int i) { - int reg = (dev->hdr_type == 1) ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS; - struct resource *r = &dev->resource[PCI_ROM_RESOURCE]; - unsigned long rom_size = r->end - r->start + 1; - - r->start = 0; - r->end = rom_size - 1; - if (pci_assign_resource(dev, PCI_ROM_RESOURCE)) - printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n", - dev->name, rom_size); - else { - DBG("PCI: Assigned address %08lx to expansion ROM of %s (0x%lx bytes)\n", r->start, dev->name, rom_size); - pci_write_config_dword(dev, reg, r->start | PCI_ROM_ADDRESS_ENABLE); + struct resource *r = &dev->resource[i]; + struct resource *pr = pci_find_parent_resource(dev, r); + unsigned long size = r->end + 1; + u32 new, check; + + if (!pr) { + printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) { + /* + * We need to avoid collisions with `mirrored' VGA ports and other strange + * ISA hardware, so we always want the addresses kilobyte aligned. + */ + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large (%ld bytes)\n", dev->slot_name, i, size); + return -EFBIG; + } + if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) { + printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); + return -EBUSY; + } + } else { + if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) { + printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size); + return -EBUSY; + } + } + if (i < 6) { + int reg = PCI_BASE_ADDRESS_0 + 4*i; + new = r->start | (r->flags & PCI_REGION_FLAG_MASK); + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if (new != check) + printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check); + } else if (i == PCI_ROM_RESOURCE) { r->flags |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK)); } + printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i); + return 0; } /* * Several buggy motherboards address only 16 devices and mirror * them to next 16 IDs. We try to detect this `feature' on all - * primary busses (those containing host bridges as they are + * primary buses (those containing host bridges as they are * expected to be unique) and remove the ghost devices. */ @@ -868,7 +918,7 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b) } if (!seen_host_bridge) return; - printk("PCI: Ignoring ghost devices on bus %d\n", b->number); + printk("PCI: Ignoring ghost devices on bus %02x\n", b->number); for(e=b->devices; e->sibling != d; e=e->sibling); e->sibling = NULL; for(z=&pci_devices; (d=*z);) @@ -901,8 +951,8 @@ static void __init pcibios_fixup_peer_bridges(void) #ifdef CONFIG_PCI_DIRECT /* * Don't search for peer host bridges if we use config type 2 - * since it reads bogus values for non-existent busses and - * chipsets supporting multiple primary busses use conf1 anyway. + * since it reads bogus values for non-existent buses and + * chipsets supporting multiple primary buses use conf1 anyway. */ if (ops == &pci_direct_conf2) return; @@ -966,7 +1016,7 @@ static void __init pci_fixup_i450nx(struct pci_dev *d) */ int pxb, reg; u8 busno, suba, subb; - printk("PCI: Searching for i450NX host bridges on %s\n", d->name); + printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name); reg = 0xd0; for(pxb=0; pxb<2; pxb++) { pci_read_config_byte(d, reg++, &busno); @@ -989,113 +1039,371 @@ static void __init pci_fixup_umc_ide(struct pci_dev *d) */ int i; - printk("PCI: Fixing base address flags for device %s\n", d->name); + printk("PCI: Fixing base address flags for device %s\n", d->slot_name); for(i=0; i<4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } +static void __init pci_fixup_ide_bases(struct pci_dev *d) +{ + int i; + + /* + * PCI IDE controllers use non-standard I/O port decoding, respect it. + */ + if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) + return; + DBG("PCI: IDE base address fixup for %s\n", d->slot_name); + for(i=0; i<4; i += 2) { + struct resource *r = &d->resource[i]; + if (r->start) { + r->start += 2; + r->end = r->start; + } + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, { 0 } }; /* - * Allocate resources for all PCI devices. We need to do that before - * we try to fix up anything. + * 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. Finally enable the I/O and Memory bits. */ -static void __init pcibios_claim_resources(struct pci_bus *bus) +static void __init pcibios_allocate_bus_resources(struct pci_bus *bus) { struct pci_dev *dev; int idx; + struct resource *r, *pr; + /* Depth-First Search on bus tree */ while (bus) { - for (dev=bus->devices; dev; dev=dev->sibling) - 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? */ - } + if (!pr || request_resource(pr, r) < 0) + printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name); + } } if (bus->children) - pcibios_claim_resources(bus->children); + pcibios_allocate_bus_resources(bus->children); bus = bus->next; } } +static void __init pcibios_allocate_resources(int pass) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r, *pr; + + for(dev=pci_devices; dev; dev=dev->next) { + 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->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->start -= r->end; + r->start = 0; + } + } + } + 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; + u16 cmd, old_cmd; + int idx; + int fault = 0; + struct resource *r; + + for(dev=pci_devices; dev; dev=dev->next) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) || + ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) + /* + * Don't touch IDE controllers and I/O ports of video cards! + * Neither enable anything in their command registers. + */ + continue; + if (!r->start && r->end) { + /* + * 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 (pcibios_assign_resource(dev, idx) < 0) + fault = 1; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + + if (cmd != old_cmd) { + if (fault) + printk("PCI: Not enabling device %s because of resource collisions\n", dev->slot_name); + else { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + } + + if (pci_probe & PCI_ASSIGN_ROMS) { + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pcibios_assign_resource(dev, PCI_ROM_RESOURCE); + } + } +} + +static void __init pcibios_resource_survey(void) +{ + pcibios_allocate_bus_resources(pci_root); + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); + pcibios_assign_resources(); +} + /* - * Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds - * for buggy PCI BIOS'es :-[). + * Fix up IRQs of all PCI devices. */ extern int skip_ioapic_setup; -static void __init pcibios_fixup_devices(void) +#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) +#define PIRQ_VERSION 0x0100 + +/* + * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. + */ + +static struct irq_routing_table * __init pcibios_find_irq_routing_table(void) { - struct pci_dev *dev; - int i, has_io, has_mem; - unsigned short cmd; + u8 *addr; + struct irq_routing_table *rt; + int i; + u8 sum; + + for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { + rt = (struct irq_routing_table *) addr; + if (rt->signature != PIRQ_SIGNATURE || + rt->version != PIRQ_VERSION || + rt->size % 16 || + rt->size < sizeof(struct irq_routing_table)) + continue; + sum = 0; + for(i=0; isize; i++) + sum += addr[i]; + if (!sum) { + printk("PCI: Interrupt Routing Table found at 0x%p [router type %04x/%04x]\n", + rt, rt->rtr_vendor, rt->rtr_device); + return rt; + } + } + return NULL; +} - for(dev = pci_devices; dev; dev=dev->next) { +/* + * If we have a IRQ routing table, use it to search for peer host + * bridges. It's a gross hack, but since there are no other known + * ways how to get a list of buses, we have to go this way. + */ + +static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt) +{ + u8 busmap[256]; + int i; + struct irq_info *e; + + memset(busmap, 0, sizeof(busmap)); + for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) { + e = &rt->slots[i]; + DBG("b=%02x d=%02x s=%02x\n", e->bus, e->devfn, e->slot); + busmap[e->bus] = 1; + } + for(i=1; i<256; i++) /* - * There are buggy BIOSes that forget to enable I/O and memory - * access to PCI devices. We try to fix this, but we need to - * be sure that the BIOS didn't forget to assign an address - * to the device. [mj] + * It might be a secondary bus, but in this case its parent is already + * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ - has_io = has_mem = 0; - for(i=0; i<6; i++) { - struct resource *r = &dev->resource[i]; - if (r->flags & PCI_BASE_ADDRESS_SPACE_IO) { - has_io = 1; - if (!r->start || r->start == PCI_BASE_ADDRESS_IO_MASK) - pcibios_fixup_io_addr(dev, i); - } else if (r->start) - has_mem = 1; - } + if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL)) + printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); + pci_probe |= PCI_NO_PEER_FIXUP; +} + +/* + * In case BIOS forgets to tell us about IRQ, we try to look it up in the routing + * table, but unfortunately we have to know the interrupt router chip. + */ + +static int __init pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin) +{ + struct irq_info *q; + struct pci_dev *router; + int i, pirq, newirq; + u32 rtrid, mask; + u8 x; + + pin--; + DBG("IRQ for %s(%d)", dev->slot_name, pin); + while (dev->bus->self) { + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + dev = dev->bus->self; + DBG(" -> %s(%d)", dev->slot_name, pin); + } + for(q = rt->slots, i = rt->size - sizeof(struct irq_routing_table); + i && (q->bus != dev->bus->number || PCI_SLOT(q->devfn) != PCI_SLOT(dev->devfn)); + i -= sizeof(struct irq_info), q++) + ; + if (!i) { + DBG(" -> not found in routing table\n"); + return 0; + } + pirq = q->irq[pin].link; + mask = q->irq[pin].bitmap; + if (!pirq) { + DBG(" -> not routed\n"); + return 0; + } + DBG(" -> PIRQ %02x, mask %04x", pirq, mask); + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + newirq = 0; + else for(newirq = 15; newirq && !(mask & (1 << newirq)); newirq--) + ; + if (!(router = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) { + DBG(" -> router not found\n"); + return 0; + } +#define ID(x,y) ((x << 16) | y) + rtrid = ID(rt->rtr_vendor, rt->rtr_device); + if (!rtrid) { /* - * Don't enable VGA-compatible cards since they have - * fixed I/O and memory space. - * - * Don't enabled disabled IDE interfaces either because - * some BIOSes may reallocate the same address when they - * find that no devices are attached. + * Several BIOSes forget to set the router type. In such cases, we + * use chip vendor/device. This doesn't guarantee us semantics of + * PIRQ values, but was found to work in practice and it's still + * better than not trying. */ - if (((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) && - ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)) { - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (has_io && !(cmd & PCI_COMMAND_IO)) { - printk("PCI: Enabling I/O for device %s\n", dev->name); - cmd |= PCI_COMMAND_IO; - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { - printk("PCI: Enabling memory for device %s\n", dev->name); - cmd |= PCI_COMMAND_MEMORY; - pci_write_config_word(dev, PCI_COMMAND, cmd); - } + DBG(" [%s]", router->slot_name); + rtrid = ID(router->vendor, router->device); + } + switch (rtrid) { + case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0): + case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0): + case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0): + /* Intel PIIX: PIRQ holds configuration register address */ + pci_read_config_byte(router, pirq, &x); + if (x < 16) { + DBG(" -> [PIIX] %02x\n", x); + return x; + } else if (newirq) { + DBG(" -> [PIIX] set to %02x\n", newirq); + pci_write_config_byte(router, pirq, newirq); + return newirq; } - /* - * Assign address to expansion ROM if requested. - */ - if ((pci_probe & PCI_ASSIGN_ROMS) && dev->resource[PCI_ROM_RESOURCE].end) - pcibios_fixup_rom_addr(dev); + DBG(" -> [PIIX] sink\n"); + return 0; + default: + DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device); + return 0; + } +#undef ID +} + +static void __init pcibios_fixup_irqs(void) +{ + struct irq_routing_table *rtable; + struct pci_dev *dev; + u8 pin; + + rtable = pcibios_find_irq_routing_table(); +#ifdef CONFIG_PCI_BIOS + if (!rtable && pci_bios_present) + rtable = pcibios_get_irq_routing_table(); +#endif + + if (rtable) + pcibios_irq_peer_trick(rtable); + + for(dev=pci_devices; dev; dev=dev->next) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #if defined(CONFIG_X86_IO_APIC) /* - * Recalculate IRQ numbers if we use the I/O APIC + * Recalculate IRQ numbers if we use the I/O APIC. */ if(!skip_ioapic_setup) { int irq; - unsigned char pin; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin) { pin--; /* interrupt pins are numbered starting from 1 */ irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); @@ -1115,14 +1423,24 @@ static void __init pcibios_fixup_devices(void) dev->irq = irq; } } + rtable = NULL; /* Avoid IRQ assignment below */ } #endif /* - * Fix out-of-range IRQ numbers + * Fix out-of-range IRQ numbers and missing IRQs. */ if (dev->irq >= NR_IRQS) dev->irq = 0; + if (pin && !dev->irq && rtable && rtable->version) { + dev->irq = pcibios_lookup_irq(dev, rtable, pin); + if (dev->irq) + printk("PCI: Assigned IRQ %d to device %s\n", dev->irq, dev->slot_name); + } } + +#ifdef CONFIG_PCI_BIOS + pcibios_free_irq_routing_table(); +#endif } /* @@ -1133,6 +1451,7 @@ static void __init pcibios_fixup_devices(void) void __init pcibios_fixup_bus(struct pci_bus *b) { pcibios_fixup_ghosts(b); + pci_read_bridge_bases(b); } /* @@ -1170,10 +1489,10 @@ void __init pcibios_init(void) printk("PCI: Probing PCI hardware\n"); pci_scan_bus(0, ops, NULL); + pcibios_fixup_irqs(); if (!(pci_probe & PCI_NO_PEER_FIXUP)) pcibios_fixup_peer_bridges(); - pcibios_claim_resources(pci_root); - pcibios_fixup_devices(); + pcibios_resource_survey(); #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) @@ -1197,6 +1516,9 @@ char * __init pcibios_setup(char *str) } else if (!strcmp(str, "nosort")) { pci_probe |= PCI_NO_SORT; return NULL; + } else if (!strcmp(str, "noirq")) { + pci_probe |= PCI_NO_IRQ_SCAN; + return NULL; } #endif #ifdef CONFIG_PCI_DIRECT diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 47f23b6b6f55..4b88dda8998f 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -323,9 +323,14 @@ ENTRY(debug) jmp error_code ENTRY(nmi) + pushl %eax + SAVE_ALL + movl %esp,%edx pushl $0 - pushl $ SYMBOL_NAME(do_nmi) - jmp error_code + pushl %edx + call SYMBOL_NAME(do_nmi) + addl $8,%esp + RESTORE_ALL ENTRY(int3) pushl $0 diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index ac854e721832..f1aa50586317 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -243,6 +243,15 @@ is386: pushl %ecx # restore original EFLAGS xorl %eax,%eax lldt %ax cld # gcc2 wants the direction flag cleared at all times +#ifdef __SMP__ + movb ready, %cl + cmpb $1,%cl + je 1f # the first CPU calls start_kernel + # all other CPUs call initialize_secondary + call SYMBOL_NAME(initialize_secondary) + jmp L6 +1: +#endif call SYMBOL_NAME(start_kernel) L6: jmp L6 # main should never return here, but diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 61422f37287c..5f5a6d50b573 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(acpi_idle); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index ce408284840a..3e9097f068a1 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -9,68 +8,23 @@ #include #include #include -#include #include #include +#include #include #include #include #include -#include #include #include #include #include - -/* - * Intel specific no controller code - * odd that no-controller should be architecture dependent - * but see the ifdef __SMP__ - */ - -static void enable_none(unsigned int irq) { } -static unsigned int startup_none(unsigned int irq) { return 0; } -static void disable_none(unsigned int irq) { } -static void ack_none(unsigned int irq) -{ -#ifdef __SMP__ - /* - * [currently unexpected vectors happen only on SMP and APIC. - * if we want to have non-APIC and non-8259A controllers - * in the future with unexpected vectors, this ack should - * probably be made controller-specific.] - */ - ack_APIC_irq(); -#endif -} - -/* startup is the same as "enable", shutdown is same as "disable" */ -#define shutdown_none disable_none -#define end_none enable_none - -struct hw_interrupt_type no_irq_type = { - "none", - startup_none, - shutdown_none, - enable_none, - disable_none, - ack_none, - end_none -}; - - -/* - * This is the 'legacy' 8259A Programmable Interrupt Controller, - * present in the majority of PC/AT boxes. - * plus some generic x86 specific things if generic specifics makes - * any sense at all. - * this file should become arch/i386/kernel/irq.c when the old irq.c - * moves to arch independent land - */ /* + * Common place to define all x86 IRQ vectors + * * This builds up the IRQ handler stubs using some ugly macros in irq.h * * These macros create the low-level assembly IRQ routines that save @@ -79,7 +33,6 @@ struct hw_interrupt_type no_irq_type = { * interrupt-controller happy. */ - BUILD_COMMON_IRQ() #define BI(x,y) \ @@ -93,7 +46,7 @@ BUILD_COMMON_IRQ() /* * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: - * (these are usually mapped to vectors 0x20-0x30) + * (these are usually mapped to vectors 0x20-0x2f) */ BUILD_16_IRQS(0x0) @@ -126,9 +79,9 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) */ BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) -BUILD_SMP_INTERRUPT(stop_cpu_interrupt,STOP_CPU_VECTOR) BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) +BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) /* * every pentium local APIC has two 'local interrupts', with a @@ -150,7 +103,7 @@ BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) -static void (*interrupt[NR_IRQS])(void) = { +void (*interrupt[NR_IRQS])(void) = { IRQLIST_16(0x0), #ifdef CONFIG_X86_IO_APIC @@ -164,17 +117,23 @@ static void (*interrupt[NR_IRQS])(void) = { #undef IRQ #undef IRQLIST_16 +/* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * plus some generic x86 specific things if generic specifics makes + * any sense at all. + * this file should become arch/i386/kernel/irq.c when the old irq.c + * moves to arch independent land + */ - - -static void enable_8259A_irq(unsigned int irq); +void enable_8259A_irq(unsigned int irq); void disable_8259A_irq(unsigned int irq); /* shutdown is same as "disable" */ #define end_8259A_irq enable_8259A_irq #define shutdown_8259A_irq disable_8259A_irq -static void mask_and_ack_8259A(unsigned int); +void mask_and_ack_8259A(unsigned int); static unsigned int startup_8259A_irq(unsigned int irq) { @@ -207,8 +166,8 @@ static unsigned int cached_irq_mask = 0xffff; /* * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) - * boards the timer interrupt is not connected to any IO-APIC pin, it's - * fed to the CPU IRQ line directly. + * boards the timer interrupt is not really connected to any IO-APIC pin, + * it's fed to the master 8259A's IR0 line only. * * Any '1' bit in this mask means the IRQ is routed through the IO-APIC. * this 'mixed mode' IRQ handling costs nothing because it's only used @@ -224,22 +183,20 @@ void disable_8259A_irq(unsigned int irq) { unsigned int mask = 1 << irq; cached_irq_mask |= mask; - if (irq & 8) { + if (irq & 8) outb(cached_A1,0xA1); - } else { + else outb(cached_21,0x21); - } } -static void enable_8259A_irq(unsigned int irq) +void enable_8259A_irq(unsigned int irq) { unsigned int mask = ~(1 << irq); cached_irq_mask &= mask; - if (irq & 8) { + if (irq & 8) outb(cached_A1,0xA1); - } else { + else outb(cached_21,0x21); - } } int i8259A_irq_pending(unsigned int irq) @@ -259,25 +216,140 @@ void make_8259A_irq(unsigned int irq) enable_irq(irq); } +/* + * This function assumes to be called rarely. Switching between + * 8259A registers is slow. + */ +static inline int i8259A_irq_real(unsigned int irq) +{ + int value; + int irqmask = 1<> 8); + outb(0x0A,0xA0); /* back to the IRR register */ + return value; +} + /* * Careful! The 8259A is a fragile beast, it pretty * much _has_ to be done exactly like this (mask it * first, _then_ send the EOI, and the order of EOI * to the two 8259s is important! */ -static void mask_and_ack_8259A(unsigned int irq) +void mask_and_ack_8259A(unsigned int irq) { - cached_irq_mask |= 1 << irq; + unsigned int irqmask = 1 << irq; + + /* + * Lightweight spurious IRQ detection. We do not want + * to overdo spurious IRQ handling - it's usually a sign + * of hardware problems, so we only do the checks we can + * do without slowing down good hardware unnecesserily. + * + * Note that IRQ7 and IRQ15 (the two spurious IRQs + * usually resulting from the 8259A-1|2 PICs) occur + * even if the IRQ is masked in the 8259A. Thus we + * can check spurious 8259A IRQs without doing the + * quite slow i8259A_irq_real() call for every IRQ. + * This does not cover 100% of spurious interrupts, + * but should be enough to warn the user that there + * is something bad going on ... + */ + if (cached_irq_mask & irqmask) + goto spurious_8259A_irq; + cached_irq_mask |= irqmask; + +handle_real_irq: if (irq & 8) { - inb(0xA1); /* DUMMY */ + inb(0xA1); /* DUMMY - (do we need this?) */ outb(cached_A1,0xA1); - outb(0x62,0x20); /* Specific EOI to cascade */ - outb(0x20,0xA0); + outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + outb(0x20,0xA0); /* 'generic EOI' to slave */ } else { - inb(0x21); /* DUMMY */ + inb(0x21); /* DUMMY - (do we need this?) */ outb(cached_21,0x21); - outb(0x20,0x20); + outb(0x20,0x20); /* 'generic EOI' to master */ } + return; + +spurious_8259A_irq: + /* + * this is the slow path - should happen rarely. + */ + if (i8259A_irq_real(irq)) + /* + * oops, the IRQ _is_ in service according to the + * 8259A - not spurious, go handle it. + */ + goto handle_real_irq; + + { + static int spurious_irq_mask = 0; + /* + * At this point we can be sure the IRQ is spurious, + * lets ACK and report it. [once per IRQ] + */ + if (!(spurious_irq_mask & irqmask)) { + printk("spurious 8259A interrupt: IRQ%d.\n", irq); + spurious_irq_mask |= irqmask; + } + irq_err_count++; + /* + * Theoretically we do not have to handle this IRQ, + * but in Linux this does not cause problems and is + * simpler for us. + */ + goto handle_real_irq; + } +} + +void init_8259A(int auto_eoi) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-2 */ + + /* + * outb_p - this has to work on a wide range of PC hardware. + */ + outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ + outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ + outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) + outb_p(0x03, 0x21); /* master does Auto EOI */ + else + outb_p(0x01, 0x21); /* master expects normal EOI */ + + outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ + outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ + outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ + outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode + is to be investigated) */ + + if (auto_eoi) + /* + * in AEOI mode we just have to mask the interrupt + * when acking. + */ + i8259A_irq_type.ack = disable_8259A_irq; + + udelay(100); /* wait for 8259A to initialize */ + + outb(cached_21, 0x21); /* restore master IRQ mask */ + outb(cached_A1, 0xA1); /* restore slave IRQ mask */ + + restore_flags(flags); } #ifndef CONFIG_VISWS @@ -307,7 +379,7 @@ static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; * IRQ2 is cascade interrupt to second interrupt controller */ -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; #endif @@ -315,6 +387,8 @@ void init_ISA_irqs (void) { int i; + init_8259A(0); + for (i = 0; i < NR_IRQS; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; @@ -357,9 +431,9 @@ void __init init_IRQ(void) #ifdef __SMP__ /* - IRQ0 must be given a fixed assignment and initialized - before init_IRQ_SMP. - */ + * IRQ0 must be given a fixed assignment and initialized, + * because it's used before the IO-APIC is set up. + */ set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]); /* @@ -371,17 +445,15 @@ void __init init_IRQ(void) /* IPI for invalidation */ set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); - /* IPI for CPU halt */ - set_intr_gate(STOP_CPU_VECTOR, stop_cpu_interrupt); - /* self generated IPI for local APIC timer */ set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); /* IPI for generic function call */ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); - /* IPI vector for APIC spurious interrupts */ + /* IPI vectors for APIC spurious and error interrupts */ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); + set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); #endif /* @@ -397,13 +469,3 @@ void __init init_IRQ(void) setup_irq(13, &irq13); #endif } - -#ifdef CONFIG_X86_IO_APIC -void __init init_IRQ_SMP(void) -{ - int i; - for (i = 0; i < NR_IRQS ; i++) - if (IO_APIC_VECTOR(i) > 0) - set_intr_gate(IO_APIC_VECTOR(i), interrupt[i]); -} -#endif diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 34e3ff86f6b0..9fb8bcd3a0b7 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1,7 +1,7 @@ /* * Intel IO-APIC support for multi-Pentium hosts. * - * Copyright (C) 1997, 1998 Ingo Molnar, Hajnalka Szabo + * Copyright (C) 1997, 1998, 1999 Ingo Molnar, Hajnalka Szabo * * Many thanks to Stig Venaas for trying out countless experimental * patches and reporting/debugging problems patiently! @@ -18,15 +18,21 @@ #include #include #include +#include #include +#undef __init +#define __init + /* * volatile is justified in this case, IO-APIC register contents * might change spontaneously, GCC should not cache it */ #define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx)) +extern int nmi_watchdog; + /* * The structure of the IO-APIC: */ @@ -59,6 +65,11 @@ int nr_ioapic_registers[MAX_IO_APICS]; enum ioapic_irq_destination_types { dest_Fixed = 0, dest_LowestPrio = 1, + dest_SMI = 2, + dest__reserved_1 = 3, + dest_NMI = 4, + dest_INIT = 5, + dest__reserved_2 = 6, dest_ExtINT = 7 }; @@ -94,14 +105,7 @@ struct IO_APIC_route_entry { * MP-BIOS irq configuration table structures: */ -enum mp_irq_source_types { - mp_INT = 0, - mp_NMI = 1, - mp_SMI = 2, - mp_ExtINT = 3 -}; - -struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */ +struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];/* I/O APIC entries */ int mp_irq_entries = 0; /* # of MP IRQ source entries */ struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* MP IRQ source entries */ @@ -202,16 +206,10 @@ static void name##_IO_APIC_irq(unsigned int irq) \ FINAL; \ } -/* - * We disable IO-APIC IRQs by setting their 'destination CPU mask' to - * zero. Trick by Ramesh Nalluri. - */ -DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */ -DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */ DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ -static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) +void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; @@ -289,7 +287,7 @@ static int __init find_irq_entry(int apic, int pin, int type) for (i = 0; i < mp_irq_entries; i++) if ( (mp_irqs[i].mpc_irqtype == type) && - (mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) && + (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid) && (mp_irqs[i].mpc_dstirq == pin)) return i; @@ -330,7 +328,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) int lbus = mp_irqs[i].mpc_srcbus; for (apic = 0; apic < nr_ioapics; apic++) - if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) + if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic) break; if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) && @@ -589,24 +587,30 @@ static int __init assign_irq_vector(int irq) static int current_vector = IRQ0_TRAP_VECTOR, offset = 0; if (IO_APIC_VECTOR(irq) > 0) return IO_APIC_VECTOR(irq); + if (current_vector == 0xFF) + panic("ran out of interrupt sources!"); +next: current_vector += 8; - if (current_vector > 0xFE) { + if (current_vector == SYSCALL_VECTOR) + goto next; + + if (current_vector > 0xFF) { offset++; current_vector = IRQ0_TRAP_VECTOR + offset; - printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n", - current_vector); } - if (current_vector == SYSCALL_VECTOR) - panic("ran out of interrupt sources!"); IO_APIC_VECTOR(irq) = current_vector; return current_vector; } +extern void (*interrupt[NR_IRQS])(void); +static struct hw_interrupt_type ioapic_level_irq_type; +static struct hw_interrupt_type ioapic_edge_irq_type; + void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; - int apic, pin, idx, irq, first_notcon = 1; + int apic, pin, idx, irq, first_notcon = 1, vector; printk("init IO_APIC IRQs\n"); @@ -621,15 +625,15 @@ void __init setup_IO_APIC_irqs(void) entry.delivery_mode = dest_LowestPrio; entry.dest_mode = 1; /* logical delivery */ entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = 0; /* but no route */ + entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */ idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { - printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin); + printk(" IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); first_notcon = 0; } else - printk(", %d-%d", mp_apics[apic].mpc_apicid, pin); + printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); continue; } @@ -639,17 +643,29 @@ void __init setup_IO_APIC_irqs(void) if (irq_trigger(idx)) { entry.trigger = 1; entry.mask = 1; - entry.dest.logical.logical_dest = 0xff; + entry.dest.logical.logical_dest = APIC_ALL_CPUS; } - irq = pin_2_irq(idx,apic,pin); + irq = pin_2_irq(idx, apic, pin); add_pin_to_irq(irq, apic, pin); if (!apic && !IO_APIC_IRQ(irq)) continue; - entry.vector = assign_irq_vector(irq); + if (IO_APIC_IRQ(irq)) { + vector = assign_irq_vector(irq); + entry.vector = vector; + + if (IO_APIC_irq_trigger(irq)) + irq_desc[irq].handler = &ioapic_level_irq_type; + else + irq_desc[irq].handler = &ioapic_edge_irq_type; + set_intr_gate(vector, interrupt[irq]); + + if (!apic && (irq < 16)) + disable_8259A_irq(irq); + } io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); } @@ -660,34 +676,47 @@ void __init setup_IO_APIC_irqs(void) } /* - * Set up a certain pin as ExtINT delivered interrupt + * Set up the 8259A-master output pin as broadcast to all + * CPUs. */ -void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq) +void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) { struct IO_APIC_route_entry entry; - /* - * add it to the IO-APIC irq-routing table: - */ memset(&entry,0,sizeof(entry)); - entry.delivery_mode = dest_ExtINT; - entry.dest_mode = 0; /* physical delivery */ - entry.mask = 0; /* unmask IRQ now */ - /* - * We use physical delivery to get the timer IRQ - * to the boot CPU. 'boot_cpu_id' is the physical - * APIC ID of the boot CPU. - */ - entry.dest.physical.physical_dest = boot_cpu_id; + disable_8259A_irq(0); - entry.vector = assign_irq_vector(irq); + apic_readaround(APIC_LVT0); + apic_write(APIC_LVT0, 0x00010700); // mask LVT0 + init_8259A(1); + + /* + * We use logical delivery to get the timer IRQ + * to the first CPU. + */ + entry.dest_mode = 1; /* logical delivery */ + entry.mask = 0; /* unmask IRQ now */ + entry.dest.logical.logical_dest = APIC_ALL_CPUS; + entry.delivery_mode = dest_LowestPrio; entry.polarity = 0; entry.trigger = 0; + entry.vector = vector; - io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); - io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); + /* + * The timer IRQ doesnt have to know that behind the + * scene we have a 8259A-master in AEOI mode ... + */ + irq_desc[0].handler = &ioapic_edge_irq_type; + + /* + * Add it to the IO-APIC irq-routing table: + */ + io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); + + enable_8259A_irq(0); } void __init UNEXPECTED_IO_APIC(void) @@ -705,7 +734,7 @@ void __init print_IO_APIC(void) printk("number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) - printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]); + printk("number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); /* * We are a bit conservative about what we expect. We have to @@ -717,8 +746,10 @@ void __init print_IO_APIC(void) *(int *)®_00 = io_apic_read(apic, 0); *(int *)®_01 = io_apic_read(apic, 1); - *(int *)®_02 = io_apic_read(apic, 2); - printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid); + if (reg_01.version >= 0x10) + *(int *)®_02 = io_apic_read(apic, 2); + + printk("\nIO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); printk(".... register #00: %08X\n", *(int *)®_00); printk("....... : physical APIC id: %02X\n", reg_00.ID); if (reg_00.__reserved_1 || reg_00.__reserved_2) @@ -730,12 +761,15 @@ void __init print_IO_APIC(void) (reg_01.entries != 0x17) && /* typical ISA+PCI boards */ (reg_01.entries != 0x1b) && /* Compaq Proliant boards */ (reg_01.entries != 0x1f) && /* dual Xeon boards */ - (reg_01.entries != 0x3F) /* bigger Xeon boards */ + (reg_01.entries != 0x22) && /* bigger Xeon boards */ + (reg_01.entries != 0x2E) && + (reg_01.entries != 0x3F) ) UNEXPECTED_IO_APIC(); printk("....... : IO APIC version: %04X\n", reg_01.version); - if ( (reg_01.version != 0x10) && /* oldest IO-APICs */ + if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */ + (reg_01.version != 0x10) && /* oldest IO-APICs */ (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */ (reg_01.version != 0x13) /* Xeon IO-APICs */ ) @@ -743,10 +777,12 @@ void __init print_IO_APIC(void) if (reg_01.__reserved_1 || reg_01.__reserved_2) UNEXPECTED_IO_APIC(); - printk(".... register #02: %08X\n", *(int *)®_02); - printk("....... : arbitration: %02X\n", reg_02.arbitration); - if (reg_02.__reserved_1 || reg_02.__reserved_2) - UNEXPECTED_IO_APIC(); + if (reg_01.version >= 0x10) { + printk(".... register #02: %08X\n", *(int *)®_02); + printk("....... : arbitration: %02X\n", reg_02.arbitration); + if (reg_02.__reserved_1 || reg_02.__reserved_2) + UNEXPECTED_IO_APIC(); + } printk(".... IRQ redirection table:\n"); @@ -797,8 +833,116 @@ void __init print_IO_APIC(void) return; } +static void print_APIC_bitfield (int base) +{ + unsigned int v; + int i, j; + + printk("0123456789abcdef0123456789abcdef\n"); + for (i = 0; i < 8; i++) { + v = apic_read(base + i*0x10); + for (j = 0; j < 32; j++) { + if (v & (1< 3) { + apic_readaround(APIC_SPIV); // not strictly necessery + apic_write(APIC_ESR, 0); + } + v = apic_read(APIC_ESR); + printk("... APIC ESR: %08x\n", v); + } + + v = apic_read(APIC_ICR); + printk("... APIC ICR: %08x\n", v); + v = apic_read(APIC_ICR2); + printk("... APIC ICR2: %08x\n", v); + + v = apic_read(APIC_LVTT); + printk("... APIC LVTT: %08x\n", v); + + if (maxlvt > 3) { /* PC is LVT#4. */ + v = apic_read(APIC_LVTPC); + printk("... APIC LVTPC: %08x\n", v); + } + v = apic_read(APIC_LVT0); + printk("... APIC LVT0: %08x\n", v); + v = apic_read(APIC_LVT1); + printk("... APIC LVT1: %08x\n", v); + + if (maxlvt > 2) { /* ERR is LVT#3. */ + v = apic_read(APIC_LVTERR); + printk("... APIC LVTERR: %08x\n", v); + } + + v = apic_read(APIC_TMICT); + printk("... APIC TMICT: %08x\n", v); + v = apic_read(APIC_TMCCT); + printk("... APIC TMCCT: %08x\n", v); + v = apic_read(APIC_TDCR); + printk("... APIC TDCR: %08x\n", v); + printk("\n"); +} + +void print_all_local_APICs (void) +{ + smp_call_function(print_local_APIC, NULL, 1, 1); + print_local_APIC(NULL); +} + static void __init init_sym_mode(void) { + struct IO_APIC_reg_01 reg_01; int i; for (i = 0; i < PIN_MAP_SIZE; i++) { @@ -809,24 +953,21 @@ static void __init init_sym_mode(void) for (i = 0; i < MAX_PIRQS; i++) pirq_entries[i] =- 1; - printk("enabling symmetric IO mode... "); - - outb(0x70, 0x22); - outb(0x01, 0x23); - - printk("...done.\n"); + if (pic_mode) { + /* + * PIC mode, enable symmetric IO mode in the IMCR. + */ + printk("leaving PIC mode, enabling symmetric IO mode.\n"); + outb(0x70, 0x22); + outb(0x01, 0x23); + } /* * The number of IO-APIC IRQ registers (== #pins): */ - { - struct IO_APIC_reg_01 reg_01; - int i; - - for (i = 0; i < nr_ioapics; i++) { - *(int *)®_01 = io_apic_read(i, 1); - nr_ioapic_registers[i] = reg_01.entries+1; - } + for (i = 0; i < nr_ioapics; i++) { + *(int *)®_01 = io_apic_read(i, 1); + nr_ioapic_registers[i] = reg_01.entries+1; } /* @@ -835,24 +976,41 @@ static void __init init_sym_mode(void) clear_IO_APIC(); } +static void clear_lapic_ints (void * dummy) +{ + int maxlvt; + + maxlvt = get_maxlvt(); + apic_write_around(APIC_LVTT, 0x00010000); + apic_write_around(APIC_LVT0, 0x00010000); + apic_write_around(APIC_LVT1, 0x00010000); + if (maxlvt >= 3) + apic_write_around(APIC_LVTERR, 0x00010000); + if (maxlvt >= 4) + apic_write_around(APIC_LVTPC, 0x00010000); +} + /* * Not an __init, needed by the reboot code */ void init_pic_mode(void) { /* - * Clear the IO-APIC before rebooting: + * Clear the IO-APIC and local APICs before rebooting: */ clear_IO_APIC(); + smp_call_function(clear_lapic_ints, NULL, 1, 1); + clear_lapic_ints(NULL); /* * Put it back into PIC mode (has an effect only on - * certain boards) + * certain older boards) */ - printk("disabling symmetric IO mode... "); + if (pic_mode) { + printk("disabling symmetric IO mode, entering PIC mode.\n"); outb_p(0x70, 0x22); outb_p(0x00, 0x23); - printk("...done.\n"); + } } static void __init setup_ioapic_id(void) @@ -914,10 +1072,13 @@ static void __init construct_default_ISA_mptable(void) * MP specification 1.4 defines some extra rules for default * configurations, fix them up here: */ - switch (mpc_default_type) { case 2: + /* + * IRQ0 is not connected: + */ + mp_irqs[0].mpc_irqtype = mp_ExtINT; break; default: /* @@ -942,7 +1103,7 @@ static int __init timer_irq_works(void) unsigned int t1 = jiffies; sti(); - mdelay(100); + mdelay(40); if (jiffies-t1>1) return 1; @@ -950,6 +1111,27 @@ static int __init timer_irq_works(void) return 0; } +extern atomic_t nmi_counter[NR_CPUS]; + +static int __init nmi_irq_works(void) +{ + atomic_t tmp[NR_CPUS]; + int j, cpu; + + memcpy(tmp, nmi_counter, sizeof(tmp)); + sti(); + mdelay(50); + + for (j = 0; j < smp_num_cpus; j++) { + cpu = cpu_logical_map(j); + if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) { + printk("CPU#%d NMI appears to be stuck.\n", cpu); + return 0; + } + } + return 1; +} + /* * In the SMP+IOAPIC case it might happen that there are an unspecified * number of pending IRQ events unhandled. These cases are very rare, @@ -964,12 +1146,11 @@ static int __init timer_irq_works(void) */ static void enable_edge_ioapic_irq(unsigned int irq) { - enable_IO_APIC_irq(irq); + unmask_IO_APIC_irq(irq); } static void disable_edge_ioapic_irq(unsigned int irq) { - disable_IO_APIC_irq(irq); } /* @@ -995,8 +1176,17 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) } #define shutdown_edge_ioapic_irq disable_edge_ioapic_irq -void static ack_edge_ioapic_irq(unsigned int i) + +/* + * Once we have recorded IRQ_PENDING already, we can mask the + * interrupt for real. This prevents IRQ storms from unhandled + * devices. + */ +void static ack_edge_ioapic_irq(unsigned int irq) { + if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) + == (IRQ_PENDING | IRQ_DISABLED)) + mask_IO_APIC_irq(irq); ack_APIC_irq(); } void static end_edge_ioapic_irq(unsigned int i){} @@ -1055,7 +1245,8 @@ static struct hw_interrupt_type ioapic_level_irq_type = { static inline void init_IO_APIC_traps(void) { - int i; + int irq; + /* * NOTE! The local APIC isn't very good at handling * multiple interrupts at the same interrupt level. @@ -1067,36 +1258,62 @@ static inline void init_IO_APIC_traps(void) * Also, we've got to be careful not to trash gate * 0x80, because int 0x80 is hm, kind of importantish. ;) */ - for (i = 0; i < NR_IRQS ; i++) { - if (IO_APIC_VECTOR(i) > 0) { - if (IO_APIC_irq_trigger(i)) - irq_desc[i].handler = &ioapic_level_irq_type; - else - irq_desc[i].handler = &ioapic_edge_irq_type; - /* - * disable it in the 8259A: - */ - if (i < 16) - disable_8259A_irq(i); - } else { - if (!IO_APIC_IRQ(i)) - continue; - + for (irq = 0; irq < NR_IRQS ; irq++) { + if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) { /* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 * interrupt if we can.. */ - if (i < 16) { - make_8259A_irq(i); - continue; - } - - /* Strange. Oh, well.. */ - irq_desc[i].handler = &no_irq_type; + if (irq < 16) + make_8259A_irq(irq); + else + /* Strange. Oh, well.. */ + irq_desc[irq].handler = &no_irq_type; } } - init_IRQ_SMP(); +} + +void static ack_lapic_irq (unsigned int irq) +{ + ack_APIC_irq(); +} + +void static end_lapic_irq (unsigned int i) { /* nothing */ } + +static struct hw_interrupt_type lapic_irq_type = { + "local-APIC-edge", + NULL, /* startup_irq() not used for IRQ0 */ + NULL, /* shutdown_irq() not used for IRQ0 */ + NULL, /* enable_irq() not used for IRQ0 */ + NULL, /* disable_irq() not used for IRQ0 */ + ack_lapic_irq, + end_lapic_irq +}; + +static void enable_NMI_through_LVT0 (void * dummy) +{ + apic_readaround(APIC_LVT0); + apic_write(APIC_LVT0, 0x00000400); // unmask and set to NMI +} + +static void setup_nmi (void) +{ + /* + * Dirty trick to enable the NMI watchdog ... + * We put the 8259A master into AEOI mode and + * unmask on all local APICs LVT0 as NMI. + * + * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire') + * is from Maciej W. Rozycki - so we do not have to EOI from + * the NMI handler or the timer interrupt. + */ + printk("activating NMI Watchdog ..."); + + smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1); + enable_NMI_through_LVT0(NULL); + + printk(" done.\n"); } /* @@ -1108,45 +1325,78 @@ static inline void init_IO_APIC_traps(void) static inline void check_timer(void) { int pin1, pin2; + int vector; + + /* + * get/set the timer IRQ vector: + */ + vector = assign_irq_vector(0); + set_intr_gate(vector, interrupt[0]); pin1 = find_timer_pin(mp_INT); pin2 = find_timer_pin(mp_ExtINT); - enable_IO_APIC_irq(0); - if (!timer_irq_works()) { - if (pin1 != -1) - printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); - printk("...trying to set up timer as ExtINT... "); + /* + * Ok, does IRQ0 through the IOAPIC work? + */ + if (timer_irq_works()) { + if (nmi_watchdog) { + disable_8259A_irq(0); + init_8259A(1); + setup_nmi(); + enable_8259A_irq(0); + if (nmi_irq_works()) + return; + } else + return; + } - if (pin2 != -1) { - printk(".. (found pin %d) ...", pin2); - /* - * legacy devices should be connected to IO APIC #0 - */ - setup_ExtINT_pin(0, pin2, 0); - make_8259A_irq(0); + if (pin1 != -1) { + printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); + clear_IO_APIC_pin(0, pin1); + } + + printk("...trying to set up timer (IRQ0) through the 8259A ... "); + if (pin2 != -1) { + printk("\n..... (found pin %d) ...", pin2); + /* + * legacy devices should be connected to IO APIC #0 + */ + setup_ExtINT_IRQ0_pin(pin2, vector); + if (timer_irq_works()) { + printk("works.\n"); + if (nmi_watchdog) { + setup_nmi(); + if (nmi_irq_works()) + return; + } else + return; } + /* + * Cleanup, just in case ... + */ + clear_IO_APIC_pin(0, pin2); + } + printk(" failed.\n"); - if (!timer_irq_works()) { - printk(" failed.\n"); - printk("...trying to set up timer as BP IRQ..."); - /* - * Just in case ... - */ - if (pin1 != -1) - clear_IO_APIC_pin(0, pin1); - if (pin2 != -1) - clear_IO_APIC_pin(0, pin2); + if (nmi_watchdog) + printk("timer doesnt work through the IO-APIC - cannot activate NMI Watchdog!\n"); - make_8259A_irq(0); + printk("...trying to set up timer as Virtual Wire IRQ..."); - if (!timer_irq_works()) { - printk(" failed.\n"); - panic("IO-APIC + timer doesn't work!"); - } - } + disable_8259A_irq(0); + irq_desc[0].handler = &lapic_irq_type; + init_8259A(1); // AEOI mode + apic_readaround(APIC_LVT0); + apic_write(APIC_LVT0, 0x00000000 | vector); // Fixed mode + enable_8259A_irq(0); + + if (timer_irq_works()) { printk(" works.\n"); + return; } + printk(" failed :(.\n"); + panic("IO-APIC + timer doesn't work! pester mingo@redhat.com"); } /* @@ -1189,6 +1439,5 @@ void __init setup_IO_APIC(void) setup_IO_APIC_irqs(); init_IO_APIC_traps(); check_timer(); - print_IO_APIC(); } diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 3106f19669c4..8ec329287122 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -30,14 +29,13 @@ #include #include #include -#include #include #include +#include #include #include #include -#include #include #include #include @@ -48,7 +46,7 @@ unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -atomic_t nmi_counter; +extern atomic_t nmi_counter[NR_CPUS]; /* * Linux has a controller-independent x86 interrupt architecture. @@ -75,7 +73,8 @@ spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; /* * Special irq handlers. @@ -83,6 +82,52 @@ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { 0, &n void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ +#if CONFIG_X86 + printk("unexpected IRQ trap at vector %02x\n", irq); +#ifdef __SMP__ + /* + * Currently unexpected vectors happen only on SMP and APIC. + * We _must_ ack these because every local APIC has only N + * irq slots per priority level, and a 'hanging, unacked' IRQ + * holds up an irq slot - in excessive cases (when multiple + * unexpected vectors occur) that might lock up the APIC + * completely. + */ + ack_APIC_irq(); +#endif +#endif +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +volatile unsigned long irq_err_count; + /* * Generic, controller-independent functions: */ @@ -106,22 +151,30 @@ int get_irq_list(char *buf) #ifndef __SMP__ p += sprintf(p, "%10u ", kstat_irqs(i)); #else - for (j=0; jtypename); p += sprintf(p, " %s", action->name); - for (action=action->next; action; action = action->next) { + for (action=action->next; action; action = action->next) p += sprintf(p, ", %s", action->name); - } *p++ = '\n'; } - p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter)); -#ifdef __SMP__ - p += sprintf(p, "ERR: %10lu\n", ipi_count); -#endif + p += sprintf(p, "NMI: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + atomic_read(nmi_counter+cpu_logical_map(j))); + p += sprintf(p, "\n"); +#if CONFIG_SMP + p += sprintf(p, "LOC: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + apic_timer_irqs[cpu_logical_map(j)]); + p += sprintf(p, "\n"); +#endif + p += sprintf(p, "ERR: %10lu\n", irq_err_count); return p - buf; } @@ -520,7 +573,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) kstat.irqs[cpu][irq]++; desc = irq_desc + irq; spin_lock(&irq_controller_lock); - irq_desc[irq].handler->ack(irq); + desc->handler->ack(irq); /* REPLAY is when Linux resends an IRQ that was dropped earlier WAITING is used by probe to mark irqs that are being tested @@ -570,9 +623,8 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) spin_unlock(&irq_controller_lock); } desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)){ - irq_desc[irq].handler->end(irq); - } + if (!(desc->status & IRQ_DISABLED)) + desc->handler->end(irq); spin_unlock(&irq_controller_lock); /* diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index f44234eb7698..e2253ccca7bb 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -1,1427 +1,108 @@ /* - * Intel MP v1.1/v1.4 specification support routines for multi-pentium - * hosts. + * Intel SMP support routines. * * (c) 1995 Alan Cox, Building #3 - * (c) 1998 Ingo Molnar + * (c) 1998-99 Ingo Molnar * - * Supported by Caldera http://www.caldera.com. - * Much of the core SMP work is based on previous work by Thomas Radke, to - * whom a great many thanks are extended. - * - * Thanks to Intel for making available several different Pentium, - * Pentium Pro and Pentium-II/Xeon MP machines. - * - * This code is released under the GNU public license version 2 or - * later. - * - * Fixes - * Felix Koop : NR_CPUS used properly - * Jose Renau : Handle single CPU case. - * Alan Cox : By repeated request 8) - Total BogoMIP report. - * Greg Wright : Fix for kernel stacks panic. - * Erich Boleyn : MP v1.4 and additional changes. - * Matthias Sattler : Changes for 2.1 kernel map. - * Michel Lespinasse : Changes for 2.1 kernel map. - * Michael Chastain : Change trampoline.S to gnu as. - * Alan Cox : Dumb bug: 'B' step PPro's are fine - * Ingo Molnar : Added APIC timers, based on code - * from Jose Renau - * Alan Cox : Added EBDA scanning - * Ingo Molnar : various cleanups and rewrites - * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define JIFFIE_TIMEOUT 100 - -extern void update_one_process( struct task_struct *p, - unsigned long ticks, unsigned long user, - unsigned long system, int cpu); -/* - * Some notes on processor bugs: - * - * Pentium and Pentium Pro (and all CPUs) have bugs. The Linux issues - * for SMP are handled as follows. - * - * Pentium Pro - * Occasional delivery of 'spurious interrupt' as trap #16. This - * is very rare. The kernel logs the event and recovers - * - * Pentium - * There is a marginal case where REP MOVS on 100MHz SMP - * machines with B stepping processors can fail. XXX should provide - * an L1cache=Writethrough or L1cache=off option. - * - * B stepping CPUs may hang. There are hardware work arounds - * for this. We warn about it in case your board doesnt have the work - * arounds. Basically thats so I can tell anyone with a B stepping - * CPU and SMP problems "tough". - * - * Specific items [From Pentium Processor Specification Update] - * - * 1AP. Linux doesn't use remote read - * 2AP. Linux doesn't trust APIC errors - * 3AP. We work around this - * 4AP. Linux never generated 3 interrupts of the same priority - * to cause a lost local interrupt. - * 5AP. Remote read is never used - * 9AP. XXX NEED TO CHECK WE HANDLE THIS XXX - * 10AP. XXX NEED TO CHECK WE HANDLE THIS XXX - * 11AP. Linux reads the APIC between writes to avoid this, as per - * the documentation. Make sure you preserve this as it affects - * the C stepping chips too. - * - * If this sounds worrying believe me these bugs are ___RARE___ and - * there's about nothing of note with C stepping upwards. - */ - - -/* Kernel spinlock */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - -/* - * function prototypes: - */ -static void cache_APIC_registers (void); -static void stop_this_cpu (void); - -static int smp_b_stepping = 0; /* Set if we find a B stepping CPU */ - -static int max_cpus = -1; /* Setup configured maximum number of CPUs to activate */ -int smp_found_config=0; /* Have we found an SMP box */ - -unsigned long cpu_present_map = 0; /* Bitmask of physically existing CPUs */ -unsigned long cpu_online_map = 0; /* Bitmask of currently online CPUs */ -int smp_num_cpus = 0; /* Total count of live CPUs */ -int smp_threads_ready=0; /* Set when the idlers are all forked */ -volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */ -volatile int __cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */ -static volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */ -static volatile unsigned long cpu_callout_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */ -volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */ -volatile unsigned long kstack_ptr; /* Stack vector for booting CPUs */ -struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per CPU bogomips and other parameters */ -static unsigned int num_processors = 1; /* Internal processor count */ -unsigned long mp_ioapic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */ -unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */ -static int smp_activated = 0; /* Tripped once we need to start cross invalidating */ -int apic_version[NR_CPUS]; /* APIC version number */ -unsigned long apic_retval; /* Just debugging the assembler.. */ - -volatile unsigned long kernel_counter=0; /* Number of times the processor holds the lock */ -volatile unsigned long syscall_count=0; /* Number of times the processor holds the syscall lock */ - -volatile unsigned long ipi_count; /* Number of IPIs delivered */ - -const char lk_lockmsg[] = "lock from interrupt context at %p\n"; - -int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; -extern int nr_ioapics; -extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS]; -extern int mp_irq_entries; -extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; -extern int mpc_default_type; -int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; -int mp_current_pci_id = 0; -unsigned long mp_lapic_addr = 0; -int skip_ioapic_setup = 0; /* 1 if "noapic" boot option passed */ - -/* #define SMP_DEBUG */ - -#ifdef SMP_DEBUG -#define SMP_PRINTK(x) printk x -#else -#define SMP_PRINTK(x) -#endif - -/* - * IA s/w dev Vol 3, Section 7.4 - */ -#define APIC_DEFAULT_PHYS_BASE 0xfee00000 - -#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000) - -/* - * Setup routine for controlling SMP activation - * - * Command-line option of "nosmp" or "maxcpus=0" will disable SMP - * activation entirely (the MPS table probe still happens, though). - * - * Command-line option of "maxcpus=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . - */ - -static int __init nosmp(char *str) -{ - max_cpus = 0; - return 1; -} - -__setup("nosmp", nosmp); - -static int __init maxcpus(char *str) -{ - get_option(&str, &max_cpus); - return 1; -} - -__setup("maxcpus=", maxcpus); - -void ack_APIC_irq(void) -{ - /* Clear the IPI */ - - /* Dummy read */ - apic_read(APIC_SPIV); - - /* Docs say use 0 for future compatibility */ - apic_write(APIC_EOI, 0); -} - -/* - * Intel MP BIOS table parsing routines: - */ - -#ifndef CONFIG_X86_VISWS_APIC -/* - * Checksum an MP configuration block. - */ - -static int mpf_checksum(unsigned char *mp, int len) -{ - int sum=0; - while(len--) - sum+=*mp++; - return sum&0xFF; -} - -/* - * Processor encoding in an MP configuration block - */ - -static char *mpc_family(int family,int model) -{ - static char n[32]; - static char *model_defs[]= - { - "80486DX","80486DX", - "80486SX","80486DX/2 or 80487", - "80486SL","Intel5X2(tm)", - "Unknown","Unknown", - "80486DX/4" - }; - if (family==0x6) - return("Pentium(tm) Pro"); - if (family==0x5) - return("Pentium(tm)"); - if (family==0x0F && model==0x0F) - return("Special controller"); - if (family==0x04 && model<9) - return model_defs[model]; - sprintf(n,"Unknown CPU [%d:%d]",family, model); - return n; -} - - -/* - * Read the MPC - */ - -static int __init smp_read_mpc(struct mp_config_table *mpc) -{ - char str[16]; - int count=sizeof(*mpc); - int ioapics = 0; - unsigned char *mpt=((unsigned char *)mpc)+count; - - if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) - { - panic("SMP mptable: bad signature [%c%c%c%c]!\n", - mpc->mpc_signature[0], - mpc->mpc_signature[1], - mpc->mpc_signature[2], - mpc->mpc_signature[3]); - return 1; - } - if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) - { - panic("SMP mptable: checksum error!\n"); - return 1; - } - if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) - { - printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec); - return 1; - } - memcpy(str,mpc->mpc_oem,8); - str[8]=0; - printk("OEM ID: %s ",str); - - memcpy(str,mpc->mpc_productid,12); - str[12]=0; - printk("Product ID: %s ",str); - - printk("APIC at: 0x%lX\n",mpc->mpc_lapic); - - /* save the local APIC address, it might be non-default */ - mp_lapic_addr = mpc->mpc_lapic; - - /* - * Now process the configuration blocks. - */ - - while(countmpc_length) - { - switch(*mpt) - { - case MP_PROCESSOR: - { - struct mpc_config_processor *m= - (struct mpc_config_processor *)mpt; - if (m->mpc_cpuflag&CPU_ENABLED) - { - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family((m->mpc_cpufeature& - CPU_FAMILY_MASK)>>8, - (m->mpc_cpufeature& - CPU_MODEL_MASK)>>4), - m->mpc_apicver); -#ifdef SMP_DEBUG - if (m->mpc_featureflag&(1<<0)) - printk(" Floating point unit present.\n"); - if (m->mpc_featureflag&(1<<7)) - printk(" Machine Exception supported.\n"); - if (m->mpc_featureflag&(1<<8)) - printk(" 64 bit compare & exchange supported.\n"); - if (m->mpc_featureflag&(1<<9)) - printk(" Internal APIC present.\n"); -#endif - if (m->mpc_cpuflag&CPU_BOOTPROCESSOR) - { - SMP_PRINTK((" Bootup CPU\n")); - boot_cpu_id=m->mpc_apicid; - } - else /* Boot CPU already counted */ - num_processors++; - - if (m->mpc_apicid>NR_CPUS) - printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS); - else - { - int ver = m->mpc_apicver; - - cpu_present_map|=(1<mpc_apicid); - /* - * Validate version - */ - if (ver == 0x0) { - printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); - ver = 0x10; - } - apic_version[m->mpc_apicid] = ver; - } - } - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - case MP_BUS: - { - struct mpc_config_bus *m= - (struct mpc_config_bus *)mpt; - memcpy(str,m->mpc_bustype,6); - str[6]=0; - SMP_PRINTK(("Bus #%d is %s\n", - m->mpc_busid, - str)); - if (strncmp(m->mpc_bustype,"ISA",3) == 0) - mp_bus_id_to_type[m->mpc_busid] = - MP_BUS_ISA; - else - if (strncmp(m->mpc_bustype,"EISA",4) == 0) - mp_bus_id_to_type[m->mpc_busid] = - MP_BUS_EISA; - if (strncmp(m->mpc_bustype,"PCI",3) == 0) { - mp_bus_id_to_type[m->mpc_busid] = - MP_BUS_PCI; - mp_bus_id_to_pci_bus[m->mpc_busid] = - mp_current_pci_id; - mp_current_pci_id++; - } - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - case MP_IOAPIC: - { - struct mpc_config_ioapic *m= - (struct mpc_config_ioapic *)mpt; - if (m->mpc_flags&MPC_APIC_USABLE) - { - ioapics++; - printk("I/O APIC #%d Version %d at 0x%lX.\n", - m->mpc_apicid,m->mpc_apicver, - m->mpc_apicaddr); - mp_apics [nr_ioapics] = *m; - if (++nr_ioapics > MAX_IO_APICS) - --nr_ioapics; - } - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - case MP_INTSRC: - { - struct mpc_config_intsrc *m= - (struct mpc_config_intsrc *)mpt; - - mp_irqs [mp_irq_entries] = *m; - if (++mp_irq_entries == MAX_IRQ_SOURCES) { - printk("Max irq sources exceeded!!\n"); - printk("Skipping remaining sources.\n"); - --mp_irq_entries; - } - - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - case MP_LINTSRC: - { - struct mpc_config_intlocal *m= - (struct mpc_config_intlocal *)mpt; - mpt+=sizeof(*m); - count+=sizeof(*m); - break; - } - } - } - if (ioapics > MAX_IO_APICS) - { - printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics); - printk("Warning: switching to non APIC mode.\n"); - skip_ioapic_setup=1; - } - return num_processors; -} - -/* - * Scan the memory blocks for an SMP configuration block. - */ - -static int __init smp_scan_config(unsigned long base, unsigned long length) -{ - unsigned long *bp=phys_to_virt(base); - struct intel_mp_floating *mpf; - - SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n", - bp,length)); - if (sizeof(*mpf)!=16) - printk("Error: MPF size\n"); - - while (length>0) - { - if (*bp==SMP_MAGIC_IDENT) - { - mpf=(struct intel_mp_floating *)bp; - if (mpf->mpf_length==1 && - !mpf_checksum((unsigned char *)bp,16) && - (mpf->mpf_specification == 1 - || mpf->mpf_specification == 4) ) - { - printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); - if (mpf->mpf_feature2&(1<<7)) - printk(" IMCR and PIC compatibility mode.\n"); - else - printk(" Virtual Wire compatibility mode.\n"); - smp_found_config=1; - /* - * Now see if we need to read further. - */ - if (mpf->mpf_feature1!=0) - { - unsigned long cfg; - - /* local APIC has default address */ - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; - /* - * We need to know what the local - * APIC id of the boot CPU is! - */ - -/* - * - * HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK - * - * It's not just a crazy hack. ;-) - */ - /* - * Standard page mapping - * functions don't work yet. - * We know that page 0 is not - * used. Steal it for now! - */ - - cfg=pg0[0]; - pg0[0] = (mp_lapic_addr | _PAGE_RW | _PAGE_PRESENT); - local_flush_tlb(); - - boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID)); - - /* - * Give it back - */ - - pg0[0]= cfg; - local_flush_tlb(); - -/* - * - * END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK - * - */ - /* - * 2 CPUs, numbered 0 & 1. - */ - cpu_present_map=3; - num_processors=2; - printk("I/O APIC at 0xFEC00000.\n"); - - /* - * Save the default type number, we - * need it later to set the IO-APIC - * up properly: - */ - mpc_default_type = mpf->mpf_feature1; - - printk("Bus #0 is "); - } - switch(mpf->mpf_feature1) - { - case 1: - case 5: - printk("ISA\n"); - break; - case 2: - printk("EISA with no IRQ8 chaining\n"); - break; - case 6: - case 3: - printk("EISA\n"); - break; - case 4: - case 7: - printk("MCA\n"); - break; - case 0: - break; - default: - printk("???\nUnknown standard configuration %d\n", - mpf->mpf_feature1); - return 1; - } - if (mpf->mpf_feature1>4) - { - printk("Bus #1 is PCI\n"); - - /* - * Set local APIC version to - * the integrated form. - * It's initialized to zero - * otherwise, representing - * a discrete 82489DX. - */ - apic_version[0] = 0x10; - apic_version[1] = 0x10; - } - /* - * Read the physical hardware table. - * Anything here will override the - * defaults. - */ - if (mpf->mpf_physptr) - smp_read_mpc((void *)mpf->mpf_physptr); - - __cpu_logical_map[0] = boot_cpu_id; - global_irq_holder = boot_cpu_id; - current->processor = boot_cpu_id; - - printk("Processors: %d\n", num_processors); - /* - * Only use the first configuration found. - */ - return 1; - } - } - bp+=4; - length-=16; - } - - return 0; -} - -void __init init_intel_smp (void) -{ - /* - * FIXME: Linux assumes you have 640K of base ram.. - * this continues the error... - * - * 1) Scan the bottom 1K for a signature - * 2) Scan the top 1K of base RAM - * 3) Scan the 64K of bios - */ - if (!smp_scan_config(0x0,0x400) && - !smp_scan_config(639*0x400,0x400) && - !smp_scan_config(0xF0000,0x10000)) { - /* - * If it is an SMP machine we should know now, unless the - * configuration is in an EISA/MCA bus machine with an - * extended bios data area. - * - * there is a real-mode segmented pointer pointing to the - * 4K EBDA area at 0x40E, calculate and scan it here. - * - * NOTE! There are Linux loaders that will corrupt the EBDA - * area, and as such this kind of SMP config may be less - * trustworthy, simply because the SMP table may have been - * stomped on during early boot. These loaders are buggy and - * should be fixed. - */ - unsigned int address; - - address = *(unsigned short *)phys_to_virt(0x40E); - address<<=4; - smp_scan_config(address, 0x1000); - if (smp_found_config) - printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n"); - } -} - -#else - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesnt have a BIOS(-configuration table). - * No problem for Linux. - */ -void __init init_visws_smp(void) -{ - smp_found_config = 1; - - cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -#endif - -/* - * - Intel MP Configuration Table - * - or SGI Visual Workstation configuration - */ -void __init init_smp_config (void) -{ -#ifndef CONFIG_VISWS - init_intel_smp(); -#else - init_visws_smp(); -#endif -} - - - -/* - * Trampoline 80x86 program as an array. - */ - -extern unsigned char trampoline_data []; -extern unsigned char trampoline_end []; -static unsigned char *trampoline_base; - -/* - * Currently trivial. Write the real->protected mode - * bootstrap into the page concerned. The caller - * has made sure it's suitably aligned. - */ - -static unsigned long __init setup_trampoline(void) -{ - memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); - return virt_to_phys(trampoline_base); -} - -/* - * We are called very early to get the low memory for the - * SMP bootup trampoline page. - */ -unsigned long __init smp_alloc_memory(unsigned long mem_base) -{ - if (virt_to_phys((void *)mem_base) >= 0x9F000) - panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base); - trampoline_base = (void *)mem_base; - return mem_base + PAGE_SIZE; -} - -/* - * The bootstrap kernel entry code has set these up. Save them for - * a given CPU - */ - -void __init smp_store_cpu_info(int id) -{ - struct cpuinfo_x86 *c=&cpu_data[id]; - - *c = boot_cpu_data; - c->pte_quick = 0; - c->pgd_quick = 0; - c->pgtable_cache_sz = 0; - identify_cpu(c); - /* - * Mask B, Pentium, but not Pentium MMX - */ - if (c->x86_vendor == X86_VENDOR_INTEL && - c->x86 == 5 && - c->x86_mask >= 1 && c->x86_mask <= 4 && - c->x86_model <= 3) - smp_b_stepping=1; /* Remember we have B step Pentia with bugs */ -} - -/* - * Architecture specific routine called by the kernel just before init is - * fired off. This allows the BP to have everything in order [we hope]. - * At the end of this all the APs will hit the system scheduling and off - * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over - * and give them jobs to do. smp_callin is a standard routine - * we use to track CPUs as they power up. - */ - -static atomic_t smp_commenced = ATOMIC_INIT(0); - -void __init smp_commence(void) -{ - /* - * Lets the callins below out of their loop. - */ - SMP_PRINTK(("Setting commenced=1, go go go\n")); - - wmb(); - atomic_set(&smp_commenced,1); -} - -void __init enable_local_APIC(void) -{ - unsigned long value; - - value = apic_read(APIC_SPIV); - value |= (1<<8); /* Enable APIC (bit==1) */ -#if 0 - value &= ~(1<<9); /* Enable focus processor (bit==0) */ -#else - value |= (1<<9); /* Disable focus processor (bit==1) */ -#endif - value |= 0xff; /* Set spurious IRQ vector to 0xff */ - apic_write(APIC_SPIV,value); - - /* - * Set Task Priority to 'accept all' - */ - value = apic_read(APIC_TASKPRI); - value &= ~APIC_TPRI_MASK; - apic_write(APIC_TASKPRI,value); - - /* - * Clear the logical destination ID, just to be safe. - * also, put the APIC into flat delivery mode. - */ - value = apic_read(APIC_LDR); - value &= ~APIC_LDR_MASK; - apic_write(APIC_LDR,value); - - value = apic_read(APIC_DFR); - value |= SET_APIC_DFR(0xf); - apic_write(APIC_DFR, value); - - udelay(100); /* B safe */ -} - -unsigned long __init init_smp_mappings(unsigned long memory_start) -{ - unsigned long apic_phys; - - memory_start = PAGE_ALIGN(memory_start); - if (smp_found_config) { - apic_phys = mp_lapic_addr; - } else { - /* - * set up a fake all zeroes page to simulate the - * local APIC and another one for the IO-APIC. We - * could use the real zero-page, but it's safer - * this way if some buggy code writes to this page ... - */ - apic_phys = __pa(memory_start); - memset((void *)memory_start, 0, PAGE_SIZE); - memory_start += PAGE_SIZE; - } - set_fixmap(FIX_APIC_BASE,apic_phys); - printk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); - -#ifdef CONFIG_X86_IO_APIC - { - unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; - int i; - - for (i = 0; i < nr_ioapics; i++) { - if (smp_found_config) { - ioapic_phys = mp_apics[i].mpc_apicaddr; - } else { - ioapic_phys = __pa(memory_start); - memset((void *)memory_start, 0, PAGE_SIZE); - memory_start += PAGE_SIZE; - } - set_fixmap(idx,ioapic_phys); - printk("mapped IOAPIC to %08lx (%08lx)\n", - __fix_to_virt(idx), ioapic_phys); - idx++; - } - } -#endif - - return memory_start; -} - -extern void calibrate_delay(void); - -void __init smp_callin(void) -{ - int cpuid; - unsigned long timeout; - - /* - * (This works even if the APIC is not enabled.) - */ - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - SMP_PRINTK(("CPU#%d waiting for CALLOUT\n", cpuid)); - - /* - * STARTUP IPIs are fragile beasts as they might sometimes - * trigger some glue motherboard logic. Complete APIC bus - * silence for 1 second, this overestimates the time the - * boot CPU is spending to send the up to 2 STARTUP IPIs - * by a factor of two. This should be enough. - */ - - /* - * Waiting 2s total for startup (udelay is not yet working) - */ - timeout = jiffies + 2*HZ; - while (time_before(jiffies,timeout)) - { - /* - * Has the boot CPU finished it's STARTUP sequence? - */ - if (test_bit(cpuid, (unsigned long *)&cpu_callout_map[0])) - break; - } - - while (!time_before(jiffies,timeout)) { - printk("BUG: CPU%d started up but did not get a callout!\n", - cpuid); - stop_this_cpu(); - } - - /* - * the boot CPU has finished the init stage and is spinning - * on callin_map until we finish. We are free to set up this - * CPU, first the APIC. (this is probably redundant on most - * boards) - */ - - SMP_PRINTK(("CALLIN, before enable_local_APIC().\n")); - enable_local_APIC(); - - /* - * Set up our APIC timer. - */ - setup_APIC_clock(); - - __sti(); - -#ifdef CONFIG_MTRR - /* Must be done before calibration delay is computed */ - mtrr_init_secondary_cpu (); -#endif - /* - * Get our bogomips. - */ - calibrate_delay(); - SMP_PRINTK(("Stack at about %p\n",&cpuid)); - - /* - * Save our processor parameters - */ - smp_store_cpu_info(cpuid); - - /* - * Allow the master to continue. - */ - set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]); -} - -int cpucount = 0; - -extern int cpu_idle(void); - -/* - * Activate a secondary processor. - */ -int __init start_secondary(void *unused) -{ - /* - * Dont put anything before smp_callin(), SMP - * booting is too fragile that we want to limit the - * things done here to the most necessary things. - */ - cpu_init(); - smp_callin(); - while (!atomic_read(&smp_commenced)) - /* nothing */ ; - return cpu_idle(); -} - -/* - * Everything has been set up for the secondary - * CPUs - they just need to reload everything - * from the task structure - * This function must not return. - */ -void __init initialize_secondary(void) -{ - /* - * We don't actually need to load the full TSS, - * basically just the stack pointer and the eip. - */ - - asm volatile( - "movl %0,%%esp\n\t" - "jmp *%1" - : - :"r" (current->thread.esp),"r" (current->thread.eip)); -} - -extern struct { - void * esp; - unsigned short ss; -} stack_start; - -static int __init fork_by_hand(void) -{ - struct pt_regs regs; - /* don't care about the eip and regs settings since we'll never - reschedule the forked task. */ - return do_fork(CLONE_VM|CLONE_PID, 0, ®s); -} - -static void __init do_boot_cpu(int i) -{ - unsigned long cfg; - pgd_t maincfg; - struct task_struct *idle; - unsigned long send_status, accept_status; - int timeout, num_starts, j; - unsigned long start_eip; - - cpucount++; - /* We can't use kernel_thread since we must _avoid_ to reschedule - the child. */ - if (fork_by_hand() < 0) - panic("failed fork for CPU %d", i); - - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ - idle = init_task.prev_task; - if (!idle) - panic("No idle process for CPU %d", i); - - idle->processor = i; - __cpu_logical_map[cpucount] = i; - cpu_number_map[i] = cpucount; - idle->has_cpu = 1; /* we schedule the first task manually */ - idle->thread.eip = (unsigned long) start_secondary; - - del_from_runqueue(idle); - unhash_process(idle); - init_tasks[cpucount] = idle; - - /* start_eip had better be page-aligned! */ - start_eip = setup_trampoline(); - - printk("Booting processor %d eip %lx\n", i, start_eip); /* So we see what's up */ - stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); - - /* - * This grunge runs the startup process for - * the targeted processor. - */ - - SMP_PRINTK(("Setting warm reset code and vector.\n")); - - CMOS_WRITE(0xa, 0xf); - local_flush_tlb(); - SMP_PRINTK(("1.\n")); - *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; - SMP_PRINTK(("2.\n")); - *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; - SMP_PRINTK(("3.\n")); - - maincfg=swapper_pg_dir[0]; - ((unsigned long *)swapper_pg_dir)[0]=0x102007; - - /* - * Be paranoid about clearing APIC errors. - */ - - if ( apic_version[i] & 0xF0 ) - { - apic_write(APIC_ESR, 0); - accept_status = (apic_read(APIC_ESR) & 0xEF); - } - - /* - * Status is now clean - */ - - send_status = 0; - accept_status = 0; - - /* - * Starting actual IPI sequence... - */ - - SMP_PRINTK(("Asserting INIT.\n")); - - /* - * Turn INIT on - */ - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); /* Send IPI */ - - udelay(200); - SMP_PRINTK(("Deasserting INIT.\n")); - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT); - apic_write(APIC_ICR, cfg); /* Send IPI */ - - /* - * Should we send STARTUP IPIs ? - * - * Determine this based on the APIC version. - * If we don't have an integrated APIC, don't - * send the STARTUP IPIs. - */ - - if ( apic_version[i] & 0xF0 ) - num_starts = 2; - else - num_starts = 0; - - /* - * Run STARTUP IPI loop. - */ - - for (j = 1; !(send_status || accept_status) - && (j <= num_starts) ; j++) - { - SMP_PRINTK(("Sending STARTUP #%d.\n",j)); - apic_write(APIC_ESR, 0); - SMP_PRINTK(("After apic_write.\n")); - - /* - * STARTUP IPI - */ - - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xCDFFF; /* Clear bits */ - cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12)); /* Boot on the stack */ - SMP_PRINTK(("Before start apic_write.\n")); - apic_write(APIC_ICR, cfg); /* Kick the second */ - - SMP_PRINTK(("Startup point 1.\n")); - - timeout = 0; - SMP_PRINTK(("Waiting for send to finish...\n")); - do { - SMP_PRINTK(("+")); - udelay(100); - send_status = apic_read(APIC_ICR) & 0x1000; - } while (send_status && (timeout++ < 1000)); - - /* - * Give the other CPU some time to accept the IPI. - */ - udelay(200); - accept_status = (apic_read(APIC_ESR) & 0xEF); - } - SMP_PRINTK(("After Startup.\n")); - - if (send_status) /* APIC never delivered?? */ - printk("APIC never delivered???\n"); - if (accept_status) /* Send accept error */ - printk("APIC delivery error (%lx).\n", accept_status); - - if ( !(send_status || accept_status) ) - { - /* - * allow APs to start initializing. - */ - SMP_PRINTK(("Before Callout %d.\n", i)); - set_bit(i, (unsigned long *)&cpu_callout_map[0]); - SMP_PRINTK(("After Callout %d.\n", i)); - - for(timeout=0;timeout<50000;timeout++) - { - if (cpu_callin_map[0]&(1< +#include - printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", - (long)cacheflush_time/(cpu_hz/1000000), - ((long)cacheflush_time*100/(cpu_hz/1000000)) % 100); -} +#include +#include +#include +#include -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_old_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; +#include +#include +#include /* - * Cycle through the processors sending APIC IPIs to boot each. + * Some notes on processor bugs: + * + * Pentium, Pentium Pro, II, III (and all CPUs) have bugs. + * The Linux implications for SMP are handled as follows: + * + * Pentium III / [Xeon] + * None of the E1AP-E3AP erratas are visible to the user. + * + * E1AP. see PII A1AP + * E2AP. see PII A2AP + * E3AP. see PII A3AP + * + * Pentium II / [Xeon] + * None of the A1AP-A3AP erratas are visible to the user. + * + * A1AP. see PPro 1AP + * A2AP. see PPro 2AP + * A3AP. see PPro 7AP + * + * Pentium Pro + * None of 1AP-9AP erratas are visible to the normal user, + * except occasional delivery of 'spurious interrupt' as trap #15. + * This is very rare and a non-problem. + * + * 1AP. Linux maps APIC as non-cacheable + * 2AP. worked around in hardware + * 3AP. fixed in C0 and above steppings microcode update. + * Linux does not use excessive STARTUP_IPIs. + * 4AP. worked around in hardware + * 5AP. symmetric IO mode (normal Linux operation) not affected. + * 'noapic' mode has vector 0xf filled out properly. + * 6AP. 'noapic' mode might be affected - fixed in later steppings + * 7AP. We do not assume writes to the LVT deassering IRQs + * 8AP. We do not enable low power mode (deep sleep) during MP bootup + * 9AP. We do not use mixed mode + * + * Pentium + * There is a marginal case where REP MOVS on 100MHz SMP + * machines with B stepping processors can fail. XXX should provide + * an L1cache=Writethrough or L1cache=off option. + * + * B stepping CPUs may hang. There are hardware work arounds + * for this. We warn about it in case your board doesnt have the work + * arounds. Basically thats so I can tell anyone with a B stepping + * CPU and SMP problems "tough". + * + * Specific items [From Pentium Processor Specification Update] + * + * 1AP. Linux doesn't use remote read + * 2AP. Linux doesn't trust APIC errors + * 3AP. We work around this + * 4AP. Linux never generated 3 interrupts of the same priority + * to cause a lost local interrupt. + * 5AP. Remote read is never used + * 6AP. not affected - worked around in hardware + * 7AP. not affected - worked around in hardware + * 8AP. worked around in hardware - we get explicit CS errors if not + * 9AP. only 'noapic' mode affected. Might generate spurious + * interrupts, we log only the first one and count the + * rest silently. + * 10AP. not affected - worked around in hardware + * 11AP. Linux reads the APIC between writes to avoid this, as per + * the documentation. Make sure you preserve this as it affects + * the C stepping chips too. + * 12AP. not affected - worked around in hardware + * 13AP. not affected - worked around in hardware + * 14AP. we always deassert INIT during bootup + * 15AP. not affected - worked around in hardware + * 16AP. not affected - worked around in hardware + * 17AP. not affected - worked around in hardware + * 18AP. not affected - worked around in hardware + * 19AP. not affected - worked around in BIOS + * + * If this sounds worrying believe me these bugs are either ___RARE___, + * or are signal timing bugs worked around in hardware and there's + * about nothing of note with C stepping upwards. */ -void __init smp_boot_cpus(void) -{ - int i; - -#ifdef CONFIG_MTRR - /* Must be done before other processors booted */ - mtrr_init_boot_cpu (); -#endif - /* - * Initialize the logical to physical CPU number mapping - * and the per-CPU profiling counter/multiplier - */ - - for (i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - prof_counter[i] = 1; - prof_old_multiplier[i] = 1; - prof_multiplier[i] = 1; - } - - /* - * Setup boot CPU information - */ - - smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */ - smp_tune_scheduling(); - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); - - /* - * not necessary because the MP table should list the boot - * CPU too, but we do it for the sake of robustness anyway. - * (and for the case when a non-SMP board boots an SMP kernel) - */ - cpu_present_map |= (1 << hard_smp_processor_id()); - - cpu_number_map[boot_cpu_id] = 0; - - init_idle(); - - /* - * If we couldnt find an SMP configuration at boot time, - * get out of here now! - */ - - if (!smp_found_config) - { - printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif - cpu_online_map = cpu_present_map; - smp_num_cpus = 1; - goto smp_done; - } - - /* - * If SMP should be disabled, then really disable it! - */ - - if (!max_cpus) - { - smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); - } - -#ifdef SMP_DEBUG - { - int reg; - - /* - * This is to verify that we're looking at - * a real local APIC. Check these against - * your board if the CPUs aren't getting - * started for no apparent reason. - */ - - reg = apic_read(APIC_VERSION); - SMP_PRINTK(("Getting VERSION: %x\n", reg)); - - apic_write(APIC_VERSION, 0); - reg = apic_read(APIC_VERSION); - SMP_PRINTK(("Getting VERSION: %x\n", reg)); - - /* - * The two version reads above should print the same - * NON-ZERO!!! numbers. If the second one is zero, - * there is a problem with the APIC write/read - * definitions. - * - * The next two are just to see if we have sane values. - * They're only really relevant if we're in Virtual Wire - * compatibility mode, but most boxes are anymore. - */ - - - reg = apic_read(APIC_LVT0); - SMP_PRINTK(("Getting LVT0: %x\n", reg)); - - reg = apic_read(APIC_LVT1); - SMP_PRINTK(("Getting LVT1: %x\n", reg)); - } -#endif - - enable_local_APIC(); - - /* - * Set up our local APIC timer: - */ - setup_APIC_clock (); - - /* - * Now scan the CPU present map and fire up the other CPUs. - */ - - /* - * Add all detected CPUs. (later on we can down individual - * CPUs which will change cpu_online_map but not necessarily - * cpu_present_map. We are pretty much ready for hot-swap CPUs.) - */ - cpu_online_map = cpu_present_map; - mb(); - - SMP_PRINTK(("CPU map: %lx\n", cpu_present_map)); - - for(i=0;i cpucount+1)) - { - do_boot_cpu(i); - } - - /* - * Make sure we unmap all failed CPUs - */ - - if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) { - printk("CPU #%d not responding. Removing from cpu_online_map.\n",i); - cpu_online_map &= ~(1 << i); - } - } - - /* - * Cleanup possible dangling ends... - */ - -#ifndef CONFIG_VISWS - { - unsigned long cfg; - - /* - * Install writable page 0 entry. - */ - cfg = pg0[0]; - pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* writeable, present, addr 0 */ - local_flush_tlb(); - - /* - * Paranoid: Set warm reset code and vector here back - * to default values. - */ - - CMOS_WRITE(0, 0xf); - - *((volatile long *) phys_to_virt(0x467)) = 0; - - /* - * Restore old page 0 entry. - */ - - pg0[0] = cfg; - local_flush_tlb(); - } -#endif - - /* - * Allow the user to impress friends. - */ - - SMP_PRINTK(("Before bogomips.\n")); - if (!cpucount) { - printk(KERN_ERR "Error: only one processor found.\n"); - cpu_online_map = (1<CPU IPIs and self-IPIs too. */ - -/* - * Silly serialization to work around CPU bug in P5s. - * We can safely turn it off on a 686. - */ -#ifdef CONFIG_X86_GOOD_APIC -# define FORCE_APIC_SERIALIZATION 0 -#else -# define FORCE_APIC_SERIALIZATION 1 -#endif - static unsigned int cached_APIC_ICR; static unsigned int cached_APIC_ICR2; @@ -1462,7 +132,7 @@ void cache_APIC_registers (void) static inline unsigned int __get_ICR (void) { -#if FORCE_APIC_SERIALIZATION +#if FORCE_READ_AROUND_WRITE /* * Wait for the APIC to become ready - this should never occur. It's * a debugging check really. @@ -1473,11 +143,11 @@ static inline unsigned int __get_ICR (void) while (count < 1000) { cfg = slow_ICR; - if (!(cfg&(1<<12))) { - if (count) - atomic_add(count, (atomic_t*)&ipi_count); + if (!(cfg&(1<<12))) return cfg; - } + printk("CPU #%d: ICR still busy [%08x]\n", + smp_processor_id(), cfg); + irq_err_count++; count++; udelay(10); } @@ -1491,19 +161,25 @@ static inline unsigned int __get_ICR (void) static inline unsigned int __get_ICR2 (void) { -#if FORCE_APIC_SERIALIZATION +#if FORCE_READ_AROUND_WRITE return slow_ICR2; #else return cached_APIC_ICR2; #endif } +#define LOGICAL_DELIVERY 1 + static inline int __prepare_ICR (unsigned int shortcut, int vector) { unsigned int cfg; cfg = __get_ICR(); - cfg |= APIC_DEST_DM_FIXED|shortcut|vector; + cfg |= APIC_DEST_DM_FIXED|shortcut|vector +#if LOGICAL_DELIVERY + |APIC_DEST_LOGICAL +#endif + ; return cfg; } @@ -1513,7 +189,11 @@ static inline int __prepare_ICR2 (unsigned int dest) unsigned int cfg; cfg = __get_ICR2(); +#if LOGICAL_DELIVERY + cfg |= SET_APIC_DEST_FIELD((1< 1) + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); } static inline void send_IPI_all(int vector) @@ -1566,7 +251,7 @@ void send_IPI_self(int vector) static inline void send_IPI_single(int dest, int vector) { unsigned long cfg; -#if FORCE_APIC_SERIALIZATION +#if FORCE_READ_AROUND_WRITE unsigned long flags; __save_flags(flags); @@ -1589,7 +274,7 @@ static inline void send_IPI_single(int dest, int vector) * Send the IPI. The write to APIC_ICR fires this off. */ apic_write(APIC_ICR, cfg); -#if FORCE_APIC_SERIALIZATION +#if FORCE_READ_AROUND_WRITE __restore_flags(flags); #endif } @@ -1715,200 +400,97 @@ void smp_send_reschedule(int cpu) } /* - * this function sends a 'stop' IPI to all other CPUs in the system. - * it goes straight through. - */ - -void smp_send_stop(void) -{ - send_IPI_allbutself(STOP_CPU_VECTOR); -} - -/* Structure and data for smp_call_function(). This is designed to minimise + * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ -struct smp_call_function_struct { +static volatile struct call_data_struct { void (*func) (void *info); void *info; - atomic_t unstarted_count; - atomic_t unfinished_count; - int wait; -}; -static volatile struct smp_call_function_struct *smp_call_function_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 retry, - int wait) -/* [SUMMARY] Run a function on all other CPUs. - The function to run. This must be fast and non-blocking. - An arbitrary pointer to pass to the function. - If true, keep retrying until ready. - If true, wait 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 <> or are or have executed. -*/ -{ - unsigned long timeout; - struct smp_call_function_struct data; - static spinlock_t lock = SPIN_LOCK_UNLOCKED; - - if (retry) { - while (1) { - if (smp_call_function_data) { - schedule (); /* Give a mate a go */ - continue; - } - spin_lock (&lock); - if (smp_call_function_data) { - spin_unlock (&lock); /* Bad luck */ - continue; - } - /* Mine, all mine! */ - break; - } - } - else { - if (smp_call_function_data) return -EBUSY; - spin_lock (&lock); - if (smp_call_function_data) { - spin_unlock (&lock); - return -EBUSY; - } - } - smp_call_function_data = &data; - spin_unlock (&lock); - data.func = func; - data.info = info; - atomic_set (&data.unstarted_count, smp_num_cpus - 1); - data.wait = wait; - if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1); - /* Send a message to all other CPUs and wait for them to respond */ - send_IPI_allbutself (CALL_FUNCTION_VECTOR); - /* Wait for response */ - timeout = jiffies + JIFFIE_TIMEOUT; - while ( (atomic_read (&data.unstarted_count) > 0) && - time_before (jiffies, timeout) ) - barrier (); - if (atomic_read (&data.unstarted_count) > 0) { - smp_call_function_data = NULL; - return -ETIMEDOUT; - } - if (wait) - while (atomic_read (&data.unfinished_count) > 0) - barrier (); - smp_call_function_data = NULL; - return 0; -} - -static unsigned int calibration_result; - -void setup_APIC_timer(unsigned int clocks); - -/* - * Local timer interrupt handler. It does both profiling and - * process statistics/rescheduling. - * - * We do profiling in every local tick, statistics/rescheduling - * happen only every 'profiling multiplier' ticks. The default - * multiplier is 1 and it can be changed by writing the new multiplier - * value into /proc/profile. - */ - -void smp_local_timer_interrupt(struct pt_regs * regs) -{ - int user = (user_mode(regs) != 0); - int cpu = smp_processor_id(); - - /* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ - if (!user) - x86_do_profile(regs->eip); - - if (!--prof_counter[cpu]) { - int system = 1 - user; - struct task_struct * p = current; - - /* - * The multiplier may have changed since the last time we got - * to this point as a result of the user writing to - * /proc/profile. In this case we need to adjust the APIC - * timer accordingly. - * - * Interrupts are already masked off at this point. - */ - prof_counter[cpu] = prof_multiplier[cpu]; - if (prof_counter[cpu] != prof_old_multiplier[cpu]) { - setup_APIC_timer(calibration_result/prof_counter[cpu]); - prof_old_multiplier[cpu] = prof_counter[cpu]; - } - - /* - * 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. - */ - - irq_enter(cpu, 0); - update_one_process(p, 1, user, system, cpu); - if (p->pid) { - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->priority < DEF_PRIORITY) { - kstat.cpu_nice += user; - kstat.per_cpu_nice[cpu] += user; - } else { - kstat.cpu_user += user; - kstat.per_cpu_user[cpu] += user; - } - kstat.cpu_system += system; - kstat.per_cpu_system[cpu] += system; + atomic_t started; + atomic_t finished; + int wait; +} *call_data = NULL; - } - irq_exit(cpu, 0); - } +/* + * 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. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, we might schedule away to lock the mutex + * 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 <> or are or have executed. + */ +{ + struct call_data_struct data; + int ret, cpus = smp_num_cpus-1; + static DECLARE_MUTEX(lock); + unsigned long timeout; + + if (nonatomic) + down(&lock); + else + if (down_trylock(&lock)) + return -EBUSY; + if (call_data) // temporary debugging check + BUG(); + + call_data = &data; + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + mb(); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(CALL_FUNCTION_VECTOR); + + /* Wait for response */ + timeout = jiffies + HZ; + while ((atomic_read(&data.started) != cpus) + && time_before(jiffies, timeout)) + barrier(); + ret = -ETIMEDOUT; + if (atomic_read(&data.started) != cpus) + goto out; + ret = 0; + if (wait) + while (atomic_read(&data.finished) != cpus) + barrier(); +out: + call_data = NULL; + up(&lock); + return 0; +} + +static void stop_this_cpu (void * dummy) +{ /* - * We take the 'long' return path, and there every subsystem - * grabs the apropriate locks (kernel lock/ irq lock). - * - * we might want to decouple profiling from the 'long path', - * and do the profiling totally in assembly. - * - * Currently this isn't too much of an issue (performance wise), - * we can take more than 100K local irqs per second on a 100 MHz P5. + * Remove this CPU: */ + clear_bit(smp_processor_id(), &cpu_online_map); + + if (cpu_data[smp_processor_id()].hlt_works_ok) + for(;;) __asm__("hlt"); + for (;;); } /* - * Local APIC timer interrupt. This is the most natural way for doing - * local interrupts, but local timer interrupts can be emulated by - * broadcast interrupts too. [in case the hw doesnt support APIC timers] - * - * [ if a single-CPU system runs an SMP kernel then we call the local - * interrupt as well. Thus we cannot inline the local irq ... ] + * this function calls the 'stop' function on all other CPUs in the system. */ -void smp_apic_timer_interrupt(struct pt_regs * regs) + +void smp_send_stop(void) { - /* - * NOTE! We'd better ACK the irq immediately, - * because timer handling can be slow, and we - * want to be able to accept NMI tlb invalidates - * during this time. - */ - ack_APIC_irq(); - smp_local_timer_interrupt(regs); + smp_call_function(stop_this_cpu, NULL, 1, 0); } /* @@ -1944,39 +526,24 @@ asmlinkage void smp_invalidate_interrupt(void) } -static void stop_this_cpu (void) +asmlinkage void smp_call_function_interrupt(void) { + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + ack_APIC_irq(); /* - * Remove this CPU: + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function */ - clear_bit(smp_processor_id(), &cpu_online_map); - - if (cpu_data[smp_processor_id()].hlt_works_ok) - for(;;) __asm__("hlt"); - for (;;); -} - -/* - * CPU halt call-back - */ -asmlinkage void smp_stop_cpu_interrupt(void) -{ - stop_this_cpu(); -} - -asmlinkage void smp_call_function_interrupt(void) -{ - void (*func) (void *info) = smp_call_function_data->func; - void *info = smp_call_function_data->info; - int wait = smp_call_function_data->wait; - - ack_APIC_irq (); - /* Notify initiating CPU that I've grabbed the data and am about to - execute the function */ - atomic_dec (&smp_call_function_data->unstarted_count); - /* At this point the structure may be out of scope unless wait==1 */ - (*func) (info); - if (wait) atomic_dec (&smp_call_function_data->unfinished_count); + atomic_inc(&call_data->started); + /* + * At this point the structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) + atomic_inc(&call_data->finished); } /* @@ -1990,6 +557,34 @@ asmlinkage void smp_spurious_interrupt(void) smp_processor_id()); } +/* + * This interrupt should never happen with our APIC/SMP architecture + */ + +static spinlock_t err_lock; + +asmlinkage void smp_error_interrupt(void) +{ + unsigned long v; + + spin_lock(&err_lock); + + v = apic_read(APIC_ESR); + printk("APIC error interrupt on CPU#%d, should never happen.\n", + smp_processor_id()); + printk("... APIC ESR0: %08lx\n", v); + + apic_write(APIC_ESR, 0); + v = apic_read(APIC_ESR); + printk("... APIC ESR1: %08lx\n", v); + + ack_APIC_irq(); + + irq_err_count++; + + spin_unlock(&err_lock); +} + /* * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts * per second. We assume that the caller has already set up the local @@ -1999,6 +594,10 @@ asmlinkage void smp_spurious_interrupt(void) * closely follows bus clocks. */ +int prof_multiplier[NR_CPUS] = { 1, }; +int prof_old_multiplier[NR_CPUS] = { 1, }; +int prof_counter[NR_CPUS] = { 1, }; + /* * The timer chip is already set up at HZ interrupts per second here, * but we do not accept timer interrupts yet. We only allow the BP @@ -2015,66 +614,102 @@ static unsigned int __init get_8254_timer_count(void) return count; } +void __init wait_8254_wraparound(void) +{ + unsigned int curr_count, prev_count=~0; + int delta; + + curr_count = get_8254_timer_count(); + + do { + prev_count = curr_count; + curr_count = get_8254_timer_count(); + delta = curr_count-prev_count; + + /* + * This limit for delta seems arbitrary, but it isn't, it's + * slightly above the level of error a buggy Mercury/Neptune + * chipset timer can cause. + */ + + } while (delta<300); +} + /* * This function sets up the local APIC timer, with a timeout of * 'clocks' APIC bus clock. During calibration we actually call - * this function twice, once with a bogus timeout value, second - * time for real. The other (noncalibrating) CPUs call this - * function only once, with the real value. - * - * We are strictly in irqs off mode here, as we do not want to - * get an APIC interrupt go off accidentally. + * this function twice on the boot CPU, once with a bogus timeout + * value, second time for real. The other (noncalibrating) CPUs + * call this function only once, with the real, calibrated value. * * We do reads before writes even if unnecessary, to get around the - * APIC double write bug. + * P5 APIC double write bug. */ #define APIC_DIVISOR 16 -void setup_APIC_timer(unsigned int clocks) +void __setup_APIC_LVTT(unsigned int clocks) { - unsigned long lvtt1_value; - unsigned int tmp_value; + unsigned int lvtt1_value, tmp_value; - /* - * Unfortunately the local APIC timer cannot be set up into NMI - * mode. With the IO APIC we can re-route the external timer - * interrupt and broadcast it as an NMI to all CPUs, so no pain. - */ tmp_value = apic_read(APIC_LVTT); - lvtt1_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; - apic_write(APIC_LVTT , lvtt1_value); + lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | + APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; + apic_write(APIC_LVTT, lvtt1_value); /* * Divide PICLK by 16 */ tmp_value = apic_read(APIC_TDCR); - apic_write(APIC_TDCR , (tmp_value & ~APIC_TDR_DIV_1 ) - | APIC_TDR_DIV_16); + apic_write(APIC_TDCR, (tmp_value + & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) + | APIC_TDR_DIV_16); tmp_value = apic_read(APIC_TMICT); apic_write(APIC_TMICT, clocks/APIC_DIVISOR); } -void __init wait_8254_wraparound(void) +void setup_APIC_timer(void * data) { - unsigned int curr_count, prev_count=~0; + unsigned int clocks = (unsigned int) data, slice, t0, t1, nr; + unsigned long flags; int delta; - curr_count = get_8254_timer_count(); - - do { - prev_count = curr_count; - curr_count = get_8254_timer_count(); - delta = curr_count-prev_count; + __save_flags(flags); + __sti(); + /* + * ok, Intel has some smart code in their APIC that knows + * if a CPU was in 'hlt' lowpower mode, and this increases + * its APIC arbitration priority. To avoid the external timer + * IRQ APIC event being in synchron with the APIC clock we + * introduce an interrupt skew to spread out timer events. + * + * The number of slices within a 'big' timeslice is smp_num_cpus+1 + */ + slice = clocks / (smp_num_cpus+1); + nr = cpu_number_map[smp_processor_id()] + 1; + printk("cpu: %d, clocks: %d, slice: %d, nr: %d.\n", + smp_processor_id(), clocks, slice, nr); /* - * This limit for delta seems arbitrary, but it isn't, it's - * slightly above the level of error a buggy Mercury/Neptune - * chipset timer can cause. + * Wait for IRQ0's slice: */ + wait_8254_wraparound(); - } while (delta<300); + __setup_APIC_LVTT(clocks); + + t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + do { + t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + delta = (int)(t0 - t1 - slice*nr); + } while (delta < 0); + + __setup_APIC_LVTT(clocks); + + printk("CPU%d\n", + smp_processor_id(), t0, t1, delta, slice, clocks); + + __restore_flags(flags); } /* @@ -2092,10 +727,11 @@ void __init wait_8254_wraparound(void) int __init calibrate_APIC_clock(void) { - unsigned long long t1,t2; - long tt1,tt2; - long calibration_result; + unsigned long long t1 = 0, t2 = 0; + long tt1, tt2; + long result; int i; + const int LOOPS = HZ/10; printk("calibrating APIC timer ... "); @@ -2104,7 +740,7 @@ int __init calibrate_APIC_clock(void) * value into the APIC clock, we just want to get the * counter running for calibration. */ - setup_APIC_timer(1000000000); + __setup_APIC_LVTT(1000000000); /* * The timer chip counts down to zero. Let's wait @@ -2112,23 +748,24 @@ int __init calibrate_APIC_clock(void) * (the current tick might have been already half done) */ - wait_8254_wraparound (); + wait_8254_wraparound(); /* * We wrapped around just now. Let's start: */ - rdtscll(t1); - tt1=apic_read(APIC_TMCCT); + if (cpu_has_tsc) + rdtscll(t1); + tt1 = apic_read(APIC_TMCCT); -#define LOOPS (HZ/10) /* * Let's wait LOOPS wraprounds: */ - for (i=0; ieip); + + if (--prof_counter[cpu] <= 0) { + int system = 1 - user; + struct task_struct * p = current; + + /* + * The multiplier may have changed since the last time we got + * to this point as a result of the user writing to + * /proc/profile. In this case we need to adjust the APIC + * timer accordingly. + * + * Interrupts are already masked off at this point. + */ + prof_counter[cpu] = prof_multiplier[cpu]; + if (prof_counter[cpu] != prof_old_multiplier[cpu]) { + __setup_APIC_LVTT(calibration_result/prof_counter[cpu]); + prof_old_multiplier[cpu] = prof_counter[cpu]; + } + + /* + * 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. + */ + + irq_enter(cpu, 0); + update_one_process(p, 1, user, system, cpu); + if (p->pid) { + p->counter -= 1; + if (p->counter <= 0) { + p->counter = 0; + p->need_resched = 1; + } + if (p->priority < DEF_PRIORITY) { + kstat.cpu_nice += user; + kstat.per_cpu_nice[cpu] += user; + } else { + kstat.cpu_user += user; + kstat.per_cpu_user[cpu] += user; + } + kstat.cpu_system += system; + kstat.per_cpu_system[cpu] += system; + + } + irq_exit(cpu, 0); + } + + /* + * We take the 'long' return path, and there every subsystem + * grabs the apropriate locks (kernel lock/ irq lock). + * + * we might want to decouple profiling from the 'long path', + * and do the profiling totally in assembly. + * + * Currently this isn't too much of an issue (performance wise), + * we can take more than 100K local irqs per second on a 100 MHz P5. + */ +} + +/* + * Local APIC timer interrupt. This is the most natural way for doing + * local interrupts, but local timer interrupts can be emulated by + * broadcast interrupts too. [in case the hw doesnt support APIC timers] + * + * [ if a single-CPU system runs an SMP kernel then we call the local + * interrupt as well. Thus we cannot inline the local irq ... ] + */ +unsigned int apic_timer_irqs [NR_CPUS] = { 0, }; + +void smp_apic_timer_interrupt(struct pt_regs * regs) +{ + /* + * the NMI deadlock-detector uses this. + */ + apic_timer_irqs[smp_processor_id()]++; + + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ + ack_APIC_irq(); + smp_local_timer_interrupt(regs); +} + diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c new file mode 100644 index 000000000000..46335ee8fa9c --- /dev/null +++ b/arch/i386/kernel/smpboot.c @@ -0,0 +1,1650 @@ +/* + * Intel MP v1.1/v1.4 specification compliant parsing routines. + * + * (c) 1995 Alan Cox, Building #3 + * (c) 1998, 1999 Ingo Molnar + * + * Much of the core SMP work is based on previous work by Thomas Radke, to + * whom a great many thanks are extended. + * + * Thanks to Intel for making available several different Pentium, + * Pentium Pro and Pentium-II/Xeon MP machines. + * Original development of Linux SMP code supported by Caldera. + * + * This code is released under the GNU public license version 2 or + * later. + * + * Fixes + * Felix Koop : NR_CPUS used properly + * Jose Renau : Handle single CPU case. + * Alan Cox : By repeated request 8) - Total BogoMIP report. + * Greg Wright : Fix for kernel stacks panic. + * Erich Boleyn : MP v1.4 and additional changes. + * Matthias Sattler : Changes for 2.1 kernel map. + * Michel Lespinasse : Changes for 2.1 kernel map. + * Michael Chastain : Change trampoline.S to gnu as. + * Alan Cox : Dumb bug: 'B' step PPro's are fine + * Ingo Molnar : Added APIC timers, based on code + * from Jose Renau + * Alan Cox : Added EBDA scanning + * Ingo Molnar : various cleanups and rewrites + * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. + * Maciej W. Rozycki : Bits for genuine 82489DX timers + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +/* Set if we find a B stepping CPU */ +static int smp_b_stepping = 0; + +/* Setup configured maximum number of CPUs to activate */ +static int max_cpus = -1; +/* 1 if "noapic" boot option passed */ +int skip_ioapic_setup = 0; + +/* Total count of live CPUs */ +int smp_num_cpus = 0; +/* Internal processor count */ +static unsigned int num_processors = 1; + +/* Have we found an SMP box */ +int smp_found_config = 0; + +/* Bitmask of physically existing CPUs */ +unsigned long cpu_present_map = 0; +/* Bitmask of currently online CPUs */ +unsigned long cpu_online_map = 0; + +/* which CPU maps to which logical number */ +volatile int cpu_number_map[NR_CPUS]; +/* which logical number maps to which CPU */ +volatile int __cpu_logical_map[NR_CPUS]; + +static volatile unsigned long cpu_callin_map = 0; +static volatile unsigned long cpu_callout_map = 0; + +/* Per CPU bogomips and other parameters */ +struct cpuinfo_x86 cpu_data[NR_CPUS]; +/* Processor that is doing the boot up */ +static unsigned int boot_cpu_id = 0; + +/* Tripped once we need to start cross invalidating */ +static int smp_activated = 0; +/* Set when the idlers are all forked */ +int smp_threads_ready = 0; + +/* + * Various Linux-internal data structures created from the + * MP-table. + */ +int apic_version [NR_CPUS]; +int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; +extern int nr_ioapics; +extern struct mpc_config_ioapic mp_ioapics [MAX_IO_APICS]; +extern int mp_irq_entries; +extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; +extern int mpc_default_type; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; +int mp_current_pci_id = 0; +unsigned long mp_lapic_addr = 0; +int pic_mode; + +extern void cache_APIC_registers (void); + +#define SMP_DEBUG 1 + +#if SMP_DEBUG +#define dprintk(x...) printk(##x) +#else +#define dprintk(x...) +#endif + +/* + * IA s/w dev Vol 3, Section 7.4 + */ +#define APIC_DEFAULT_PHYS_BASE 0xfee00000 + +/* + * Setup routine for controlling SMP activation + * + * Command-line option of "nosmp" or "maxcpus=0" will disable SMP + * activation entirely (the MPS table probe still happens, though). + * + * Command-line option of "maxcpus=", where is an integer + * greater than 0, limits the maximum number of CPUs activated in + * SMP mode to . + */ + +static int __init nosmp(char *str) +{ + max_cpus = 0; + return 1; +} + +__setup("nosmp", nosmp); + +static int __init maxcpus(char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); + +/* + * Intel MP BIOS table parsing routines: + */ + +#ifndef CONFIG_X86_VISWS_APIC +/* + * Checksum an MP configuration block. + */ + +static int __init mpf_checksum(unsigned char *mp, int len) +{ + int sum=0; + while(len--) + sum+=*mp++; + return sum&0xFF; +} + +/* + * Processor encoding in an MP configuration block + */ + +static char __init *mpc_family(int family,int model) +{ + static char n[32]; + static char *model_defs[]= + { + "80486DX","80486DX", + "80486SX","80486DX/2 or 80487", + "80486SL","80486SX/2", + "Unknown","80486DX/2-WB", + "80486DX/4","80486DX/4-WB" + }; + + switch (family) { + case 0x04: + if (model < 10) + return model_defs[model]; + break; + + case 0x05: + return("Pentium(tm)"); + + case 0x06: + return("Pentium(tm) Pro"); + + case 0x0F: + if (model == 0x0F) + return("Special controller"); + } + sprintf(n,"Unknown CPU [%d:%d]",family, model); + return n; +} + +static void __init MP_processor_info (struct mpc_config_processor *m) +{ + int ver; + + if (!(m->mpc_cpuflag & CPU_ENABLED)) + return; + + printk("Processor #%d %s APIC version %d\n", + m->mpc_apicid, + mpc_family( (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , + (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), + m->mpc_apicver); + +#ifdef SMP_DEBUG + if (m->mpc_featureflag&(1<<0)) + printk(" Floating point unit present.\n"); + if (m->mpc_featureflag&(1<<7)) + printk(" Machine Exception supported.\n"); + if (m->mpc_featureflag&(1<<8)) + printk(" 64 bit compare & exchange supported.\n"); + if (m->mpc_featureflag&(1<<9)) + printk(" Internal APIC present.\n"); +#endif + + if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { + dprintk(" Bootup CPU\n"); + boot_cpu_id = m->mpc_apicid; + } else + /* Boot CPU already counted */ + num_processors++; + + if (m->mpc_apicid > NR_CPUS) { + printk("Processor #%d unused. (Max %d processors).\n", + m->mpc_apicid, NR_CPUS); + return; + } + ver = m->mpc_apicver; + + cpu_present_map |= (1<mpc_apicid); + /* + * Validate version + */ + if (ver == 0x0) { + printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + ver = 0x10; + } + apic_version[m->mpc_apicid] = ver; +} + +static void __init MP_bus_info (struct mpc_config_bus *m) +{ + char str[7]; + + memcpy(str, m->mpc_bustype, 6); + str[6] = 0; + dprintk("Bus #%d is %s\n", m->mpc_busid, str); + + if (strncmp(str, "ISA", 3) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; + } else { + if (strncmp(str, "EISA", 4) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; + } else { + if (strncmp(str, "PCI", 3) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; + mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; + mp_current_pci_id++; + } else { + printk("Unknown bustype %s\n", str); + panic("cannot handle bus - mail to linux-smp@vger.rutgers.edu"); + } } } +} + +static void __init MP_ioapic_info (struct mpc_config_ioapic *m) +{ + if (!(m->mpc_flags & MPC_APIC_USABLE)) + return; + + printk("I/O APIC #%d Version %d at 0x%lX.\n", + m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); + if (nr_ioapics >= MAX_IO_APICS) { + printk("Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IO_APICS, nr_ioapics); + panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); + } + mp_ioapics[nr_ioapics] = *m; + nr_ioapics++; +} + +static void __init MP_intsrc_info (struct mpc_config_intsrc *m) +{ + mp_irqs [mp_irq_entries] = *m; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!!\n"); +} + +static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) +{ + /* + * Well it seems all SMP boards in existence + * use ExtINT/LVT1 == LINT0 and + * NMI/LVT2 == LINT1 - the following check + * will show us if this assumptions is false. + * Until then we do not have to add baggage. + */ + if ((m->mpc_irqtype == mp_ExtINT) && + (m->mpc_destapiclint != 0)) + BUG(); + if ((m->mpc_irqtype == mp_NMI) && + (m->mpc_destapiclint != 1)) + BUG(); +} + +/* + * Read/parse the MPC + */ + +static int __init smp_read_mpc(struct mp_config_table *mpc) +{ + char str[16]; + int count=sizeof(*mpc); + unsigned char *mpt=((unsigned char *)mpc)+count; + + if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) + { + panic("SMP mptable: bad signature [%c%c%c%c]!\n", + mpc->mpc_signature[0], + mpc->mpc_signature[1], + mpc->mpc_signature[2], + mpc->mpc_signature[3]); + return 1; + } + if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) + { + panic("SMP mptable: checksum error!\n"); + return 1; + } + if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) + { + printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec); + return 1; + } + memcpy(str,mpc->mpc_oem,8); + str[8]=0; + printk("OEM ID: %s ",str); + + memcpy(str,mpc->mpc_productid,12); + str[12]=0; + printk("Product ID: %s ",str); + + printk("APIC at: 0x%lX\n",mpc->mpc_lapic); + + /* save the local APIC address, it might be non-default */ + mp_lapic_addr = mpc->mpc_lapic; + + /* + * Now process the configuration blocks. + */ + while (count < mpc->mpc_length) { + switch(*mpt) { + case MP_PROCESSOR: + { + struct mpc_config_processor *m= + (struct mpc_config_processor *)mpt; + MP_processor_info(m); + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + case MP_BUS: + { + struct mpc_config_bus *m= + (struct mpc_config_bus *)mpt; + MP_bus_info(m); + mpt += sizeof(*m); + count += sizeof(*m); + break; + } + case MP_IOAPIC: + { + struct mpc_config_ioapic *m= + (struct mpc_config_ioapic *)mpt; + MP_ioapic_info(m); + mpt+=sizeof(*m); + count+=sizeof(*m); + break; + } + case MP_INTSRC: + { + struct mpc_config_intsrc *m= + (struct mpc_config_intsrc *)mpt; + + MP_intsrc_info(m); + mpt+=sizeof(*m); + count+=sizeof(*m); + break; + } + case MP_LINTSRC: + { + struct mpc_config_lintsrc *m= + (struct mpc_config_lintsrc *)mpt; + MP_lintsrc_info(m); + mpt+=sizeof(*m); + count+=sizeof(*m); + break; + } + } + } + return num_processors; +} + +/* + * Scan the memory blocks for an SMP configuration block. + */ +static int __init smp_get_mpf(struct intel_mp_floating *mpf) +{ + printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); + if (mpf->mpf_feature2 & (1<<7)) { + printk(" IMCR and PIC compatibility mode.\n"); + pic_mode = 1; + } else { + printk(" Virtual Wire compatibility mode.\n"); + pic_mode = 0; + } + smp_found_config = 1; + /* + * default CPU id - if it's different in the mptable + * then we change it before first using it. + */ + boot_cpu_id = 0; + /* + * Now see if we need to read further. + */ + if (mpf->mpf_feature1 != 0) { + /* + * local APIC has default address + */ + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + /* + * 2 CPUs, numbered 0 & 1. + */ + cpu_present_map = 3; + num_processors = 2; + + nr_ioapics = 1; + mp_ioapics[0].mpc_apicaddr = 0xFEC00000; + /* + * Save the default type number, we + * need it later to set the IO-APIC + * up properly: + */ + mpc_default_type = mpf->mpf_feature1; + + printk("Bus #0 is "); + } + + switch (mpf->mpf_feature1) { + case 1: + case 5: + printk("ISA\n"); + break; + case 2: + printk("EISA with no IRQ0 and no IRQ13 DMA chaining\n"); + break; + case 6: + case 3: + printk("EISA\n"); + break; + case 4: + case 7: + printk("MCA\n"); + break; + case 0: + if (!mpf->mpf_physptr) + BUG(); + break; + default: + printk("???\nUnknown standard configuration %d\n", + mpf->mpf_feature1); + return 1; + } + if (mpf->mpf_feature1 > 4) { + printk("Bus #1 is PCI\n"); + + /* + * Set local APIC version to the integrated form. + * It's initialized to zero otherwise, representing + * a discrete 82489DX. + */ + apic_version[0] = 0x10; + apic_version[1] = 0x10; + } + /* + * Read the physical hardware table. Anything here will override the + * defaults. + */ + if (mpf->mpf_physptr) + smp_read_mpc((void *)mpf->mpf_physptr); + + __cpu_logical_map[0] = boot_cpu_id; + global_irq_holder = boot_cpu_id; + current->processor = boot_cpu_id; + + printk("Processors: %d\n", num_processors); + /* + * Only use the first configuration found. + */ + return 1; +} + +static int __init smp_scan_config(unsigned long base, unsigned long length) +{ + unsigned long *bp = phys_to_virt(base); + struct intel_mp_floating *mpf; + + dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); + if (sizeof(*mpf) != 16) + printk("Error: MPF size\n"); + + while (length > 0) { + mpf = (struct intel_mp_floating *)bp; + if ((*bp == SMP_MAGIC_IDENT) && + (mpf->mpf_length == 1) && + !mpf_checksum((unsigned char *)bp, 16) && + ((mpf->mpf_specification == 1) + || (mpf->mpf_specification == 4)) ) { + + printk("found SMP MP-table at %08ld\n", + virt_to_phys(mpf)); + smp_get_mpf(mpf); + return 1; + } + bp += 4; + length -= 16; + } + return 0; +} + +void __init init_intel_smp (void) +{ + unsigned int address; + + /* + * FIXME: Linux assumes you have 640K of base ram.. + * this continues the error... + * + * 1) Scan the bottom 1K for a signature + * 2) Scan the top 1K of base RAM + * 3) Scan the 64K of bios + */ + if (smp_scan_config(0x0,0x400) || + smp_scan_config(639*0x400,0x400) || + smp_scan_config(0xF0000,0x10000)) + return; + /* + * If it is an SMP machine we should know now, unless the + * configuration is in an EISA/MCA bus machine with an + * extended bios data area. + * + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E, calculate and scan it here. + * + * NOTE! There are Linux loaders that will corrupt the EBDA + * area, and as such this kind of SMP config may be less + * trustworthy, simply because the SMP table may have been + * stomped on during early boot. These loaders are buggy and + * should be fixed. + */ + + address = *(unsigned short *)phys_to_virt(0x40E); + address <<= 4; + smp_scan_config(address, 0x1000); + if (smp_found_config) + printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.rutgers.edu if you experience SMP problems!\n"); +} + +#else + +/* + * The Visual Workstation is Intel MP compliant in the hardware + * sense, but it doesnt have a BIOS(-configuration table). + * No problem for Linux. + */ +void __init init_visws_smp(void) +{ + smp_found_config = 1; + + cpu_present_map |= 2; /* or in id 1 */ + apic_version[1] |= 0x10; /* integrated APIC */ + apic_version[0] |= 0x10; + + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; +} + +#endif + +/* + * - Intel MP Configuration Table + * - or SGI Visual Workstation configuration + */ +void __init init_smp_config (void) +{ +#ifndef CONFIG_VISWS + init_intel_smp(); +#else + init_visws_smp(); +#endif +} + + + +/* + * Trampoline 80x86 program as an array. + */ + +extern unsigned char trampoline_data []; +extern unsigned char trampoline_end []; +static unsigned char *trampoline_base; + +/* + * Currently trivial. Write the real->protected mode + * bootstrap into the page concerned. The caller + * has made sure it's suitably aligned. + */ + +static unsigned long __init setup_trampoline(void) +{ + memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); + return virt_to_phys(trampoline_base); +} + +/* + * We are called very early to get the low memory for the + * SMP bootup trampoline page. + */ +unsigned long __init smp_alloc_memory(unsigned long mem_base) +{ + if (virt_to_phys((void *)mem_base) >= 0x9F000) + BUG(); + trampoline_base = (void *)mem_base; + return mem_base + PAGE_SIZE; +} + +/* + * The bootstrap kernel entry code has set these up. Save them for + * a given CPU + */ + +void __init smp_store_cpu_info(int id) +{ + struct cpuinfo_x86 *c=&cpu_data[id]; + + *c = boot_cpu_data; + c->pte_quick = 0; + c->pgd_quick = 0; + c->pgtable_cache_sz = 0; + identify_cpu(c); + /* + * Mask B, Pentium, but not Pentium MMX + */ + if (c->x86_vendor == X86_VENDOR_INTEL && + c->x86 == 5 && + c->x86_mask >= 1 && c->x86_mask <= 4 && + c->x86_model <= 3) + /* + * Remember we have B step Pentia with bugs + */ + smp_b_stepping = 1; +} + +/* + * Architecture specific routine called by the kernel just before init is + * fired off. This allows the BP to have everything in order [we hope]. + * At the end of this all the APs will hit the system scheduling and off + * we go. Each AP will load the system gdt's and jump through the kernel + * init into idle(). At this point the scheduler will one day take over + * and give them jobs to do. smp_callin is a standard routine + * we use to track CPUs as they power up. + */ + +static atomic_t smp_commenced = ATOMIC_INIT(0); + +void __init smp_commence(void) +{ + /* + * Lets the callins below out of their loop. + */ + dprintk("Setting commenced=1, go go go\n"); + + wmb(); + atomic_set(&smp_commenced,1); +} + +extern void __error_in_io_apic_c(void); + + +int get_maxlvt(void) +{ + unsigned int v, ver, maxlvt; + + v = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(v); + /* 82489DXs do not report # of LVT entries. */ + maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; + return maxlvt; +} + +void __init setup_local_APIC(void) +{ + unsigned long value, ver, maxlvt; + + if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) + __error_in_io_apic_c(); + + value = apic_read(APIC_SPIV); + value = 0xf; + /* + * Enable APIC + */ + value |= (1<<8); +#if 0 + /* Enable focus processor (bit==0) */ + value &= ~(1<<9); +#else + /* Disable focus processor (bit==1) */ + value |= (1<<9); +#endif + /* + * Set spurious IRQ vector + */ + value |= SPURIOUS_APIC_VECTOR; + apic_write(APIC_SPIV,value); + + /* + * Set up LVT0, LVT1: + * + * set up through-local-APIC on the BP's LINT0. This is not + * strictly necessery in pure symmetric-IO mode, but sometimes + * we delegate interrupts to the 8259A. + */ + if (hard_smp_processor_id() == boot_cpu_id) { + value = 0x00000700; + printk("enabled ExtINT on CPU#%d\n", hard_smp_processor_id()); + } else { + value = 0x00010700; + printk("masked ExtINT on CPU#%d\n", hard_smp_processor_id()); + } + apic_write_around(APIC_LVT0,value); + + /* + * only the BP should see the LINT1 NMI signal, obviously. + */ + if (hard_smp_processor_id() == boot_cpu_id) + value = 0x00000400; // unmask NMI + else + value = 0x00010400; // mask NMI + apic_write_around(APIC_LVT1,value); + + value = apic_read(APIC_LVR); + ver = GET_APIC_VERSION(value); + if (APIC_INTEGRATED(ver)) { /* !82489DX */ + maxlvt = get_maxlvt(); + /* + * Due to the Pentium erratum 3AP. + */ + if (maxlvt > 3) { + apic_readaround(APIC_SPIV); // not strictly necessery + apic_write(APIC_ESR, 0); + } + value = apic_read(APIC_ESR); + printk("ESR value before enabling vector: %08lx\n", value); + + value = apic_read(APIC_LVTERR); + value = ERROR_APIC_VECTOR; // enables sending errors + apic_write(APIC_LVTERR,value); + /* + * spec says clear errors after enabling vector. + */ + if (maxlvt != 3) { + apic_readaround(APIC_SPIV); + apic_write(APIC_ESR, 0); + } + value = apic_read(APIC_ESR); + printk("ESR value after enabling vector: %08lx\n", value); + } else + printk("No ESR for 82489DX.\n"); + + /* + * Set Task Priority to 'accept all'. We never change this + * later on. + */ + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; + apic_write(APIC_TASKPRI,value); + + /* + * Set up the logical destination ID and put the + * APIC into flat delivery mode. + */ + value = apic_read(APIC_LDR); + value &= ~APIC_LDR_MASK; + value |= (1<<(smp_processor_id()+24)); + apic_write(APIC_LDR,value); + + value = apic_read(APIC_DFR); + value |= SET_APIC_DFR(0xf); + apic_write(APIC_DFR, value); +} + +unsigned long __init init_smp_mappings(unsigned long memory_start) +{ + unsigned long apic_phys; + + memory_start = PAGE_ALIGN(memory_start); + if (smp_found_config) { + apic_phys = mp_lapic_addr; + } else { + /* + * set up a fake all zeroes page to simulate the + * local APIC and another one for the IO-APIC. We + * could use the real zero-page, but it's safer + * this way if some buggy code writes to this page ... + */ + apic_phys = __pa(memory_start); + memset((void *)memory_start, 0, PAGE_SIZE); + memory_start += PAGE_SIZE; + } + set_fixmap(FIX_APIC_BASE,apic_phys); + dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); + +#ifdef CONFIG_X86_IO_APIC + { + unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; + int i; + + for (i = 0; i < nr_ioapics; i++) { + if (smp_found_config) { + ioapic_phys = mp_ioapics[i].mpc_apicaddr; + } else { + ioapic_phys = __pa(memory_start); + memset((void *)memory_start, 0, PAGE_SIZE); + memory_start += PAGE_SIZE; + } + set_fixmap(idx,ioapic_phys); + dprintk("mapped IOAPIC to %08lx (%08lx)\n", + __fix_to_virt(idx), ioapic_phys); + idx++; + } + } +#endif + + return memory_start; +} + +/* + * TSC synchronization. + * + * We first check wether all CPUs have their TSC's synchronized, + * then we print a warning if not, and always resync. + */ + +static atomic_t tsc_start_flag = ATOMIC_INIT(0); +static atomic_t tsc_count_start = ATOMIC_INIT(0); +static atomic_t tsc_count_stop = ATOMIC_INIT(0); +static unsigned long long tsc_values[NR_CPUS] = { 0, }; + +#define NR_LOOPS 5 + +extern unsigned long fast_gettimeoffset_quotient; + +/* + * accurate 64-bit/32-bit division, expanded to 32-bit divisions and 64-bit + * multiplication. Not terribly optimized but we need it at boot time only + * anyway. + * + * result == a / b + * == (a1 + a2*(2^32)) / b + * == a1/b + a2*(2^32/b) + * == a1/b + a2*((2^32-1)/b) + a2/b + (a2*((2^32-1) % b))/b + * ^---- (this multiplication can overflow) + */ + +static unsigned long long div64 (unsigned long long a, unsigned long b0) +{ + unsigned int a1, a2; + unsigned long long res; + + a1 = ((unsigned int*)&a)[0]; + a2 = ((unsigned int*)&a)[1]; + + res = a1/b0 + + (unsigned long long)a2 * (unsigned long long)(0xffffffff/b0) + + a2 / b0 + + (a2 * (0xffffffff % b0)) / b0; + + return res; +} + +static void __init synchronize_tsc_bp (void) +{ + int i; + unsigned long long t0; + unsigned long long sum, avg; + long long delta; + unsigned long one_usec; + int buggy = 0; + + printk("checking TSC synchronization across CPUs: "); + + one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2); + + atomic_set(&tsc_start_flag, 1); + wmb(); + + /* + * We loop a few times to get a primed instruction cache, + * then the last pass is more or less synchronized and + * the BP and APs set their cycle counters to zero all at + * once. This reduces the chance of having random offsets + * between the processors, and guarantees that the maximum + * delay between the cycle counters is never bigger than + * the latency of information-passing (cachelines) between + * two CPUs. + */ + for (i = 0; i < NR_LOOPS; i++) { + /* + * all APs synchronize but they loop on '== num_cpus' + */ + while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb(); + atomic_set(&tsc_count_stop, 0); + wmb(); + /* + * this lets the APs save their current TSC: + */ + atomic_inc(&tsc_count_start); + + rdtscll(tsc_values[smp_processor_id()]); + /* + * We clear the TSC in the last loop: + */ + if (i == NR_LOOPS-1) + write_tsc(0, 0); + + /* + * Wait for all APs to leave the synchronization point: + */ + while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb(); + atomic_set(&tsc_count_start, 0); + wmb(); + atomic_inc(&tsc_count_stop); + } + + sum = 0; + for (i = 0; i < NR_CPUS; i++) { + if (!(cpu_online_map & (1 << i))) + continue; + + t0 = tsc_values[i]; + sum += t0; + } + avg = div64(sum, smp_num_cpus); + + sum = 0; + for (i = 0; i < NR_CPUS; i++) { + if (!(cpu_online_map & (1 << i))) + continue; + + delta = tsc_values[i] - avg; + if (delta < 0) + delta = -delta; + /* + * We report bigger than 2 microseconds clock differences. + */ + if (delta > 2*one_usec) { + long realdelta; + if (!buggy) { + buggy = 1; + printk("\n"); + } + realdelta = div64(delta, one_usec); + if (tsc_values[i] < avg) + realdelta = -realdelta; + + printk("BIOS BUG: CPU#%d improperly initialized, has %ld usecs TSC skew! FIXED.\n", + i, realdelta); + } + + sum += delta; + } + if (!buggy) + printk("passed.\n"); +} + +static void __init synchronize_tsc_ap (void) +{ + int i; + + /* + * smp_num_cpus is not necessarily known at the time + * this gets called, so we first wait for the BP to + * finish SMP initialization: + */ + while (!atomic_read(&tsc_start_flag)) mb(); + + for (i = 0; i < NR_LOOPS; i++) { + atomic_inc(&tsc_count_start); + while (atomic_read(&tsc_count_start) != smp_num_cpus) mb(); + + rdtscll(tsc_values[smp_processor_id()]); + if (i == NR_LOOPS-1) + write_tsc(0, 0); + + atomic_inc(&tsc_count_stop); + while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb(); + } +} +#undef NR_LOOPS + +extern void calibrate_delay(void); + +void __init smp_callin(void) +{ + int cpuid; + unsigned long timeout; + + /* + * (This works even if the APIC is not enabled.) + */ + cpuid = GET_APIC_ID(apic_read(APIC_ID)); + + dprintk("CPU#%d waiting for CALLOUT\n", cpuid); + + /* + * STARTUP IPIs are fragile beasts as they might sometimes + * trigger some glue motherboard logic. Complete APIC bus + * silence for 1 second, this overestimates the time the + * boot CPU is spending to send the up to 2 STARTUP IPIs + * by a factor of two. This should be enough. + */ + + /* + * Waiting 2s total for startup (udelay is not yet working) + */ + timeout = jiffies + 2*HZ; + while (time_before(jiffies, timeout)) { + /* + * Has the boot CPU finished it's STARTUP sequence? + */ + if (test_bit(cpuid, &cpu_callout_map)) + break; + } + + if (!time_before(jiffies, timeout)) { + printk("BUG: CPU%d started up but did not get a callout!\n", + cpuid); + BUG(); + } + + /* + * the boot CPU has finished the init stage and is spinning + * on callin_map until we finish. We are free to set up this + * CPU, first the APIC. (this is probably redundant on most + * boards) + */ + + dprintk("CALLIN, before setup_local_APIC().\n"); + setup_local_APIC(); + + sti(); + +#ifdef CONFIG_MTRR + /* + * Must be done before calibration delay is computed + */ + mtrr_init_secondary_cpu (); +#endif + /* + * Get our bogomips. + */ + calibrate_delay(); + dprintk("Stack at about %p\n",&cpuid); + + /* + * Save our processor parameters + */ + smp_store_cpu_info(cpuid); + + /* + * Allow the master to continue. + */ + set_bit(cpuid, &cpu_callin_map); + + /* + * Synchronize the TSC with the BP + */ + if (cpu_has_tsc) + synchronize_tsc_ap (); +} + +int cpucount = 0; + +extern int cpu_idle(void); + +/* + * Activate a secondary processor. + */ +int __init start_secondary(void *unused) +{ + /* + * Dont put anything before smp_callin(), SMP + * booting is too fragile that we want to limit the + * things done here to the most necessary things. + */ + cpu_init(); + smp_callin(); + while (!atomic_read(&smp_commenced)) + /* nothing */ ; + return cpu_idle(); +} + +/* + * Everything has been set up for the secondary + * CPUs - they just need to reload everything + * from the task structure + * This function must not return. + */ +void __init initialize_secondary(void) +{ + /* + * We don't actually need to load the full TSS, + * basically just the stack pointer and the eip. + */ + + asm volatile( + "movl %0,%%esp\n\t" + "jmp *%1" + : + :"r" (current->thread.esp),"r" (current->thread.eip)); +} + +extern struct { + void * esp; + unsigned short ss; +} stack_start; + +static int __init fork_by_hand(void) +{ + struct pt_regs regs; + /* + * don't care about the eip and regs settings since + * we'll never reschedule the forked task. + */ + return do_fork(CLONE_VM|CLONE_PID, 0, ®s); +} + +static void __init do_boot_cpu(int i) +{ + unsigned long cfg; + pgd_t maincfg; + struct task_struct *idle; + unsigned long send_status, accept_status; + int timeout, num_starts, j; + unsigned long start_eip; + + cpucount++; + /* + * We can't use kernel_thread since we must avoid to + * reschedule the child. + */ + if (fork_by_hand() < 0) + panic("failed fork for CPU %d", i); + + /* + * We remove it from the pidhash and the runqueue + * once we got the process: + */ + idle = init_task.prev_task; + if (!idle) + panic("No idle process for CPU %d", i); + + idle->processor = i; + __cpu_logical_map[cpucount] = i; + cpu_number_map[i] = cpucount; + idle->has_cpu = 1; /* we schedule the first task manually */ + idle->thread.eip = (unsigned long) start_secondary; + + del_from_runqueue(idle); + unhash_process(idle); + init_tasks[cpucount] = idle; + + /* start_eip had better be page-aligned! */ + start_eip = setup_trampoline(); + + /* So we see what's up */ + printk("Booting processor %d eip %lx\n", i, start_eip); + stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); + + /* + * This grunge runs the startup process for + * the targeted processor. + */ + + dprintk("Setting warm reset code and vector.\n"); + + CMOS_WRITE(0xa, 0xf); + local_flush_tlb(); + dprintk("1.\n"); + *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; + dprintk("2.\n"); + *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; + dprintk("3.\n"); + + maincfg=swapper_pg_dir[0]; + ((unsigned long *)swapper_pg_dir)[0]=0x102007; + + /* + * Be paranoid about clearing APIC errors. + */ + + if (APIC_INTEGRATED(apic_version[i])) { + apic_readaround(APIC_SPIV); + apic_write(APIC_ESR, 0); + accept_status = (apic_read(APIC_ESR) & 0xEF); + } + + /* + * Status is now clean + */ + send_status = 0; + accept_status = 0; + + /* + * Starting actual IPI sequence... + */ + + dprintk("Asserting INIT.\n"); + + /* + * Turn INIT on + */ + cfg = apic_read(APIC_ICR2); + cfg &= 0x00FFFFFF; + + /* + * Target chip + */ + apic_write(APIC_ICR2, cfg | SET_APIC_DEST_FIELD(i)); + + /* + * Send IPI + */ + cfg = apic_read(APIC_ICR); + cfg &= ~0xCDFFF; + cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_ASSERT | APIC_DEST_DM_INIT); + apic_write(APIC_ICR, cfg); + + udelay(200); + dprintk("Deasserting INIT.\n"); + + /* Target chip */ + cfg = apic_read(APIC_ICR2); + cfg &= 0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); + + /* Send IPI */ + cfg = apic_read(APIC_ICR); + cfg &= ~0xCDFFF; + cfg |= (APIC_DEST_LEVELTRIG | APIC_DEST_DM_INIT); + apic_write(APIC_ICR, cfg); + + /* + * Should we send STARTUP IPIs ? + * + * Determine this based on the APIC version. + * If we don't have an integrated APIC, don't + * send the STARTUP IPIs. + */ + + if (APIC_INTEGRATED(apic_version[i])) + num_starts = 2; + else + num_starts = 0; + + /* + * Run STARTUP IPI loop. + */ + + for (j = 1; j <= num_starts; j++) { + dprintk("Sending STARTUP #%d.\n",j); + apic_readaround(APIC_SPIV); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + dprintk("After apic_write.\n"); + + /* + * STARTUP IPI + */ + + /* Target chip */ + cfg = apic_read(APIC_ICR2); + cfg &= 0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(i)); + + /* Boot on the stack */ + cfg = apic_read(APIC_ICR); + cfg &= ~0xCDFFF; + cfg |= (APIC_DEST_DM_STARTUP | (start_eip >> 12)); + + /* Kick the second */ + apic_write(APIC_ICR, cfg); + + dprintk("Startup point 1.\n"); + + dprintk("Waiting for send to finish...\n"); + timeout = 0; + do { + dprintk("+"); + udelay(100); + send_status = apic_read(APIC_ICR) & 0x1000; + } while (send_status && (timeout++ < 1000)); + + /* + * Give the other CPU some time to accept the IPI. + */ + udelay(200); + accept_status = (apic_read(APIC_ESR) & 0xEF); + if (send_status || accept_status) + break; + } + dprintk("After Startup.\n"); + + if (send_status) + printk("APIC never delivered???\n"); + if (accept_status) + printk("APIC delivery error (%lx).\n", accept_status); + + if (!send_status && !accept_status) { + /* + * allow APs to start initializing. + */ + dprintk("Before Callout %d.\n", i); + set_bit(i, &cpu_callout_map); + dprintk("After Callout %d.\n", i); + + /* + * Wait 5s total for a response + */ + for (timeout = 0; timeout < 50000; timeout++) { + if (test_bit(i, &cpu_callin_map)) + break; /* It has booted */ + udelay(100); + } + + if (test_bit(i, &cpu_callin_map)) { + /* number CPUs logically, starting from 1 (BSP is 0) */ + printk("OK.\n"); + printk("CPU%d: ", i); + print_cpu_info(&cpu_data[i]); + } else { + if (*((volatile unsigned char *)phys_to_virt(8192)) + == 0xA5) /* trampoline code not run */ + printk("Stuck ??\n"); + else + printk("CPU booted but not responding.\n"); + } + dprintk("CPU has booted.\n"); + } else { + __cpu_logical_map[cpucount] = -1; + cpu_number_map[i] = -1; + cpucount--; + } + + swapper_pg_dir[0]=maincfg; + local_flush_tlb(); + + /* mark "stuck" area as not stuck */ + *((volatile unsigned long *)phys_to_virt(8192)) = 0; +} + +cycles_t cacheflush_time; +extern unsigned long cpu_hz; + +static void smp_tune_scheduling (void) +{ + unsigned long cachesize; + /* + * Rough estimation for SMP scheduling, this is the number of + * cycles it takes for a fully memory-limited process to flush + * the SMP-local cache. + * + * (For a P5 this pretty much means we will choose another idle + * CPU almost always at wakeup time (this is due to the small + * L1 cache), on PIIs it's around 50-100 usecs, depending on + * the cache size) + */ + + if (!cpu_hz) { + /* + * this basically disables processor-affinity + * scheduling on SMP without a TSC. + */ + cacheflush_time = 0; + return; + } else { + cachesize = boot_cpu_data.x86_cache_size; + if (cachesize == -1) + cachesize = 8; /* Pentiums */ + + cacheflush_time = cpu_hz/1024*cachesize/5000; + } + + printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", + (long)cacheflush_time/(cpu_hz/1000000), + ((long)cacheflush_time*100/(cpu_hz/1000000)) % 100); +} + +/* + * Cycle through the processors sending APIC IPIs to boot each. + */ + +extern int prof_multiplier[NR_CPUS]; +extern int prof_old_multiplier[NR_CPUS]; +extern int prof_counter[NR_CPUS]; + +void __init smp_boot_cpus(void) +{ + int i; + +#ifdef CONFIG_MTRR + /* Must be done before other processors booted */ + mtrr_init_boot_cpu (); +#endif + /* + * Initialize the logical to physical CPU number mapping + * and the per-CPU profiling counter/multiplier + */ + + for (i = 0; i < NR_CPUS; i++) { + cpu_number_map[i] = -1; + prof_counter[i] = 1; + prof_old_multiplier[i] = 1; + prof_multiplier[i] = 1; + } + + /* + * Setup boot CPU information + */ + + smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */ + smp_tune_scheduling(); + printk("CPU%d: ", boot_cpu_id); + print_cpu_info(&cpu_data[boot_cpu_id]); + + /* + * not necessary because the MP table should list the boot + * CPU too, but we do it for the sake of robustness anyway. + * (and for the case when a non-SMP board boots an SMP kernel) + */ + cpu_present_map |= (1 << hard_smp_processor_id()); + + cpu_number_map[boot_cpu_id] = 0; + + init_idle(); + + /* + * If we couldnt find an SMP configuration at boot time, + * get out of here now! + */ + + if (!smp_found_config) { + printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); +#ifndef CONFIG_VISWS + io_apic_irqs = 0; +#endif + cpu_online_map = cpu_present_map; + smp_num_cpus = 1; + goto smp_done; + } + + /* + * If SMP should be disabled, then really disable it! + */ + + if (!max_cpus) { + smp_found_config = 0; + printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); + } + +#ifdef SMP_DEBUG + { + int reg; + + /* + * This is to verify that we're looking at + * a real local APIC. Check these against + * your board if the CPUs aren't getting + * started for no apparent reason. + */ + + reg = apic_read(APIC_LVR); + dprintk("Getting VERSION: %x\n", reg); + + apic_write(APIC_LVR, 0); + reg = apic_read(APIC_LVR); + dprintk("Getting VERSION: %x\n", reg); + + /* + * The two version reads above should print the same + * NON-ZERO!!! numbers. If the second one is zero, + * there is a problem with the APIC write/read + * definitions. + * + * The next two are just to see if we have sane values. + * They're only really relevant if we're in Virtual Wire + * compatibility mode, but most boxes are anymore. + */ + + + reg = apic_read(APIC_LVT0); + dprintk("Getting LVT0: %x\n", reg); + + reg = apic_read(APIC_LVT1); + dprintk("Getting LVT1: %x\n", reg); + } +#endif + + setup_local_APIC(); + + if (GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_id) + BUG(); + + /* + * Now scan the CPU present map and fire up the other CPUs. + */ + + /* + * Add all detected CPUs. (later on we can down individual + * CPUs which will change cpu_online_map but not necessarily + * cpu_present_map. We are pretty much ready for hot-swap CPUs.) + */ + cpu_online_map = cpu_present_map; + mb(); + + dprintk("CPU map: %lx\n", cpu_present_map); + + for (i = 0; i < NR_CPUS; i++) { + /* + * Don't even attempt to start the boot CPU! + */ + if (i == boot_cpu_id) + continue; + + if ((cpu_online_map & (1 << i)) + && (max_cpus < 0 || max_cpus > cpucount+1)) { + do_boot_cpu(i); + } + + /* + * Make sure we unmap all failed CPUs + */ + if (cpu_number_map[i] == -1 && (cpu_online_map & (1 << i))) { + printk("CPU #%d not responding - cannot use it.\n",i); + cpu_online_map &= ~(1 << i); + } + } + + /* + * Cleanup possible dangling ends... + */ + +#ifndef CONFIG_VISWS + { + unsigned long cfg; + + /* + * Install writable page 0 entry to set BIOS data area. + */ + cfg = pg0[0]; + /* writeable, present, addr 0 */ + pg0[0] = _PAGE_RW | _PAGE_PRESENT | 0; + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + CMOS_WRITE(0, 0xf); + + *((volatile long *) phys_to_virt(0x467)) = 0; + + /* + * Restore old page 0 entry. + */ + pg0[0] = cfg; + local_flush_tlb(); + } +#endif + + /* + * Allow the user to impress friends. + */ + + dprintk("Before bogomips.\n"); + if (!cpucount) { + printk(KERN_ERR "Error: only one processor found.\n"); + cpu_online_map = (1<used_math) __asm__("frstor %0": :"m" (current->thread.i387)); else @@ -489,7 +588,6 @@ void __init trap_init_f00f_bug(void) pmd_t * pmd; pte_t * pte; -return; /* * Allocate a new page in virtual address space, * move the IDT into it and write protect this page. @@ -658,7 +756,7 @@ cobalt_init(void) */ set_fixmap(FIX_APIC_BASE, APIC_PHYS_BASE); printk("Local APIC ID %lx\n", apic_read(APIC_ID)); - printk("Local APIC Version %lx\n", apic_read(APIC_VERSION)); + printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); @@ -679,7 +777,7 @@ void __init trap_init(void) set_trap_gate(0,÷_error); set_trap_gate(1,&debug); - set_trap_gate(2,&nmi); + set_intr_gate(2,&nmi); set_system_gate(3,&int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); set_system_gate(5,&bounds); diff --git a/arch/m68k/config.in b/arch/m68k/config.in index 54e8448d33ed..a458ff609349 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -9,41 +9,32 @@ comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL endmenu -mainmenu_option next_comment -comment 'Loadable module support' -bool 'Enable loadable module support' CONFIG_MODULES -if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD -fi -endmenu - mainmenu_option next_comment comment 'Platform dependent setup' bool 'Amiga support' CONFIG_AMIGA bool 'Atari support' CONFIG_ATARI if [ "$CONFIG_ATARI" = "y" ]; then - bool ' Hades support' CONFIG_HADES - if [ "$CONFIG_HADES" = "y" ]; then - define_bool CONFIG_PCI y - fi + bool ' Hades support' CONFIG_HADES + if [ "$CONFIG_HADES" = "y" ]; then + define_bool CONFIG_PCI y + fi fi bool 'Macintosh support' CONFIG_MAC if [ "$CONFIG_MAC" = "y" ]; then - define_bool CONFIG_NUBUS y - define_bool CONFIG_M68K_L2_CACHE y + define_bool CONFIG_NUBUS y + define_bool CONFIG_M68K_L2_CACHE y fi bool 'Apollo support' CONFIG_APOLLO bool 'VME (Motorola and BVM) support' CONFIG_VME if [ "$CONFIG_VME" = "y" ]; then - bool 'MVME147 support' CONFIG_MVME147 - bool 'MVME162, 166 and 167 support' CONFIG_MVME16x - bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000 + bool ' MVME147 support' CONFIG_MVME147 + bool ' MVME162, 166 and 167 support' CONFIG_MVME16x + bool ' BVME4000 and BVME6000 support' CONFIG_BVME6000 fi bool 'HP9000/300 support' CONFIG_HP300 if [ "$CONFIG_HP300" = "y" ]; then - bool 'DIO bus support' CONFIG_DIO + bool ' DIO bus support' CONFIG_DIO fi bool 'Sun3x support' CONFIG_SUN3X @@ -56,19 +47,19 @@ bool '68030 support' CONFIG_M68030 bool '68040 support' CONFIG_M68040 bool '68060 support' CONFIG_M68060 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Math emulation support' CONFIG_M68KFPU_EMU - if [ "$CONFIG_M68KFPU_EMU" = "y" ]; then - bool 'Math emulation extra precision' CONFIG_M68KFPU_EMU_EXTRAPREC - bool 'Math emulation only kernel' CONFIG_M68KFPU_EMU_ONLY - fi + bool 'Math emulation support (EXPERIMENTAL)' CONFIG_M68KFPU_EMU + if [ "$CONFIG_M68KFPU_EMU" = "y" ]; then + bool ' Math emulation extra precision' CONFIG_M68KFPU_EMU_EXTRAPREC + bool ' Math emulation only kernel' CONFIG_M68KFPU_EMU_ONLY + fi fi bool 'Advanced configuration options' CONFIG_ADVANCED if [ "$CONFIG_ADVANCED" = "y" ]; then - bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS - bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK - if [ "$CONFIG_M68060" = "y" ]; then - bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH - fi + bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS + bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK + if [ "$CONFIG_M68060" = "y" ]; then + bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH + fi fi endmenu @@ -86,55 +77,64 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga Zorro (AutoConfig) bus support' CONFIG_ZORRO if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Amiga 1200/600 PCMCIA support' CONFIG_AMIGA_PCMCIA + bool 'Amiga 1200/600 PCMCIA support (EXPERIMENTAL)' CONFIG_AMIGA_PCMCIA fi fi if [ "$CONFIG_ATARI" = "y" ]; then - bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP - bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC + bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP + bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then - bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT + bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT else if [ "$CONFIG_HP300" = "y" ]; then -# We have a dedicated heartbeat LED. :-) - define_bool CONFIG_HEARTBEAT y + # We have a dedicated heartbeat LED. :-) + define_bool CONFIG_HEARTBEAT y fi fi bool '/proc/hardware support' CONFIG_PROC_HARDWARE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Parallel port support (EXPERIMENTAL)' CONFIG_PARPORT - if [ "$CONFIG_PARPORT" != "n" ]; then - if [ "$CONFIG_AMIGA" != "n" ]; then - dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT - if [ "$CONFIG_ZORRO" != "n" ]; then - dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT + tristate 'Parallel port support (EXPERIMENTAL)' CONFIG_PARPORT + if [ "$CONFIG_PARPORT" != "n" ]; then + if [ "$CONFIG_AMIGA" != "n" ]; then + dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT + if [ "$CONFIG_ZORRO" != "n" ]; then + dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT + fi fi - fi - if [ "$CONFIG_Q40" != "n" ]; then - tristate ' Q40 Parallel port' CONFIG_PARPORT - if [ "$CONFIG_PARPORT" != "n" ]; then - define_bool CONFIG_PARPORT_PC y - fi - fi - fi - if [ "$CONFIG_ATARI" == "y" ]; then - dep_tristate ' Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT - fi - dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT - if [ "$CONFIG_PRINTER" != "n" ]; then - bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK - fi + if [ "$CONFIG_Q40" != "n" ]; then + tristate ' Q40 Parallel port' CONFIG_PARPORT + if [ "$CONFIG_PARPORT" != "n" ]; then + define_bool CONFIG_PARPORT_PC y + fi + fi + fi + if [ "$CONFIG_ATARI" = "y" ]; then + dep_tristate ' Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT + fi + dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT + if [ "$CONFIG_PRINTER" != "n" ]; then + bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK + fi fi endmenu +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD +fi +endmenu + source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in + source net/Config.in fi mainmenu_option next_comment @@ -144,154 +144,154 @@ tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then -comment 'SCSI support type (disk, tape, CD-ROM)' + comment 'SCSI support type (disk, tape, CD-ROM)' -dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI -dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI -dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI -if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR -fi -dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI + dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then + bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + fi + dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI -comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' -bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN + bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN -bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS -bool 'SCSI logging facility' CONFIG_SCSI_LOGGING + bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + bool ' SCSI logging facility' CONFIG_SCSI_LOGGING -mainmenu_option next_comment -comment 'SCSI low-level drivers' + mainmenu_option next_comment + comment 'SCSI low-level drivers' -if [ "$CONFIG_AMIGA" = "y" ]; then - dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'A4000T SCSI support' CONFIG_A4000T_SCSI - fi -fi -if [ "$CONFIG_ZORRO" = "y" ]; then - dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI - dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI - dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI - dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI - dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI - dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI - dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'A4091 SCSI support' CONFIG_A4091_SCSI - bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI - bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI - dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI - bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI -# bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI - fi -fi -if [ "$CONFIG_ATARI" = "y" ]; then - dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI - if [ "$CONFIG_ATARI_SCSI" != "n" ]; then - bool ' Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY - bool ' Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT - if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then - bool ' Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL - fi - fi -fi -if [ "$CONFIG_MAC" = "y" ]; then - bool 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI - dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI -fi -#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI + if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI + fi + fi + if [ "$CONFIG_ZORRO" = "y" ]; then + dep_tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI + dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI + dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI + bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI + bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI + dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI + bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI +# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI + fi + fi + if [ "$CONFIG_ATARI" = "y" ]; then + dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI + if [ "$CONFIG_ATARI_SCSI" != "n" ]; then + bool ' Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY + bool ' Reset SCSI-devices at boottime' CONFIG_ATARI_SCSI_RESET_BOOT + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then + bool ' Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL + fi + fi + fi + if [ "$CONFIG_MAC" = "y" ]; then + bool 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI + dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI + fi +# dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI -if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then - bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI -fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then + bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI + fi -if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then - bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI -fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then + bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI + fi -if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then - bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI -fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then + bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI + fi -if [ "$CONFIG_SUN3X" = "y" ]; then - bool 'ESP SCSI driver' CONFIG_SUN3X_ESP -fi + if [ "$CONFIG_SUN3X" = "y" ]; then + bool 'ESP SCSI driver' CONFIG_SUN3X_ESP + fi -endmenu + endmenu fi endmenu if [ "$CONFIG_NET" = "y" ]; then -mainmenu_option next_comment -comment 'Network device support' - -bool 'Network device support' CONFIG_NETDEVICES -if [ "$CONFIG_NETDEVICES" = "y" ]; then -# -# Network device configuration -# -tristate 'Dummy net driver support' CONFIG_DUMMY -tristate 'SLIP (serial line) support' CONFIG_SLIP -if [ "$CONFIG_SLIP" != "n" ]; then - bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED - bool ' Keepalive and linefill' CONFIG_SLIP_SMART - bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 -fi -tristate 'PPP (point-to-point) support' CONFIG_PPP -if [ ! "$CONFIG_PPP" = "n" ]; then - comment 'CCP compressors for PPP are only built as modules.' -fi -tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER -if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'Ariadne support' CONFIG_ARIADNE - tristate 'Ariadne II support' CONFIG_ARIADNE2 - tristate 'A2065 support' CONFIG_A2065 - tristate 'Hydra support' CONFIG_HYDRA -fi -if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then - tristate 'PCMCIA NE2000 support' CONFIG_APNE -fi -if [ "$CONFIG_APOLLO" = "y" ] ; then - tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS -fi -if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT -# bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE - bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC -fi -if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then - tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET -fi -if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then - tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET -fi -if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then - tristate 'BVME6000 Ethernet support' CONFIG_BVME6000_NET -fi -if [ "$CONFIG_ATARI" = "y" ]; then - tristate 'Atari Lance support' CONFIG_ATARILANCE - if [ "$CONFIG_ATARI_ACSI" != "n" ]; then - tristate 'BioNet-100 support' CONFIG_ATARI_BIONET - tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET - fi -fi -if [ "$CONFIG_SUN3X" = "y" ]; then - bool 'Sun3x Lance support' CONFIG_SUNLANCE -fi -if [ "$CONFIG_HP300" = "y" ]; then - bool 'HP on-board LANCE support' CONFIG_HPLANCE -fi -if [ "$CONFIG_Q40" = "y" ]; then - if [ ! "$CONFIG_PARPORT" = "n" ]; then - dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT - fi -fi -fi -endmenu + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + # + # Network device configuration + # + tristate ' Dummy net driver support' CONFIG_DUMMY + tristate ' SLIP (serial line) support' CONFIG_SLIP + if [ "$CONFIG_SLIP" != "n" ]; then + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED + bool ' Keepalive and linefill' CONFIG_SLIP_SMART + bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 + fi + tristate ' PPP (point-to-point) support' CONFIG_PPP + if [ ! "$CONFIG_PPP" = "n" ]; then + comment 'CCP compressors for PPP are only built as modules.' + fi + tristate ' EQL (serial line load balancing) support' CONFIG_EQUALIZER + if [ "$CONFIG_ZORRO" = "y" ]; then + tristate ' Ariadne support' CONFIG_ARIADNE + tristate ' Ariadne II support' CONFIG_ARIADNE2 + tristate ' A2065 support' CONFIG_A2065 + tristate ' Hydra support' CONFIG_HYDRA + fi + if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then + tristate ' PCMCIA NE2000 support' CONFIG_APNE + fi + if [ "$CONFIG_APOLLO" = "y" ]; then + tristate ' Apollo 3c505 support' CONFIG_APOLLO_ELPLUS + fi + if [ "$CONFIG_MAC" = "y" ]; then + bool ' Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT +# bool ' Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE + bool ' Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC + fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then + tristate ' MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET + fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then + tristate ' MVME16x Ethernet support' CONFIG_MVME16x_NET + fi + if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then + tristate ' BVME6000 Ethernet support' CONFIG_BVME6000_NET + fi + if [ "$CONFIG_ATARI" = "y" ]; then + tristate ' Atari Lance support' CONFIG_ATARILANCE + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + tristate ' BioNet-100 support' CONFIG_ATARI_BIONET + tristate ' PAMsNet support' CONFIG_ATARI_PAMSNET + fi + fi + if [ "$CONFIG_SUN3X" = "y" ]; then + bool ' Sun3x Lance support' CONFIG_SUNLANCE + fi + if [ "$CONFIG_HP300" = "y" ]; then + bool ' HP on-board LANCE support' CONFIG_HPLANCE + fi + if [ "$CONFIG_Q40" = "y" ]; then + if [ ! "$CONFIG_PARPORT" = "n" ]; then + dep_tristate ' PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT + fi + fi + fi + endmenu fi @@ -303,85 +303,85 @@ if [ "$CONFIG_Q40" = "y" ]; then fi if [ "$CONFIG_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE - bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + bool ' Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED fi if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then - bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS - bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ -# bool ' Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ - bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT - bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 + bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS + bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ +# bool ' Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ + bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT + bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 fi if [ "$CONFIG_VME" = "n" ]; then - define_bool CONFIG_VT y - if [ "$CONFIG_VT" = "y" ]; then - bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE - fi + define_bool CONFIG_VT y + if [ "$CONFIG_VT" = "y" ]; then + bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE + fi fi if [ "$CONFIG_ATARI" = "y" ]; then - define_bool CONFIG_NVRAM y + define_bool CONFIG_NVRAM y fi if [ "$CONFIG_AMIGA" = "y" ]; then - tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE - if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then - define_bool CONFIG_BUSMOUSE y - fi + tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE + if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then + define_bool CONFIG_BUSMOUSE y + fi fi if [ "$CONFIG_ATARI" = "y" ]; then - tristate 'Atari mouse support' CONFIG_ATARIMOUSE - if [ "$CONFIG_ATARIMOUSE" != "n" ]; then - define_bool CONFIG_BUSMOUSE y - fi + tristate 'Atari mouse support' CONFIG_ATARIMOUSE + if [ "$CONFIG_ATARIMOUSE" != "n" ]; then + define_bool CONFIG_BUSMOUSE y + fi fi if [ "$CONFIG_MAC" = "y" ]; then bool 'Mac ADB mouse support' CONFIG_ADBMOUSE - if [ "$CONFIG_ADBMOUSE" != "n" ]; then - define_bool CONFIG_BUSMOUSE y - fi + if [ "$CONFIG_ADBMOUSE" != "n" ]; then + define_bool CONFIG_BUSMOUSE y + fi fi if [ "$CONFIG_ATARI" = "y" ]; then - tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER - tristate 'Atari SCC serial support' CONFIG_ATARI_SCC - if [ "$CONFIG_ATARI_SCC" = "y" -o "$CONFIG_ATARI_SCC" = "m" ]; then - bool 'Atari SCC serial DMA support' CONFIG_ATARI_SCC_DMA - fi - tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Atari DSP56k support (EXPERIMENTAL)' CONFIG_ATARI_DSP56K - fi + tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER + tristate 'Atari SCC serial support' CONFIG_ATARI_SCC + if [ "$CONFIG_ATARI_SCC" = "y" -o "$CONFIG_ATARI_SCC" = "m" ]; then + bool ' Atari SCC serial DMA support' CONFIG_ATARI_SCC_DMA + fi + tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Atari DSP56k support (EXPERIMENTAL)' CONFIG_ATARI_DSP56K + fi fi if [ "$CONFIG_AMIGA" = "y" ]; then - tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL - if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then - tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL - fi + tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL + if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then + tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL + fi fi if [ "$CONFIG_PARPORT" = "n" ]; then - if [ "$CONFIG_ZORRO" = "y" ]; then - tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT - dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT - dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT - tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY - fi + if [ "$CONFIG_ZORRO" = "y" ]; then + tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT + dep_tristate ' GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT + dep_tristate ' GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT + tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY + fi fi if [ "$CONFIG_MAC" = "y" ]; then - bool 'Mac SCC serial support' CONFIG_MAC_SCC + bool 'Mac SCC serial support' CONFIG_MAC_SCC fi if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then - tristate 'HP DCA serial support' CONFIG_HPDCA + tristate 'HP DCA serial support' CONFIG_HPDCA fi if [ "$CONFIG_SUN3X" = "y" ]; then - bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS - if [ "$CONFIG_SUN3X_ZS" = "y" ]; then - bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD - bool 'Sun mouse support' CONFIG_SUN_MOUSE - if [ "$CONFIG_SUN_MOUSE" != "n" ]; then - define_bool CONFIG_BUSMOUSE y + bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS + if [ "$CONFIG_SUN3X_ZS" = "y" ]; then + bool ' Sun keyboard support' CONFIG_SUN_KEYBOARD + bool ' Sun mouse support' CONFIG_SUN_MOUSE + if [ "$CONFIG_SUN_MOUSE" != "n" ]; then + define_bool CONFIG_BUSMOUSE y fi define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y @@ -391,43 +391,43 @@ fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \ "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \ "$CONFIG_SUN3X" = "y" ]; then - if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ - "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \ - "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ - "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \ - "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then - bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE - fi + if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ + "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \ + "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ + "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \ + "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then + bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE + fi fi if [ "$CONFIG_VME" = "y" ]; then - define_bool CONFIG_SERIAL_CONSOLE y - if [ "$CONFIG_MVME147" = "y" ]; then - bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC - fi - if [ "$CONFIG_MVME16x" = "y" ]; then - bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167 - bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC - fi - if [ "$CONFIG_BVME6000" = "y" ]; then - bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC - fi + define_bool CONFIG_SERIAL_CONSOLE y + if [ "$CONFIG_MVME147" = "y" ]; then + bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC + fi + if [ "$CONFIG_MVME16x" = "y" ]; then + bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167 + bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC + fi + if [ "$CONFIG_BVME6000" = "y" ]; then + bool 'SCC support for BVME6000 serial ports' CONFIG_BVME6000_SCC + fi fi if [ "$CONFIG_APOLLO" = "y" ]; then - bool 'Support for DN serial port (dummy)' CONFIG_SERIAL - bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE + bool 'Support for DN serial port (dummy)' CONFIG_SERIAL + bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then - bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT - bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG + bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT + bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG fi if [ "$CONFIG_ATARI" = "y" ]; then - bool 'Enhanced Real Time Clock Support' CONFIG_RTC + bool 'Enhanced Real Time Clock Support' CONFIG_RTC fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 + int ' Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 fi endmenu @@ -437,22 +437,22 @@ comment 'Sound support' tristate 'Sound support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then - dep_tristate 'Amiga or Atari DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND + dep_tristate ' Amiga or Atari DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND fi endmenu source fs/Config.in if [ "$CONFIG_VME" = "n" ]; then - mainmenu_option next_comment - comment 'Console drivers' - if [ "$CONFIG_HP300" = "y" ]; then - bool 'Frame buffer support' CONFIG_FB - else - define_bool CONFIG_FB y - fi - source drivers/video/Config.in - endmenu + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_HP300" = "y" ]; then + bool 'Frame buffer support' CONFIG_FB + else + define_bool CONFIG_FB y + fi + source drivers/video/Config.in + endmenu fi mainmenu_option next_comment diff --git a/arch/mips/config.in b/arch/mips/config.in index 0c26f1a8b923..2375108f4c7d 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -13,9 +13,9 @@ mainmenu_option next_comment comment 'Machine selection' bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Support for Algorithmics P4032' CONFIG_ALGOR_P4032 - bool 'Support for BAGET MIPS series' CONFIG_BAGET_MIPS - bool 'Support for DECstations' CONFIG_DECSTATION + bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032 + bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS + bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION fi bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700 @@ -30,19 +30,19 @@ unset CONFIG_MIPS_JAZZ unset CONFIG_VIDEO_G364 if [ "$CONFIG_ALGOR_P4032" = "y" ]; then - define_bool CONFIG_PCI y + define_bool CONFIG_PCI y fi if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ "$CONFIG_OLIVETTI_M700" = "y" ]; then - define_bool CONFIG_MIPS_JAZZ y - define_bool CONFIG_FB y - define_bool CONFIG_FB_G364 y + define_bool CONFIG_MIPS_JAZZ y + define_bool CONFIG_FB y + define_bool CONFIG_FB_G364 y fi if [ "$CONFIG_ACER_PICA_61" = "y" ]; then - define_bool CONFIG_MIPS_JAZZ y + define_bool CONFIG_MIPS_JAZZ y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then - define_bool CONFIG_PCI y + define_bool CONFIG_PCI y fi endmenu @@ -64,16 +64,16 @@ mainmenu_option next_comment comment 'General setup' if [ "$CONFIG_DECSTATION" = "y" ]; then - define_bool CONFIG_CPU_LITTLE_ENDIAN y + define_bool CONFIG_CPU_LITTLE_ENDIAN y else - bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN + bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN fi define_bool CONFIG_ELF_KERNEL y if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then - define_bool CONFIG_BINFMT_IRIX y - define_bool CONFIG_FORWARD_KEYBOARD y + define_bool CONFIG_BINFMT_IRIX y + define_bool CONFIG_FORWARD_KEYBOARD y fi define_bool CONFIG_BINFMT_AOUT n define_bool CONFIG_BINFMT_ELF y @@ -85,7 +85,7 @@ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then -source drivers/parport/Config.in + source drivers/parport/Config.in fi endmenu @@ -93,24 +93,20 @@ mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD -fi - -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB + bool ' Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD fi endmenu if [ "$CONFIG_DECSTATION" = "y" ]; then - mainmenu_option next_comment - comment 'TURBOchannel support' - bool 'TURBOchannel support' CONFIG_TC -# if [ "$CONFIG_TC" = "y" ]; then -# tristate 'MAGMA Parallel port support' CONFIG_PARPORT -# fi - endmenu + mainmenu_option next_comment + comment 'TURBOchannel support' + bool 'TURBOchannel support' CONFIG_TC +# if [ "$CONFIG_TC" = "y" ]; then +# tristate ' MAGMA Parallel port support' CONFIG_PARPORT +# fi + endmenu fi source drivers/i2o/Config.in @@ -120,7 +116,7 @@ source drivers/pnp/Config.in source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in + source net/Config.in fi mainmenu_option next_comment @@ -129,125 +125,125 @@ comment 'SCSI support' tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then - if [ "$CONFIG_SGI" = "y" -o "$CONFIG_DECSTATION" = "y" ]; then - comment 'SCSI support type (disk, tape, CDrom)' - - dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI - dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI - dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI - dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI - - comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' - - bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN - - bool 'Verbose SCSI error reporting' CONFIG_SCSI_CONSTANTS - - #mainmenu_option next_comment - comment 'SCSI low-level drivers' - if [ "$CONFIG_SGI" = "y" ]; then - dep_tristate 'SGI wd93 Scsi Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI - else - if [ "$CONFIG_TC" = "y" ]; then - dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI - fi - dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI - fi - else - source drivers/scsi/Config.in - fi + if [ "$CONFIG_SGI" = "y" -o "$CONFIG_DECSTATION" = "y" ]; then + comment ' SCSI support type (disk, tape, CDrom)' + + dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + dep_tristate ' SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI + + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' + + bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN + + bool ' Verbose SCSI error reporting' CONFIG_SCSI_CONSTANTS + + #mainmenu_option next_comment + comment 'SCSI low-level drivers' + if [ "$CONFIG_SGI" = "y" ]; then + dep_tristate 'SGI wd93 Scsi Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI + else + if [ "$CONFIG_TC" = "y" ]; then + dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI + fi + dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI + fi + else + source drivers/scsi/Config.in + fi fi endmenu if [ "$CONFIG_NET" = "y" ]; then - mainmenu_option next_comment - comment 'Network device support' - - bool 'Network device support' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then - source drivers/net/Config.in - else - tristate 'Dummy net driver support' CONFIG_DUMMY - tristate 'SLIP (serial line) support' CONFIG_SLIP - if [ "$CONFIG_SLIP" != "n" ]; then - bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED - bool ' Keepalive and linefill' CONFIG_SLIP_SMART - fi - tristate 'PPP (point-to-point) support' CONFIG_PPP - if [ ! "$CONFIG_PPP" = "n" ]; then - comment 'CCP compressors for PPP are only built as modules.' - fi - if [ "$CONFIG_SGI" = "y" ]; then - bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ - fi - if [ "$CONFIG_DECSTATION" = "y" ]; then - bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi - if [ "$CONFIG_BAGET_MIPS" = "y" ]; then - tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE - tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM - fi - fi - fi - endmenu + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then + source drivers/net/Config.in + else + tristate ' Dummy net driver support' CONFIG_DUMMY + tristate ' SLIP (serial line) support' CONFIG_SLIP + if [ "$CONFIG_SLIP" != "n" ]; then + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED + bool ' Keepalive and linefill' CONFIG_SLIP_SMART + fi + tristate ' PPP (point-to-point) support' CONFIG_PPP + if [ ! "$CONFIG_PPP" = "n" ]; then + comment ' CCP compressors for PPP are only built as modules.' + fi + if [ "$CONFIG_SGI" = "y" ]; then + bool ' SGI Seeq ethernet controller support' CONFIG_SGISEEQ + fi + if [ "$CONFIG_DECSTATION" = "y" ]; then + bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE + fi + if [ "$CONFIG_BAGET_MIPS" = "y" ]; then + tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE + tristate ' Baget Backplane Shared Memory support' CONFIG_BAGETBSM + fi + fi + fi + endmenu fi if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then - source drivers/net/hamradio/Config.in + source drivers/net/hamradio/Config.in - mainmenu_option next_comment - comment 'ISDN subsystem' + mainmenu_option next_comment + comment 'ISDN subsystem' - if [ "$CONFIG_NET" != "n" ]; then - tristate 'ISDN support' CONFIG_ISDN - if [ "$CONFIG_ISDN" != "n" ]; then - source drivers/isdn/Config.in - fi - fi - endmenu + if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi + fi + endmenu - mainmenu_option next_comment - comment comment 'Old CD-ROM drivers (not SCSI, not IDE)' + mainmenu_option next_comment + comment comment 'Old CD-ROM drivers (not SCSI, not IDE)' - bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI - if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then - source drivers/cdrom/Config.in - fi - endmenu + bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI + if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in + fi + endmenu fi if [ "$CONFIG_DECSTATION" != "y" ]; then - source drivers/char/Config.in + source drivers/char/Config.in else - mainmenu_option next_comment - comment 'DECstation Character devices' - - bool 'Virtual terminal' CONFIG_VT - if [ "$CONFIG_VT" = "y" ]; then - bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE - fi - tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL - if [ "$CONFIG_SGI" = "y" ]; then - bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE - fi - if [ "$CONFIG_SERIAL" = "y" ]; then - bool 'DZ11 Serial Support' CONFIG_DZ - if [ "$CONFIG_TC" = "y" ]; then - bool 'Z85C30 Serial Support' CONFIG_ZS - fi - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE - fi - bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS - if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 - fi - bool 'Keyboard Support' CONFIG_KEYBOARD - bool 'Mouse Support' CONFIG_MOUSE -# bool 'Enhanced Real Time Clock Support' CONFIG_RTC - endmenu + mainmenu_option next_comment + comment 'DECstation Character devices' + + bool 'Virtual terminal' CONFIG_VT + if [ "$CONFIG_VT" = "y" ]; then + bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE + fi + if [ "$CONFIG_SGI" = "y" ]; then + bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE + fi + tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL + if [ "$CONFIG_SERIAL" = "y" ]; then + bool ' DZ11 Serial Support' CONFIG_DZ + if [ "$CONFIG_TC" = "y" ]; then + bool ' Z85C30 Serial Support' CONFIG_ZS + fi + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + fi + bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS + if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 + fi + bool 'Keyboard Support' CONFIG_KEYBOARD + bool 'Mouse Support' CONFIG_MOUSE +# bool 'Enhanced Real Time Clock Support' CONFIG_RTC + endmenu fi source drivers/usb/Config.in @@ -255,36 +251,36 @@ source drivers/usb/Config.in source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - if [ "$CONFIG_SGI" = "y" ]; then - tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE - if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y - fi - else - if [ "$CONFIG_DECSTATION" != "y" ]; then - bool 'VGA text console' CONFIG_VGA_CONSOLE - fi - bool 'Support for frame buffer devices' CONFIG_FB - source drivers/video/Config.in - fi - endmenu + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_SGI" = "y" ]; then + tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE + if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + else + if [ "$CONFIG_DECSTATION" != "y" ]; then + bool 'VGA text console' CONFIG_VGA_CONSOLE + fi + bool 'Support for frame buffer devices' CONFIG_FB + source drivers/video/Config.in + fi + endmenu fi if [ "$CONFIG_DECSTATION" != "y" ]; then - mainmenu_option next_comment - comment 'Sound' - - tristate 'Sound card support' CONFIG_SOUND - if [ "$CONFIG_SOUND" != "n" ]; then - source drivers/sound/Config.in - fi - endmenu + mainmenu_option next_comment + comment 'Sound' + + tristate 'Sound card support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in + fi + endmenu fi if [ "$CONFIG_SGI" = "y" ]; then - source drivers/sgi/Config.in + source drivers/sgi/Config.in fi mainmenu_option next_comment @@ -293,10 +289,10 @@ comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE if [ "$CONFIG_MODULES" = "y" ]; then - bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE + bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE fi if [ "$CONFIG_SERIAL" = "y" ]; then - bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG + bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff --git a/arch/mips/kernel/pci.c b/arch/mips/kernel/pci.c index 49ddf61a1373..98723b746192 100644 --- a/arch/mips/kernel/pci.c +++ b/arch/mips/kernel/pci.c @@ -13,7 +13,6 @@ #include #include #include -#include #ifdef CONFIG_PCI diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c index 845bb370c6d6..b1d7f49dcda1 100644 --- a/arch/mips/sni/pci.c +++ b/arch/mips/sni/pci.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #ifdef CONFIG_PCI diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 574dfee25299..5da395473897 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -31,7 +31,6 @@ #include #include #include -#include /* * Initial irq handlers. diff --git a/arch/ppc/8xx_io/Config.in b/arch/ppc/8xx_io/Config.in new file mode 100644 index 000000000000..7af7116fff94 --- /dev/null +++ b/arch/ppc/8xx_io/Config.in @@ -0,0 +1,16 @@ +# +# MPC8xx Communication options +# +if [ "$CONFIG_NET_ETHERNET" = "y" ]; then + mainmenu_option next_comment + comment 'MPC8xx Communication Options' + bool 'CPM SCC Ethernet' CONFIG_SCC_ENET + if [ "$CONFIG_SCC_ENET" = "y" ]; then + bool 'Ethernet on SCC1' CONFIG_SCC1_ENET + if [ "$CONFIG_SCC1_ENET" != "y" ]; then + bool 'Ethernet on SCC2' CONFIG_SCC2_ENET + fi + fi + bool '860T FEC Ethernet' CONFIG_FEC_ENET + endmenu +fi diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile index 0da0a492d68c..aecb92c2a69b 100644 --- a/arch/ppc/8xx_io/Makefile +++ b/arch/ppc/8xx_io/Makefile @@ -9,11 +9,12 @@ O_TARGET := 8xx_io.a O_OBJS = commproc.o uart.o -ifdef CONFIG_MBX -O_OBJS += enet.o -endif -ifdef CONFIG_FADS + +ifdef CONFIG_FEC_ENET O_OBJS += fec.o endif +ifdef CONFIG_SCC_ENET +O_OBJS += enet.o +endif include $(TOPDIR)/Rules.make diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 707f3c97cc2c..acdc7c11dba9 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -30,12 +30,7 @@ #include #include #include -#ifdef CONFIG_MBX -#include -#endif -#ifdef CONFIG_FADS -#include -#endif +#include #include #include #include @@ -95,32 +90,36 @@ m8xx_cpm_reset(uint host_page_addr) */ dp_alloc_base = CPM_DATAONLY_BASE; dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; + /* Set the host page for allocation. */ host_buffer = host_page_addr; /* Host virtual page address */ host_end = host_page_addr + PAGE_SIZE; - pte = va_to_pte(&init_task, host_page_addr); + pte = find_pte(&init_mm, host_page_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(current->mm->mmap, host_buffer); /* Tell everyone where the comm processor resides. */ cpmp = (cpm8xx_t *)commproc; +} +/* This is called during init_IRQ. We used to do it above, but this + * was too early since init_IRQ was not yet called. + */ +void +cpm_interrupt_init(void) +{ /* Initialize the CPM interrupt controller. */ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | - (((5)/2) << 13) | CICR_HP_MASK; - /* I hard coded the CPM interrupt to 5 above - * since the CPM_INTERRUPT define is relative to - * the linux irq structure not what the hardware - * belives. -- Cort - */ + ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; + /* Set our interrupt handler with the core CPU. */ - if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) + if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) panic("Could not allocate CPM IRQ!"); /* Install our own error handler. @@ -178,6 +177,16 @@ cpm_install_handler(int vec, void (*handler)(void *), void *dev_id) ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); } +/* Free a CPM interrupt handler. +*/ +void +cpm_free_handler(int vec) +{ + cpm_vecs[vec].handler = NULL; + cpm_vecs[vec].dev_id = NULL; + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); +} + /* Allocate some memory from the dual ported ram. We may want to * enforce alignment restrictions, but right now everyone is a good * citizen. @@ -218,7 +227,7 @@ m8xx_cpm_hostalloc(uint size) * The internal baud rate clock is the system clock divided by 16. * This assumes the baudrate is 16x oversampled by the uart. */ -#define BRG_INT_CLK (((bd_t *)res)->bi_intfreq * 1000000) +#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) #define BRG_UART_CLK (BRG_INT_CLK/16) void diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h index 50140ab267f0..373db5fef37c 100644 --- a/arch/ppc/8xx_io/commproc.h +++ b/arch/ppc/8xx_io/commproc.h @@ -32,6 +32,7 @@ #define CPM_CR_INIT_TRX ((ushort)0x0000) #define CPM_CR_INIT_RX ((ushort)0x0001) #define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) #define CPM_CR_STOP_TX ((ushort)0x0004) #define CPM_CR_RESTART_TX ((ushort)0x0006) #define CPM_CR_SET_GADDR ((ushort)0x0008) @@ -78,6 +79,7 @@ typedef struct cpm_buf_desc { #define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ #define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ #define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ #define BD_SC_CM ((ushort)0x0200) /* Continous mode */ #define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ #define BD_SC_P ((ushort)0x0100) /* xmt preamble */ @@ -90,6 +92,7 @@ typedef struct cpm_buf_desc { /* Parameter RAM offsets. */ #define PROFF_SCC1 ((uint)0x0000) +#define PROFF_IIC ((uint)0x0080) #define PROFF_SCC2 ((uint)0x0100) #define PROFF_SCC3 ((uint)0x0200) #define PROFF_SMC1 ((uint)0x0280) @@ -97,6 +100,7 @@ typedef struct cpm_buf_desc { #define PROFF_SMC2 ((uint)0x0380) /* Define enough so I can at least use the serial port as a UART. + * The MBX uses SMC1 as the host serial port. */ typedef struct smc_uart { ushort smc_rbase; /* Rx Buffer descriptor base address */ @@ -136,11 +140,54 @@ typedef struct smc_uart { #define SMCMR_SM_TRANS ((ushort)0x0030) #define SMCMR_SM_MASK ((ushort)0x0030) #define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN #define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN #define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ #define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ #define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) +/* SMC2 as Centronics parallel printer. It is half duplex, in that + * it can only receive or transmit. The parameter ram values for + * each direction are either unique or properly overlap, so we can + * include them in one structure. + */ +typedef struct smc_centronics { + ushort scent_rbase; + ushort scent_tbase; + u_char scent_cfcr; + u_char scent_smask; + ushort scent_mrblr; + uint scent_rstate; + uint scent_r_ptr; + ushort scent_rbptr; + ushort scent_r_cnt; + uint scent_rtemp; + uint scent_tstate; + uint scent_t_ptr; + ushort scent_tbptr; + ushort scent_t_cnt; + uint scent_ttemp; + ushort scent_max_sl; + ushort scent_sl_cnt; + ushort scent_character1; + ushort scent_character2; + ushort scent_character3; + ushort scent_character4; + ushort scent_character5; + ushort scent_character6; + ushort scent_character7; + ushort scent_character8; + ushort scent_rccm; + ushort scent_rccr; +} smc_cent_t; + +/* Centronics Status Mask Register. +*/ +#define SMC_CENT_F ((u_char)0x08) +#define SMC_CENT_PE ((u_char)0x04) +#define SMC_CENT_S ((u_char)0x02) + /* SMC Event and Mask register. */ #define SMCM_TXE ((unsigned char)0x10) @@ -329,6 +376,7 @@ typedef struct scc_enet { ushort sen_taddrl; /* temp address (LSB) */ } scc_enet_t; +#ifdef CONFIG_MBX /* Bits in parallel I/O port registers that have to be set/cleared * to configure the pins for SCC1 use. The TCLK and RCLK seem unique * to the MBX860 board. Any two of the four available clocks could be @@ -348,6 +396,65 @@ typedef struct scc_enet { */ #define SICR_ENET_MASK ((uint)0x000000ff) #define SICR_ENET_CLKRT ((uint)0x0000003d) +#endif + +#ifdef CONFIG_RPXLITE +/* This ENET stuff is for the MPC850 with ethernet on SCC2. Some of + * this may be unique to the RPX-Lite configuration. + * Note TENA is on Port B. + */ +#define PA_ENET_RXD ((ushort)0x0004) +#define PA_ENET_TXD ((ushort)0x0008) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PB_ENET_TENA ((uint)0x00002000) +#define PC_ENET_CLSN ((ushort)0x0040) +#define PC_ENET_RENA ((ushort)0x0080) + +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00003d00) +#endif + +#ifdef CONFIG_BSEIP +/* This ENET stuff is for the MPC823 with ethernet on SCC2. + * This is unique to the BSE ip-Engine board. + */ +#define PA_ENET_RXD ((ushort)0x0004) +#define PA_ENET_TXD ((ushort)0x0008) +#define PA_ENET_TCLK ((ushort)0x0100) +#define PA_ENET_RCLK ((ushort)0x0200) +#define PB_ENET_TENA ((uint)0x00002000) +#define PC_ENET_CLSN ((ushort)0x0040) +#define PC_ENET_RENA ((ushort)0x0080) + +/* BSE uses port B and C bits for PHY control also. +*/ +#define PB_BSE_POWERUP ((uint)0x00000004) +#define PB_BSE_FDXDIS ((uint)0x00008000) +#define PC_BSE_LOOPBACK ((ushort)0x0800) + +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002c00) +#endif + +#ifdef CONFIG_RPXCLASSIC +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0001) +#define PA_ENET_TXD ((ushort)0x0002) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PB_ENET_TENA ((uint)0x00001000) +#define PC_ENET_CLSN ((ushort)0x0010) +#define PC_ENET_RENA ((ushort)0x0020) + +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000003d) +#endif /* SCC Event register as used by Ethernet. */ @@ -476,6 +583,30 @@ typedef struct scc_trans { uint st_cmask; /* Constant mask for CRC */ } scc_trans_t; +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ +} iic_t; + +#define BD_IIC_START ((ushort)0x0400) + /* CPM interrupts. There are nearly 32 interrupts generated by CPM * channels or devices. All of these are presented to the PPC core * as a single interrupt. The CPM interrupt handler dispatches its diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index 737abbebfa88..879b326a789e 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -4,12 +4,13 @@ * * I copied the basic skeleton from the lance driver, because I did not * know how to write the Linux driver, but I did know how the LANCE worked. - * This version of the driver is specific to the MBX implementation, - * since the board contains control registers external to the processor - * for the control of the MC68160 SIA/transceiver. The MPC860 manual - * describes connections using the internal parallel port I/O. * - * The MBX860 uses the CPM SCC1 serial port for the Ethernet interface. + * This version of the driver is somewhat selectable for the different + * processor/board combinations. It works for the boards I know about + * now, and should be easily modified to include others. Some of the + * configuration information is contained in "commproc.h" and the + * remainder is here. + * * Buffer descriptors are kept in the CPM dual port RAM, and the frame * buffers are in the host memory. * @@ -21,7 +22,6 @@ * small packets. * */ -#include #include #include #include @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include #include "commproc.h" @@ -164,16 +164,17 @@ static void set_multicast_list(struct net_device *dev); */ /*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/ -/* Right now, only the boards with an 860 use SCC1 for the Ethernet. - * All others use SCC2. We may need to make this board specific someday. +/* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards + * use SCC2. This is easily extended if necessary. */ -#ifndef CONFIG_MPC860 -/*static ushort my_enet_addr[] = { 0x2700, 0x00ec, 0x1000 };*/ +#ifdef CONFIG_SCC2_ENET #define CPM_CR_ENET CPM_CR_CH_SCC2 #define PROFF_ENET PROFF_SCC2 #define SCC_ENET 1 /* Index, not number! */ #define CPMVEC_ENET CPMVEC_SCC2 -#else +#endif + +#ifdef CONFIG_SCC1_ENET #define CPM_CR_ENET CPM_CR_CH_SCC1 #define PROFF_ENET PROFF_SCC1 #define SCC_ENET 0 @@ -326,7 +327,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) static void cpm_enet_interrupt(void *dev_id) { - struct net_device *dev = dev_id; + struct net_device *dev = dev_id; volatile struct cpm_enet_private *cep; volatile cbd_t *bdp; ushort int_events; @@ -357,43 +358,10 @@ cpm_enet_interrupt(void *dev_id) * I don't know if "normally" implies TXB is set when the buffer * descriptor is closed.....trial and error :-). */ -#if 0 - if (int_events & SCCE_ENET_TXE) { - - /* Transmission errors. - */ - bdp = cep->dirty_tx; -#ifndef final_version - printk("CPM ENET xmit error %x\n", bdp->cbd_sc); - if (bdp->cbd_sc & BD_ENET_TX_READY) - printk("HEY! Enet xmit interrupt and TX_READY.\n"); -#endif - if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ - cep->stats.tx_heartbeat_errors++; - if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ - cep->stats.tx_window_errors++; - if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ - cep->stats.tx_aborted_errors++; - if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ - cep->stats.tx_fifo_errors++; - if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ - cep->stats.tx_carrier_errors++; - - cep->stats.tx_errors++; - - /* No heartbeat or Lost carrier are not really bad errors. - * The others require a restart transmit command. - */ - if (bdp->cbd_sc & - (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) - must_restart = 1; - } -#endif /* Transmit OK, or non-fatal error. Update the buffer descriptors. */ if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { -#if 1 bdp = cep->dirty_tx; while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) @@ -421,13 +389,7 @@ cpm_enet_interrupt(void *dev_id) } cep->stats.tx_packets++; -#else - bdp = cep->dirty_tx; -#if 1 - if (bdp->cbd_sc & BD_ENET_TX_READY) - printk("HEY! Enet xmit interrupt and TX_READY.\n"); -#endif -#endif + /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ @@ -697,9 +659,7 @@ static void set_multicast_list(struct net_device *dev) * transmit and receive to make sure we don't catch the CPM with some * inconsistent control information. */ -/* until this gets cleared up -- Cort */ -int __init cpm_enet_init() { m8xx_enet_init(); } -int __init m8xx_enet_init(void) +int __init cpm_enet_init(void) { struct net_device *dev; struct cpm_enet_private *cep; @@ -718,7 +678,7 @@ int __init m8xx_enet_init(void) immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ - bd = (bd_t *)res; + bd = (bd_t *)__res; /* Allocate some private information. */ @@ -830,8 +790,8 @@ int __init m8xx_enet_init(void) ep->sen_maxflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ ep->sen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ - ep->sen_maxd1 = PKT_MAXBUF_SIZE; /* maximum DMA1 length */ - ep->sen_maxd2 = PKT_MAXBUF_SIZE; /* maximum DMA2 length */ + ep->sen_maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ + ep->sen_maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ /* Clear hash tables. */ @@ -849,6 +809,9 @@ int __init m8xx_enet_init(void) * If we performed a MBX diskless boot, the Ethernet controller * has been initialized and we copy the address out into our * own structure. + * + * All other types of boards supply the address in the board + * information structure, so we copy that into the controller. */ eap = (unsigned char *)&(ep->sen_paddrh); #ifndef CONFIG_MBX @@ -891,7 +854,7 @@ int __init m8xx_enet_init(void) /* Make it uncached. */ - pte = va_to_pte(&init_task, mem_addr); + pte = find_pte(&init_mm, mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(current->mm->mmap, mem_addr); @@ -983,7 +946,9 @@ int __init m8xx_enet_init(void) dev->base_addr = (unsigned long)ep; dev->priv = cep; +#if 0 dev->name = "CPM_ENET"; +#endif /* The CPM Ethernet specific entries in the device structure. */ dev->open = cpm_enet_open; @@ -996,7 +961,7 @@ int __init m8xx_enet_init(void) */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - printk("CPM ENET Version 0.1, "); + printk("%s: CPM 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]); diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index fb12757f5fd5..aa45d4d27b47 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include #include @@ -123,7 +123,7 @@ static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; */ typedef struct mii_list { uint mii_regval; - void (*mii_func)(uint val); + void (*mii_func)(int val); struct mii_list *mii_next; } mii_list_t; @@ -244,7 +244,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Push the data cache so the CPM does not get stale memory * data. */ - /*flush_dcache_range(skb->data, skb->data + skb->len);*/ + flush_dcache_range(skb->data, skb->data + skb->len); /* Send it on its way. Tell CPM its ready, interrupt when done, * its the last BD of the frame, and to put the CRC on the end. @@ -282,7 +282,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - struct net_device *dev = dev_id; + struct net_device *dev = dev_id; struct fec_enet_private *fep; volatile cbd_t *bdp; volatile fec_t *ep; @@ -600,6 +600,9 @@ mii_status(uint mii_reg) else printk(", Half-Duplex\n"); } + if (((mii_reg >> 18) & 0x1f) == 0x1f) { + printk("fec: %x\n", mii_reg); + } } static void @@ -609,6 +612,7 @@ mii_startup_cmds(void) /* Read status registers to clear any pending interrupt. */ mii_queue(mk_mii_read(1), mii_status); +#ifndef CONFIG_RPXCLASSIC mii_queue(mk_mii_read(18), mii_status); /* Read extended chip status register. @@ -616,8 +620,23 @@ mii_startup_cmds(void) mii_queue(mk_mii_read(0x14), mii_status); /* Enable Link status change interrupts. + */ mii_queue(mk_mii_write(0x11, 0x0002), NULL); + +#ifdef CONFIG_FADS + /* FADS uses the TRSTE in the BCSR, which is kind of weird. + * This really controls the startup default configuration. + * Changing the state of TRSTE once powered up doesn't do + * anything, you have to whack the control register. + * This of course screws up any autoconfig that was done....... + */ + mii_queue(mk_mii_write(0, 0x1000), NULL); +#endif +#else + /* Experimenting with the QS6612 PHY....not done yet. */ + mii_queue(mk_mii_read(31), mii_status); +#endif } /* This supports the mii_link interrupt below. @@ -676,7 +695,7 @@ mii_relink(uint mii_reg) static void mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - struct net_device *dev = dev_id; + struct net_device *dev = dev_id; struct fec_enet_private *fep; volatile fec_t *ep; @@ -691,8 +710,19 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) * as part of the "normal" processing. */ mii_queue(mk_mii_read(1), mii_relink); +#ifndef CONFIG_RPXCLASSIC + + /* Unique to LevelOne PHY. + */ mii_queue(mk_mii_read(18), mii_relink); mii_queue(mk_mii_read(20), mii_relink); +#else + + /* Unique to QS6612 PHY. + */ + mii_queue(mk_mii_read(6), mii_relink); + mii_queue(mk_mii_read(31), mii_relink); +#endif } static int @@ -788,9 +818,9 @@ static void set_multicast_list(struct net_device *dev) } } -/* Initialize the FECC Ethernet on 860T. +/* Initialize the FEC Ethernet on 860T. */ -int __init m8xx_enet_init(void) +int __init fec_enet_init(void) { struct net_device *dev; struct fec_enet_private *fep; @@ -802,7 +832,10 @@ int __init m8xx_enet_init(void) cbd_t *cbd_base; volatile immap_t *immap; volatile fec_t *fecp; - unsigned char rtc_save_cfg, rtc_val; + unsigned char *iap; + bd_t *bd; + + bd = (bd_t *)__res; immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ @@ -833,15 +866,27 @@ int __init m8xx_enet_init(void) fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; + /* Right now, all of the boards supply the ethernet address in + * the board descriptor. If someone doesn't we can just use + * the hard coded address in this driver for testing (this is + * a Motorola address for a board I have, so it is unlikely to + * be used elsewhere). + */ + eap = (unsigned char *)&my_enet_addr[0]; +#if 1 + iap = bd->bi_enetaddr; + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++ = *iap++; +#else + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++; +#endif + /* Set station address. */ fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; fecp->fec_addr_high = my_enet_addr[2]; - eap = (unsigned char *)&my_enet_addr[0]; - for (i=0; i<6; i++) - dev->dev_addr[i] = *eap++; - /* Reset all multicast. */ fecp->fec_hash_table_high = 0; @@ -855,8 +900,8 @@ int __init m8xx_enet_init(void) /* Allocate memory for buffer descriptors. */ if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { - printk("FECC init error. Need more space.\n"); - printk("FECC initialization failed.\n"); + printk("FEC init error. Need more space.\n"); + printk("FEC initialization failed.\n"); return 1; } mem_addr = __get_free_page(GFP_KERNEL); @@ -864,7 +909,7 @@ int __init m8xx_enet_init(void) /* Make it uncached. */ - pte = va_to_pte(&init_task, (int)mem_addr); + pte = find_pte(&init_mm, (int)mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(current->mm->mmap, mem_addr); @@ -891,7 +936,7 @@ int __init m8xx_enet_init(void) /* Make it uncached. */ - pte = va_to_pte(&init_task, mem_addr); + pte = find_pte(&init_mm, mem_addr); pte_val(*pte) |= _PAGE_NO_CACHE; flush_tlb_page(current->mm->mmap, mem_addr); @@ -948,9 +993,9 @@ int __init m8xx_enet_init(void) /* Install our interrupt handlers. The 860T FADS board uses * IRQ2 for the MII interrupt. */ - if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) + if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) panic("Could not allocate FEC IRQ!"); - if (request_irq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) + if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) panic("Could not allocate MII IRQ!"); dev->base_addr = (unsigned long)fecp; diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 4bb555c77927..94e900ceb25f 100644 --- a/arch/ppc/8xx_io/uart.c +++ b/arch/ppc/8xx_io/uart.c @@ -38,13 +38,7 @@ #include #include #include - -#ifdef CONFIG_MBX -#include -#endif -#ifdef CONFIG_FADS -#include -#endif +#include #include "commproc.h" #ifdef CONFIG_SERIAL_CONSOLE @@ -101,18 +95,40 @@ static int serial_console_setup(struct console *co, char *options); * The SMCs do not support any modem control signals. */ #define smc_scc_num hub6 -#define SCC_NUM_BASE 2 -/* The index into the CPM registers for the first SCC in the table. +/* SMC2 is sometimes used for low performance TDM interfaces. Define + * this as 1 if you want SMC2 as a serial port UART managed by this driver. + * Define this as 0 if you wish to use SMC2 for something else. + */ +#define USE_SMC2 1 + +/* Define SCC to ttySx mapping. */ -#define SCC_IDX_BASE 1 +#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ + +/* Define which SCC is the first one to use for a serial port. These + * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used + * for Ethernet, and the first available SCC for serial UART is SCC2. + * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and + * interrupt vectors in the table below to match. + */ +#define SCC_IDX_BASE 1 /* table index */ +/* Processors other than the 860 only get SMCs configured by default. + * Either they don't have SCCs or they are allocated somewhere else. + * Of course, there are now 860s without some SCCs, so we will need to + * address that someday. + */ static struct serial_state rs_table[] = { /* UART CLK PORT IRQ FLAGS NUM */ { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */ - { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC1 ttyS0 */ - { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, 2 }, /* SCC2 ttyS2 */ - { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, 3 }, /* SCC3 ttyS3 */ +#if USE_SMC2 + { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */ +#endif +#if defined(CONFIG_MPC860) || defined(CONFIG_MPC860T) + { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, SCC_NUM_BASE}, /* SCC2 ttyS2 */ + { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, SCC_NUM_BASE + 1}, /* SCC3 ttyS3 */ +#endif }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) @@ -820,15 +836,10 @@ static void change_speed(ser_info_t *info) /* Determine divisor based on baud rate */ i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 4) - info->tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; - } - - baud_rate = baud_table[i]; + if (i >= (sizeof(baud_table)/sizeof(int))) + baud_rate = 9600; + else + baud_rate = baud_table[i]; info->timeout = (TX_BUF_SIZE*HZ*bits); info->timeout += HZ/50; /* Add .02 seconds of slop */ @@ -1692,7 +1703,7 @@ static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout) schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) + if (timeout && ((orig_jiffies + timeout) < jiffies)) break; bdp = info->tx_cur; } while (bdp->cbd_sc & BD_SC_READY); @@ -2251,6 +2262,13 @@ long __init console_8xx_init(long kmem_start, long kmem_end) #endif +/* This will be used for all boards when the MBX board information + * is modified to include a default baud rate. + */ +#ifndef CONFIG_MBX +static int baud_idx; +#endif + /* * The serial driver boot-time initialization code! */ @@ -2291,7 +2309,11 @@ int __init rs_8xx_init(void) serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = +#ifndef CONFIG_MBX + baud_idx | CS8 | CREAD | HUPCL | CLOCAL; +#else B9600 | CS8 | CREAD | HUPCL | CLOCAL; +#endif serial_driver.flags = TTY_DRIVER_REAL_RAW; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; @@ -2337,12 +2359,21 @@ int __init rs_8xx_init(void) /* Configure SMCs Tx/Rx instead of port B parallel I/O. */ +#if USE_SMC2 cp->cp_pbpar |= 0x00000cc0; cp->cp_pbdir &= ~0x00000cc0; cp->cp_pbodr &= ~0x00000cc0; +#else + /* This will only enable SMC1 if you want SMC2 for something else. + */ + cp->cp_pbpar |= 0x000000c0; + cp->cp_pbdir &= ~0x000000c0; + cp->cp_pbodr &= ~0x000000c0; +#endif /* Configure SCC2 and SCC3 instead of port A parallel I/O. */ +#if defined(CONFIG_MPC860) || defined(CONFIG_MPC860T) #ifndef CONFIG_MBX /* The "standard" configuration through the 860. */ @@ -2366,15 +2397,16 @@ int __init rs_8xx_init(void) immap->im_ioport.iop_pcdir |= 0x03c6; immap->im_ioport.iop_pcpar &= ~0x03c6; - /* Wire BRG1 to SMC1 and BRG2 to SMC2. - */ - cp->cp_simode = 0x10000000; - /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and * BRG4 to SCC3. */ cp->cp_sicr &= ~0x00ffff00; cp->cp_sicr |= 0x001b1200; +#endif + + /* Wire BRG1 to SMC1 and BRG2 to SMC2. + */ + cp->cp_simode = 0x10000000; for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; @@ -2580,7 +2612,12 @@ int __init rs_8xx_init(void) /* Set up the baud rate generator. */ +#ifndef CONFIG_MBX + m8xx_cpm_setbrg(state->smc_scc_num, + baud_table[baud_idx]); +#else m8xx_cpm_setbrg(state->smc_scc_num, 9600); +#endif /* If the port is the console, enable Rx and Tx. */ @@ -2599,12 +2636,26 @@ int __init rs_8xx_init(void) static int __init serial_console_setup(struct console *co, char *options) { struct serial_state *ser; - uint mem_addr, dp_addr; + uint mem_addr, dp_addr, bidx; volatile cbd_t *bdp; volatile cpm8xx_t *cp; volatile smc_t *sp; volatile smc_uart_t *up; + +#ifndef CONFIG_MBX + bd_t *bd; + + bd = (bd_t *)__res; + + for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) + if (bd->bi_baudrate == baud_table[bidx]) + break; + + co->cflag = CREAD|CLOCAL|bidx|CS8; + baud_idx = bidx; +#else co->cflag = CREAD|CLOCAL|B9600|CS8; +#endif ser = rs_table + co->index; @@ -2670,7 +2721,11 @@ static int __init serial_console_setup(struct console *co, char *options) /* Set up the baud rate generator. */ +#ifndef CONFIG_MBX + m8xx_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate); +#else m8xx_cpm_setbrg(ser->smc_scc_num, 9600); +#endif /* And finally, enable Rx and Tx. */ diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 9977db20405b..6282a0a6da8d 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -27,7 +27,7 @@ CFLAGS := $(CFLAGS) -I$(HPATH) -D__powerpc__ -fsigned-char -msoft-float \ CPP = $(CC) -E $(CFLAGS) ifdef CONFIG_8xx -CFLAGS := $(CFLAGS) -mcpu=860 +CFLAGS := $(CFLAGS) -mcpu=860 -I../8xx_io endif ifdef CONFIG_PPC64 @@ -45,7 +45,7 @@ SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS) ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES) CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES) -ifdef CONFIG_8xx +ifdef CONFIG_MATH_EMULATION SUBDIRS += arch/ppc/math-emu ARCHIVES += arch/ppc/math-emu/math-emu.o CORE_FILES += arch/ppc/math-emu/math-emu.o @@ -77,7 +77,7 @@ checks: BOOT_TARGETS = zImage znetboot.initrd zImage.initrd -ifdef CONFIG_MBX +ifdef CONFIG_8xx $(BOOT_TARGETS): $(CHECKS) vmlinux @$(MAKECOFFBOOT) $@ @$(MAKEMBXBOOT) $@ diff --git a/arch/ppc/amiga/Makefile b/arch/ppc/amiga/Makefile index 2658af4c745e..2d5ec4811494 100644 --- a/arch/ppc/amiga/Makefile +++ b/arch/ppc/amiga/Makefile @@ -12,4 +12,8 @@ O_OBJS := config.o amiints.o cia.o time.o \ bootinfo.o amisound.o chipram.o ints.o OX_OBJS := amiga_ksyms.o +ifdef CONFIG_AMIGA_PCMCIA +O_OBJS := $(O_OBJS) pcmcia.o +endif + include $(TOPDIR)/Rules.make diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c index 795ea6378bfc..408f8211c3d5 100644 --- a/arch/ppc/amiga/amiints.c +++ b/arch/ppc/amiga/amiints.c @@ -1,7 +1,3 @@ -/* Rename a few functions. */ -#define amiga_request_irq request_irq -#define amiga_free_irq free_irq - /* * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code * @@ -23,6 +19,20 @@ * called again. * The whole interrupt handling for CIAs is moved to cia.c * /Roman Zippel + * + * 07/08/99: rewamp of the interrupt handling - we now have two types of + * interrupts, normal and fast handlers, fast handlers being + * marked with SA_INTERRUPT and runs with all other interrupts + * disabled. Normal interrupts disable their own source but + * run with all other interrupt sources enabled. + * PORTS and EXTER interrupts are always shared even if the + * drivers do not explicitly mark this when calling + * request_irq which they really should do. + * This is similar to the way interrupts are handled on all + * other architectures and makes a ton of sense besides + * having the advantage of making it easier to share + * drivers. + * /Jes */ #include @@ -90,7 +100,7 @@ void __init amiga_init_IRQ(void) } else { ami_irq_list[i] = new_irq_node(); ami_irq_list[i]->handler = ami_badint; - ami_irq_list[i]->flags = IRQ_FLG_STD; + ami_irq_list[i]->flags = 0; ami_irq_list[i]->dev_id = NULL; ami_irq_list[i]->devname = NULL; ami_irq_list[i]->next = NULL; @@ -108,7 +118,7 @@ void __init amiga_init_IRQ(void) custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interrupt requests. Circumvents bug in + /* Clear any inter-CPU interupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); @@ -124,7 +134,7 @@ void __init amiga_init_IRQ(void) cia_init_IRQ(&ciab_base); } -static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node) +static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node) { unsigned long flags; irq_node_t *cur; @@ -138,19 +148,18 @@ static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node) cur = *list; - if (node->flags & IRQ_FLG_FAST) { - node->flags &= ~IRQ_FLG_SLOW; - while (cur && cur->flags & IRQ_FLG_FAST) { - list = &cur->next; - cur = cur->next; - } - } else if (node->flags & IRQ_FLG_SLOW) { - while (cur) { + if (node->flags & SA_INTERRUPT) { + if (node->flags & SA_SHIRQ) + return -EBUSY; + /* + * There should never be more than one + */ + while (cur && cur->flags & SA_INTERRUPT) { list = &cur->next; cur = cur->next; } } else { - while (cur && !(cur->flags & IRQ_FLG_SLOW)) { + while (cur) { list = &cur->next; cur = cur->next; } @@ -160,6 +169,7 @@ static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node) *list = node; restore_flags(flags); + return 0; } static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) @@ -189,13 +199,16 @@ static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) * If the addition was successful, it returns 0. */ -int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +int amiga_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { irq_node_t *node; + int error = 0; if (irq >= AMI_IRQS) { - printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); + printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, + irq, devname); return -ENXIO; } @@ -211,6 +224,11 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, handler, flags, devname, dev_id); + /* + * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared, + * we could add a check here for the SA_SHIRQ flag but all drivers + * should be aware of sharing anyway. + */ if (ami_servers[irq]) { if (!(node = new_irq_node())) return -ENOMEM; @@ -219,20 +237,8 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r node->dev_id = dev_id; node->devname = devname; node->next = NULL; - amiga_insert_irq(&ami_irq_list[irq], node); + error = amiga_insert_irq(&ami_irq_list[irq], node); } else { - if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) { - if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) { - printk("%s: IRQ %d from %s is not replaceable\n", - __FUNCTION__, irq, ami_irq_list[irq]->devname); - return -EBUSY; - } - if (!(flags & IRQ_FLG_REPLACE)) { - printk("%s: %s can't replace IRQ %d from %s\n", - __FUNCTION__, devname, irq, ami_irq_list[irq]->devname); - return -EBUSY; - } - } ami_irq_list[irq]->handler = handler; ami_irq_list[irq]->flags = flags; ami_irq_list[irq]->dev_id = dev_id; @@ -243,7 +249,7 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) custom.intena = IF_SETCLR | ami_intena_vals[irq]; - return 0; + return error; } void amiga_free_irq(unsigned int irq, void *dev_id) @@ -276,7 +282,7 @@ void amiga_free_irq(unsigned int irq, void *dev_id) printk("%s: removing probably wrong IRQ %d from %s\n", __FUNCTION__, irq, ami_irq_list[irq]->devname); ami_irq_list[irq]->handler = ami_badint; - ami_irq_list[irq]->flags = IRQ_FLG_STD; + ami_irq_list[irq]->flags = 0; ami_irq_list[irq]->dev_id = NULL; ami_irq_list[irq]->devname = NULL; custom.intena = ami_intena_vals[irq]; @@ -366,45 +372,58 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp) void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) { irq_node_t *node, *slow_nodes; - unsigned short flags; + unsigned short flags, intena; kstat.irqs[0][SYS_IRQS + irq]++; if (server->count++) server->reentrance = 1; - /* serve first fast and normal handlers */ - for (node = ami_irq_list[irq]; - node && (!(node->flags & IRQ_FLG_SLOW)); - node = node->next) - node->handler(irq, node->dev_id, fp); - custom.intreq = ami_intena_vals[irq]; + + intena = ami_intena_vals[irq]; + custom.intreq = intena; + + /* serve first fast handlers - there can only be one of these */ + node = ami_irq_list[irq]; + + /* + * Timer interrupts show up like this + */ if (!node) { server->count--; return; } -#ifdef CONFIG_APUS - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET - | (~(fp->mq) & IPLEMU_IPLMASK))); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); -#else + + if (node && (node->flags & SA_INTERRUPT)) { + save_flags(flags); + cli(); + node->handler(irq, node->dev_id, fp); + restore_flags(flags); + + server->count--; + return; + } + + /* + * Disable the interrupt source in question and reenable all + * other interrupts. No interrupt handler should ever touch + * the intena flags directly! + */ + custom.intena = intena; save_flags(flags); - restore_flags((flags & ~0x0700) | (fp->sr & 0x0700)); -#endif - /* if slow handlers exists, serve them now */ + sti(); + slow_nodes = node; for (;;) { for (; node; node = node->next) node->handler(irq, node->dev_id, fp); - /* if reentrance occurred, serve slow handlers again */ - custom.intena = ami_intena_vals[irq]; + if (!server->reentrance) { server->count--; - custom.intena = IF_SETCLR | ami_intena_vals[irq]; + restore_flags(flags); + custom.intena = IF_SETCLR | intena; return; } + server->reentrance = 0; - custom.intena = IF_SETCLR | ami_intena_vals[irq]; node = slow_nodes; } } @@ -522,24 +541,13 @@ int amiga_get_irq_list(char *buf) for (i = 0; i < AMI_STD_IRQS; i++) { if (!(node = ami_irq_list[i])) continue; - if (node->flags & IRQ_FLG_STD) - continue; len += sprintf(buf+len, "ami %2d: %10u ", i, kstat.irqs[0][SYS_IRQS + i]); do { - if (ami_servers[i]) { - if (node->flags & IRQ_FLG_FAST) - len += sprintf(buf+len, "F "); - else if (node->flags & IRQ_FLG_SLOW) - len += sprintf(buf+len, "S "); - else - len += sprintf(buf+len, " "); - } else { - if (node->flags & IRQ_FLG_LOCK) - len += sprintf(buf+len, "L "); - else - len += sprintf(buf+len, " "); - } + if (node->flags & SA_INTERRUPT) + len += sprintf(buf+len, "F "); + else + len += sprintf(buf+len, " "); len += sprintf(buf+len, "%s\n", node->devname); if ((node = node->next)) len += sprintf(buf+len, " "); diff --git a/arch/ppc/amiga/bootinfo.c b/arch/ppc/amiga/bootinfo.c index 21fd37aa18b7..6011910e0181 100644 --- a/arch/ppc/amiga/bootinfo.c +++ b/arch/ppc/amiga/bootinfo.c @@ -16,9 +16,11 @@ extern char cmd_line[CL_SIZE]; -int num_memory = 0; -struct mem_info memory[NUM_MEMINFO]; -struct mem_info ramdisk; +extern int num_memory; +extern int m68k_realnum_memory; +extern struct mem_info memory[NUM_MEMINFO]; +extern struct mem_info m68k_memory[NUM_MEMINFO]; +extern struct mem_info ramdisk; extern int amiga_parse_bootinfo(const struct bi_record *); extern int atari_parse_bootinfo(const struct bi_record *); @@ -42,6 +44,11 @@ void __init parse_bootinfo(const struct bi_record *record) memory[num_memory].addr = data[0]; memory[num_memory].size = data[1]; num_memory++; + + /* FIXME: duplicate for m68k drivers. */ + m68k_memory[m68k_realnum_memory].addr = data[0]; + m68k_memory[m68k_realnum_memory].size = data[1]; + m68k_realnum_memory++; } else printk("parse_bootinfo: too many memory chunks\n"); break; diff --git a/arch/ppc/amiga/chipram.c b/arch/ppc/amiga/chipram.c index e6ab3c6b223c..31f91a7943de 100644 --- a/arch/ppc/amiga/chipram.c +++ b/arch/ppc/amiga/chipram.c @@ -1 +1,175 @@ -#include "../../m68k/amiga/chipram.c" +/* +** linux/amiga/chipram.c +** +** Modified 03-May-94 by Geert Uytterhoeven +** (Geert.Uytterhoeven@cs.kuleuven.ac.be) +** - 64-bit aligned allocations for full AGA compatibility +*/ + +#include +#include +#include +#include +#include + +struct chip_desc { + unsigned first : 1; + unsigned last : 1; + unsigned alloced : 1; + unsigned length : 24; + long pad; /* We suppose this makes this struct 64 bits long!! */ +}; + +#define DP(ptr) ((struct chip_desc *)(ptr)) + +u_long amiga_chip_size; +static unsigned long chipavail; + +unsigned long amiga_chip_avail( void ) +{ +#ifdef DEBUG + printk("chip_avail : %ld bytes\n",chipavail); +#endif + return chipavail; +} + + +__init +void amiga_chip_init (void) +{ + struct chip_desc *dp; + + if (!AMIGAHW_PRESENT(CHIP_RAM)) + return; + +#ifndef CONFIG_APUS_FAST_EXCEPT + /* + * Remove the first 4 pages where PPC exception handlers will + * be located. + */ + amiga_chip_size -= 0x4000; +#endif + + /* initialize start boundary */ + + dp = DP(chipaddr); + dp->first = 1; + + dp->alloced = 0; + dp->length = amiga_chip_size - 2*sizeof(*dp); + + /* initialize end boundary */ + dp = DP(chipaddr + amiga_chip_size) - 1; + dp->last = 1; + + dp->alloced = 0; + dp->length = amiga_chip_size - 2*sizeof(*dp); + chipavail = dp->length; /*MILAN*/ + +#ifdef DEBUG + printk ("chipram end boundary is %p, length is %d\n", dp, + dp->length); +#endif +} + +void *amiga_chip_alloc (long size) +{ + /* last chunk */ + struct chip_desc *dp; + void *ptr; + + /* round off */ + size = (size + 7) & ~7; + +#ifdef DEBUG + printk("chip_alloc: allocate %ld bytes\n", size); +#endif + + /* + * get pointer to descriptor for last chunk by + * going backwards from end chunk + */ + dp = DP(chipaddr + amiga_chip_size) - 1; + dp = DP((unsigned long)dp - dp->length) - 1; + + while ((dp->alloced || dp->length < size) + && !dp->first) + dp = DP ((unsigned long)dp - dp[-1].length) - 2; + + if (dp->alloced || dp->length < size) { + printk ("no chipmem available for %ld allocation\n", size); + return NULL; + } + + if (dp->length < (size + 2*sizeof(*dp))) { + /* length too small to split; allocate the whole thing */ + dp->alloced = 1; + ptr = (void *)(dp+1); + dp = DP((unsigned long)ptr + dp->length); + dp->alloced = 1; +#ifdef DEBUG + printk ("chip_alloc: no split\n"); +#endif + } else { + /* split the extent; use the end part */ + long newsize = dp->length - (2*sizeof(*dp) + size); + +#ifdef DEBUG + printk ("chip_alloc: splitting %d to %ld\n", dp->length, + newsize); +#endif + dp->length = newsize; + dp = DP((unsigned long)(dp+1) + newsize); + dp->first = dp->last = 0; + dp->alloced = 0; + dp->length = newsize; + dp++; + dp->first = dp->last = 0; + dp->alloced = 1; + dp->length = size; + ptr = (void *)(dp+1); + dp = DP((unsigned long)ptr + size); + dp->alloced = 1; + dp->length = size; + } + +#ifdef DEBUG + printk ("chip_alloc: returning %p\n", ptr); +#endif + + if ((unsigned long)ptr & 7) + panic("chip_alloc: alignment violation\n"); + + chipavail -= size + (2*sizeof(*dp)); /*MILAN*/ + + return ptr; +} + +void amiga_chip_free (void *ptr) +{ + struct chip_desc *sdp = DP(ptr) - 1, *dp2; + struct chip_desc *edp = DP((unsigned long)ptr + sdp->length); + + chipavail += sdp->length + (2* sizeof(sdp)); /*MILAN*/ +#ifdef DEBUG + printk("chip_free: free %ld bytes at %p\n",sdp->length,ptr); +#endif + /* deallocate the chunk */ + sdp->alloced = edp->alloced = 0; + + /* check if we should merge with the previous chunk */ + if (!sdp->first && !sdp[-1].alloced) { + dp2 = DP((unsigned long)sdp - sdp[-1].length) - 2; + dp2->length += sdp->length + 2*sizeof(*sdp); + edp->length = dp2->length; + sdp = dp2; + } + + /* check if we should merge with the following chunk */ + if (!edp->last && !edp[1].alloced) { + dp2 = DP((unsigned long)edp + edp[1].length) + 2; + dp2->length += edp->length + 2*sizeof(*sdp); + sdp->length = dp2->length; + edp = dp2; + } +} diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c index 59050c4216d0..47b8f64ea6f1 100644 --- a/arch/ppc/amiga/config.c +++ b/arch/ppc/amiga/config.c @@ -1,13 +1,12 @@ #define m68k_debug_device debug_device -#define m68k_num_memory num_memory -#define m68k_memory memory #include /* machine dependent "kbd-reset" setup function */ -void (*kbd_reset_setup) (char *, int) __initdata = 0; +void (*mach_kbd_reset_setup) (char *, int) __initdata = 0; #include +#include /* * linux/arch/m68k/amiga/config.c @@ -41,6 +40,7 @@ void (*kbd_reset_setup) (char *, int) __initdata = 0; #include #include +unsigned long powerup_PCI_present; unsigned long amiga_model; unsigned long amiga_eclock; unsigned long amiga_masterclock; @@ -61,7 +61,6 @@ static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); /* amiga specific keyboard functions */ extern int amiga_keyb_init(void); extern int amiga_kbdrate (struct kbd_repeat *); -extern void amiga_kbd_reset_setup(char*, int); /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); @@ -137,8 +136,13 @@ int amiga_parse_bootinfo(const struct bi_record *record) switch (record->tag) { case BI_AMIGA_MODEL: - amiga_model = *data; - break; + { + unsigned long d = *data; + + powerup_PCI_present = d & 0x100; + amiga_model = d & 0xff; + } + break; case BI_AMIGA_ECLOCK: amiga_eclock = *data; @@ -352,7 +356,6 @@ void __init config_amiga(void) mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; mach_kbdrate = amiga_kbdrate; - kbd_reset_setup = amiga_kbd_reset_setup; mach_init_IRQ = amiga_init_IRQ; mach_default_handler = &amiga_default_handler; #ifndef CONFIG_APUS @@ -451,8 +454,7 @@ static void __init amiga_sched_init(void (*timer_routine)(int, void *, * Please don't change this to use ciaa, as it interferes with the * SCSI code. We'll have to take a look at this later */ - request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, - "timer", NULL); + request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, 0, "timer", NULL); /* start timer */ ciab.cra |= 0x11; } @@ -741,7 +743,7 @@ static void amiga_savekmsg_init(void) static void amiga_serial_putc(char c) { custom.serdat = (unsigned char)c | 0x100; - iobarrier_rw (); + mb(); while (!(custom.serdatr & 0x2000)) ; } @@ -921,3 +923,30 @@ static int amiga_get_hardware_list(char *buffer) return(len); } + +#ifdef CONFIG_APUS +int get_hardware_list(char *buffer) +{ + extern int get_cpuinfo(char *buffer); + int len = 0; + char model[80]; + u_long mem; + int i; + + if (mach_get_model) + mach_get_model(model); + else + strcpy(model, "Unknown PowerPC"); + + len += sprintf(buffer+len, "Model:\t\t%s\n", model); + len += get_cpuinfo(buffer+len); + for (mem = 0, i = 0; i < m68k_realnum_memory; i++) + mem += m68k_memory[i].size; + len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); + + if (mach_get_hardware_list) + len += mach_get_hardware_list(buffer+len); + + return(len); +} +#endif diff --git a/arch/ppc/amiga/ints.c b/arch/ppc/amiga/ints.c index c3eabcc833db..80c63f7ab0f1 100644 --- a/arch/ppc/amiga/ints.c +++ b/arch/ppc/amiga/ints.c @@ -5,19 +5,22 @@ * Needed to drive the m68k emulating IRQ hardware on the PowerUp boards. */ +#include #include +#include #include -#include #include #include #include +#include #include #include +#include #include /* table for system interrupt handlers */ -irq_handler_t irq_list[SYS_IRQS]; +static irq_handler_t irq_list[SYS_IRQS]; static const char *default_names[SYS_IRQS] = { "spurious int", "int1 handler", "int2 handler", "int3 handler", @@ -42,14 +45,15 @@ static irq_node_t nodes[NUM_IRQ_NODES]; * the IRQ handling routines. */ -void __init apus_init_IRQ(void) +__init +void m68k_init_IRQ(void) { int i; for (i = 0; i < SYS_IRQS; i++) { if (mach_default_handler) irq_list[i].handler = (*mach_default_handler)[i]; - irq_list[i].flags = IRQ_FLG_STD; + irq_list[i].flags = 0; irq_list[i].dev_id = NULL; irq_list[i].devname = default_names[i]; } @@ -83,6 +87,7 @@ int sys_request_irq(unsigned int irq, return -ENXIO; } +#if 0 if (!(irq_list[irq].flags & IRQ_FLG_STD)) { if (irq_list[irq].flags & IRQ_FLG_LOCK) { printk("%s: IRQ %d from %s is not replaceable\n", @@ -95,6 +100,8 @@ int sys_request_irq(unsigned int irq, return -EBUSY; } } +#endif + irq_list[irq].handler = handler; irq_list[irq].flags = flags; irq_list[irq].dev_id = dev_id; @@ -114,7 +121,7 @@ void sys_free_irq(unsigned int irq, void *dev_id) __FUNCTION__, irq, irq_list[irq].devname); irq_list[irq].handler = (*mach_default_handler)[irq]; - irq_list[irq].flags = IRQ_FLG_STD; + irq_list[irq].flags = 0; irq_list[irq].dev_id = NULL; irq_list[irq].devname = default_names[irq]; } @@ -134,7 +141,7 @@ asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) } } -int get_irq_list(char *buf) +int m68k_get_irq_list(char *buf) { int i, len = 0; @@ -143,9 +150,6 @@ int get_irq_list(char *buf) for (i = 0; i < SYS_IRQS; i++) { len += sprintf(buf+len, "auto %2d: %10u ", i, i ? kstat.irqs[0][i] : num_spurious); - if (irq_list[i].flags & IRQ_FLG_LOCK) - len += sprintf(buf+len, "L "); - else len += sprintf(buf+len, " "); len += sprintf(buf+len, "%s\n", irq_list[i].devname); } diff --git a/arch/ppc/amiga/pcmcia.c b/arch/ppc/amiga/pcmcia.c new file mode 100644 index 000000000000..5d29dc65093c --- /dev/null +++ b/arch/ppc/amiga/pcmcia.c @@ -0,0 +1 @@ +#include "../../m68k/amiga/pcmcia.c" diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c index 65f94d778ea5..a78f8aa41b19 100644 --- a/arch/ppc/amiga/time.c +++ b/arch/ppc/amiga/time.c @@ -15,7 +15,7 @@ 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 apus_get_rtc_time(void) +unsigned long m68k_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; @@ -30,7 +30,7 @@ unsigned long apus_get_rtc_time(void) return mktime(year, mon, day, hour, min, sec); } -int apus_set_rtc_time(unsigned long nowtime) +int m68k_set_rtc_time(unsigned long nowtime) { if (mach_set_clock_mmss) return mach_set_clock_mmss (nowtime); @@ -89,4 +89,6 @@ void apus_heartbeat (void) dist = period / 4; } #endif + /* should be made smarter */ + ppc_md.heartbeat_count = 1; } diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index 9e637aa7b44b..8709e3729aee 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -25,6 +25,10 @@ ZSZ = 0 IOFF = 0 ISZ = 0 +ifeq ($(CONFIG_ALL_PPC),y) +CONFIG_PREP=y +endif + ifeq ($(CONFIG_SMP),y) TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE) else @@ -72,16 +76,19 @@ zvmlinux.initrd: zvmlinux rm zvmlinux.initrd.tmp zImage: zvmlinux mkprep sImage +ifdef CONFIG_PREP ./mkprep -pbp zvmlinux zImage +endif sImage: ../../../vmlinux ifdef CONFIG_GEMINI $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage -else endif zImage.initrd: zvmlinux.initrd mkprep +ifdef CONFIG_PREP ./mkprep -pbp zvmlinux.initrd zImage.initrd +endif zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # @@ -110,7 +117,9 @@ mkprep : mkprep.c $(HOSTCC) -o mkprep mkprep.c znetboot : zImage +ifdef CONFIG_PREP cp zImage $(TFTPIMAGE) +endif ifdef CONFIG_GEMINI cp sImage /tftpboot/ endif diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig index 44c17cfcb7eb..0bcbf06aa5cd 100644 --- a/arch/ppc/common_defconfig +++ b/arch/ppc/common_defconfig @@ -1,5 +1,5 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # # @@ -13,6 +13,7 @@ CONFIG_6xx=y # CONFIG_PREP is not set # CONFIG_CHRP is not set CONFIG_ALL_PPC=y +# CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_MBX is not set # CONFIG_SMP is not set @@ -26,8 +27,6 @@ CONFIG_MODULES=y CONFIG_MODVERSIONS=y CONFIG_KMOD=y CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -40,9 +39,14 @@ CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_KEYBOARD=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_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -50,14 +54,16 @@ CONFIG_BOOTX_TEXT=y # CONFIG_CMDLINE_BOOL is not set # -# Block devices +# Plug and Play configuration # -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# Block devices # +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set @@ -77,10 +83,6 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set @@ -96,10 +98,11 @@ CONFIG_BLK_DEV_IDE_MODES=y # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set CONFIG_NETLINK=y # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -112,17 +115,10 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_INET_RARP=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 @@ -134,7 +130,6 @@ CONFIG_ATALK=m # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -145,19 +140,11 @@ CONFIG_ATALK=m # SCSI support # CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -175,6 +162,7 @@ CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -187,8 +175,6 @@ CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_G_NCR5380_PORT is not set -# CONFIG_SCSI_G_NCR5380_MEM is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set @@ -232,6 +218,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) @@ -244,11 +231,12 @@ CONFIG_BMAC=y # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set +# CONFIG_SIS900 is not set # CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y -# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -264,6 +252,7 @@ CONFIG_DE4X5=y # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set +# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -275,10 +264,9 @@ CONFIG_DE4X5=y # CONFIG_COPS is not set # CONFIG_IPDDP is not set CONFIG_PPP=y - -# -# CCP compressors for PPP are only built as modules. -# +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set @@ -286,6 +274,7 @@ CONFIG_PPP=y # Token ring devices # # CONFIG_TR is not set +# CONFIG_NET_FC is not set # CONFIG_RCPCI is not set # CONFIG_SHAPER is not set @@ -297,6 +286,13 @@ CONFIG_PPP=y # CONFIG_SEALEVEL_4021 is not set # CONFIG_DLCI is not set +# +# PCMCIA network devices +# +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_RAYCS is not set + # # Amateur Radio support # @@ -316,21 +312,22 @@ CONFIG_PPP=y # Console drivers # CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -# CONFIG_FB_ATY is not set CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y # CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y # CONFIG_FB_MATROX_MILLENIUM is not set CONFIG_FB_MATROX_MYSTIQUE=y CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set -# CONFIG_FB_ATY is not set +CONFIG_FB_ATY=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -365,7 +362,7 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y +# CONFIG_ADB_MOUSE is not set CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -385,19 +382,14 @@ CONFIG_NVRAM=y # # CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_FT_NORMAL_DEBUG is not set -# CONFIG_FT_FULL_DEBUG is not set -# CONFIG_FT_NO_TRACE is not set -# CONFIG_FT_NO_TRACE_AT_ALL is not set -# CONFIG_FT_STD_FDC is not set -# CONFIG_FT_MACH2 is not set -# CONFIG_FT_PROBE_FC10 is not set -# CONFIG_FT_ALT_FDC is not set +# CONFIG_DRM is not set # # USB drivers - not for the faint of heart @@ -413,9 +405,13 @@ CONFIG_AUTOFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -442,12 +438,14 @@ CONFIG_LOCKD=y # # Partition Types # -# CONFIG_BSD_DISKLABEL is not set +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MAC_PARTITION=y -# CONFIG_SMD_DISKLABEL is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_SGI_DISKLABEL is not set # CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # @@ -458,6 +456,8 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set @@ -472,6 +472,7 @@ CONFIG_SOUND_OSS=y # CONFIG_SOUND_MSS is not set # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_MAD16 is not set # CONFIG_SOUND_WAVEFRONT is not set CONFIG_SOUND_CS4232=m diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 5d2d2165a8a4..af3d5876f20d 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.103 1999/09/01 19:04:44 cort Exp $ +# $Id: config.in,v 1.106 1999/09/14 19:21:18 cort Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -10,16 +10,33 @@ define_bool CONFIG_PPC y choice 'Processor type' \ "6xx/7xx CONFIG_6xx \ 630/Power3(64-Bit) CONFIG_PPC64 \ - 860/821 CONFIG_8xx" 6xx/7xx + 82xx CONFIG_82xx \ + 8xx CONFIG_8xx" 6xx/7xx -choice 'Machine Type' \ +if [ "$CONFIG_8xx" = "y" ]; then + choice 'Processor Model' \ + "821 CONFIG_MPC821 \ + 823 CONFIG_MPC823 \ + 850 CONFIG_MPC850 \ + 855 CONFIG_MPC855 \ + 860 CONFIG_MPC860 \ + 860T CONFIG_MPC860T" 860 + define_bool CONFIG_SERIAL_CONSOLE y + choice 'Machine Type' \ + "RPX-Lite CONFIG_RPXLITE \ + RPX-Classic CONFIG_RPXCLASSIC \ + BSE-IP CONFIG_BSEIP \ + MBX CONFIG_MBX \ + WinCept CONFIG_WINCEPT" RPX-Lite +else + choice 'Machine Type' \ "PowerMac CONFIG_PMAC \ PReP/MTX CONFIG_PREP \ CHRP CONFIG_CHRP \ PowerMac/PReP/CHRP CONFIG_ALL_PPC \ Gemini CONFIG_GEMINI \ - APUS CONFIG_APUS \ - MBX CONFIG_MBX" PowerMac + APUS CONFIG_APUS" PowerMac +fi bool 'Symmetric multi-processing support' CONFIG_SMP if [ "$CONFIG_ALL_PPC" != "y" ];then @@ -35,10 +52,6 @@ else fi endmenu -if [ "$CONFIG_MBX" = "y" ];then - define_bool CONFIG_SERIAL_CONSOLE y -fi - mainmenu_option next_comment comment 'General setup' @@ -52,7 +65,11 @@ fi if [ "$CONFIG_APUS" = "y" ]; then define_bool CONFIG_PCI n else - define_bool CONFIG_PCI y + if [ "$CONFIG_8xx" = "y" ]; then + bool 'QSpan PCI' CONFIG_PCI + else + define_bool CONFIG_PCI y + fi fi bool 'Networking support' CONFIG_NET @@ -67,23 +84,32 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC source drivers/parport/Config.in -bool 'Support for VGA Console' CONFIG_VGA_CONSOLE -bool 'Support for frame buffer devices' CONFIG_FB -if [ "$CONFIG_FB" = "y" ]; then - bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC -fi +if [ "$CONFIG_8xx" != "y" ]; then + bool 'Support for VGA Console' CONFIG_VGA_CONSOLE + bool 'Support for frame buffer devices' CONFIG_FB + if [ "$CONFIG_FB" = "y" ]; then + bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC + fi -bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK -bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD -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 + 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 + fi + bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE + bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP + bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT + bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP fi -bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE -bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP -bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT -bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP + if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then @@ -183,6 +209,10 @@ fi endmenu +if [ "$CONFIG_8xx" = "y" ]; then +source arch/ppc/8xx_io/Config.in +fi + mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index 44c17cfcb7eb..0bcbf06aa5cd 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -1,5 +1,5 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # # @@ -13,6 +13,7 @@ CONFIG_6xx=y # CONFIG_PREP is not set # CONFIG_CHRP is not set CONFIG_ALL_PPC=y +# CONFIG_GEMINI is not set # CONFIG_APUS is not set # CONFIG_MBX is not set # CONFIG_SMP is not set @@ -26,8 +27,6 @@ CONFIG_MODULES=y CONFIG_MODVERSIONS=y CONFIG_KMOD=y CONFIG_PCI=y -# CONFIG_PCI_QUIRKS is not set -CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -40,9 +39,14 @@ CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_KEYBOARD=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_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -50,14 +54,16 @@ CONFIG_BOOTX_TEXT=y # CONFIG_CMDLINE_BOOL is not set # -# Block devices +# Plug and Play configuration # -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# Block devices # +CONFIG_BLK_DEV_FD=y +CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set @@ -77,10 +83,6 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set @@ -96,10 +98,11 @@ CONFIG_BLK_DEV_IDE_MODES=y # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set CONFIG_NETLINK=y # CONFIG_RTNETLINK is not set # CONFIG_NETLINK_DEV is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -112,17 +115,10 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_INET_RARP=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 @@ -134,7 +130,6 @@ CONFIG_ATALK=m # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -145,19 +140,11 @@ CONFIG_ATALK=m # SCSI support # CONFIG_SCSI=y - -# -# SCSI support type (disk, tape, CD-ROM) -# CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -175,6 +162,7 @@ CONFIG_SCSI_AIC7XXX=y CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -187,8 +175,6 @@ CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_G_NCR5380_PORT is not set -# CONFIG_SCSI_G_NCR5380_MEM is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set @@ -232,6 +218,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) @@ -244,11 +231,12 @@ CONFIG_BMAC=y # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set +# CONFIG_SIS900 is not set # CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y CONFIG_PCNET32=y -# CONFIG_ACENIC is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -264,6 +252,7 @@ CONFIG_DE4X5=y # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set +# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set @@ -275,10 +264,9 @@ CONFIG_DE4X5=y # CONFIG_COPS is not set # CONFIG_IPDDP is not set CONFIG_PPP=y - -# -# CCP compressors for PPP are only built as modules. -# +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set @@ -286,6 +274,7 @@ CONFIG_PPP=y # Token ring devices # # CONFIG_TR is not set +# CONFIG_NET_FC is not set # CONFIG_RCPCI is not set # CONFIG_SHAPER is not set @@ -297,6 +286,13 @@ CONFIG_PPP=y # CONFIG_SEALEVEL_4021 is not set # CONFIG_DLCI is not set +# +# PCMCIA network devices +# +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_RAYCS is not set + # # Amateur Radio support # @@ -316,21 +312,22 @@ CONFIG_PPP=y # Console drivers # CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -# CONFIG_FB_ATY is not set CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y # CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y # CONFIG_FB_MATROX_MILLENIUM is not set CONFIG_FB_MATROX_MYSTIQUE=y CONFIG_FB_MATROX_G100=y # CONFIG_FB_MATROX_MULTIHEAD is not set -# CONFIG_FB_ATY is not set +CONFIG_FB_ATY=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -365,7 +362,7 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y +# CONFIG_ADB_MOUSE is not set CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -385,19 +382,14 @@ CONFIG_NVRAM=y # # CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_FT_NORMAL_DEBUG is not set -# CONFIG_FT_FULL_DEBUG is not set -# CONFIG_FT_NO_TRACE is not set -# CONFIG_FT_NO_TRACE_AT_ALL is not set -# CONFIG_FT_STD_FDC is not set -# CONFIG_FT_MACH2 is not set -# CONFIG_FT_PROBE_FC10 is not set -# CONFIG_FT_ALT_FDC is not set +# CONFIG_DRM is not set # # USB drivers - not for the faint of heart @@ -413,9 +405,13 @@ CONFIG_AUTOFS_FS=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -442,12 +438,14 @@ CONFIG_LOCKD=y # # Partition Types # -# CONFIG_BSD_DISKLABEL is not set +# CONFIG_PARTITION_ADVANCED is not set CONFIG_MAC_PARTITION=y -# CONFIG_SMD_DISKLABEL is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_SGI_DISKLABEL is not set # CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # @@ -458,6 +456,8 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set @@ -472,6 +472,7 @@ CONFIG_SOUND_OSS=y # CONFIG_SOUND_MSS is not set # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_MAD16 is not set # CONFIG_SOUND_WAVEFRONT is not set CONFIG_SOUND_CS4232=m diff --git a/arch/ppc/gemini_defconfig b/arch/ppc/gemini_defconfig index f0f5dc3f6fc6..cebd77dfe68a 100644 --- a/arch/ppc/gemini_defconfig +++ b/arch/ppc/gemini_defconfig @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # @@ -8,14 +8,25 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_PPC64 is not set +# CONFIG_82xx is not set # CONFIG_8xx is not set +# CONFIG_MPC821 is not set +# CONFIG_MPC823 is not set +# CONFIG_MPC850 is not set +# CONFIG_MPC855 is not set +# CONFIG_MPC860 is not set +# CONFIG_MPC860T is not set +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT 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_APUS is not set -# CONFIG_MBX is not set # CONFIG_SMP is not set CONFIG_MACH_SPECIFIC=y CONFIG_6xx=y @@ -39,9 +50,9 @@ CONFIG_KERNEL_ELF=y # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set # CONFIG_PMAC_PBOOK is not set -CONFIG_MAC_KEYBOARD=y # CONFIG_MAC_FLOPPY is not set # 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 @@ -51,15 +62,22 @@ CONFIG_MAC_KEYBOARD=y # Plug and Play configuration # # CONFIG_PNP is not set -# CONFIG_ISAPNP is not set # # 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 +# # CONFIG_BLK_DEV_HD_ONLY is not set # CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set @@ -91,10 +109,18 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y 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 + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set @@ -116,11 +142,19 @@ CONFIG_SKB_LARGE=y # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -147,6 +181,8 @@ 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_G_NCR5380_PORT is not set +# CONFIG_SCSI_G_NCR5380_MEM is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set @@ -194,7 +230,21 @@ CONFIG_NETDEVICES=y # # Ethernet (10 or 100Mbit) # -# CONFIG_NET_ETHERNET is not set +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +CONFIG_NCR885E=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_SIS900 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PPP is not set @@ -241,7 +291,6 @@ CONFIG_NETDEVICES=y # CONFIG_VT=y CONFIG_VT_CONSOLE=y -CONFIG_PC_KEYB=y CONFIG_SERIAL=y CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set @@ -256,14 +305,13 @@ 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 # CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y +# CONFIG_NVRAM is not set # CONFIG_RTC is not set # @@ -283,6 +331,15 @@ CONFIG_NVRAM=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_FT_NORMAL_DEBUG is not set +# CONFIG_FT_FULL_DEBUG is not set +# CONFIG_FT_NO_TRACE is not set +# CONFIG_FT_NO_TRACE_AT_ALL is not set +# CONFIG_FT_STD_FDC is not set +# CONFIG_FT_MACH2 is not set +# CONFIG_FT_PROBE_FC10 is not set +# CONFIG_FT_ALT_FDC is not set +# CONFIG_DRM is not set # # USB drivers - not for the faint of heart @@ -298,12 +355,10 @@ CONFIG_NVRAM=y # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -347,6 +402,6 @@ CONFIG_MSDOS_PARTITION=y # # Kernel hacking # -CONFIG_MAGIC_SYSRQ=y +# CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index a177a3642f82..5e61fd001e95 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -12,49 +12,84 @@ O_TARGET := kernel.o OX_OBJS := ppc_ksyms.o setup.o +KHEAD := head.o +ifdef CONFIG_PPC_ALL +CONFIG_PMAC=y +CONFIG_PREP=y +CONFIG_CHRP=y +endif O_OBJS := entry.o traps.o irq.o idle.o time.o process.o signal.o syscalls.o \ misc.o bitops.o ptrace.o align.o ppc_htab.o semaphore.o + ifndef CONFIG_8xx O_OBJS += hashtable.o endif + ifdef CONFIG_PCI O_OBJS += pci.o endif + ifdef CONFIG_KGDB O_OBJS += ppc-stub.o endif + ifdef CONFIG_TOTALMP O_OBJS += totalmp.o endif -ifeq ($(CONFIG_MBX),y) -O_OBJS += mbx_setup.o mbx_pci.o i8259.o ppc8xx_pic.o +ifdef CONFIG_PMAC_PBOOK +O_OBJS += sleep.o +endif + +ifdef CONFIG_SMP +O_OBJS += smp.o +endif + +ifeq ($(CONFIG_8xx),y) +KHEAD := head_8xx.o +O_OBJS += m8xx_setup.o ppc8xx_pic.o +ifndef CONFIG_MATH_EMULATION +O_OBJS += softemu8xx.o +endif +ifdef CONFIG_PCI +O_OBJS += qspan_pci.c +endif +ifdef CONFIG_MBX +O_OBJS += i8259.o +endif else ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o prom.o open_pic.o else -ifneq ($(CONFIG_MBX),y) -O_OBJS += prep_time.o pmac_time.o chrp_time.o \ - pmac_setup.o pmac_support.o \ - prep_pci.o pmac_pci.o chrp_pci.o \ - residual.o prom.o open_pic.o feature.o \ - prep_nvram.o i8259.o pmac_pic.o indirect_pci.o \ +ifneq ($(CONFIG_8xx),y) +O_OBJS += chrp_setup.o chrp_pci.o chrp_time.o \ + pmac_time.o pmac_support.o pmac_pci.o pmac_setup.o \ + prom.o open_pic.o feature.o \ + i8259.o pmac_pic.o indirect_pci.o \ gemini_pci.o gemini_prom.o gemini_setup.o -OX_OBJS += chrp_setup.o prep_setup.o + +ifeq ($(CONFIG_PREP), y) +O_OBJS += prep_pci.o prep_setup.o prep_nvram.o prep_time.o residual.o endif + +ifeq ($(CONFIG_PMAC), y) endif + +ifeq ($(CONFIG_PMAC), y) endif -ifdef CONFIG_SMP -O_OBJS += smp.o +endif +endif endif -all: head.o kernel.o +all: $(KHEAD) kernel.o head.o: head.S ppc_defs.h +head_8xx.o: head_8xx.S ppc_defs.h + ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/mmu.h \ $(TOPDIR)/include/asm/processor.h \ diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index 5b9e3f137ad4..80377490a326 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -1,11 +1,16 @@ /* * linux/arch/ppc/kernel/apus_setup.c * - * Copyright (C) 1998 Jesper Skov + * Copyright (C) 1998, 1999 Jesper Skov * * Basically what is needed to replace functionality found in * arch/m68k allowing Amiga drivers to work under APUS. * Bits of code and/or ideas from arch/m68k and arch/ppc files. + * + * TODO: + * This file needs a *really* good cleanup. Restructure and optimize. + * Make sure it can be compiled for non-APUS configs. Begin to move + * Amiga specific stuff into linux/machine/amiga. */ #include @@ -14,79 +19,96 @@ #include #include #include +#include #include +#include +#include + +#ifdef CONFIG_APUS +#include +#endif /* Get the IDE stuff from the 68k file */ +#include #define ide_init_hwif_ports m68k_ide_init_hwif_ports #define ide_default_irq m68k_ide_default_irq +#define ide_request_irq m68k_ide_request_irq #define ide_default_io_base m68k_ide_default_io_base #define ide_check_region m68k_ide_check_region #define ide_request_region m68k_ide_request_region #define ide_release_region m68k_ide_release_region #define ide_fix_driveid m68k_ide_fix_driveid +#define ide_init_default_hwifs m68k_ide_init_default_hwifs +#define select_t m68k_select_t +#define ide_free_irq m68k_ide_free_irq +//#include #include +#undef ide_free_irq +#undef select_t +#undef ide_request_irq +#undef ide_init_default_hwifs #undef ide_init_hwif_ports -#define ide_default_irq -#define ide_default_io_base -#define ide_check_region -#define ide_request_region -#define ide_release_region -#define ide_fix_driveid - - +#undef ide_default_irq +#undef ide_default_io_base +#undef ide_check_region +#undef ide_request_region +#undef ide_release_region +#undef ide_fix_driveid +/*-------------------------------------------*/ + +#include #include #include #include #include #include +#include #include -#include +#include -#include "time.h" #include "local_irq.h" -unsigned long apus_get_rtc_time(void); -int apus_set_rtc_time(unsigned long nowtime); - -/* APUS defs */ -extern int parse_bootinfo(const struct bi_record *); -extern char _end[]; -#ifdef CONFIG_APUS -struct mem_info ramdisk; -unsigned long isa_io_base; -unsigned long isa_mem_base; -unsigned long pci_dram_offset; -#endif -/* END APUS defs */ - -unsigned long m68k_machtype; -char debug_device[6] = ""; +unsigned long m68k_machtype __apusdata; +char debug_device[6] __apusdata = ""; void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata; /* machine dependent keyboard functions */ int (*mach_keyb_init) (void) __initdata; -int (*mach_kbdrate) (struct kbd_repeat *) = NULL; -void (*mach_kbd_leds) (unsigned int) = NULL; +int (*mach_kbdrate) (struct kbd_repeat *) __apusdata = NULL; +void (*mach_kbd_leds) (unsigned int) __apusdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata; -void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; -void (*mach_get_model) (char *model) = NULL; -int (*mach_get_hardware_list) (char *buffer) = NULL; -int (*mach_get_irq_list) (char *) = NULL; -void (*mach_process_int) (int, struct pt_regs *) = NULL; +void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) __apusdata = NULL; +void (*mach_get_model) (char *model) __apusdata = NULL; +int (*mach_get_hardware_list) (char *buffer) __apusdata = NULL; +int (*mach_get_irq_list) (char *) __apusdata = NULL; +void (*mach_process_int) (int, struct pt_regs *) __apusdata = NULL; /* machine dependent timer functions */ -unsigned long (*mach_gettimeoffset) (void); -void (*mach_gettod) (int*, int*, int*, int*, int*, int*); -int (*mach_hwclk) (int, struct hwclk_time*) = NULL; -int (*mach_set_clock_mmss) (unsigned long) = NULL; -void (*mach_reset)( void ); -long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) +unsigned long (*mach_gettimeoffset) (void) __apusdata; +void (*mach_gettod) (int*, int*, int*, int*, int*, int*) __apusdata; +int (*mach_hwclk) (int, struct hwclk_time*) __apusdata = NULL; +int (*mach_set_clock_mmss) (unsigned long) __apusdata = NULL; +void (*mach_reset)( void ) __apusdata; +long mach_max_dma_address __apusdata = 0x00ffffff; /* default set to the lower 16MB */ +#if defined(CONFIG_AMIGA_FLOPPY) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; -void (*mach_floppy_eject) (void) = NULL; +void (*mach_floppy_eject) (void) __apusdata = NULL; #endif #ifdef CONFIG_HEARTBEAT -void (*mach_heartbeat) (int) = NULL; +void (*mach_heartbeat) (int) __apusdata = NULL; +extern void apus_heartbeat (void); +static int heartbeat_enabled = 1; + +void enable_heartbeat(void) +{ + heartbeat_enabled = 1; +} + +void disable_heartbeat(void) +{ + heartbeat_enabled = 0; + mach_heartbeat(0); +} #endif extern unsigned long amiga_model; @@ -94,22 +116,154 @@ extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */ extern unsigned count_period_num; /* 1 decrementer count equals */ extern unsigned count_period_den; /* count_period_num / count_period_den us */ -extern struct mem_info memory[NUM_MEMINFO];/* memory description */ +int num_memory __apusdata = 0; +struct mem_info memory[NUM_MEMINFO] __apusdata;/* memory description */ +/* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */ +int m68k_realnum_memory __apusdata = 0; +struct mem_info m68k_memory[NUM_MEMINFO] __apusdata;/* memory description */ + +struct mem_info ramdisk __apusdata; extern void amiga_floppy_setup(char *, int *); extern void config_amiga(void); -static int __60nsram = 0; +static int __60nsram __apusdata = 0; + +/* for cpuinfo */ +static int __bus_speed __apusdata = 0; +static int __speed_test_failed __apusdata = 0; + +/********************************************** COMPILE PROTECTION */ +/* Provide some stubs that links to Amiga specific functions. + * This allows CONFIG_APUS to be removed from generic PPC files while + * preventing link errors for other PPC targets. + */ +__apus +unsigned long apus_get_rtc_time(void) +{ +#ifdef CONFIG_APUS + extern unsigned long m68k_get_rtc_time(void); + + return m68k_get_rtc_time (); +#else + return 0; +#endif +} + +__apus +int apus_set_rtc_time(unsigned long nowtime) +{ +#ifdef CONFIG_APUS + extern int m68k_set_rtc_time(unsigned long nowtime); + + return m68k_set_rtc_time (nowtime); +#else + return 0; +#endif +} + +__apus +int apus_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id) +{ +#ifdef CONFIG_APUS + extern int amiga_request_irq(unsigned int irq, + void (*handler)(int, void *, + struct pt_regs *), + unsigned long flags, + const char *devname, + void *dev_id); + + return amiga_request_irq (irq, handler, flags, devname, dev_id); +#else + return 0; +#endif +} + +__apus +void apus_free_irq(unsigned int irq, void *dev_id) +{ +#ifdef CONFIG_APUS + extern void amiga_free_irq(unsigned int irq, void *dev_id); + + amiga_free_irq (irq, dev_id); +#endif +} + +__apus +void apus_process_int(unsigned long vec, void *fp) +{ +#ifdef CONFIG_APUS + extern void process_int(unsigned long vec, struct pt_regs *fp); + + process_int (vec, (struct pt_regs*)fp); +#endif +} + +__apus +int apus_get_irq_list(char *buf) +{ +#ifdef CONFIG_APUS + extern int m68k_get_irq_list (char*); + + return m68k_get_irq_list (buf); +#else + return 0; +#endif +} + + +/* Here some functions we don't support, but which the other ports reference */ +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); + return 0; +} +int pckbd_getkeycode(unsigned int scancode) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); + return 0; +} +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); + return 0; +} +char pckbd_unexpected_up(unsigned char keycode) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); + return 0; +} +void pckbd_leds(unsigned char leds) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); +} +void pckbd_init_hw(void) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); +} +unsigned char pckbd_sysrq_xlate[128]; + +struct pci_bus * __init pci_scan_peer_bridge(int bus) +{ + printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n"); + return NULL; +} /*********************************************************** SETUP */ /* From arch/m68k/kernel/setup.c. */ void __init apus_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { +#ifdef CONFIG_APUS extern char cmd_line[]; int i; char *p, *q; + /* Let m68k-shared code know it should do the Amiga thing. */ m68k_machtype = MACH_AMIGA; /* Parse the command line for arch-specific options. @@ -143,10 +297,46 @@ void __init apus_setup_arch(unsigned long * memory_start_p, } config_amiga(); + + { +#define LOG_SIZE 4096 + void* base; + + /* Throw away some memory - the P5 firmare stomps on top + * of CHIP memory during bootup. + */ + amiga_chip_alloc(0x1000); + + base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t)); + LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE); + } +#endif } +__apus +int +apus_get_cpuinfo(char *buffer) +{ +#ifdef CONFIG_APUS + extern int __map_without_bats; + extern unsigned long powerup_PCI_present; + int len; + + len = sprintf(buffer, "machine\t\t: Amiga\n"); + len += sprintf(buffer+len, "bus speed\t: %d%s", __bus_speed, + (__speed_test_failed) ? " [failed]\n" : "\n"); + len += sprintf(buffer+len, "using BATs\t: %s\n", + (__map_without_bats) ? "No" : "Yes"); + len += sprintf(buffer+len, "ram speed\t: %dns\n", + (__60nsram) ? 60 : 70); + len += sprintf(buffer+len, "PCI bridge\t: %s\n", + (powerup_PCI_present) ? "Yes" : "No"); + return len; +#endif +} -void get_current_tb(unsigned long long *time) +__apus +static void get_current_tb(unsigned long long *time) { __asm __volatile ("1:mftbu 4 \n\t" " mftb 5 \n\t" @@ -161,14 +351,17 @@ void get_current_tb(unsigned long long *time) } +__apus void apus_calibrate_decr(void) { +#ifdef CONFIG_APUS int freq, divisor; /* This algorithm for determining the bus speed was contributed by Ralph Schmidt. */ unsigned long long start, stop; int bus_speed; + int speed_test_failed = 0; { unsigned long loop = amiga_eclock / 10; @@ -200,16 +393,23 @@ void apus_calibrate_decr(void) "Defaulting to 50MHz", bus_speed); bus_speed = 50; freq = 12500000; + speed_test_failed = 1; } /* Ease diagnostics... */ { extern int __map_without_bats; + extern unsigned long powerup_PCI_present; - printk ("APUS: BATs=%d, BUS=%dMHz, RAM=%dns\n", + printk ("APUS: BATs=%d, BUS=%dMHz", (__map_without_bats) ? 0 : 1, - bus_speed, - (__60nsram) ? 60 : 70); + bus_speed); + if (speed_test_failed) + printk ("[FAILED - please report]"); + + printk (", RAM=%dns, PCI bridge=%d\n", + (__60nsram) ? 60 : 70, + (powerup_PCI_present) ? 1 : 0); /* print a bit more if asked politely... */ if (!(ciaa.pra & 0x40)){ @@ -232,25 +432,67 @@ void apus_calibrate_decr(void) decrementer_count = freq / HZ / divisor; count_period_num = divisor; count_period_den = freq / 1000000; + + __bus_speed = bus_speed; + __speed_test_failed = speed_test_failed; +#endif } +__apus void arch_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec) { +#ifdef CONFIG_APUS if (mach_gettod) mach_gettod(year, mon, day, hour, min, sec); else *year = *mon = *day = *hour = *min = *sec = 0; +#endif +} + +/* for "kbd-reset" cmdline param */ +__init +void kbd_reset_setup(char *str, int *ints) +{ +} + +#if defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL) + +long m68k_rs_init(void); +int m68k_register_serial(struct serial_struct *); +void m68k_unregister_serial(int); +long m68k_serial_console_init(long, long ); + +int rs_init(void) +{ + return m68k_rs_init(); +} +int register_serial(struct serial_struct *p) +{ + return m68k_register_serial(p); +} +void unregister_serial(int i) +{ + m68k_unregister_serial(i); } +#ifdef CONFIG_SERIAL_CONSOLE +long serial_console_init(long kmem_start, long kmem_end) +{ + return m68k_serial_console_init(kmem_start, kmem_end); +} +#endif +#endif /*********************************************************** FLOPPY */ -#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) -void __init floppy_setup(char *str, int *ints) +#if defined(CONFIG_AMIGA_FLOPPY) +__init +void floppy_setup(char *str, int *ints) { if (mach_floppy_setup) mach_floppy_setup (str, ints); } +__apus void floppy_eject(void) { if (mach_floppy_eject) @@ -259,44 +501,13 @@ void floppy_eject(void) #endif /*********************************************************** MEMORY */ -extern void -map_page(struct task_struct *tsk, unsigned long va, - unsigned long pa, int flags); - -#define KMAP_MAX 8 -static unsigned long kmap_chunks[KMAP_MAX*3]; -static int kmap_chunk_count = 0; - -/* Based on arch/ppc/mm/init.c:ioremap() which maps the address range - to the same virtual address as the physical address - which may - cause problems since Z3 IO space is not the same as PCI/ISA. - This should be rewritten to something more like the m68k version. */ -unsigned long kernel_map (unsigned long phys_addr, unsigned long size, - int cacheflag, unsigned long *memavailp) -{ - unsigned long v_ret, end; - /* Remap to 0x90000000. Related comment in ppc/mm/init.c. */ - static unsigned long virt = 0x90000000; - v_ret = virt; - - if (kmap_chunk_count == KMAP_MAX*3) - panic ("kernel_map: Can only map %d chunks.\n", - KMAP_MAX); - - kmap_chunks[kmap_chunk_count++] = phys_addr; - kmap_chunks[kmap_chunk_count++] = size; - kmap_chunks[kmap_chunk_count++] = v_ret; - - for (end = phys_addr + size ; phys_addr < end; - phys_addr += PAGE_SIZE, virt += PAGE_SIZE) { - map_page(&init_task, virt, phys_addr, - pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED); - } - return v_ret; -} +#define KMAP_MAX 32 +unsigned long kmap_chunks[KMAP_MAX*3] __apusdata; +int kmap_chunk_count __apusdata = 0; /* From pgtable.h */ -extern __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) +__apus +static __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) { pgd_t *dir = 0; pmd_t *pmd = 0; @@ -318,10 +529,11 @@ extern __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) /* Again simulating an m68k/mm/kmap.c function. */ +__apus void kernel_set_cachemode( unsigned long address, unsigned long size, unsigned int cmode ) { - int mask, flags; + unsigned long mask, flags; switch (cmode) { @@ -360,6 +572,7 @@ void kernel_set_cachemode( unsigned long address, unsigned long size, } } +__apus unsigned long mm_ptov (unsigned long paddr) { unsigned long ret; @@ -388,6 +601,7 @@ exit: return ret; } +__apus int mm_end_of_chunk (unsigned long addr, int len) { if (memory[0].addr + memory[0].size == addr + len) @@ -399,6 +613,7 @@ int mm_end_of_chunk (unsigned long addr, int len) #define L1_CACHE_BYTES 32 #define MAX_CACHE_SIZE 8192 +__apus void cache_push(__u32 addr, int length) { addr = mm_ptov(addr); @@ -417,6 +632,8 @@ void cache_push(__u32 addr, int length) "sync \n\t" : : "r" (addr)); } + +__apus void cache_clear(__u32 addr, int length) { if (MAX_CACHE_SIZE < length) @@ -450,6 +667,7 @@ void cache_clear(__u32 addr, int length) : : "r" (addr)); } +/****************************************************** from setup.c */ void apus_restart(char *cmd) { @@ -478,37 +696,13 @@ apus_halt(void) apus_restart(NULL); } -void -apus_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) -{ - int old_level, new_level; - - /* I don't think we need SMP code here - Corey */ - - old_level = ~(regs->mq) & IPLEMU_IPLMASK; - new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK; - if (new_level != 0) - { - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET - | (~(new_level) & IPLEMU_IPLMASK))); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); - - process_int (VEC_SPUR+new_level, regs); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); - APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); - APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET - | (~(old_level) & IPLEMU_IPLMASK))); - } - APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); -} - +/****************************************************** from setup.c/IDE */ #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) /* * IDE stuff. */ +void ide_insw(ide_ioreg_t port, void *buf, int ns); +void ide_outsw(ide_ioreg_t port, void *buf, int ns); void apus_ide_insw(ide_ioreg_t port, void *buf, int ns) { @@ -524,13 +718,13 @@ apus_ide_outsw(ide_ioreg_t port, void *buf, int ns) int apus_ide_default_irq(ide_ioreg_t base) { - m68k_ide_default_irq(base); + return m68k_ide_default_irq(base); } ide_ioreg_t apus_ide_default_io_base(int index) { - m68k_ide_default_io_base(index); + return 0; } int @@ -560,25 +754,156 @@ apus_ide_fix_driveid(struct hd_driveid *id) m68k_ide_fix_driveid(id); } -void __init -apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) +__init +void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) { m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq); } #endif +/****************************************************** from irq.c */ +#define VEC_SPUR (24) + +void +apus_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int old_level, new_level; + + new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK; + + if (0 != new_level && 7 != new_level) { + old_level = ~(regs->mq) & IPLEMU_IPLMASK; + + apus_process_int (VEC_SPUR+new_level, regs); + + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET + | (~(old_level) & IPLEMU_IPLMASK))); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); + } +} + +__apus +static void apus_save_flags(unsigned long* flags) +{ + unsigned short __f; + APUS_READ(APUS_IPL_EMU, __f); + return ((~__f) & IPLEMU_IPLMASK) << 8; +} + +__apus +static void apus_restore_flags(unsigned long flags) +{ + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET + | (~(flags >> 8) & IPLEMU_IPLMASK)); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); +} + +__apus +static void apus_sti(void) +{ + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); +} + +__apus +static void apus_cli(void) +{ + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); +} + +/****************************************************** keyboard */ +__apus +static int apus_kbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + return -EOPNOTSUPP; +} + +__apus +static int apus_kbd_getkeycode(unsigned int scancode) +{ + return scancode > 127 ? -EINVAL : scancode; +} + +__apus +static int apus_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode) +{ + *keycodep = keycode; + return 1; +} + +__apus +static char apus_kbd_unexpected_up(unsigned char keycode) +{ + return 0200; +} + +__apus +static void apus_kbd_leds(unsigned char leds) +{ +} + +__apus +static void apus_kbd_init_hw(void) +{ +#ifdef CONFIG_APUS + extern int amiga_keyb_init(void); + +printk("**** " __FUNCTION__ "\n"); + amiga_keyb_init(); +#endif +} + -void __init -apus_local_init_IRQ(void) +/****************************************************** init */ +extern void amiga_disable_irq(unsigned int irq); +extern void amiga_enable_irq(unsigned int irq); +extern void m68k_init_IRQ (void); + +struct hw_interrupt_type amiga_irq_ctl = { + " Amiga ", + NULL, + NULL, + NULL, + amiga_enable_irq, + amiga_disable_irq, + NULL, + 0 +}; + +__init +void apus_init_IRQ(void) { - ppc_md.mask_irq = amiga_disable_irq; - ppc_md.unmask_irq = amiga_enable_irq; - apus_init_IRQ(); + int i; + + for (i = 0; i < NR_IRQS; i++) + irq_desc[i].ctl = &amiga_irq_ctl; + m68k_init_IRQ (); + + int_control.int_sti = apus_sti; + int_control.int_cli = apus_cli; + int_control.int_save_flags = apus_save_flags; + int_control.int_restore_flags = apus_restore_flags; } -void __init -apus_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +__init +void apus_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) { + extern int parse_bootinfo(const struct bi_record *); + extern char _end[]; + /* Parse bootinfo. The bootinfo is located right after the kernel bss */ parse_bootinfo((const struct bi_record *)&_end); @@ -591,9 +916,6 @@ apus_init(unsigned long r3, unsigned long r4, unsigned long r5, initrd_end = (unsigned long) __va(ramdisk.size + ramdisk.addr); } - /* Make sure code below is not executed. */ - r4 = 0; - r6 = 0; #endif /* CONFIG_BLK_DEV_INITRD */ ISA_DMA_THRESHOLD = 0x00ffffff; @@ -604,7 +926,10 @@ apus_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = apus_init_IRQ; ppc_md.do_IRQ = apus_do_IRQ; - ppc_md.get_irq_source = NULL; +#ifdef CONFIG_HEARTBEAT + ppc_md.heartbeat = apus_heartbeat; + ppc_md.heartbeat_count = 1; +#endif ppc_md.init = NULL; ppc_md.restart = apus_restart; @@ -616,24 +941,29 @@ apus_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.get_rtc_time = apus_get_rtc_time; ppc_md.calibrate_decr = apus_calibrate_decr; + ppc_md.nvram_read_val = NULL; + ppc_md.nvram_write_val = NULL; + /* These should not be used for the APUS yet, since it uses the M68K keyboard now. */ - ppc_md.kbd_setkeycode = NULL; - ppc_md.kbd_getkeycode = NULL; - ppc_md.kbd_translate = NULL; - ppc_md.kbd_unexpected_up = NULL; - ppc_md.kbd_leds = NULL; - ppc_md.kbd_init_hw = NULL; + ppc_md.kbd_setkeycode = apus_kbd_setkeycode; + ppc_md.kbd_getkeycode = apus_kbd_getkeycode; + ppc_md.kbd_translate = apus_kbd_translate; + ppc_md.kbd_unexpected_up = apus_kbd_unexpected_up; + ppc_md.kbd_leds = apus_kbd_leds; + ppc_md.kbd_init_hw = apus_kbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ ppc_md.kbd_sysrq_xlate = NULL; +#endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = apus_ide_insw; ppc_ide_md.outsw = apus_ide_outsw; ppc_ide_md.default_irq = apus_ide_default_irq; ppc_ide_md.default_io_base = apus_ide_default_io_base; - ppc_ide_md.check_region = apus_ide_check_region; - ppc_ide_md.request_region = apus_ide_request_region; - ppc_ide_md.release_region = apus_ide_release_region; + ppc_ide_md.ide_check_region = apus_ide_check_region; + ppc_ide_md.ide_request_region = apus_ide_request_region; + ppc_ide_md.ide_release_region = apus_ide_release_region; ppc_ide_md.fix_driveid = apus_ide_fix_driveid; ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports; diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index 397f69c18e52..da752ccb63b7 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -354,7 +354,8 @@ chrp_setup_pci_ptrs(void) else { if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) || - !strncmp("IBM,7046-155", get_property(find_path_device("/"), "name", NULL),12) ) + !strncmp("IBM,7046-155", get_property(find_path_device("/"), "name", NULL),12) || + !strncmp("IBM,7046-B50", get_property(find_path_device("/"), "name", NULL),12) ) { pci_dram_offset = 0; isa_mem_base = 0x80000000; diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 7faa1ed4b14e..2739c541daa1 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -46,7 +48,6 @@ #include #include #include -#include #include #include @@ -55,14 +56,6 @@ #include "i8259.h" #include "open_pic.h" -/* Fixme - need to move these into their own .c and .h file */ -extern void i8259_mask_and_ack_irq(unsigned int irq_nr); -extern void i8259_set_irq_mask(unsigned int irq_nr); -extern void i8259_mask_irq(unsigned int irq_nr); -extern void i8259_unmask_irq(unsigned int irq_nr); -extern void i8259_init(void); - -/* Fixme - remove this when it is fixed. - Corey */ extern volatile unsigned char *chrp_int_ack_special; unsigned long chrp_get_rtc_time(void); @@ -91,7 +84,6 @@ extern void mackbd_leds(unsigned char leds); extern void mackbd_init_hw(void); extern unsigned char mackbd_sysrq_xlate[128]; -/* for the mac fs */ kdev_t boot_dev; extern PTE *Hash, *Hash_end; @@ -185,12 +177,11 @@ chrp_get_cpuinfo(char *buffer) } /* - * Fixes for the National Semiconductor PC78308VUL SuperI/O - * - * Some versions of Open Firmware incorrectly initialize the IRQ settings - * for keyboard and mouse - */ - + * Fixes for the National Semiconductor PC78308VUL SuperI/O + * + * Some versions of Open Firmware incorrectly initialize the IRQ settings + * for keyboard and mouse + */ static inline void __init sio_write(u8 val, u8 index) { outb(index, 0x15c); @@ -236,7 +227,7 @@ static void __init sio_init(void) void __init - chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) +chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) { extern char cmd_line[]; struct device_node *device; @@ -358,6 +349,46 @@ chrp_irq_cannonicalize(u_int irq) } } +int chrp_get_irq( struct pt_regs *regs ) +{ + int irq; + + irq = openpic_irq( smp_processor_id() ); + if (irq == IRQ_8259_CASCADE) + { + /* + * This magic address generates a PCI IACK cycle. + */ + if ( chrp_int_ack_special ) + irq = *chrp_int_ack_special; + else + irq = i8259_irq( smp_processor_id() ); + /* + * Acknowledge as soon as possible to allow i8259 + * interrupt nesting */ + openpic_eoi( smp_processor_id() ); + } + if (irq == OPENPIC_VEC_SPURIOUS) + /* + * Spurious interrupts should never be + * acknowledged + */ + irq = -1; + return irq; +} + +void chrp_post_irq(int irq) +{ + /* + * If it's an i8259 irq then we've already done the + * openpic irq. So we just check to make sure the controller + * is an openpic and if it is then eoi -- Cort + */ + if ( irq_desc[irq].ctl == &open_pic ) + openpic_eoi( smp_processor_id() ); +} + +#if 0 void chrp_do_IRQ(struct pt_regs *regs, int cpu, @@ -432,9 +463,9 @@ out: if (!openpic_eoi_done) openpic_eoi(0); } +#endif -void __init - chrp_init_IRQ(void) +void __init chrp_init_IRQ(void) { struct device_node *np; int i; @@ -465,11 +496,8 @@ void __init } void __init - chrp_init2(void) +chrp_init2(void) { - adb_init(); - - /* Should this be here? - Corey */ pmac_nvram_init(); } @@ -482,8 +510,9 @@ int chrp_ide_ports_known = 0; ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; ide_ioreg_t chrp_idedma_regbase; -void chrp_ide_probe(void) { - +void +chrp_ide_probe(void) +{ struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); chrp_ide_ports_known = 1; @@ -570,11 +599,12 @@ chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_ hw->irq = chrp_ide_irq; } +#if defined(CONFIG_BLK_DEV_IDE_MODULE) EXPORT_SYMBOL(chrp_ide_irq); EXPORT_SYMBOL(chrp_ide_ports_known); EXPORT_SYMBOL(chrp_ide_regbase); EXPORT_SYMBOL(chrp_ide_probe); - +#endif #endif void __init @@ -601,7 +631,8 @@ void __init ppc_md.get_cpuinfo = chrp_get_cpuinfo; ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.get_irq = chrp_get_irq; + ppc_md.post_irq = chrp_post_irq; ppc_md.init = chrp_init2; @@ -616,7 +647,7 @@ void __init #ifdef CONFIG_VT #ifdef CONFIG_MAC_KEYBOAD - if ( adb_hardware == ADB_NONE ) + if (adb_driver == NULL) { ppc_md.kbd_setkeycode = pckbd_setkeycode; ppc_md.kbd_getkeycode = pckbd_getkeycode; @@ -678,7 +709,8 @@ void __init if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); } -void chrp_progress(char *s, unsigned short hex) +void +chrp_progress(char *s, unsigned short hex) { extern unsigned int rtas_data; int max_width, width; diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index abff78bc36e9..9c940a0373f2 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/entry.S * - * $Id: entry.S,v 1.3 1999/09/05 11:56:26 paulus Exp $ + * $Id: entry.S,v 1.4 1999/09/14 05:18:14 dmalek Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -26,6 +26,7 @@ #include "ppc_asm.h" #include #include +#include #include #include #include diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index 25ee3424bf1c..a9a30396a0b2 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -41,7 +41,9 @@ static u32 feature_bits_pbook[] = { OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ 0, /* FEATURE_BMac_reset */ 0, /* FEATURE_BMac_IO_enable */ - 0 /* FEATURE_Modem_Reset -> guess...*/ + 0, /* FEATURE_Modem_Reset -> guess... */ + OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */ + OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */ }; /* assume these are the same as the ohare until proven otherwise */ @@ -63,7 +65,9 @@ static u32 feature_bits_heathrow[] = { OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ 0x80000000, /* FEATURE_BMac_reset */ 0x60000000, /* FEATURE_BMac_IO_enable */ - 0x02000000 /* FEATURE_Modem_Reset -> guess...*/ + 0x02000000, /* FEATURE_Modem_Reset -> guess...*/ + OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */ + OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */ }; /* definition of a feature controller object */ @@ -191,9 +195,10 @@ feature_set(struct device_node* device, enum system_feature f) save_flags(flags); cli(); - st_le32( controllers[controller].reg, - ld_le32(controllers[controller].reg) | + out_le32( controllers[controller].reg, + in_le32(controllers[controller].reg) | controllers[controller].bits[f]); + (void)in_le32(controllers[controller].reg); restore_flags(flags); udelay(10); @@ -220,9 +225,10 @@ feature_clear(struct device_node* device, enum system_feature f) save_flags(flags); cli(); - st_le32( controllers[controller].reg, - ld_le32(controllers[controller].reg) & + out_le32( controllers[controller].reg, + in_le32(controllers[controller].reg) & ~(controllers[controller].bits[f])); + (void)in_le32(controllers[controller].reg); restore_flags(flags); udelay(10); @@ -241,7 +247,7 @@ feature_test(struct device_node* device, enum system_feature f) if (controller < 0) return controller; - return (ld_le32(controllers[controller].reg) & + return (in_le32(controllers[controller].reg) & controllers[controller].bits[f]) != 0; } diff --git a/arch/ppc/kernel/gemini_pci.c b/arch/ppc/kernel/gemini_pci.c index 89ed43501494..3d6feed13e09 100644 --- a/arch/ppc/kernel/gemini_pci.c +++ b/arch/ppc/kernel/gemini_pci.c @@ -244,7 +244,6 @@ __init void layout_bus( struct pci_bus *bus ) void __init gemini_pcibios_fixup(void) { - struct pci_bus *bus; unsigned long orig_mem_base, orig_io_base; orig_mem_base = pci_mem_base; diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c index 4af02958a43c..6e599cff2134 100644 --- a/arch/ppc/kernel/gemini_setup.c +++ b/arch/ppc/kernel/gemini_setup.c @@ -53,6 +53,8 @@ static unsigned int cpu_6xx[16] = { 0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0 }; +int chrp_get_irq(struct pt_regs *); +void chrp_post_irq(int); static inline unsigned long _get_HID1(void) { @@ -479,7 +481,7 @@ void __init gemini_calibrate_decr(void) void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - void chrp_do_IRQ(struct pt_regs *, int, int); + int chrp_get_irq( struct pt_regs * ); void layout_bus( struct pci_bus * ); gemini_setup_pci_ptrs(); @@ -501,7 +503,8 @@ void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.get_cpuinfo = gemini_get_cpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = gemini_init_IRQ; - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.get_irq = chrp_get_irq; + ppc_md.post_irq = chrp_post_irq; ppc_md.init = NULL; ppc_md.restart = gemini_restart; diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 9a0ee6346807..85de3348fcb2 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.143 1999/09/05 11:56:28 paulus Exp $ + * $Id: head.S,v 1.147 1999/09/15 23:58:53 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -333,8 +333,12 @@ label: \ .long ret_from_except /* System reset */ -#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */ +#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ +#ifdef CONFIG_GEMINI + STD_EXCEPTION(0x100, Reset, __secondary_start_gemini) +#else /* CONFIG_GEMINI */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) +#endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) #endif @@ -421,6 +425,8 @@ HardwareInterrupt: li r20,MSR_KERNEL li r4,0 bl transfer_to_handler + .globl do_IRQ_intercept +do_IRQ_intercept: .long do_IRQ; .long ret_from_except @@ -461,7 +467,17 @@ FPUnavailable: .long KernelFP .long ret_from_except - STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + . = 0x900 +Decrementer: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + bl transfer_to_handler + .globl timer_interrupt_intercept +timer_interrupt_intercept: + .long timer_interrupt + .long ret_from_except + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) STD_EXCEPTION(0xb00, Trap_0b, UnknownException) @@ -1011,6 +1027,20 @@ __secondary_hold: mr r24,r3 /* cpu # */ blr + .globl __secondary_start_gemini +__secondary_start_gemini: +1011: b 1011b + + mfspr r4,HID0 + ori r4,r4,HID0_ICFI + li r3,0 + ori r3,r3,HID0_ICE + andc r4,r4,r3 + mtspr HID0,r4 + sync + bl prom_init + b __secondary_start + .globl __secondary_start_psurge __secondary_start_psurge: li r24,1 /* cpu # */ diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index fcda01719fe3..c5a55c6a2cd1 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/except_8xx.S * - * $Id: head_8xx.S,v 1.2 1999/08/23 02:53:19 paulus Exp $ + * $Id: head_8xx.S,v 1.4 1999/09/18 18:43:19 dmalek Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -28,6 +28,8 @@ #include #include #include +#include +#include .text .globl _stext @@ -109,25 +111,19 @@ __start: mtspr MI_AP, r8 mtspr MD_AP, r8 -/* We will get these from a configuration file as soon as I verify - * the extraneous bits don't cause problems in the TLB. - */ -#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE) -#define BOOT_IMMR 0xfa000000 -#endif -#ifdef CONFIG_BSEIP -#define BOOT_IMMR 0xff000000 -#endif - /* Map another 8 MByte at 0xfa000000 to get the processor + /* Map another 8 MByte at the IMMR to get the processor * internal registers (among other things). */ - lis r8, BOOT_IMMR@h /* Create vaddr for TLB */ + mfspr r9, 638 /* Get current IMMR */ + andis. r9, r9, 0xff80 /* Get 8Mbyte boundary */ + + mr r8, r9 /* Create vaddr for TLB */ ori r8, r8, MD_EVALID /* Mark it valid */ mtspr MD_EPN, r8 li r8, MD_PS8MEG /* Set 8M byte page */ ori r8, r8, MD_SVALID /* Make it valid */ mtspr MD_TWC, r8 - lis r8, BOOT_IMMR@h /* Create paddr for TLB */ + mr r8, r9 /* Create paddr for TLB */ ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ mtspr MD_RPN, r8 @@ -301,6 +297,8 @@ HardwareInterrupt: li r20,MSR_KERNEL li r4,0 bl transfer_to_handler + .globl do_IRQ_intercept +do_IRQ_intercept: .long do_IRQ; .long ret_from_except @@ -335,7 +333,17 @@ ProgramCheck: */ STD_EXCEPTION(0x800, FPUnavailable, UnknownException) - STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + . = 0x900 +Decrementer: + EXCEPTION_PROLOG + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + bl transfer_to_handler + .globl timer_interrupt_intercept +timer_interrupt_intercept: + .long timer_interrupt + .long ret_from_except + STD_EXCEPTION(0xa00, Trap_0a, UnknownException) STD_EXCEPTION(0xb00, Trap_0b, UnknownException) @@ -553,7 +561,6 @@ DataTLBError: mtcr r21 lwz r21, 4(r0) b DataAccess -#endif /* CONFIG_8xx */ STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) diff --git a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c index 4ec6d3e118f8..3a3a16d9ef5f 100644 --- a/arch/ppc/kernel/i8259.c +++ b/arch/ppc/kernel/i8259.c @@ -96,7 +96,6 @@ struct hw_interrupt_type i8259_pic = { " i8259 ", NULL, NULL, - NULL, i8259_unmask_irq, i8259_mask_irq, i8259_mask_and_ack_irq, diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index f8f59440c2f3..09066a84870a 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.66 1999/09/05 11:56:30 paulus Exp $ + * $Id: idle.c,v 1.67 1999/09/10 05:05:47 paulus Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -73,7 +73,7 @@ int idled(void) * SMP entry into the idle task - calls the same thing as the * non-smp versions. -- Cort */ -int cpu_idle() +int cpu_idle(void) { idled(); return 0; diff --git a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c index 641d77a5253d..552c552dc8d4 100644 --- a/arch/ppc/kernel/indirect_pci.c +++ b/arch/ppc/kernel/indirect_pci.c @@ -19,7 +19,7 @@ unsigned char * pci_config_data; int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { - unsigned flags; + unsigned long flags; save_flags(flags); cli(); @@ -35,7 +35,7 @@ int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { - unsigned flags; + unsigned long flags; if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; @@ -53,7 +53,7 @@ int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { - unsigned flags; + unsigned long flags; if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; @@ -71,7 +71,7 @@ int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { - unsigned flags; + unsigned long flags; save_flags(flags); cli(); @@ -87,7 +87,7 @@ int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { - unsigned flags; + unsigned long flags; if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER; @@ -105,7 +105,7 @@ int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { - unsigned flags; + unsigned long flags; if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER; diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index eece8308a78f..9c157d41b9fd 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -1,5 +1,5 @@ /* - * $Id: irq.c,v 1.109 1999/09/05 11:56:31 paulus Exp $ + * $Id: irq.c,v 1.113 1999/09/17 17:22:56 cort Exp $ * * arch/ppc/kernel/irq.c * @@ -79,8 +79,8 @@ volatile unsigned char *chrp_int_ack_special; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) +struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, }; int ppc_spurious_interrupts = 0; - unsigned int ppc_local_bh_count[NR_CPUS]; unsigned int ppc_local_irq_count[NR_CPUS]; struct irqaction *ppc_irq_action[NR_IRQS]; @@ -124,9 +124,16 @@ void irq_kfree(void *ptr) kfree(ptr); } -struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, }; - +#ifndef CONFIG_8xx int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +#else +/* Name change so we can catch standard drivers that potentially mess up + * the internal interrupt controller on 8xx and 82xx. Just bear with me, + * I don't like this either and I am searching a better solution. For + * now, this is what I need. -- Dan + */ +int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +#endif unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction *old, **p, *action; @@ -186,7 +193,11 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) void free_irq(unsigned int irq, void *dev_id) { +#ifndef CONFIG_8xx request_irq(irq, NULL, 0, NULL, dev_id); +#else + request_8xxirq(irq, NULL, 0, NULL, dev_id); +#endif } /* XXX should implement irq disable depth like on intel */ @@ -277,12 +288,28 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) asmlinkage void do_IRQ(struct pt_regs *regs, int isfake) { int cpu = smp_processor_id(); + int irq; + + hardirq_enter( cpu ); - hardirq_enter(cpu); - ppc_md.do_IRQ(regs, cpu, isfake); - hardirq_exit(cpu); + /* every arch is required to have a get_irq -- Cort */ + irq = ppc_md.get_irq( regs ); + if ( irq < 0 ) + { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + return; + } + ppc_irq_dispatch_handler( regs, irq ); + if ( ppc_md.post_irq ) + ppc_md.post_irq( irq ); + + hardirq_exit( cpu ); } + + unsigned long probe_irq_on (void) { return 0; @@ -469,7 +496,7 @@ static inline void get_irqlock(int cpu) */ void __global_cli(void) { - unsigned int flags; + unsigned long flags; __save_flags(flags); if (flags & (1 << 15)) { diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h index adf028590c4e..8e9fe6df6098 100644 --- a/arch/ppc/kernel/local_irq.h +++ b/arch/ppc/kernel/local_irq.h @@ -4,29 +4,10 @@ #include #include +#include void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); -/* Structure describing interrupts */ -struct hw_interrupt_type { - const char * typename; - void (*startup)(unsigned int irq); - void (*shutdown)(unsigned int irq); - void (*handle)(unsigned int irq, struct pt_regs * regs); - void (*enable)(unsigned int irq); - void (*disable)(unsigned int irq); - void (*mask_and_ack)(unsigned int irq); - int irq_offset; -}; - -struct irqdesc { - struct irqaction *action; - struct hw_interrupt_type *ctl; -}; - -extern struct irqdesc irq_desc[NR_IRQS]; - - #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) extern int ppc_spurious_interrupts; diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c new file mode 100644 index 000000000000..f99f5b3357d8 --- /dev/null +++ b/arch/ppc/kernel/m8xx_setup.c @@ -0,0 +1,521 @@ +/* + * $Id: m8xx_setup.c,v 1.4 1999/09/18 18:40:36 dmalek Exp $ + * + * linux/arch/ppc/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Adapted from 'alpha' version by Gary Thomas + * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net) + * Further modified for generic 8xx by Dan. + */ + +/* + * bootup setup stuff.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "time.h" +#include "ppc8xx_pic.h" + +static int m8xx_set_rtc_time(unsigned long time); +unsigned long m8xx_get_rtc_time(void); +void m8xx_calibrate_decr(void); + +#if 0 +extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int mackbd_getkeycode(unsigned int scancode); +extern int mackbd_pretranslate(unsigned char scancode, char raw_mode); +extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mackbd_unexpected_up(unsigned char keycode); +extern void mackbd_leds(unsigned char leds); +extern void mackbd_init_hw(void); +#endif + +extern unsigned long loops_per_sec; + +unsigned char __res[sizeof(bd_t)]; +unsigned long empty_zero_page[1024]; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +extern char saved_command_line[256]; + +extern unsigned long find_available_memory(void); +extern void m8xx_cpm_reset(uint); + +void __init adbdev_init(void) +{ +} + +void __init +m8xx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) +{ + int cpm_page; + extern char cmd_line[]; + + cpm_page = *memory_start_p; + *memory_start_p += PAGE_SIZE; + + printk("Boot arguments: %s\n", cmd_line); + + /* Reset the Communication Processor Module. + */ + m8xx_cpm_reset(cpm_page); + +#ifdef notdef + ROOT_DEV = to_kdev_t(0x0301); /* hda1 */ +#endif + +#ifdef CONFIG_BLK_DEV_INITRD +#if 0 + ROOT_DEV = to_kdev_t(0x0200); /* floppy */ + rd_prompt = 1; + rd_doload = 1; + rd_image_start = 0; +#endif + /* initrd_start and size are setup by boot/head.S and kernel/head.S */ + if ( initrd_start ) + { + if (initrd_end > *memory_end_p) + { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,*memory_end_p); + initrd_start = 0; + } + } +#endif +} + +void +abort(void) +{ +#ifdef CONFIG_XMON + extern void xmon(void *); + xmon(0); +#endif + machine_restart(NULL); +} + +/* 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. + */ +void __init m8xx_calibrate_decr(void) +{ + bd_t *binfo = (bd_t *)__res; + int freq, fp, divisor; + + /* Unlock the SCCR. + */ + ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY; + + /* Force all 8xx processors to use divide by 16 processor clock. + */ + ((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000; + + /* Processor frequency is MHz. + * The value 'fp' is the number of decrementer ticks per second. + */ + fp = (binfo->bi_intfreq * 1000000) / 16; + freq = fp*60; /* try to make freq/1e6 an integer */ + divisor = 60; + printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); + decrementer_count = freq / HZ / divisor; + count_period_num = divisor; + count_period_den = freq / 1000000; +} + +/* 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. + * To protect them from corruption during power down, registers + * that are maintained by keep alive power are "locked". To + * modify these registers we have to write the key value to + * the key location associated with the register. + * Some boards power up with these unlocked, while others + * are locked. Writing anything (including the unlock code?) + * to the unlocked registers will lock them again. So, here + * we guarantee the registers are locked, then we unlock them + * for our use. + */ + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = ~KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = KAPWR_KEY; + + /* Disable the RTC one second and alarm interrupts. + */ + ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &= + ~(RTCSC_SIE | RTCSC_ALE); + + /* Enabling the decrementer also enables the timebase interrupts + * (or from the other point of view, to get decrementer interrupts + * we have to enable the timebase). The decrementer interrupt + * is wired into the vector table, nothing to do here for that. + */ + ((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!"); + + /* Get time from the RTC. + */ + return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc)); +} + +void +m8xx_restart(char *cmd) +{ + extern void m8xx_gorom(void); + + m8xx_gorom(); +} + +void +m8xx_power_off(void) +{ + m8xx_restart(NULL); +} + +void +m8xx_halt(void) +{ + m8xx_restart(NULL); +} + + +int m8xx_setup_residual(char *buffer) +{ + int len = 0; + bd_t *bp; + + bp = (bd_t *)__res; + + len += sprintf(len+buffer,"clock\t\t: %dMHz\n" + "bus clock\t: %dMHz\n", + bp->bi_intfreq /*/ 1000000*/, + bp->bi_busfreq /*/ 1000000*/); + + return len; +} + +/* Initialize the internal interrupt controller. The number of + * interrupts supported can vary with the processor type, and the + * 82xx family can have up to 64. + * External interrupts can be either edge or level triggered, and + * need to be initialized by the appropriate driver. + */ +void __init +m8xx_init_IRQ(void) +{ + int i; + void cpm_interrupt_init(void); + + ppc8xx_pic.irq_offset = 0; + for ( i = 0 ; i < NR_SIU_INTS ; i++ ) + irq_desc[i].ctl = &ppc8xx_pic; + + /* We could probably incorporate the CPM into the multilevel + * interrupt structure. + */ + cpm_interrupt_init(); + unmask_irq(CPM_INTERRUPT); + +#if defined(CONFIG_PCI) + for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ ) + irq_desc[i].ctl = &i8259_pic; + i8259_pic.irq_offset = NR_SIU_INTS; + i8259_init(); + request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL); + enable_irq(ISA_BRIDGE_INT); +#endif +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + +/* Define this to make a PCMCIA ATA Flash card work. +*/ +#define ATA_FLASH 1 + +/* + * IDE stuff. + */ +void +m8xx_ide_insw(ide_ioreg_t port, void *buf, int ns) +{ +#ifdef ATA_FLASH + ide_insw(port, buf, ns); +#else + ide_insw(port+_IO_BASE, buf, ns); +#endif +} + +void +m8xx_ide_outsw(ide_ioreg_t port, void *buf, int ns) +{ +#ifdef ATA_FLASH + ide_outsw(port, buf, ns); +#else + ide_outsw(port+_IO_BASE, buf, ns); +#endif +} + +int +m8xx_ide_default_irq(ide_ioreg_t base) +{ +#ifdef ATA_FLASH + return PCMCIA_INTERRUPT; +#else + return 14; +#endif +} + +ide_ioreg_t +m8xx_ide_default_io_base(int index) +{ + return index; +} + +int +m8xx_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return 0; +} + +void +m8xx_ide_request_region(ide_ioreg_t from, + unsigned int extent, + const char *name) +{ +} + +void +m8xx_ide_release_region(ide_ioreg_t from, + unsigned int extent) +{ +} + +int +m8xx_ide_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, + const char *device, + void *dev_id) +{ +#ifdef ATA_FLASH + return request_8xxirq(irq, handler, flags, device, dev_id); +#else + return request_irq(irq, handler, flags, device, dev_id); +#endif +} + +void +m8xx_ide_fix_driveid(struct hd_driveid *id) +{ + ppc_generic_ide_fix_driveid(id); +} + +/* We can use an external IDE controller or wire the IDE interface to + * the internal PCMCIA controller. + */ +void __init m8xx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) +{ + ide_ioreg_t port = base; + int i; +#ifdef ATA_FLASH + volatile pcmconf8xx_t *pcmp; +#endif + +#ifdef ATA_FLASH + *p = 0; + *irq = 0; + + if (base != 0) /* Only map the first ATA flash drive */ + return; + + pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); + if (pcmp->pcmc_pipr & 0x18000000) + return; /* No card in slot */ + + base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200); + + /* For the M-Systems ATA card, the first 8 registers map 1:1. + * The following register, control/Altstatus, is located at 0x0e. + * Following that, the irq offset, is not used, so we place it in + * an unused location, 0x0a. + */ + *p++ = base + 8; + for (i = 1; i < 8; ++i) + *p++ = base + i; + *p++ = base + 0x0e; /* control/altstatus */ + *p = base + 0x0a; /* IRQ, not used */ + if (irq) + *irq = PCMCIA_INTERRUPT; + + /* Configure the interface for this interrupt. + */ + pcmp->pcmc_pgcra = (mk_int_int_mask(PCMCIA_INTERRUPT) << 24) | + (mk_int_int_mask(PCMCIA_INTERRUPT) << 16); + + /* Enable status change interrupt from slot A. + */ + pcmp->pcmc_per = 0xff100000; + pcmp->pcmc_pscr = ~0; +#else + + /* Just a regular IDE drive on some I/O port. + */ + i = 8; + while (i--) + *p++ = port++; + *p++ = base + 0x206; + if (irq != NULL) + *irq = 0; +#endif +} +#endif + +void __init +m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + + if ( r3 ) + memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); + +#ifdef CONFIG_PCI + m8xx_setup_pci_ptrs(); +#endif + +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if ( r4 ) + { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + /* take care of cmd line */ + if ( r6 ) + { + + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + + ppc_md.setup_arch = m8xx_setup_arch; + ppc_md.setup_residual = m8xx_setup_residual; + ppc_md.get_cpuinfo = NULL; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = m8xx_init_IRQ; + ppc_md.get_irq = m8xx_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = m8xx_restart; + ppc_md.power_off = m8xx_power_off; + ppc_md.halt = m8xx_halt; + + ppc_md.time_init = NULL; + ppc_md.set_rtc_time = m8xx_set_rtc_time; + ppc_md.get_rtc_time = m8xx_get_rtc_time; + ppc_md.calibrate_decr = m8xx_calibrate_decr; + +#if 0 + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_pretranslate = pckbd_pretranslate; + 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.kbd_sysrq_xlate = pckbd_sysrq_xlate; +#endif +#else + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.kbd_sysrq_xlate = NULL; +#endif +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.insw = m8xx_ide_insw; + ppc_ide_md.outsw = m8xx_ide_outsw; + ppc_ide_md.default_irq = m8xx_ide_default_irq; + ppc_ide_md.default_io_base = m8xx_ide_default_io_base; + ppc_ide_md.check_region = m8xx_ide_check_region; + ppc_ide_md.request_region = m8xx_ide_request_region; + ppc_ide_md.release_region = m8xx_ide_release_region; + ppc_ide_md.fix_driveid = m8xx_ide_fix_driveid; + ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports; + ppc_ide_md.ide_request_irq = m8xx_ide_request_irq; + + ppc_ide_md.io_base = _IO_BASE; +#endif +} diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index c4bed05e90fd..32be1899aa90 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -45,17 +45,34 @@ _GLOBAL(reloc_offset) mtlr r0 blr -_GLOBAL(__cli) +/* void __no_use_save_flags(unsigned long *flags) */ +_GLOBAL(__no_use_save_flags) + mfmsr r4 + stw r4,0(r3) + blr + +/* void __no_use_restore_flags(unsigned long flags) */ +_GLOBAL(__no_use_restore_flags) + andi. r4,r3,MSR_EE + bne 10f + lis r4,ppc_n_lost_interrupts@ha + lwz r4,ppc_n_lost_interrupts@l(r4) + cmpi 0,r4,0 /* lost interrupts to process first? */ + bne- do_lost_interrupts +10: sync + mtmsr r3 + isync + blr + +_GLOBAL(__no_use_cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ - li r4,0 /* Need [unsigned] value of MSR_EE */ - ori r4,r4,MSR_EE /* Set to turn off bit */ - andc r0,r0,r4 /* Clears bit in (r4) */ + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ sync /* Some chip revs have problems here... */ mtmsr r0 /* Update machine state */ blr /* Done */ -_GLOBAL(__sti) +_GLOBAL(__no_use_sti) lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ @@ -472,6 +489,7 @@ _GLOBAL(_outsl_ns) * * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000 + * lshrdi3: XXXYYY/ZZZAAA -> 000XXX/YYYZZZ */ _GLOBAL(__ashrdi3) li r6,32 @@ -481,7 +499,7 @@ _GLOBAL(__ashrdi3) or r4,r4,r7 /* YYYZZZ */ sraw r3,r3,r5 /* SSSXXX */ blr - + _GLOBAL(__ashldi3) li r6,32 sub r6,r6,r5 @@ -491,6 +509,15 @@ _GLOBAL(__ashldi3) or r3,r3,r7 /* YYYZZZ */ 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 */ + blr + _GLOBAL(abs) cmpi 0,r3,0 bge 10f @@ -553,36 +580,42 @@ _GLOBAL(_get_PVR) Author: Terry Greeniaus (tgree@phys.ualberta.ca) Please e-mail updates to this file to me, thanks! */ +/* Usage: + + When setting the L2CR register, you must do a few special + things. If you are enabling the cache, you must perform a + global invalidate. If you are disabling the cache, you must + flush the cache contents first. This routine takes care of + doing these things. When first enabling the cache, make sure + you pass in the L2CR you want, as well as passing in the + global invalidate bit set. A global invalidate will only be + performed if the L2I bit is set in applyThis. When enabling + the cache, you should also set the L2E bit in applyThis. If + you want to modify the L2CR contents after the cache has been + enabled, the recommended procedure is to first call + __setL2CR(0) to disable the cache and then call it again with + the new values for L2CR. Examples: + + _setL2CR(0) - disables the cache + _setL2CR(0xB3A04000) - enables my G3 upgrade card: + - L2E set to turn on the cache + - L2SIZ set to 1MB + - L2CLK set to 1:1 + - L2RAM set to pipelined synchronous late-write + - L2I set to perform a global invalidation + - L2OH set to 0.5 nS + - L2DF set because this upgrade card + requires it + + A similar call should work for your card. You need to know + the correct setting for your card and then place them in the + fields I have outlined above. Other fields support optional + features, such as L2DO which caches only data, or L2TS which + causes cache pushes from the L1 cache to go to the L2 cache + instead of to main memory. +*/ _GLOBAL(_set_L2CR) - /* Usage: - - When setting the L2CR register, you must do a few special things. If you are enabling the - cache, you must perform a global invalidate. If you are disabling the cache, you must - flush the cache contents first. This routine takes care of doing these things. When first - enabling the cache, make sure you pass in the L2CR you want, as well as passing in the - global invalidate bit set. A global invalidate will only be performed if the L2I bit is set - in applyThis. When enabling the cache, you should also set the L2E bit in applyThis. If you - want to modify the L2CR contents after the cache has been enabled, the recommended - procedure is to first call __setL2CR(0) to disable the cache and then call it again with - the new values for L2CR. Examples: - - _setL2CR(0) - disables the cache - _setL2CR(0xB3A04000) - enables my G3 upgrade card: - - L2E set to turn on the cache - - L2SIZ set to 1MB - - L2CLK set to 1:1 - - L2RAM set to pipelined syncronous late-write - - L2I set to perform a global invalidation - - L2OH set to 0.5 nS - - L2DF set because this upgrade card requires it - - A similar call should work for your card. You need to know the correct setting for your - card and then place them in the fields I have outlined above. Other fields support optional - features, such as L2DO which caches only data, or L2TS which causes cache pushes from - the L1 cache to go to the L2 cache instead of to main memory. - */ - /* Make sure this is a 750 chip */ mfspr r4,PVR rlwinm r4,r4,16,16,31 @@ -594,76 +627,74 @@ _GLOBAL(_set_L2CR) thisIs750: /* Get the current enable bit of the L2CR into r4 */ mfspr r4,L2CR - rlwinm r4,r4,0,0,0 + mfmsr r7 /* See if we want to perform a global inval this time. */ - rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */ - rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */ - rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ - rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ - or r3,r3,r4 /* Keep the enable bit the same as it was for now. */ - bne dontDisableCache /* Only disable the cache if L2CRApply has the enable bit off */ + rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */ + rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */ + rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ + rlwimi r3,r4,0,0,0 /* Keep the enable bit the same as it was. */ + bne dontDisableCache /* Only disable the cache if L2CRApply + has the enable bit off */ disableCache: - /* Disable the cache. First, we turn off data relocation. */ - mfmsr r7 - rlwinm r4,r7,0,28,26 /* Turn off DR bit */ - rlwinm r4,r4,0,17,15 /* Turn off EE bit - an external exception while we are flushing - the cache is fatal (comment this line and see!) */ + /* Disable the cache. First, we turn off interrupts. + An interrupt while we are flushing the cache could bring + in data which may not get properly flushed. */ + rlwinm r4,r7,0,17,15 /* Turn off EE bit */ sync mtmsr r4 sync - /* - Now, read the first 2MB of memory to put new data in the cache. - (Actually we only need the size of the L2 cache plus - the size of the L1 cache, but 2MB will cover everything just to be safe). - */ +/* + Now, read the first 2MB of memory to put new data in the cache. + (Actually we only need the size of the L2 cache plus the size + of the L1 cache, but 2MB will cover everything just to be safe). +*/ lis r4,0x0001 mtctr r4 - li r4,0 -loadLoop: - lwzx r0,r0,r4 + lis r4,KERNELBASE@h +1: lwzx r0,r0,r4 addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz loadLoop + bdnz 1b /* Now, flush the first 2MB of memory */ lis r4,0x0001 mtctr r4 - li r4,0 + lis r4,KERNELBASE@h sync -flushLoop: - dcbf r0,r4 +2: dcbf r0,r4 addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz flushLoop + bdnz 2b /* Turn off the L2CR enable bit. */ rlwinm r3,r3,0,1,31 - /* Reenable data relocation. */ - sync - mtmsr r7 - sync - dontDisableCache: /* Set up the L2CR configuration bits */ sync mtspr L2CR,r3 sync + + /* Reenable interrupts if necessary. */ + mtmsr r7 + sync + cmplwi r6,0 beq noInval /* Perform a global invalidation */ oris r3,r3,0x0020 sync - mtspr 1017,r3 + mtspr L2CR,r3 sync -invalCompleteLoop: /* Wait for the invalidation to complete */ - mfspr r3,1017 + + /* Wait for the invalidation to complete */ +3: mfspr r3,L2CR rlwinm. r4,r3,0,31,31 - bne invalCompleteLoop + bne 3b - rlwinm r3,r3,0,11,9; /* Turn off the L2I bit */ + rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */ sync mtspr L2CR,r3 sync @@ -672,8 +703,7 @@ noInval: /* See if we need to enable the cache */ cmplwi r5,0 beqlr - -enableCache: + /* Enable the cache */ oris r3,r3,0x8000 mtspr L2CR,r3 @@ -967,7 +997,7 @@ sys_call_table: .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll -#ifdef CONFIG_NFSD +#ifdef CONFIG_NFSD .long sys_nfsservctl #else .long sys_ni_syscall diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index 519407eea134..2b54937474d0 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -33,7 +33,6 @@ struct hw_interrupt_type open_pic = { " OpenPIC ", NULL, NULL, - NULL, openpic_enable_irq, openpic_disable_irq, 0, @@ -352,6 +351,13 @@ void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask) openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask); } +void openpic_enable_IPI(u_int ipi) +{ + check_arg_ipi(ipi); + openpic_clearfield(&OpenPIC->Global.IPI_Vector_Priority(ipi), + OPENPIC_MASK); +} + /* * Initialize a timer interrupt (and disable it) * @@ -384,13 +390,13 @@ void openpic_maptimer(u_int timer, u_int cpumask) void openpic_enable_irq(u_int irq) { check_arg_irq(irq); - openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); + openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK); } void openpic_disable_irq(u_int irq) { check_arg_irq(irq); - openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); + openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].ctl->irq_offset].Vector_Priority, OPENPIC_MASK); } /* diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 2ed0f4a5b9d6..575a18afe8f8 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.60 1999/09/08 03:04:07 cort Exp $ + * $Id: pci.c,v 1.64 1999/09/17 18:01:53 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -92,7 +92,7 @@ static void __init pcibios_claim_resources(struct pci_bus *bus) struct resource *pr; if (!r->start) continue; - pr = pci_find_parent_resource(dev, r); + pr = pci_find_parent_resource(dev, r, 0); if (!pr || request_resource(pr, r) < 0) { printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); @@ -117,7 +117,7 @@ char __init *pcibios_setup(char *str) return str; } -#ifndef CONFIG_MBX +#ifndef CONFIG_8xx /* Recursively searches any node that is of type PCI-PCI bridge. Without * this, the old code would miss children of P2P bridges and hence not * fix IRQ's for cards located behind P2P bridges. @@ -141,8 +141,3 @@ void __init fix_intr(struct device_node *node, struct pci_dev *dev) } } #endif - -int pcibios_assign_resource(struct pci_dev *pdev, int resource) -{ - return 0; -} diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index f8404cc9a4bf..683aac568282 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -102,7 +102,6 @@ struct hw_interrupt_type pmac_pic = { " PMAC-PIC ", NULL, NULL, - NULL, pmac_unmask_irq, pmac_mask_irq, pmac_mask_and_ack_irq, @@ -113,7 +112,6 @@ struct hw_interrupt_type gatwick_pic = { " GATWICK ", NULL, NULL, - NULL, pmac_unmask_irq, pmac_mask_irq, pmac_mask_and_ack_irq, @@ -143,6 +141,7 @@ static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) ppc_irq_dispatch_handler( regs, irq ); } +#if 0 void pmac_do_IRQ(struct pt_regs *regs, int cpu, @@ -155,19 +154,13 @@ pmac_do_IRQ(struct pt_regs *regs, /* IPI's are a hack on the powersurge -- Cort */ if ( cpu != 0 ) { - if (!isfake) - { #ifdef CONFIG_XMON - static int xmon_2nd; - if (xmon_2nd) - xmon(regs); + static int xmon_2nd; + if (xmon_2nd) + xmon(regs); #endif - smp_message_recv(); - goto out; - } - /* could be here due to a do_fake_interrupt call but we don't - mess with the controller from the second cpu -- Cort */ - goto out; + smp_message_recv(); + return -1; } { @@ -214,11 +207,65 @@ pmac_do_IRQ(struct pt_regs *regs, out: #endif /* CONFIG_SMP */ } +#endif + +int +pmac_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits = 0; + +#ifdef __SMP__ + /* 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 + smp_message_recv(); + return -1; + } + + { + unsigned int loops = MAXCOUNT; + 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 /* __SMP__ */ + + for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | ppc_lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + + return irq; +} /* This routine will fix some missing interrupt values in the device tree * on the gatwick mac-io controller used by some PowerBooks */ -static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +static void __init +pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) { struct device_node *node; int count; @@ -362,3 +409,41 @@ pmac_pic_init(void) request_irq(20, xmon_irq, 0, "NMI - XMON", 0); #endif /* CONFIG_XMON */ } + +#ifdef CONFIG_PMAC_PBOOK +/* + * These procedures are used in implementing sleep on the powerbooks. + * sleep_save_intrs() saves the states of all interrupt enables + * and disables all interupts except for the nominated one. + * sleep_restore_intrs() restores the states of all interrupt enables. + */ +unsigned int sleep_save_mask[2]; + +void +sleep_save_intrs(int viaint) +{ + sleep_save_mask[0] = ppc_cached_irq_mask[0]; + sleep_save_mask[1] = ppc_cached_irq_mask[1]; + ppc_cached_irq_mask[0] = 0; + ppc_cached_irq_mask[1] = 0; + set_bit(viaint, ppc_cached_irq_mask); + out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); + if (max_real_irqs > 32) + out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); + mb(); +} + +void +sleep_restore_intrs(void) +{ + int i; + + out_le32(&pmac_irq_hw[0]->enable, 0); + if (max_real_irqs > 32) + out_le32(&pmac_irq_hw[1]->enable, 0); + mb(); + for (i = 0; i < max_real_irqs; ++i) + if (test_bit(i, sleep_save_mask)) + pmac_unmask_irq(i); +} +#endif /* CONFIG_PMAC_PBOOK */ diff --git a/arch/ppc/kernel/pmac_pic.h b/arch/ppc/kernel/pmac_pic.h index 335a9ef692b6..e2ad2063889d 100644 --- a/arch/ppc/kernel/pmac_pic.h +++ b/arch/ppc/kernel/pmac_pic.h @@ -6,10 +6,7 @@ extern struct hw_interrupt_type pmac_pic; void pmac_pic_init(void); -void pmac_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake); - +int pmac_get_irq(struct pt_regs *regs); +void pmac_post_irq(int); #endif /* _PPC_KERNEL_PMAC_PIC_H */ - diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index ac84aa92b2de..6de8e50360e4 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -43,6 +43,9 @@ #include #include #include +#include +#include +#include #include #include @@ -51,9 +54,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -166,16 +166,24 @@ pmac_get_cpuinfo(char *buffer) /* find ram info */ np = find_devices("memory"); if (np != 0) { + int n; struct reg_property *reg = (struct reg_property *) - get_property(np, "reg", NULL); + get_property(np, "reg", &n); + if (reg != 0) { - len += sprintf(buffer+len, "memory\t\t: %dMB\n", - reg->size >> 20); + unsigned long total = 0; + + for (n /= sizeof(struct reg_property); n > 0; --n) + total += (reg++)->size; + len += sprintf(buffer+len, "memory\t\t: %luMB\n", + total >> 20); } } /* Checks "l2cr-value" property in the registry */ np = find_devices("cpus"); + if (np == 0) + np = find_type_devices("cpu"); if (np != 0) { unsigned int *l2cr = (unsigned int *) get_property(np, "l2cr-value", NULL); @@ -267,6 +275,8 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p) /* Checks "l2cr-value" property in the registry */ if ( (_get_PVR() >> 16) == 8) { struct device_node *np = find_devices("cpus"); + if (np == 0) + np = find_type_devices("cpu"); if (np != 0) { unsigned int *l2cr = (unsigned int *) get_property(np, "l2cr-value", NULL); @@ -290,8 +300,12 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p) zs_kgdb_hook(0); #endif +#ifdef CONFIG_ADB_CUDA find_via_cuda(); +#endif +#ifdef CONFIG_ADB_PMU find_via_pmu(); +#endif #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -360,9 +374,10 @@ kdev_t boot_dev; void __init pmac_init2(void) { - adb_init(); pmac_nvram_init(); +#ifdef CONFIG_PMAC_PBOOK media_bay_init(); +#endif } #ifdef CONFIG_SCSI @@ -470,19 +485,24 @@ void note_bootable_part(kdev_t dev, int part) void pmac_restart(char *cmd) { +#ifdef CONFIG_ADB_CUDA struct adb_request req; +#endif /* CONFIG_ADB_CUDA */ - switch (adb_hardware) { - case ADB_VIACUDA: + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); for (;;) cuda_poll(); break; - - case ADB_VIAPMU: +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: pmu_restart(); break; +#endif /* CONFIG_ADB_PMU */ default: } } @@ -490,19 +510,24 @@ pmac_restart(char *cmd) void pmac_power_off(void) { +#ifdef CONFIG_ADB_CUDA struct adb_request req; +#endif /* CONFIG_ADB_CUDA */ - switch (adb_hardware) { - case ADB_VIACUDA: + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); for (;;) cuda_poll(); break; - - case ADB_VIAPMU: +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: pmu_shutdown(); break; +#endif /* CONFIG_ADB_PMU */ default: } } @@ -609,7 +634,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.get_cpuinfo = pmac_get_cpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = pmac_pic_init; - ppc_md.do_IRQ = pmac_do_IRQ; + ppc_md.get_irq = pmac_get_irq; ppc_md.init = pmac_init2; ppc_md.restart = pmac_restart; @@ -621,7 +646,7 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; -#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD) +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) ppc_md.kbd_setkeycode = mackbd_setkeycode; ppc_md.kbd_getkeycode = mackbd_getkeycode; ppc_md.kbd_translate = mackbd_translate; @@ -648,4 +673,3 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_ide_md.io_base = _IO_BASE; /* actually too early for this :-( */ #endif } - diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index b7cd026b6750..9d043ee85e11 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -12,8 +12,8 @@ #include #include #include -#include -#include +#include +#include /* * Read and write the non-volatile RAM on PowerMacs and CHRP machines. @@ -47,7 +47,7 @@ void pmac_nvram_init(void) } else if (nvram_naddrs == 2) { nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); - } else if (nvram_naddrs == 0 && adb_hardware == ADB_VIAPMU) { + } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) { nvram_naddrs = -1; } else { printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", @@ -55,6 +55,7 @@ void pmac_nvram_init(void) } } +#ifdef CONFIG_NVRAM unsigned char nvram_read_byte(int addr) { struct adb_request req; @@ -100,3 +101,4 @@ void nvram_write_byte(unsigned char val, int addr) } eieio(); } +#endif /* CONFIG_NVRAM */ diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index 03795efdcd87..60b497cd6568 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -15,11 +15,11 @@ #include #include #include +#include +#include +#include #include -#include -#include -#include #include #include #include @@ -55,11 +55,14 @@ __pmac unsigned long pmac_get_rtc_time(void) { +#ifdef CONFIG_ADB struct adb_request req; +#endif /* Get the time from the RTC */ - switch (adb_hardware) { - case ADB_VIACUDA: + switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA + case SYS_CTRLER_CUDA: if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) return 0; while (!req.complete) @@ -69,7 +72,9 @@ unsigned long pmac_get_rtc_time(void) req.reply_len); return (req.reply[3] << 24) + (req.reply[4] << 16) + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; - case ADB_VIAPMU: +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU + case SYS_CTRLER_PMU: if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) return 0; while (!req.complete) @@ -79,6 +84,7 @@ unsigned long pmac_get_rtc_time(void) req.reply_len); return (req.reply[1] << 24) + (req.reply[2] << 16) + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET; +#endif /* CONFIG_ADB_PMU */ default: return 0; } @@ -141,13 +147,12 @@ int __init via_calibrate_decr(void) /* * Reset the time after a sleep. */ -static int time_sleep_notify(struct notifier_block *this, unsigned long event, - void *x) +static int time_sleep_notify(struct pmu_sleep_notifier *self, int when) { static unsigned long time_diff; - switch (event) { - case PBOOK_SLEEP: + switch (when) { + case PBOOK_SLEEP_NOW: time_diff = xtime.tv_sec - pmac_get_rtc_time(); break; case PBOOK_WAKE: @@ -157,11 +162,11 @@ static int time_sleep_notify(struct notifier_block *this, unsigned long event, last_rtc_update = xtime.tv_sec; break; } - return NOTIFY_DONE; + return PBOOK_SLEEP_OK; } -static struct notifier_block time_sleep_notifier = { - time_sleep_notify, NULL, 100 +static struct pmu_sleep_notifier time_sleep_notifier = { + time_sleep_notify, SLEEP_LEVEL_MISC, }; #endif /* CONFIG_PMAC_PBOOK */ @@ -176,7 +181,7 @@ void __init pmac_calibrate_decr(void) int freq, *fp, divisor; #ifdef CONFIG_PMAC_PBOOK - notifier_chain_register(&sleep_notifier_list, &time_sleep_notifier); + pmu_register_sleep_notifier(&time_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ if (via_calibrate_decr()) diff --git a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c index 87bc6d0f8f72..96c1e72604fe 100644 --- a/arch/ppc/kernel/ppc8xx_pic.c +++ b/arch/ppc/kernel/ppc8xx_pic.c @@ -5,45 +5,170 @@ #include #include #include -#include +#include #include "ppc8xx_pic.h" +/* The 8xx or 82xx internal interrupt controller. It is usually + * the only interrupt controller. Some boards, like the MBX and + * Sandpoint have the 8259 as a secondary controller. Depending + * upon the processor type, the internal controller can have as + * few as 16 interrups or as many as 64. We could use the + * "clear_bit()" and "set_bit()" functions like other platforms, + * but they are overkill for us. + */ -static void mbx_mask_irq(unsigned int irq_nr) +static void m8xx_mask_irq(unsigned int irq_nr) { - if ( irq_nr == ISA_BRIDGE_INT ) return; - if ( irq_nr >= ppc8xx_pic.irq_offset ) - irq_nr -= ppc8xx_pic.irq_offset; - ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0]; + int bit, word; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); +#ifdef CONFIG_82xx + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] = + ppc_cached_irq_mask[word]; +#else + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = + ppc_cached_irq_mask[word]; +#endif } -static void mbx_unmask_irq(unsigned int irq_nr) +static void m8xx_unmask_irq(unsigned int irq_nr) { - if ( irq_nr >= ppc8xx_pic.irq_offset ) - irq_nr -= ppc8xx_pic.irq_offset; - ppc_cached_irq_mask[0] |= (1 << (31-irq_nr)); - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0]; + int bit, word; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31-bit)); +#ifdef CONFIG_82xx + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] = + ppc_cached_irq_mask[word]; +#else + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = + ppc_cached_irq_mask[word]; +#endif } -static void mbx_mask_and_ack(unsigned int irq_nr) +static void m8xx_mask_and_ack(unsigned int irq_nr) { - /* this shouldn't be masked, we mask the 8259 if we need to -- Cort */ - if ( irq_nr != ISA_BRIDGE_INT ) - mbx_mask_irq(irq_nr); - if ( irq_nr >= ppc8xx_pic.irq_offset ) - irq_nr -= ppc8xx_pic.irq_offset; - /* clear the pending bits */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr); + int bit, word; + + bit = irq_nr & 0x1f; + word = irq_nr >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); +#ifdef CONFIG_82xx + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask[word] = + ppc_cached_irq_mask[word]; + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend[word] = 1 << (31-bit); +#else + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = + ppc_cached_irq_mask[word]; + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit); +#endif } struct hw_interrupt_type ppc8xx_pic = { " 8xx SIU ", NULL, NULL, - NULL, - mbx_unmask_irq, - mbx_mask_irq, - mbx_mask_and_ack, + m8xx_unmask_irq, + m8xx_mask_irq, + m8xx_mask_and_ack, 0 }; + +#if 0 +void +m8xx_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake) +{ + int irq; + unsigned long bits = 0; + + /* For MPC8xx, read the SIVEC register and shift the bits down + * to get the irq number. */ + bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; + irq = bits >> 26; +#if 0 + irq += ppc8xx_pic.irq_offset; +#endif + bits = 1UL << irq; + + if (irq < 0) { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } + else { + ppc_irq_dispatch_handler( regs, irq ); + } + +} +#endif + + +int +m8xx_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits = 0; + + /* For MPC8xx, read the SIVEC register and shift the bits down + * to get the irq number. */ + bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec; + irq = bits >> 26; +#if 0 + irq += ppc8xx_pic.irq_offset; +#endif + return irq; +} + +/* The MBX is the only 8xx board that uses the 8259. +*/ +#ifdef CONFIG_MBX +void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs) +{ + int bits, irq; + + /* A bug in the QSpan chip causes it to give us 0xff always + * when doing a character read. So read 32 bits and shift. + * This doesn't seem to return useful values anyway, but + * read it to make sure things are acked. + * -- Cort + */ + irq = (inl(0x508) >> 24)&0xff; + if ( irq != 0xff ) printk("iack %d\n", irq); + + outb(0x0C, 0x20); + irq = inb(0x20) & 7; + if (irq == 2) + { + outb(0x0C, 0xA0); + irq = inb(0xA0); + irq = (irq&7) + 8; + } + bits = 1UL << irq; + irq += i8259_pic.irq_offset; + ppc_irq_dispatch_handler( regs, irq ); +} +#endif + +/* Only the MBX uses the external 8259. This allows us to catch standard + * drivers that may mess up the internal interrupt controllers, and also + * allow them to run without modification on the MBX. + */ +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + +#ifdef CONFIG_MBX + irq += i8259_pic.irq_offset; + return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); +#else + panic("request_irq"); +#endif +} diff --git a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h index d6b424fecb0c..c4de8f12e176 100644 --- a/arch/ppc/kernel/ppc8xx_pic.h +++ b/arch/ppc/kernel/ppc8xx_pic.h @@ -6,4 +6,16 @@ extern struct hw_interrupt_type ppc8xx_pic; +void m8xx_pic_init(void); +void m8xx_do_IRQ(struct pt_regs *regs, + int cpu, + int isfake); +int m8xx_get_irq(struct pt_regs *regs); + +#ifdef CONFIG_MBX +#include "i8259.h" +#include +void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs); +#endif + #endif /* _PPC_KERNEL_PPC8xx_H */ diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 9da8db6e89a0..0b7c77683a74 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -1,5 +1,5 @@ /* - * $Id: ppc_htab.c,v 1.28 1999/06/27 10:53:32 davem Exp $ + * $Id: ppc_htab.c,v 1.29 1999/09/10 05:05:50 paulus Exp $ * * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. @@ -256,6 +256,8 @@ return_string: return 0; if (n > strlen(buffer) - *ppos) n = strlen(buffer) - *ppos; + if (n > count) + n = count; copy_to_user(buf, buffer + *ppos, n); *ppos += n; return n; @@ -533,7 +535,21 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp, int vleft, first=1, len, left, val; #define TMPBUFLEN 256 char buf[TMPBUFLEN], *p; - + static const char *sizestrings[4] = { + "unknown size", "256KB", "512KB", "1MB" + }; + static const char *clockstrings[8] = { + "clock disabled", "+1 clock", "+1.5 clock", "reserved(3)", + "+2 clock", "+2.5 clock", "+3 clock", "reserved(7)" + }; + static const char *typestrings[4] = { + "flow-through burst SRAM", "reserved SRAM", + "pipelined burst SRAM", "pipelined late-write SRAM" + }; + static const char *holdstrings[4] = { + "0.5", "1.0", "(reserved2)", "(reserved3)" + }; + if ( (_get_PVR() >> 16) != 8) return -EFAULT; if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) { @@ -586,55 +602,13 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp, p += sprintf(p, " %s", (val&0x80000000)?"enabled":"disabled"); p += sprintf(p,",%sparity",(val&0x40000000)?"":"no "); - - switch( (val >> 28) & 0x3 ) - { - case 1: p += sprintf(p,",256Kb"); - break; - case 2: p += sprintf(p,",512Kb"); - break; - case 3: p += sprintf(p,",1M"); - break; - default: p += sprintf(p,",unknown size"); - break; - } - - - switch( (val >> 25) & 0x7 ) - { - case 0: p += sprintf(p,",clock disabled"); - break; - case 1: p += sprintf(p,",+1 clock"); - break; - case 2: p += sprintf(p,",+1.5 clock"); - break; - case 7: - case 3: p += sprintf(p,",reserved clock"); - break; - case 4: p += sprintf(p,",+2 clock"); - break; - case 5: p += sprintf(p,",+2.5 clock"); - break; - case 6: p += sprintf(p,",+3 clock"); - break; - } - - switch( (val >> 23) & 0x2 ) - { - case 0: p += sprintf(p,",flow-through burst SRAM"); - break; - case 1: p += sprintf(p,",reserved SRAM"); - break; - case 2: p += sprintf(p,",pipelined burst SRAM"); - break; - case 3: p += sprintf(p,",pipelined late-write SRAM"); - break; - } - - p += sprintf(p,"%s",(val>>22)?"":",data only"); - p += sprintf(p,"%s",(val>>20)?",ZZ enabled":""); - p += sprintf(p,",%s",(val>>19)?"write-through":"copy-back"); - p += sprintf(p,",%sns hold",(val>>16)?"1.0":"0.5"); + p += sprintf(p, ",%s", sizestrings[(val >> 28) & 3]); + p += sprintf(p, ",%s", clockstrings[(val >> 25) & 7]); + p += sprintf(p, ",%s", typestrings[(val >> 23) & 0x2]); + p += sprintf(p,"%s",(val>>22)&1?"":",data only"); + p += sprintf(p,"%s",(val>>20)&1?",ZZ enabled":""); + p += sprintf(p,",%s",(val>>19)&1?"write-through":"copy-back"); + p += sprintf(p,",%sns hold", holdstrings[(val>>16)&3]); p += sprintf(p,"\n"); diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 61806f1af15f..547b1142cdf8 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -21,9 +21,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -31,6 +31,9 @@ #include #include #include +#ifdef __SMP__ +#include +#endif /* __SMP__ */ /* Tell string.h we don't want memcpy etc. as cpp defines */ #define EXPORT_SYMTAB_STROPS @@ -47,6 +50,8 @@ extern atomic_t ppc_n_lost_interrupts; extern void do_lost_interrupts(unsigned long); extern int do_signal(sigset_t *, struct pt_regs *); +asmlinkage long long __ashrdi3(long long, int); +asmlinkage long long __lshrdi3(long long, int); asmlinkage int abs(int); EXPORT_SYMBOL(clear_page); @@ -67,15 +72,24 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(ppc_local_irq_count); EXPORT_SYMBOL(ppc_local_bh_count); +#ifdef __SMP__ +EXPORT_SYMBOL(kernel_flag); +#endif /* __SMP__ */ +#ifndef CONFIG_8xx EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); EXPORT_SYMBOL(pci_dram_offset); +#endif EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); +#ifndef CONFIG_8xx +#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); +#endif +#endif EXPORT_SYMBOL(atomic_add); EXPORT_SYMBOL(atomic_sub); @@ -175,20 +189,30 @@ EXPORT_SYMBOL(_write_lock); EXPORT_SYMBOL(_write_unlock); #endif +#ifndef CONFIG_MACH_SPECIFIC EXPORT_SYMBOL(_machine); +#endif 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(cuda_request); EXPORT_SYMBOL(cuda_poll); EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); +#endif /* CONFIG_ADB */ #ifdef CONFIG_PMAC_PBOOK -EXPORT_SYMBOL(sleep_notifier_list); +EXPORT_SYMBOL(pmu_register_sleep_notifier); +EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); #endif CONFIG_PMAC_PBOOK EXPORT_SYMBOL(abort); +#ifndef CONFIG_8xx EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -200,15 +224,18 @@ EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); +#endif #ifdef CONFIG_SCSI EXPORT_SYMBOL(note_scsi_host); #endif EXPORT_SYMBOL(kd_mksound); -#ifdef CONFIG_PMAC +#ifdef CONFIG_NVRAM EXPORT_SYMBOL(nvram_read_byte); EXPORT_SYMBOL(nvram_write_byte); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_NVRAM */ +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); @@ -216,8 +243,17 @@ EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL(abs); +#ifndef CONFIG_8xx EXPORT_SYMBOL(device_is_compatible); +#endif #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + +EXPORT_SYMBOL(int_control); +EXPORT_SYMBOL(timer_interrupt_intercept); +EXPORT_SYMBOL(timer_interrupt); +extern unsigned long do_IRQ_intercept; +EXPORT_SYMBOL(do_IRQ_intercept); +EXPORT_SYMBOL(irq_desc); diff --git a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c index 6a352b341daa..c3dcdea07f05 100644 --- a/arch/ppc/kernel/prep_nvram.c +++ b/arch/ppc/kernel/prep_nvram.c @@ -29,14 +29,14 @@ static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0]; unsigned char *rs_pcNvRAM; -unsigned char prep_nvram_read_val(int addr) +unsigned char __prep prep_nvram_read_val(int addr) { outb(addr, PREP_NVRAM_AS0); outb(addr>>8, PREP_NVRAM_AS1); return inb(PREP_NVRAM_DATA); } -void prep_nvram_write_val(int addr, +void __prep prep_nvram_write_val(int addr, unsigned char val) { outb(addr, PREP_NVRAM_AS0); @@ -47,12 +47,12 @@ void prep_nvram_write_val(int addr, /* * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space */ -unsigned char rs_nvram_read_val(int addr) +unsigned char __prep rs_nvram_read_val(int addr) { return rs_pcNvRAM[addr]; } -void rs_nvram_write_val(int addr, +void __prep rs_nvram_write_val(int addr, unsigned char val) { rs_pcNvRAM[addr]=val; @@ -113,7 +113,7 @@ void __init init_prep_nvram(void) } __prep -char *prep_nvram_get_var(const char *name) +char __prep *prep_nvram_get_var(const char *name) { char *cp; int namelen; @@ -133,7 +133,7 @@ char *prep_nvram_get_var(const char *name) } __prep -char *prep_nvram_first_var(void) +char __prep *prep_nvram_first_var(void) { if (nvram->Header.GELength == 0) { return NULL; @@ -144,7 +144,7 @@ char *prep_nvram_first_var(void) } __prep -char *prep_nvram_next_var(char *name) +char __prep *prep_nvram_next_var(char *name) { char *cp; diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c index 78f207a54f56..a01962b121c0 100644 --- a/arch/ppc/kernel/prep_pci.c +++ b/arch/ppc/kernel/prep_pci.c @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.39 1999/08/31 15:42:39 cort Exp $ + * $Id: prep_pci.c,v 1.40 1999/09/17 17:23:05 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -39,7 +39,8 @@ unsigned char *Motherboard_routes; /* Used for Motorola to store system config register */ static unsigned long *ProcInfo; -extern void chrp_do_IRQ(struct pt_regs *,int , int); +extern int chrp_get_irq(struct pt_regs *); +extern void chrp_post_irq(int); /* Tables for known hardware */ @@ -734,7 +735,8 @@ int __init raven_init(void) OpenPIC_InitSenses = mvme2600_openpic_initsenses; OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses); - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.get_irq = chrp_get_irq; + ppc_md.post_irq = chrp_post_irq; /* If raven is present on Motorola store the system config register * for later use. diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index 14cce93bda31..53c859a162a5 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -86,7 +86,6 @@ extern void pckbd_init_hw(void); extern unsigned char pckbd_sysrq_xlate[128]; extern void prep_setup_pci_ptrs(void); -extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake); extern char saved_command_line[256]; int _prep_type; @@ -114,8 +113,7 @@ extern int rd_image_start; /* starting block # of image */ unsigned long vgacon_remap_base; #endif -__prep -int +int __prep prep_get_cpuinfo(char *buffer) { extern char *Motherboard_map_name; @@ -312,7 +310,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p) * it's the only way to support both addrs from one binary. * -- Cort */ - if ( is_prep ) + if ( _machine == _MACH_prep ) { extern struct card_info snd_installed_cards[]; struct card_info *snd_ptr; @@ -486,7 +484,7 @@ void __init mk48t59_calibrate_decr(void) count_period_den = freq / 1000000; } -void +void __prep prep_restart(char *cmd) { unsigned long i = 10000; @@ -509,7 +507,7 @@ prep_restart(char *cmd) /* * This function will restart a board regardless of port 92 functionality */ -void +void __prep prep_direct_restart(char *cmd) { u32 jumpaddr=0xfff00100; @@ -532,7 +530,7 @@ prep_direct_restart(char *cmd) */ } -void +void __prep prep_halt(void) { unsigned long flags; @@ -552,13 +550,14 @@ prep_halt(void) */ } -void +void __prep prep_power_off(void) { prep_halt(); } -int prep_setup_residual(char *buffer) +int __prep +prep_setup_residual(char *buffer) { int len = 0; @@ -576,7 +575,7 @@ int prep_setup_residual(char *buffer) return len; } -u_int +u_int __prep prep_irq_cannonicalize(u_int irq) { if (irq == 2) @@ -589,7 +588,8 @@ prep_irq_cannonicalize(u_int irq) } } -void +#if 0 +void __prep prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake) { int irq; @@ -602,6 +602,13 @@ prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake) return; } ppc_irq_dispatch_handler( regs, irq ); +} +#endif + +int __prep +prep_get_irq(struct pt_regs *regs) +{ + return i8259_irq(smp_processor_id()); } void __init @@ -628,19 +635,19 @@ prep_init_IRQ(void) /* * IDE stuff. */ -void +void __prep prep_ide_insw(ide_ioreg_t port, void *buf, int ns) { _insw((unsigned short *)((port)+_IO_BASE), buf, ns); } -void +void __prep prep_ide_outsw(ide_ioreg_t port, void *buf, int ns) { _outsw((unsigned short *)((port)+_IO_BASE), buf, ns); } -int +int __prep prep_ide_default_irq(ide_ioreg_t base) { switch (base) { @@ -653,7 +660,7 @@ prep_ide_default_irq(ide_ioreg_t base) } } -ide_ioreg_t +ide_ioreg_t __prep prep_ide_default_io_base(int index) { switch (index) { @@ -666,13 +673,13 @@ prep_ide_default_io_base(int index) } } -int +int __prep prep_ide_check_region(ide_ioreg_t from, unsigned int extent) { return check_region(from, extent); } -void +void __prep prep_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name) @@ -680,14 +687,14 @@ prep_ide_request_region(ide_ioreg_t from, request_region(from, extent, name); } -void +void __prep prep_ide_release_region(ide_ioreg_t from, unsigned int extent) { release_region(from, extent); } -void +void __prep prep_ide_fix_driveid(struct hd_driveid *id) { } @@ -776,7 +783,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.irq_cannonicalize = prep_irq_cannonicalize; ppc_md.init_IRQ = prep_init_IRQ; /* this gets changed later on if we have an OpenPIC -- Cort */ - ppc_md.do_IRQ = prep_do_IRQ; + ppc_md.get_irq = prep_get_irq; ppc_md.init = NULL; ppc_md.restart = prep_restart; diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index b6f6415ff54f..d71029b254d7 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -1,5 +1,5 @@ /* - * $Id: process.c,v 1.95 1999/08/31 06:54:07 davem Exp $ + * $Id: process.c,v 1.97 1999/09/14 19:07:42 cort Exp $ * * linux/arch/ppc/kernel/process.c * @@ -162,7 +162,7 @@ _switch_to(struct task_struct *prev, struct task_struct *new, struct task_struct **last) { struct thread_struct *new_thread, *old_thread; - int s; + unsigned long s; __save_flags(s); __cli(); @@ -513,7 +513,7 @@ void __init ll_puts(const char *s) * vidmem just needs to be setup for it. * -- Cort */ - if ( ! is_prep ) + if ( _machine != _MACH_prep ) return; x = orig_x; y = orig_y; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index a7859ca9a603..79e86ed35af6 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.73 1999/09/05 11:56:32 paulus Exp $ + * $Id: prom.c,v 1.77 1999/09/14 01:13:19 cort Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -109,9 +109,9 @@ static void flushscreen(void); #ifdef CONFIG_BOOTX_TEXT -static void drawchar(char c); +void drawchar(char c); +void drawstring(const char *c); static void drawhex(unsigned long v); -static void drawstring(const char *c); static void scrollscreen(void); static void draw_byte(unsigned char c, long locX, long locY); @@ -138,7 +138,6 @@ static unsigned long inspect_node(phandle, struct device_node *, unsigned long, unsigned long, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, interpret_func *); -static void relocate_nodes(void); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); static void *early_get_property(unsigned long, unsigned long, char *); @@ -287,7 +286,7 @@ prom_init(int r3, int r4, prom_entry pp) gemini_prom_init(); return; #endif /* CONFIG_GEMINI */ - + /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) return; @@ -304,6 +303,8 @@ prom_init(int r3, int r4, prom_entry pp) #endif RELOC(boot_infos) = PTRUNRELOC(bi); + if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) + bi->logicalDisplayBase = 0; clearscreen(); @@ -357,9 +358,13 @@ prom_init(int r3, int r4, prom_entry pp) } } - space = bi->deviceTreeOffset + bi->deviceTreeSize; - if (bi->ramDisk) - space = bi->ramDisk + bi->ramDiskSize; + /* Move klimit to enclose device tree, args, ramdisk, etc... */ + if (bi->version < 5) { + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + } else + space = bi->totalParamsSize; RELOC(klimit) = PTRUNRELOC((char *) bi + space); /* New BootX will have flushed all TLBs and enters kernel with @@ -748,8 +753,6 @@ finish_device_tree(void) { unsigned long mem = (unsigned long) klimit; - if (boot_infos) - relocate_nodes(); mem = finish_node(allnodes, mem, NULL); printk(KERN_INFO "device tree used %lu bytes\n", mem - (unsigned long) allnodes); @@ -843,7 +846,7 @@ finish_node(struct device_node *np, unsigned long mem_start, * This procedure updates the pointers. */ __init -static void relocate_nodes(void) +void relocate_nodes(void) { unsigned long base; struct device_node *np; @@ -1183,6 +1186,23 @@ device_is_compatible(struct device_node *device, const char *compat) return 0; } + +/* + * Indicates whether the root node has a given value in its + * compatible property. + */ +__openfirmware +int +machine_is_compatible(const char *compat) +{ + struct device_node *root; + + root = find_path_device("/"); + if (root == 0) + return 0; + return device_is_compatible(root, compat); +} + /* * Construct and return a list of the device_nodes with a given type * and compatible property. @@ -1316,7 +1336,8 @@ call_rtas(const char *service, int nargs, int nret, unsigned long *outputs, ...) { va_list list; - int i, s; + int i; + unsigned long s; struct device_node *rtas; int *tokp; union { @@ -1361,19 +1382,41 @@ abort() prom_exit(); } +#ifdef CONFIG_XMON +__init +void +map_bootx_text(void) +{ + if (boot_infos == 0) + return; + boot_infos->logicalDisplayBase = + ioremap((unsigned long) boot_infos->dispDeviceBase, + boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]); +} +#endif /* CONFIG_XMON */ + /* Calc the base address of a given point (x,y) */ -#define CALC_BASE(x,y) ((BOOT_INFO_IS_V2_COMPATIBLE(bi) ? bi->logicalDisplayBase : \ - bi->dispDeviceBase) + (bi->dispDeviceRect[0] + (x)) * \ - (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * \ - ((y) + bi->dispDeviceRect[1])) +__pmac +static unsigned char * +calc_base(boot_infos_t *bi, int x, int y) +{ + unsigned char *base; + + base = bi->logicalDisplayBase; + if (base == 0) + base = bi->dispDeviceBase; + base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3); + base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes; + return base; +} -__init +__pmac static void clearscreen(void) { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned long *base = (unsigned long *)CALC_BASE(0,0); + unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; @@ -1392,13 +1435,13 @@ __inline__ void dcbst(const void* addr) __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr)); } -__init +__pmac static void flushscreen(void) { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned long *base = (unsigned long *)CALC_BASE(0,0); + unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; @@ -1416,14 +1459,14 @@ flushscreen(void) #ifdef CONFIG_BOOTX_TEXT -__init +__pmac static void scrollscreen(void) { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned long *src = (unsigned long *)CALC_BASE(0,16); - unsigned long *dst = (unsigned long *)CALC_BASE(0,0); + unsigned long *src = (unsigned long *)calc_base(bi,0,16); + unsigned long *dst = (unsigned long *)calc_base(bi,0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; @@ -1446,21 +1489,33 @@ scrollscreen(void) } } -__init -static void +__pmac +void drawchar(char c) { unsigned long offset = reloc_offset(); - switch(c) { - case '\r': RELOC(g_loc_X) = 0; break; - case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break; - default: - draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); - if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y)++; - } + switch (c) { + case '\b': + if (RELOC(g_loc_X) > 0) + --RELOC(g_loc_X); + break; + case '\t': + RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8; + break; + case '\r': + RELOC(g_loc_X) = 0; + break; + case '\n': + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y)++; + break; + default: + draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + } + if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) { + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y)++; } while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) { scrollscreen(); @@ -1468,15 +1523,15 @@ drawchar(char c) } } -__init -static void +__pmac +void drawstring(const char *c) { - while(*c) - drawchar(*(c++)); + while (*c) + drawchar(*c++); } -__init +__pmac static void drawhex(unsigned long v) { @@ -1494,13 +1549,13 @@ drawhex(unsigned long v) } -__init +__pmac static void draw_byte(unsigned char c, long locX, long locY) { unsigned long offset = reloc_offset(); boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); - unsigned char *base = CALC_BASE(locX << 3, locY << 4); + unsigned char *base = calc_base(bi, locX << 3, locY << 4); unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; switch(bi->dispDeviceDepth) { @@ -1518,7 +1573,7 @@ draw_byte(unsigned char c, long locX, long locY) } } -__init +__pmac static unsigned long expand_bits_8[16] = { 0x00000000, 0x000000ff, @@ -1538,7 +1593,7 @@ static unsigned long expand_bits_8[16] = { 0xffffffff }; -__init +__pmac static unsigned long expand_bits_16[4] = { 0x00000000, 0x0000ffff, @@ -1547,7 +1602,7 @@ static unsigned long expand_bits_16[4] = { }; -__init +__pmac static void draw_byte_32(unsigned char *font, unsigned long *base) { @@ -1573,7 +1628,7 @@ draw_byte_32(unsigned char *font, unsigned long *base) } } -__init +__pmac static void draw_byte_16(unsigned char *font, unsigned long *base) { @@ -1595,7 +1650,7 @@ draw_byte_16(unsigned char *font, unsigned long *base) } } -__init +__pmac static void draw_byte_8(unsigned char *font, unsigned long *base) { @@ -1615,7 +1670,7 @@ draw_byte_8(unsigned char *font, unsigned long *base) } } -__init +__pmac static unsigned char vga_font[cmapsz] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, diff --git a/arch/ppc/kernel/qspan_pci.c b/arch/ppc/kernel/qspan_pci.c new file mode 100644 index 000000000000..6d331b2b4536 --- /dev/null +++ b/arch/ppc/kernel/qspan_pci.c @@ -0,0 +1,379 @@ +/* + * QSpan pci routines. + * Most 8xx boards use the QSpan PCI bridge. The config address register + * is located 0x500 from the base of the bridge control/status registers. + * The data register is located at 0x504. + * This is a two step operation. First, the address register is written, + * then the data register is read/written as required. + * I don't know what to do about interrupts (yet). + * + * The RPX Classic implementation shares a chip select for normal + * PCI access and QSpan control register addresses. The selection is + * further selected by a bit setting in a board control register. + * Although it should happen, we disable interrupts during this operation + * to make sure some driver doesn't accidently access the PCI while + * we have switched the chip select. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pci.h" + + +/* + * This blows...... + * When reading the configuration space, if something does not respond + * the bus times out and we get a machine check interrupt. So, the + * good ol' exception tables come to mind to trap it and return some + * value. + * + * On an error we just return a -1, since that is what the caller wants + * returned if nothing is present. I copied this from __get_user_asm, + * with the only difference of returning -1 instead of EFAULT. + * There is an associated hack in the machine check trap code. + * + * The QSPAN is also a big endian device, that is it makes the PCI + * look big endian to us. This presents a problem for the Linux PCI + * functions, which assume little endian. For example, we see the + * first 32-bit word like this: + * ------------------------ + * | Device ID | Vendor ID | + * ------------------------ + * If we read/write as a double word, that's OK. But in our world, + * when read as a word, device ID is at location 0, not location 2 as + * the little endian PCI would believe. We have to switch bits in + * the PCI addresses given to us to get the data to/from the correct + * byte lanes. + * + * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. + * It always forces the MS bit to zero. Therefore, dev_fn values + * greater than 128 are returned as "no device found" errors. + * + * The QSPAN can only perform long word (32-bit) configuration cycles. + * The "offset" must have the two LS bits set to zero. Read operations + * require we read the entire word and then sort out what should be + * returned. Write operations other than long word require that we + * read the long word, update the proper word or byte, then write the + * entire long word back. + * + * PCI Bridge hack. We assume (correctly) that bus 0 is the primary + * PCI bus from the QSPAN. If we are called with a bus number other + * than zero, we create a Type 1 configuration access that a downstream + * PCI bridge will interpret. + */ + +#define __get_qspan_pci_config(x, addr, op) \ + __asm__ __volatile__( \ + "1: "op" %0,0(%1)\n" \ + " eieio\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".text" \ + : "=r"(x) : "r"(addr)) + +#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) +#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) + +#define mk_config_addr(bus, dev, offset) \ + (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) + +#define mk_config_type1(bus, dev, offset) \ + mk_config_addr(bus, dev, offset) | 1; + +int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + uint temp; + u_char *cp; +#ifdef CONFIG_RPXCLASSIC + unsigned long flags; +#endif + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + +#ifdef CONFIG_RPXCLASSIC + save_flags(flags); + cli(); + *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; + eieio(); +#endif + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz"); + +#ifdef CONFIG_RPXCLASSIC + *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; + eieio(); + restore_flags(flags); +#endif + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *val = *cp; + return PCIBIOS_SUCCESSFUL; +} + +int qspan_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + uint temp; + ushort *sp; +#ifdef CONFIG_RPXCLASSIC + unsigned long flags; +#endif + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + +#ifdef CONFIG_RPXCLASSIC + save_flags(flags); + cli(); + *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; + eieio(); +#endif + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz"); + offset ^= 0x02; + +#ifdef CONFIG_RPXCLASSIC + *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; + eieio(); + restore_flags(flags); +#endif + + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *val = *sp; + return PCIBIOS_SUCCESSFUL; +} + +int qspan_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ +#ifdef CONFIG_RPXCLASSIC + unsigned long flags; +#endif + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + +#ifdef CONFIG_RPXCLASSIC + save_flags(flags); + cli(); + *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; + eieio(); +#endif + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_qspan_pci_config(*val, QS_CONFIG_DATA, "lwz"); + +#ifdef CONFIG_RPXCLASSIC + *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; + eieio(); + restore_flags(flags); +#endif + + return PCIBIOS_SUCCESSFUL; +} + +int qspan_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + uint temp; + u_char *cp; +#ifdef CONFIG_RPXCLASSIC + unsigned long flags; +#endif + + if ((bus > 7) || (dev_fn > 127)) + return PCIBIOS_DEVICE_NOT_FOUND; + + qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *cp = val; + +#ifdef CONFIG_RPXCLASSIC + save_flags(flags); + cli(); + *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; + eieio(); +#endif + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + +#ifdef CONFIG_RPXCLASSIC + *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; + eieio(); + restore_flags(flags); +#endif + + return PCIBIOS_SUCCESSFUL; +} + +int qspan_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + uint temp; + ushort *sp; +#ifdef CONFIG_RPXCLASSIC + unsigned long flags; +#endif + + if ((bus > 7) || (dev_fn > 127)) + return PCIBIOS_DEVICE_NOT_FOUND; + + qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x02; + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *sp = val; + +#ifdef CONFIG_RPXCLASSIC + save_flags(flags); + cli(); + *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; + eieio(); +#endif + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + +#ifdef CONFIG_RPXCLASSIC + *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; + eieio(); + restore_flags(flags); +#endif + + return PCIBIOS_SUCCESSFUL; +} + +int qspan_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ +#ifdef CONFIG_RPXCLASSIC + unsigned long flags; +#endif + + if ((bus > 7) || (dev_fn > 127)) + return PCIBIOS_DEVICE_NOT_FOUND; + +#ifdef CONFIG_RPXCLASSIC + save_flags(flags); + cli(); + *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL; + eieio(); +#endif + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *(unsigned int *)QS_CONFIG_DATA = val; + +#ifdef CONFIG_RPXCLASSIC + *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL; + eieio(); + restore_flags(flags); +#endif + + return PCIBIOS_SUCCESSFUL; +} + +int qspan_pcibios_find_device(unsigned short vendor, unsigned short dev_id, + unsigned short index, unsigned char *bus_ptr, + unsigned char *dev_fn_ptr) +{ + int num, devfn; + unsigned int x, vendev; + + if (vendor == 0xffff) + return PCIBIOS_BAD_VENDOR_ID; + vendev = (dev_id << 16) + vendor; + num = 0; + for (devfn = 0; devfn < 32; devfn++) { + qspan_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x); + if (x == vendev) { + if (index == num) { + *bus_ptr = 0; + *dev_fn_ptr = devfn<<3; + return PCIBIOS_SUCCESSFUL; + } + ++num; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +int qspan_pcibios_find_class(unsigned int class_code, unsigned short index, + unsigned char *bus_ptr, unsigned char *dev_fn_ptr) +{ + int devnr, x, num; + + num = 0; + for (devnr = 0; devnr < 32; devnr++) { + qspan_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x); + if ((x>>8) == class_code) { + if (index == num) { + *bus_ptr = 0; + *dev_fn_ptr = devnr<<3; + return PCIBIOS_SUCCESSFUL; + } + ++num; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +void __init +m8xx_pcibios_fixup(void)) +{ + /* Lots to do here, all board and configuration specific. */ +} + +void __init +m8xx_setup_pci_ptrs(void)) +{ + set_config_access_method(qspan); + + ppc_md.pcibios_fixup = m8xx_pcibios_fixup; +} + diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c index d9fb23970254..09eafd5f79d8 100644 --- a/arch/ppc/kernel/residual.c +++ b/arch/ppc/kernel/residual.c @@ -1,5 +1,5 @@ /* - * $Id: residual.c,v 1.15 1999/05/14 07:24:27 davem Exp $ + * $Id: residual.c,v 1.16 1999/09/17 17:23:09 cort Exp $ * * Code to deal with the PReP residual data. * @@ -50,6 +50,9 @@ #include +unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,}; +RESIDUAL *res = (RESIDUAL *)&__res; + const char * PnP_BASE_TYPES[] __initdata = { "Reserved", "MassStorageDevice", diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 8015b8d30636..7ae97c81d9b5 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.148 1999/09/05 11:56:34 paulus Exp $ + * $Id: setup.c,v 1.159 1999/09/18 18:40:38 dmalek Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -13,9 +13,6 @@ #include #include -#include -#include -#include #include #include #include @@ -27,8 +24,8 @@ #include #include #include -#ifdef CONFIG_MBX -#include +#ifdef CONFIG_8xx +#include #include #endif #include @@ -52,7 +49,7 @@ extern void prep_init(unsigned long r3, unsigned long r6, unsigned long r7); -extern void mbx_init(unsigned long r3, +extern void m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, @@ -74,18 +71,17 @@ extern boot_infos_t *boot_infos; extern char cmd_line[512]; char saved_command_line[256]; unsigned char aux_device_present; - +struct int_control_struct int_control; struct ide_machdep_calls ppc_ide_md; unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; -/* Temporary hacks until machdep.h is fully done. */ +#ifndef CONFIG_MACH_SPECIFIC int _machine = 0; -/* do we have OF? */ int have_of = 0; -int is_prep = 0; -int is_chrp = 0; +#endif /* CONFIG_MACH_SPECIFIC */ + #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; #endif /* CONFIG_MAGIC_SYSRQ */ @@ -98,21 +94,19 @@ struct machdep_calls ppc_md; /* copy of the residual data */ -#ifndef CONFIG_MBX -unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,}; +#ifndef CONFIG_8xx +extern unsigned char __res[sizeof(RESIDUAL)]; #else -unsigned char __res[sizeof(bd_t)] = {0,}; +extern unsigned char __res[sizeof(bd_t)]; #endif -RESIDUAL *res = (RESIDUAL *)&__res; - /* * Perhaps we can put the pmac screen_info[] here * on pmac as well so we don't need the ifdef's. * Until we get multiple-console support in here * that is. -- Cort */ -#ifndef CONFIG_MBX +#ifndef CONFIG_8xx struct screen_info screen_info = { 0, 25, /* orig-x, orig-y */ 0, /* unused */ @@ -136,7 +130,7 @@ void __init pmac_find_display(void) { } -#else /* CONFIG_MBX */ +#else /* CONFIG_8xx */ /* We need this to satisfy some external references until we can * strip the kernel down. @@ -152,7 +146,7 @@ struct screen_info screen_info = { 0, /* orig-video-isVGA */ 16 /* orig-video-points */ }; -#endif /* CONFIG_MBX */ +#endif /* CONFIG_8xx */ void machine_restart(char *cmd) { @@ -267,6 +261,7 @@ int get_cpuinfo(char *buffer) * Assume here that all clock rates are the same in a * smp system. -- Cort */ +#ifndef CONFIG_8xx if ( have_of ) { struct device_node *cpu_node; @@ -290,6 +285,7 @@ int get_cpuinfo(char *buffer) len += sprintf(len+buffer, "clock\t\t: %dMHz\n", *fp / 1000000); } +#endif if (ppc_md.setup_residual != NULL) { @@ -345,9 +341,8 @@ unsigned long __init identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { -#ifdef __SMP__ - if ( first_cpu_booted ) return 0; -#endif /* __SMP__ */ + +#ifndef CONFIG_8xx if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); #ifndef CONFIG_MACH_SPECIFIC @@ -358,68 +353,46 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, r3 = 0; } /* prep boot loader tells us if we're prep or not */ - else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) { + else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) + { _machine = _MACH_prep; - is_prep = 1; - } else { + } else + { char *model; + struct device_node *root; have_of = 1; - + /* prom_init has already been called from __start */ - finish_device_tree(); + if (boot_infos) + relocate_nodes(); + /* ask the OF info if we're a chrp or pmac */ - model = get_property(find_path_device("/"), "device_type", NULL); - if ( model && !strncmp("chrp",model,4) ) - { - _machine = _MACH_chrp; - is_chrp = 1; - } - else - { - model = get_property(find_path_device("/"), - "model", NULL); - if ( model && !strncmp(model, "IBM", 3)) - { + /* we need to set _machine before calling finish_device_tree */ + root = find_path_device("/"); + if (root != 0) { + /* assume pmac unless proven to be chrp -- Cort */ + _machine = _MACH_Pmac; + model = get_property(root, "device_type", NULL); + if (model && !strncmp("chrp", model, 4)) _machine = _MACH_chrp; - is_chrp = 1; - } - else - { - _machine = _MACH_Pmac; + else { + model = get_property(root, "model", NULL); + if (model && !strncmp(model, "IBM", 3)) + _machine = _MACH_chrp; } } + finish_device_tree(); } -#else /* CONFIG_MACH_SPECIFIC */ - -#ifdef CONFIG_PREP - _machine = _MACH_prep; - is_prep = 1; -#elif defined(CONFIG_CHRP) - _machine = _MACH_chrp; - is_chrp = 1; - have_of = 1; -#elif defined(CONFIG_PMAC) - _machine = _MACH_Pmac; - have_of = 1; -#elif defined(CONFIG_MBX) - _machine = _MACH_mbx; -#elif defined(CONFIG_FADS) - _machine = _MACH_fads; -#elif defined(CONFIG_APUS) - _machine = _MACH_apus; -#elif defined(CONFIG_GEMINI) - _machine = _MACH_gemini; -#else -#error "Machine not defined correctly" -#endif /* CONFIG_APUS */ #endif /* CONFIG_MACH_SPECIFIC */ if ( have_of ) { #ifdef CONFIG_MACH_SPECIFIC /* prom_init has already been called from __start */ + if (boot_infos) + relocate_nodes(); finish_device_tree(); #endif /* CONFIG_MACH_SPECIFIC */ /* @@ -473,6 +446,11 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, cmd_line[sizeof(cmd_line) - 1] = 0; } + int_control.int_sti = __no_use_sti; + int_control.int_cli = __no_use_cli; + int_control.int_save_flags = __no_use_save_flags; + int_control.int_restore_flags = __no_use_restore_flags; + switch (_machine) { case _MACH_Pmac: @@ -489,14 +467,11 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, apus_init(r3, r4, r5, r6, r7); break; #endif -#ifdef CONFIG_MBX - case _MACH_mbx: - mbx_init(r3, r4, r5, r6, r7); - break; -#endif +#ifdef CONFIG_GEMINI case _MACH_gemini: gemini_init(r3, r4, r5, r6, r7); break; +#endif default: printk("Unknown machine type in identify_machine!\n"); } @@ -505,6 +480,17 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, extern int __map_without_bats; __map_without_bats = 1; } +#else /* CONFIG_8xx */ + int_control.int_sti = __no_use_sti; + int_control.int_cli = __no_use_cli; + int_control.int_save_flags = __no_use_save_flags; + int_control.int_restore_flags = __no_use_restore_flags; + + m8xx_init(r3, r4, r5, r6, r7); +#endif + + /* this is for modules since _machine can be a define -- Cort */ + ppc_md.ppc_machine = _machine; if ( ppc_md.progress ) ppc_md.progress("id mach(): done", 0x200); return 0; diff --git a/arch/ppc/kernel/sleep.S b/arch/ppc/kernel/sleep.S new file mode 100644 index 000000000000..3ead7bd28eb6 --- /dev/null +++ b/arch/ppc/kernel/sleep.S @@ -0,0 +1,264 @@ +/* + * This file contains sleep low-level functions for PowerBook G3. + * Copyright (C) 1999 Benjamin Herrenschmidt (bh40@calva.net) + * and Paul Mackerras (paulus@cs.anu.edu.au). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include "ppc_asm.tmpl" +#include +#include + +#define MAGIC 0x4c617273 /* 'Lars' */ + +/* + * Structure for storing CPU registers on the stack. + */ +#define SL_SP 0 +#define SL_PC 4 +#define SL_MSR 8 +#define SL_SDR1 0xc +#define SL_SPRG0 0x10 /* 4 sprg's */ +#define SL_DBAT0 0x20 +#define SL_IBAT0 0x28 +#define SL_DBAT1 0x30 +#define SL_IBAT1 0x38 +#define SL_DBAT2 0x40 +#define SL_IBAT2 0x48 +#define SL_DBAT3 0x50 +#define SL_IBAT3 0x58 +#define SL_TB 0x60 +#define SL_HID0 0x68 +#define SL_R2 0x6c +#define SL_R12 0x70 /* r12 to r31 */ +#define SL_SIZE (SL_R12 + 80) + +#define tophys(rd,rs) addis rd,rs,-KERNELBASE@h +#define tovirt(rd,rs) addis rd,rs,KERNELBASE@h + + .text + +_GLOBAL(low_sleep_handler) + mflr r0 + stw r0,4(r1) + stwu r1,-SL_SIZE(r1) + stw r2,SL_R2(r1) + stmw r12,SL_R12(r1) + + /* Save MSR, SDR1, TB */ + mfmsr r4 + stw r4,SL_MSR(r1) + mfsdr1 r4 + stw r4,SL_SDR1(r1) +1: + mftbu r4 + stw r4,SL_TB(r1) + mftb r5 + stw r5,SL_TB+4(r1) + mftbu r3 + cmpw r3,r4 + bne 1b + + /* Save SPRGs */ + mfsprg r4,0 + stw r4,SL_SPRG0(r1) + mfsprg r4,1 + stw r4,SL_SPRG0+4(r1) + mfsprg r4,2 + stw r4,SL_SPRG0+8(r1) + mfsprg r4,3 + stw r4,SL_SPRG0+12(r1) + + /* Save BATs */ + mfdbatu r4,0 + stw r4,SL_DBAT0(r1) + mfdbatl r4,0 + stw r4,SL_DBAT0+4(r1) + mfdbatu r4,1 + stw r4,SL_DBAT1(r1) + mfdbatl r4,1 + stw r4,SL_DBAT1+4(r1) + mfdbatu r4,2 + stw r4,SL_DBAT2(r1) + mfdbatl r4,2 + stw r4,SL_DBAT2+4(r1) + mfdbatu r4,3 + stw r4,SL_DBAT3(r1) + mfdbatl r4,3 + stw r4,SL_DBAT3+4(r1) + mfibatu r4,0 + stw r4,SL_IBAT0(r1) + mfibatl r4,0 + stw r4,SL_IBAT0+4(r1) + mfibatu r4,1 + stw r4,SL_IBAT1(r1) + mfibatl r4,1 + stw r4,SL_IBAT1+4(r1) + mfibatu r4,2 + stw r4,SL_IBAT2(r1) + mfibatl r4,2 + stw r4,SL_IBAT2+4(r1) + mfibatu r4,3 + stw r4,SL_IBAT3(r1) + mfibatl r4,3 + stw r4,SL_IBAT3+4(r1) + + /* Save HID0 */ + mfspr r4,HID0 + stw r4,SL_HID0(r1) + + /* Set up stuff at address 0 */ + lis r5,wake_up@ha + addi r5,r5,wake_up@l + tophys(r5,r5) + stw r5,SL_PC(r1) + lis r4,KERNELBASE@h + tophys(r5,r1) + addi r5,r5,SL_PC + lis r6,MAGIC@ha + addi r6,r6,MAGIC@l + stw r5,0(r4) + stw r6,4(r4) + +/* + * Flush the L1 data cache by reading the first 64kB of RAM + * and then flushing the same area with the dcbf instruction. + * The L2 cache has already been disabled. + */ + li r4,0x0800 /* 64kB / 32B */ + mtctr r4 + lis r4,KERNELBASE@h +1: + lwz r0,0(r4) + addi r4,r4,0x0020 /* Go to start of next cache line */ + bdnz 1b + sync + + li r4,0x0800 /* 64k */ + mtctr r4 + lis r4,KERNELBASE@h +1: + dcbf r0,r4 + addi r4,r4,0x0020 /* Go to start of next cache line */ + bdnz 1b + sync + +/* + * Set the HID0 and MSR for sleep. + */ + mfspr r2,HID0 + rlwinm r2,r2,0,10,7 /* clear doze, nap */ + oris r2,r2,HID0_SLEEP@h + sync + mtspr HID0,r2 + sync + + mfmsr r2 + oris r2,r2,MSR_POW@h +1: sync + mtmsr r2 + isync + b 1b + +/* + * Here is the resume code. + * r1 has the physical address of SL_PC(sp). + */ + +wake_up: + /* Restore the HID0 register. This turns on the L1 caches. */ + subi r1,r1,SL_PC + lwz r3,SL_HID0(r1) + sync + isync + mtspr HID0,r3 + sync + + /* Restore the kernel's segment registers, the + BATs, and SDR1. Then we can turn on the MMU. */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + + lwz r4,SL_SDR1(r1) + mtsdr1 r4 + lwz r4,SL_SPRG0(r1) + mtsprg 0,r4 + lwz r4,SL_SPRG0+4(r1) + mtsprg 1,r4 + lwz r4,SL_SPRG0+8(r1) + mtsprg 2,r4 + lwz r4,SL_SPRG0+12(r1) + mtsprg 3,r4 + + lwz r4,SL_DBAT0(r1) + mtdbatu 0,r4 + lwz r4,SL_DBAT0+4(r1) + mtdbatl 0,r4 + lwz r4,SL_DBAT1(r1) + mtdbatu 1,r4 + lwz r4,SL_DBAT1+4(r1) + mtdbatl 1,r4 + lwz r4,SL_DBAT2(r1) + mtdbatu 2,r4 + lwz r4,SL_DBAT2+4(r1) + mtdbatl 2,r4 + lwz r4,SL_DBAT3(r1) + mtdbatu 3,r4 + lwz r4,SL_DBAT3+4(r1) + mtdbatl 3,r4 + lwz r4,SL_IBAT0(r1) + mtibatu 0,r4 + lwz r4,SL_IBAT0+4(r1) + mtibatl 0,r4 + lwz r4,SL_IBAT1(r1) + mtibatu 1,r4 + lwz r4,SL_IBAT1+4(r1) + mtibatl 1,r4 + lwz r4,SL_IBAT2(r1) + mtibatu 2,r4 + lwz r4,SL_IBAT2+4(r1) + mtibatl 2,r4 + lwz r4,SL_IBAT3(r1) + mtibatu 3,r4 + lwz r4,SL_IBAT3+4(r1) + mtibatl 3,r4 + + /* restore the MSR and turn on the MMU */ + lwz r3,SL_MSR(r1) + bl turn_on_mmu + + /* get back the stack pointer */ + tovirt(r1,r1) + + /* Restore TB */ + lwz r3,SL_TB(r1) + lwz r4,SL_TB+4(r1) + mttbu r3 + mttbl r4 + + /* Restore the callee-saved registers and return */ + lwz r2,SL_R2(r1) + lmw r12,SL_R12(r1) + addi r1,r1,SL_SIZE + lwz r0,4(r1) + mtlr r0 + blr + +turn_on_mmu: + mflr r4 + tovirt(r4,r4) + mtsrr0 r4 + mtsrr1 r3 + sync + rfi diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 3d2fb057f22f..638e06b26a88 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -1,11 +1,13 @@ /* - * $Id: smp.c,v 1.62 1999/09/05 11:56:34 paulus Exp $ + * $Id: smp.c,v 1.68 1999/09/17 19:38:05 cort Exp $ * * Smp support for ppc. * * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great * deal of code from the sparc and intel versions. * + * Copyright (C) 1999 Cort Dougan + * * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes * (troy@microux.com, hozer@drgw.net) */ @@ -34,9 +36,9 @@ #include #include #include +#include #include "time.h" -int first_cpu_booted = 0; int smp_threads_ready = 0; volatile int smp_commenced = 0; int smp_num_cpus = 1; @@ -251,7 +253,6 @@ void __init smp_boot_cpus(void) printk("Entering SMP Mode...\n"); /* let other processors know to not do certain initialization */ - first_cpu_booted = 1; smp_num_cpus = 1; smp_store_cpu_info(0); @@ -276,7 +277,7 @@ void __init smp_boot_cpus(void) */ cacheflush_time = 5 * 1024; - if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) ) + if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_gemini)) ) { printk("SMP not supported on this machine.\n"); return; @@ -297,6 +298,10 @@ void __init smp_boot_cpus(void) #endif cpu_nr = smp_chrp_cpu_nr; break; + case _MACH_gemini: + cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2; + cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr; + break; } /* @@ -307,7 +312,6 @@ void __init smp_boot_cpus(void) { int c; struct pt_regs regs; - struct task_struct *idle; /* create a process for the processor */ /* we don't care about the values in regs since we'll @@ -360,6 +364,10 @@ void __init smp_boot_cpus(void) __pa(__secondary_start_chrp), i); #endif break; + case _MACH_gemini: + openpic_init_processor( 1<dar); return; -#endif /* CONFIG_MBX */ +#endif #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler) { debugger_fault_handler(regs); @@ -241,10 +241,14 @@ SoftwareEmulation(struct pt_regs *regs) panic("Kernel Mode Software FPU Emulation"); } +#ifdef CONFIG_MATH_EMULATION if ((errcode = do_mathemu(regs))) { +#else + if ((errcode = Soft_emulate_8xx(regs))) { +#endif if (errcode > 0) _exception(SIGFPE, regs); - else if (errcode == -EFAULT; + else if (errcode == -EFAULT) _exception(SIGSEGV, regs); else _exception(SIGILL, regs); diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c index d6b56dc5f9dd..60d8576da857 100644 --- a/arch/ppc/lib/locks.c +++ b/arch/ppc/lib/locks.c @@ -1,5 +1,5 @@ /* - * $Id: locks.c,v 1.24 1999/08/03 19:16:47 cort Exp $ + * $Id: locks.c,v 1.25 1999/09/10 10:40:13 davem Exp $ * * Locks for smp ppc * diff --git a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile index 235a79e7af98..ce86ebbe8af4 100644 --- a/arch/ppc/mbxboot/Makefile +++ b/arch/ppc/mbxboot/Makefile @@ -1,5 +1,5 @@ # -# arch/ppc/boot/Makefile +# arch/ppc/mbxboot/Makefile # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive @@ -14,7 +14,7 @@ .s.o: $(AS) -o $*.o $< .c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< + $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< .S.s: $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $< .S.o: @@ -29,30 +29,46 @@ TFTPIMAGE=/tftpboot/zImage.mbx ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000 GZIP_FLAGS = -v9 -OBJECTS := head.o misc.o ../coffboot/zlib.o mbxtty.o -CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_MBX +OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o +CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_8xx OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc +ifeq ($(CONFIG_MBX),y) +OBJECTS += pci.o qspan_pci.o +CFLAGS += -DCONFIG_MBX +endif +ifeq ($(CONFIG_RPXLITE),y) +CFLAGS += -DCONFIG_RPXLITE +OBJECTS += iic.o embed_config.o +endif +ifeq ($(CONFIG_RPXCLASSIC),y) +CFLAGS += -DCONFIG_RPXCLASSIC +OBJECTS += iic.o embed_config.o pci.o qspan_pci.o +endif +ifeq ($(CONFIG_BSEIP),y) +CFLAGS += -DCONFIG_BSEIP +OBJECTS += iic.o embed_config.o +endif + all: zImage zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=ramdisk.image.gz \ --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp zvmlinux.initrd - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ - -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c + zvmlinux.initrd.tmp1 zvmlinux.initrd1 + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \ + -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \ + -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=ramdisk.image.gz \ --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.initrd.tmp $@ - rm zvmlinux.initrd.tmp zImage: zvmlinux ln -sf zvmlinux zImage @@ -73,7 +89,7 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ diff --git a/arch/ppc/mbxboot/embed_config.c b/arch/ppc/mbxboot/embed_config.c new file mode 100644 index 000000000000..009d0b4bcb03 --- /dev/null +++ b/arch/ppc/mbxboot/embed_config.c @@ -0,0 +1,207 @@ + +/* Board specific functions for those embedded 8xx boards that do + * not have boot monitor support for board information. + */ +#include +#include "asm/mpc8xx.h" + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +extern void iic_read(uint devaddr, u_char *buf, uint offset, uint count); +extern u_char aschex_to_byte(u_char *cp); + +static void rpx_eth(bd_t *bd, u_char *cp); +static void rpx_brate(bd_t *bd, u_char *cp); +static void rpx_memsize(bd_t *bd, u_char *cp); +static void rpx_cpuspeed(bd_t *bd, u_char *cp); + +/* Read the EEPROM on the RPX-Lite board. +*/ +void +rpx_cfg(bd_t *bd) +{ + u_char eebuf[256], *cp; + + /* Read the first 256 bytes of the EEPROM. I think this + * is really all there is, and I hope if it gets bigger the + * info we want is still up front. + */ +#if 1 + iic_read(0xa8, eebuf, 0, 128); + iic_read(0xa8, &eebuf[128], 128, 128); + { + int i; + cp = (u_char *)0xfa000000; + + for (i=0; i<256; i++) + *cp++ = eebuf[i]; + } + + /* We look for two things, the Ethernet address and the + * serial baud rate. The records are separated by + * newlines. + */ + cp = eebuf; + for (;;) { + if (*cp == 'E') { + cp++; + if (*cp == 'A') { + cp += 2; + rpx_eth(bd, cp); + } + } + if (*cp == 'S') { + cp++; + if (*cp == 'B') { + cp += 2; + rpx_brate(bd, cp); + } + } + if (*cp == 'D') { + cp++; + if (*cp == '1') { + cp += 2; + rpx_memsize(bd, cp); + } + } + if (*cp == 'H') { + cp++; + if (*cp == 'Z') { + cp += 2; + rpx_cpuspeed(bd, cp); + } + } + + /* Scan to the end of the record. + */ + while ((*cp != '\n') && (*cp != 0xff)) + cp++; + + /* If the next character is a 0 or ff, we are done. + */ + cp++; + if ((*cp == 0) || (*cp == 0xff)) + break; + } + bd->bi_memstart = 0; + +#else + bd->bi_memstart = 0; + bd->bi_memsize = (4 * 1024 * 1024); + bd->bi_intfreq = 48; + bd->bi_busfreq = 48; + bd->bi_baudrate = 9600; +#endif +} + +static void +rpx_eth(bd_t *bd, u_char *cp) +{ + int i; + + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = aschex_to_byte(cp); + cp += 2; + } +} + +static void +rpx_brate(bd_t *bd, u_char *cp) +{ + uint rate; + + rate = 0; + + while (*cp != '\n') { + rate *= 10; + rate += (*cp) - '0'; + cp++; + } + + bd->bi_baudrate = rate * 100; +} + +static void +rpx_memsize(bd_t *bd, u_char *cp) +{ + uint size; + + size = 0; + + while (*cp != '\n') { + size *= 10; + size += (*cp) - '0'; + cp++; + } + + bd->bi_memsize = size * 1024 * 1024; +} + +static void +rpx_cpuspeed(bd_t *bd, u_char *cp) +{ + uint num, den; + + num = den = 0; + + while (*cp != '\n') { + num *= 10; + num += (*cp) - '0'; + cp++; + if (*cp == '/') { + cp++; + den = (*cp) - '0'; + break; + } + } + + /* I don't know why the RPX just can't state the actual + * CPU speed..... + */ + if (den) { + num /= den; + num *= den; + } + bd->bi_intfreq = bd->bi_busfreq = num; + + /* The 8xx can only run a maximum 50 MHz bus speed (until + * Motorola changes this :-). Greater than 50 MHz parts + * run internal/2 for bus speed. + */ + if (num > 50) + bd->bi_busfreq /= 2; +} + +/* Build a board information structure for the BSE ip-Engine. + * There is more to come since we will add some environment + * variables and a function to read them. + */ +void +bseip_cfg(bd_t *bd) +{ + u_char *cp; + int i; + + /* Baud rate and processor speed will eventually come + * from the environment variables. + */ + bd->bi_baudrate = 9600; + + /* Get the Ethernet station address from the Flash ROM. + */ + cp = (u_char *)0xfe003ffa; + for (i=0; i<6; i++) { + bd->bi_enetaddr[i] = *cp++; + } + + /* The rest of this should come from the environment as well. + */ + bd->bi_memstart = 0; + bd->bi_memsize = (16 * 1024 * 1024); + bd->bi_intfreq = 48; + bd->bi_busfreq = 48; +} + diff --git a/arch/ppc/mbxboot/head.S b/arch/ppc/mbxboot/head.S index a7b3f4ffc8e5..87ed12725f8b 100644 --- a/arch/ppc/mbxboot/head.S +++ b/arch/ppc/mbxboot/head.S @@ -1,3 +1,4 @@ +#include #include "../kernel/ppc_defs.h" #include "../kernel/ppc_asm.tmpl" #include @@ -6,37 +7,101 @@ .text /* - * $Id: head.S,v 1.4 1999/04/22 06:32:09 davem Exp $ + * $Id: head.S,v 1.6 1999/09/15 00:02:25 dmalek Exp $ * * This code is loaded by the ROM loader at some arbitrary location. * Move it to high memory so that it can load the kernel at 0x0000. * - * The MBX EPPC-Bug understands ELF, so it loads us into the location - * specified in the header. This is a two step process. First, EPPC-Bug - * loads the file into the intermediate buffer memory location specified - * by the environment parameters. When it discovers this is an ELF - * binary, it relocates to the link address for us. Unfortunately, the - * header does not move with the file, so we have to find the - * intermediate load location and read the header from there. From - * information provided by Motorola (thank you), we know this intermediate - * location can be found from the NVRAM environment. - * All of these addresses must be somewhat carefully chosen to make sure - * we don't overlap the regions. I chose to load the kernel at 0, the - * compressed image loads at 0x00100000, and the MBX intermediate buffer - * was set to 0x00200000. Provided the loaded kernel image never grows - * over one megabyte (which I am going to ensure never happens :-), these - * will work fine. When we get called from EPPC-Bug, registers are: + * This is a three step process that will also work when booting from + * a Flash PROM normally located in high memory. + * + * First, the entire image is loaded into some high memory address. + * This is usually at or above 0x02000000. This is done by a network + * boot function supported by the board or a debugger over BDM port. + * + * Second, the start up function here will relocate the decompress + * function to run at the link address of 0x01000000. + * + * Last, the decompression function will reloate the initrd, zImage, and + * the residual data to locations under 8 Meg. This is necessary because + * the embedded kernel start up uses 8 Meg translations to access physical + * space before the MMU is enabled. Finally, the zImage is uncompressed + * to location 0 and we jump to it. + * + * On the MBX, * R1 - Stack pointer at a high memory address. * R3 - Pointer to Board Information Block. * R4 - Pointer to argument string. * Interrupts masked, cache and MMU disabled. + * + * ...and the first and second functions listed above are + * done for us (it knows ELF images). + * + * For other embedded boards we build the Board Information Block. */ .globl start start: bl start_ start_: - mr r11,r3 /* Save pointer to residual/board data */ +#ifndef CONFIG_MBX + lis r11, local_bd_info@h + ori r11, r11, local_bd_info@l +#else + mr r11, r3 +#endif + + mfmsr r3 /* Turn off interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r3,r3,r4 + mtmsr r3 + +/* check if we need to relocate ourselves to the link addr or were we + loaded there to begin with -- Cort */ + lis r4,start@h + ori r4,r4,start@l + mflr r3 + subi r3,r3,4 /* we get the nip, not the ip of the branch */ + mr r8,r3 +#if 0 + cmp 0,r3,r4 + beq start_ldr /* Branch if loaded OK */ +#endif + +/* + * no matter where we're loaded, move ourselves to -Ttext address + * This computes the sizes we need to determine other things. + */ + lis r5,end@h + ori r5,r5,end@l + addi r5,r5,3 /* Round up - just in case */ + sub r5,r5,r4 /* Compute # longwords to move */ + srwi r5,r5,2 + mtctr r5 + mr r7,r5 + li r6,0 + subi r3,r3,4 /* Set up for loop */ + subi r4,r4,4 +00: lwzu r5,4(r3) + stwu r5,4(r4) + xor r6,r6,r5 + bdnz 00b + + lis r3,start_ldr@h + ori r3,r3,start_ldr@l + mtlr r3 /* Easiest way to do an absolute jump */ + blr + +start_ldr: +/* Most 8xx boards don't boot up with the I-cache enabled. Do that + * now because the decompress runs much faster that way. + */ + lis r3, IDC_INVALL@h + mtspr IC_CST, r3 + lis r3, IDC_ENABLE@h + mtspr IC_CST, r3 + /* Clear all of BSS */ lis r3,edata@h ori r3,r3,edata@l @@ -48,39 +113,60 @@ start_: 50: stwu r0,4(r3) cmp 0,r3,r4 bne 50b -90: mr r9,r1 /* Save old stack pointer (in case it matters) */ + lis r1,.stack@h ori r1,r1,.stack@l addi r1,r1,4096*2 subi r1,r1,256 li r2,0x000F /* Mask pointer to 16-byte boundary */ andc r1,r1,r2 -/* Run loader */ + + /* Perform configuration of the various boards. This is done + * by reading some configuration data from EEPROM and building + * the board information structure. + */ mr r3, r11 mr r21, r11 + mr r22, r8 + mr r23, r7 + mr r24, r6 + +#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) + bl rpx_cfg + mr r3, r21 +#endif +#ifdef CONFIG_BSEIP + bl bseip_cfg + mr r3, r21 +#endif bl serial_init /* Init MBX serial port */ - lis r8, 0xfa200000@h /* Disable Ethernet SCC */ + mr r11, r21 + mr r8, r22 + mr r7, r23 + mr r6, r24 + +#ifdef CONFIG_MBX + lis r18, 0xfa200000@h /* Disable Ethernet SCC */ li r0, 0 - stw r0, 0x0a00(r8) + stw r0, 0x0a00(r18) - mr r11, r21 - lis r8,start@h - ori r8,r8,start@l - lis r9,end@h - ori r9,r9,end@l - sub r7,r8,r9 - srwi r7,r7,2 + /* On the MBX (or anything that will TFTP load an ELF image), + * we have to find the intermediate address. The ELF loader + * only moves the Linux boostrap/decompress, not the zImage. + */ #define ILAP_ADDRESS 0xfa000020 lis r8, ILAP_ADDRESS@h lwz r8, ILAP_ADDRESS@l(r8) addis r8, r8, 1 /* Add 64K */ +#endif + mr r3,r8 /* Load point */ mr r4,r7 /* Program length */ mr r5,r6 /* Checksum */ mr r6,r11 /* Residual data */ bl decompress_kernel - + /* changed to use r3 (as firmware does) for kernel as ptr to residual -- Cort*/ lis r6,cmd_line@h @@ -99,14 +185,17 @@ start_: ori r2,r2,initrd_end@l lwz r5,0(r2) - /* tell kernel we're prep */ - /* - * get start address of kernel code which is stored as a coff - * entry. see boot/head.S -- Cort - */ + /* The world starts from the beginning. + */ li r9,0x0 - lwz r9,0(r9) mtlr r9 + + /* Invalidate the instruction cache because we just copied a + * bunch of kernel instructions. + */ + lis r9, IDC_INVALL@h + mtspr IC_CST, r9 + blr hang: b hang @@ -117,19 +206,6 @@ hang: */ .globl udelay udelay: - mfspr r4,PVR - srwi r4,r4,16 - cmpi 0,r4,1 /* 601 ? */ - bne .udelay_not_601 -00: li r0,86 /* Instructions / microsecond? */ - mtctr r0 -10: addi r0,r0,0 /* NOP */ - bdnz 10b - subic. r3,r3,1 - bne 00b - blr - -.udelay_not_601: mulli r4,r3,1000 /* nanoseconds */ addi r4,r4,59 li r5,60 @@ -150,16 +226,6 @@ udelay: blt 2b 3: blr -.globl _get_HID0 -_get_HID0: - mfspr r3,HID0 - blr - -.globl _put_HID0 -_put_HID0: - mtspr HID0,r3 - blr - .globl _get_MSR _get_MSR: mfmsr r3 @@ -170,31 +236,14 @@ _put_MSR: mtmsr r3 blr -/* - * Flush instruction cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_instruction_cache) - mflr r5 - bl flush_data_cache - mtlr r5 - blr - -#define NUM_CACHE_LINES 128*8 -#define CACHE_LINE_SIZE 32 -#define cache_flush_buffer 0x1000 - -/* - * Flush data cache - * *** I'm really paranoid here! - */ -_GLOBAL(flush_data_cache) - lis r3,cache_flush_buffer@h - ori r3,r3,cache_flush_buffer@l - li r4,NUM_CACHE_LINES - mtctr r4 -00: lwz r4,0(r3) - addi r3,r3,CACHE_LINE_SIZE /* Next line, please */ - bdnz 00b -10: blr .comm .stack,4096*2,4 +#ifndef CONFIG_MBX +local_bd_info: + .long 0 + .long 0x01000000 + .long 64 + .long 64 + .long 0 + .long 0 + .long 0 +#endif diff --git a/arch/ppc/mbxboot/iic.c b/arch/ppc/mbxboot/iic.c new file mode 100644 index 000000000000..7775350d5002 --- /dev/null +++ b/arch/ppc/mbxboot/iic.c @@ -0,0 +1,250 @@ + +/* Minimal support functions to read configuration from IIC EEPROMS + * on MPC8xx boards. Originally written for RPGC RPX-Lite. + * Dan Malek (dmalek@jlc.net). + */ +#include +#include +#include "asm/mpc8xx.h" +#include "../8xx_io/commproc.h" + + +/* IIC functions. + * These are just the basic master read/write operations so we can + * examine serial EEPROM. + */ +void iic_read(uint devaddr, u_char *buf, uint offset, uint count); +u_char aschex_to_byte(u_char *cp); + +static int iic_init_done; + +static void +iic_init() +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + uint dpaddr; + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + /* Reset the CPM. This is necessary on the 860 processors + * that may have started the SCC1 ethernet without relocating + * the IIC. + * This also stops the Ethernet in case we were loaded by a + * BOOTP rom monitor. + */ + cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + + /* Wait for it. + */ + while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG)); + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + /* Initialize Port B IIC pins. + */ + cp->cp_pbpar |= 0x00000030; + cp->cp_pbdir |= 0x00000030; + cp->cp_pbodr |= 0x00000030; + + /* Initialize the parameter ram. + */ + + /* Allocate space for a two transmit and one receive buffer + * descriptor in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0840; + + /* Set up the IIC parameters in the parameter ram. + */ + iip->iic_tbase = dpaddr; + iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t)); + + iip->iic_tfcr = SMC_EB; + iip->iic_rfcr = SMC_EB; + + /* This should really be done by the reader/writer. + */ + iip->iic_mrblr = 128; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Select an arbitrary address. Just make sure it is unique. + */ + i2c->i2c_i2add = 0x34; + + /* Make clock run maximum slow. + */ + i2c->i2c_i2brg = 7; + + /* Disable interrupts. + */ + i2c->i2c_i2cmr = 0; + i2c->i2c_i2cer = 0xff; + + /* Enable SDMA. + */ + immap->im_siu_conf.sc_sdcr = 1; + + iic_init_done = 1; +} + +/* Read from IIC. + * Caller provides device address, memory buffer, and byte count. + */ +static u_char iitemp[32]; + +void +iic_read(uint devaddr, u_char *buf, uint offset, uint count) +{ + volatile iic_t *iip; + volatile i2c8xx_t *i2c; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + volatile immap_t *immap; + u_char *tb; + uint dpaddr, temp; + + /* If the interface has not been initialized, do that now. + */ + if (!iic_init_done) + iic_init(); + + immap = (immap_t *)IMAP_ADDR; + cp = (cpm8xx_t *)&(immap->im_cpm); + + iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; + i2c = (i2c8xx_t *)&(immap->im_i2c); + + tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase]; + + /* Send a "dummy write" operation. This is a write request with + * only the offset sent, followed by another start condition. + * This will ensure we start reading from the first location + * of the EEPROM. + */ + tb = iitemp; + tb = (u_char *)(((uint)tb + 15) & ~15); + tbdf->cbd_bufaddr = tb; + *tb = devaddr & 0xfe; /* Device address */ + *(tb+1) = offset; /* Offset */ + tbdf->cbd_datlen = 2; /* Length */ + tbdf->cbd_sc = + BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 3) == 0); + + if (tbdf->cbd_sc & BD_SC_READY) + printf("IIC ra complete but tbuf ready\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#if 0 + /* We can't do this...there is no serial port yet! + */ + if (temp == 0) { + printf("Timeout reading EEPROM\n"); + return; + } +#endif +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; + + /* To read, we need an empty buffer of the proper length. + * All that is used is the first byte for address, the remainder + * is just used for timing (and doesn't really have to exist). + */ + tbdf->cbd_bufaddr = tb; + *tb = devaddr | 1; /* Device address */ + rbdf->cbd_bufaddr = (uint)buf; /* Desination buffer */ + tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1; /* Length */ + tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START; + rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + + /* Chip bug, set enable here. + */ + i2c->i2c_i2mod = 1; /* Enable */ + i2c->i2c_i2cer = 0xff; + i2c->i2c_i2com = 0x81; /* Start master */ + + /* Wait for IIC transfer. + */ +#if 0 + while ((i2c->i2c_i2cer & 1) == 0); + + if (rbdf->cbd_sc & BD_SC_EMPTY) + printf("IIC read complete but rbuf empty\n"); +#else + temp = 10000000; + while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0)) + temp--; +#endif + + /* Chip errata, clear enable. + */ + i2c->i2c_i2mod = 0; +} + +/* Because I didn't find anything that would do this....... +*/ +u_char +aschex_to_byte(u_char *cp) +{ + u_char byte, c; + + c = *cp++; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } + else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } + else { + c -= '0'; + } + + byte = c * 16; + + c = *cp; + + if ((c >= 'A') && (c <= 'F')) { + c -= 'A'; + c += 10; + } + else if ((c >= 'a') && (c <= 'f')) { + c -= 'a'; + c += 10; + } + else { + c -= '0'; + } + + byte += c; + + return(byte); +} diff --git a/arch/ppc/mbxboot/m8xx_tty.c b/arch/ppc/mbxboot/m8xx_tty.c new file mode 100644 index 000000000000..a591d824d6d3 --- /dev/null +++ b/arch/ppc/mbxboot/m8xx_tty.c @@ -0,0 +1,253 @@ + + +/* Minimal serial functions needed to send messages out the serial + * port on the MBX console. + * + * The MBX uxes SMC1 for the serial port. We reset the port and use + * only the first BD that EPPC-Bug set up as a character FIFO. + * + * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug + * use COM1 instead of SMC1 as the console port. This kinda sucks + * for the rest of the kernel, so here we force the use of SMC1 again. + */ +#include +#include +#include +#include +#include "../8xx_io/commproc.h" + +#ifdef CONFIG_MBX +#define MBX_CSR1 ((volatile u_char *)0xfa100000) +#define CSR1_COMEN (u_char)0x02 +#endif + +static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); + +void +serial_init(bd_t *bd) +{ + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile cbd_t *tbdf, *rbdf; + volatile cpm8xx_t *cp; + uint dpaddr, memaddr; + + cp = cpmp; + sp = (smc_t*)&(cp->cp_smc[0]); + up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC1]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + +#ifndef CONFIG_MBX + { + /* Initialize SMC1 and use it for the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. EPPC-Bug isn't + * running any more, so we can do this. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + */ + cp->cp_simode = 0x10000000; + cp->cp_brgc1 = + ((((bd->bi_intfreq * 1000000)/16) / bd->bi_baudrate) << 1) | CPM_BRG_EN; + +#else /* CONFIG_MBX */ + if (*MBX_CSR1 & CSR1_COMEN) { + /* COM1 is enabled. Initialize SMC1 and use it for + * the console port. + */ + + /* Enable SDMA. + */ + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + + /* Use Port B for SMCs instead of other functions. + */ + cp->cp_pbpar |= 0x00000cc0; + cp->cp_pbdir &= ~0x00000cc0; + cp->cp_pbodr &= ~0x00000cc0; + + /* Allocate space for two buffer descriptors in the DP ram. + * For now, this address seems OK, but it may have to + * change with newer versions of the firmware. + */ + dpaddr = 0x0800; + + /* Grab a few bytes from the top of memory. EPPC-Bug isn't + * running any more, so we can do this. + */ + memaddr = (bd->bi_memsize - 32) & ~15; + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr]; + rbdf->cbd_bufaddr = memaddr; + rbdf->cbd_sc = 0; + tbdf = rbdf + 1; + tbdf->cbd_bufaddr = memaddr+4; + tbdf->cbd_sc = 0; + + /* Set up the uart parameters in the parameter ram. + */ + up->smc_rbase = dpaddr; + up->smc_tbase = dpaddr+sizeof(cbd_t); + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Mask all interrupts and remove anything pending. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + + /* Set up the baud rate generator. + * See 8xx_io/commproc.c for details. + */ + cp->cp_simode = 0x10000000; + cp->cp_brgc1 = + ((((bd->bi_intfreq * 1000000)/16) / 9600) << 1) | CPM_BRG_EN; + + /* Enable SMC1 for console output. + */ + *MBX_CSR1 &= ~CSR1_COMEN; + } + else { +#endif /* ndef CONFIG_MBX */ + /* SMC1 is used as console port. + */ + tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; + rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase]; + + /* Issue a stop transmit, and wait for it. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, + CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + + /* Make the first buffer the only buffer. + */ + tbdf->cbd_sc |= BD_SC_WRAP; + rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP; + + /* Single character receive. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + + /* Initialize Tx/Rx parameters. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Enable transmitter/receiver. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +} + +void +serial_putchar(const char c) +{ + volatile cbd_t *tbdf; + volatile char *buf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; + tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase]; + + /* Wait for last character to go. + */ + buf = (char *)tbdf->cbd_bufaddr; + while (tbdf->cbd_sc & BD_SC_READY); + + *buf = c; + tbdf->cbd_datlen = 1; + tbdf->cbd_sc |= BD_SC_READY; +} + +char +serial_getc() +{ + volatile cbd_t *rbdf; + volatile char *buf; + volatile smc_uart_t *up; + char c; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + /* Wait for character to show up. + */ + buf = (char *)rbdf->cbd_bufaddr; + while (rbdf->cbd_sc & BD_SC_EMPTY); + c = *buf; + rbdf->cbd_sc |= BD_SC_EMPTY; + + return(c); +} + +int +serial_tstc() +{ + volatile cbd_t *rbdf; + volatile smc_uart_t *up; + + up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC1]; + rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase]; + + return(!(rbdf->cbd_sc & BD_SC_EMPTY)); +} diff --git a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c index 15bff41dd739..7ecf18512bb5 100644 --- a/arch/ppc/mbxboot/misc.c +++ b/arch/ppc/mbxboot/misc.c @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.1 1999/02/17 05:00:06 cort Exp $ + * $Id: misc.c,v 1.2 1999/09/14 05:55:29 dmalek Exp $ * * Adapted for PowerPC by Gary Thomas * @@ -17,11 +17,8 @@ #include #include #include -#ifdef CONFIG_MBX -#include -#endif -#ifdef CONFIG_FADS -#include +#ifdef CONFIG_8xx +#include #endif /* @@ -34,41 +31,37 @@ char *avail_ram; char *end_avail; -/* Because of the limited amount of memory on the MBX, it presents +/* See comment below..... +*/ +unsigned int initrd_offset, initrd_size; + +/* Because of the limited amount of memory on embedded, it presents * loading problems. The biggest is that we load this boot program * into a relatively low memory address, and the Linux kernel Bss often * extends into this space when it get loaded. When the kernel starts * and zeros the BSS space, it also writes over the information we * save here and pass to the kernel (command line and board info). - * On the MBX we grab some known memory holes to hold this information. + * On these boards, we grab some known memory holes to hold this information. */ -#if defined(CONFIG_SERIAL_CONSOLE) -char cmd_preset[] = "console=ttyS0,9600n8"; -#else -char cmd_preset[] = ""; -#endif char cmd_buf[256]; char *cmd_line = cmd_buf; -char *root_string = "root=/dev/nfs"; +char *root_string = "root=/dev/nfs rw"; char *nfsaddrs_string = "nfsaddrs="; char *nfsroot_string = "nfsroot="; char *defroot_string = "/sys/mbxroot"; +char *ramroot_string = "root=/dev/ram"; int do_ipaddrs(char **cmd_cp, int echo); void do_nfsroot(char **cmd_cp, char *dp); int strncmp(const char * cs,const char * ct,size_t count); char *strrchr(const char * s, int c); -RESIDUAL hold_resid_buf; -RESIDUAL *hold_residual = &hold_resid_buf; +bd_t hold_resid_buf; +bd_t *hold_residual = &hold_resid_buf; unsigned long initrd_start = 0, initrd_end = 0; char *zimage_start; int zimage_size; -char *vidmem = (char *)0xC00B8000; -int lines, cols; -int orig_x, orig_y; - void puts(const char *); void putc(const char c); void puthex(unsigned long val); @@ -88,7 +81,7 @@ void exit() while(1); } -/* The MBX is just the serial port. +/* The MPC8xx is just the serial port. */ tstc(void) { @@ -119,7 +112,6 @@ void puts(const char *s) } } - void * memcpy(void * __dest, __const void * __src, int __n) { @@ -231,45 +223,43 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) unsigned char sanity[0x2000]; unsigned long -decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual) +decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp) { int timer; extern unsigned long start; char *cp, ch; - unsigned long i, motorola_id = 0; - char needs_reloc = 0; - BATU *u; - BATL *l; + unsigned long i; char *dp; - lines = 25; - cols = 80; - orig_x = 0; - orig_y = 24; + /* These values must be variables. If not, the compiler optimizer + * will remove some code, causing the size of the code to vary + * when these values are zero. This is bad because we first + * compile with these zero to determine the size and offsets + * in an image, than compile again with these set to the proper + * discovered value.....Ya know, we used to read these from the + * header a long time ago..... + */ + initrd_offset = INITRD_OFFSET; + initrd_size = INITRD_SIZE; /* Grab some space for the command line and board info. Since * we no longer use the ELF header, but it was loaded, grab * that space. */ +#ifdef CONFIG_MBX cmd_line = (char *)(load_addr - 0x10000); - hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf)); +#else + cmd_line = (char *)(0x200000); +#endif + hold_residual = (bd_t *)(cmd_line + sizeof(cmd_buf)); /* copy board data */ - if (residual) - memcpy(hold_residual,residual,sizeof(bd_t)); + if (bp) + memcpy(hold_residual,bp,sizeof(bd_t)); - /* MBX/prep sometimes put the residual/board info at the end of mem - * assume 16M for now -- Cort - * To boot on standard MBX boards with 4M, we can't use initrd, - * and we have to assume less memory. -- Dan + /* Set end of memory available to us. It is always the highest + * memory address provided by the board information. */ - if ( INITRD_OFFSET ) - end_avail = (char *)0x01000000; - else - end_avail = (char *)0x00400000; - - /* let residual data tell us it's higher */ - if ( (unsigned long)residual > 0x00800000 ) - end_avail = (char *)PAGE_ALIGN((unsigned long)residual); + end_avail = (char *)(bp->bi_memsize); puts("loaded at: "); puthex(load_addr); puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n"); @@ -281,11 +271,11 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R puts("\n"); } - if ( residual ) + if ( bp ) { - puts("board data at: "); puthex((unsigned long)residual); + puts("board data at: "); puthex((unsigned long)bp); puts(" "); - puthex((unsigned long)((unsigned long)residual + sizeof(bd_t))); + puthex((unsigned long)((unsigned long)bp + sizeof(bd_t))); puts("\n"); puts("relocated to: "); puthex((unsigned long)hold_residual); @@ -299,11 +289,11 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET); zimage_size = ZIMAGE_SIZE; - if ( INITRD_OFFSET ) - initrd_start = load_addr - 0x10000 + INITRD_OFFSET; + if ( initrd_offset ) + initrd_start = load_addr - 0x10000 + initrd_offset; else initrd_start = 0; - initrd_end = INITRD_SIZE + initrd_start; + initrd_end = initrd_size + initrd_start; /* * setup avail_ram - this is the first part of ram usable @@ -321,66 +311,49 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R puts("zimage at: "); puthex((unsigned long)zimage_start); puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n"); /* - * don't relocate the zimage if it was loaded above 16M since - * things get weird if we try to relocate -- Cort - * We don't relocate zimage on a base MBX board because of - * insufficient memory. In this case we don't have initrd either, - * so use that as an indicator. -- Dan + * There is no reason (yet) to relocate zImage for embedded boards. + * To support boot from flash rom on 8xx embedded boards, I + * assume if zimage start is over 16M we are booting from flash. + * In this case, avilable ram will start just above the space we + * have allocated for the command buffer and board information. */ - - /* Determine if we have a Motorola board */ - needs_reloc = 0; - if ( (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start) - || needs_reloc) - { - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size), - (void *)zimage_start, zimage_size ); - zimage_start = (char *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size); - end_avail = (char *)zimage_start; - puts("relocated to: "); puthex((unsigned long)zimage_start); - puts(" "); - puthex((unsigned long)zimage_size+(unsigned long)zimage_start); - puts("\n"); - } + if ((unsigned long)zimage_start > 0x01000000) + avail_ram = (char *)PAGE_ALIGN((unsigned long)hold_residual + sizeof(bd_t)); /* relocate initrd */ if ( initrd_start ) { puts("initrd at: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); - /* - * Memory is really tight on the MBX (we can assume 4M) - * so put the initrd at the TOP of ram, and set end_avail - * to right after that. - * - * I should do something like this for prep, too and keep - * a variable end_of_DRAM to keep track of what we think the - * max ram is. - * -- Cort + + /* We only have to relocate initrd if we find it is in Flash + * rom. This is because the kernel thinks it can toss the + * pages into the free memory pool after it is done. Use + * the same 16M test. */ - if (needs_reloc) - { - memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+ - (unsigned long)end_avail-INITRD_SIZE), + if ((unsigned long)initrd_start > 0x01000000) { + memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), (void *)initrd_start, - INITRD_SIZE ); - initrd_start = PAGE_ALIGN(-PAGE_SIZE+ - (unsigned long)end_avail-INITRD_SIZE); - initrd_end = initrd_start + INITRD_SIZE; + initrd_size ); + initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE); + initrd_end = initrd_start + initrd_size; end_avail = (char *)initrd_start; puts("relocated to: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); } + else { + avail_ram = (char *)PAGE_ALIGN((unsigned long)initrd_end); + } } + puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); puthex((unsigned long)end_avail); puts("\n"); puts("\nLinux/PPC load: "); timer = 0; cp = cmd_line; - memcpy (cmd_line, cmd_preset, sizeof(cmd_preset)); - while ( *cp ) putc(*cp++); + while (timer++ < 5*1000) { if (tstc()) { while ((ch = getc()) != '\n' && ch != '\r') { @@ -389,11 +362,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R cp--; puts("\b \b"); } - } else if (ch == '?') { - if (!do_ipaddrs(&cp, 1)) { - *cp++ = ch; - putc(ch); - } } else { *cp++ = ch; putc(ch); @@ -404,40 +372,27 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R udelay(1000); /* 1 msec */ } *cp = 0; - /* The MBX does not currently have any default boot strategy. - * If the command line is not filled in, we will automatically - * create the default network boot. + + /* If the command line is not filled in, we will automatically + * create the default boot. */ if (cmd_line[0] == 0) { - dp = root_string; - while (*dp != 0) - *cp++ = *dp++; - *cp++ = ' '; - dp = nfsaddrs_string; + /* An initrd on these boards means we booted from Flash + * ROM and want to use the ramdisk as the root file system. + * Otherwise, we perform a diskless NFS boot. + */ + if (initrd_start) + dp = ramroot_string; + else + dp = root_string; while (*dp != 0) *cp++ = *dp++; - dp = cp; - do_ipaddrs(&cp, 0); - *cp++ = ' '; - - /* Add the server address to the root file system path. - */ - dp = strrchr(dp, ':'); - dp++; - do_nfsroot(&cp, dp); *cp = 0; } + puts("\n"); - /* mappings on early boot can only handle 16M */ - if ( (int)(cmd_line[0]) > (16<<20)) - puts("cmd_line located > 16M\n"); - if ( (int)hold_residual > (16<<20)) - puts("hold_residual located > 16M\n"); - if ( initrd_start > (16<<20)) - puts("initrd_start located > 16M\n"); - puts("Uncompressing Linux..."); gunzip(0, 0x400000, zimage_start, &zimage_size); @@ -446,148 +401,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R return (unsigned long)hold_residual; } -int -do_ipaddrs(char **cmd_cp, int echo) -{ - char *cp, *ip, ch; - unsigned char ipd; - int i, j, retval; - - /* We need to create the string: - * : - */ - cp = *cmd_cp; - retval = 0; - - if ((cp - 9) >= cmd_line) { - if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) { - ip = (char *)0xfa000060; - retval = 1; - for (j=0; j<2; j++) { - for (i=0; i<4; i++) { - ipd = *ip++; - - ch = ipd/100; - if (ch) { - ch += '0'; - if (echo) - putc(ch); - *cp++ = ch; - ipd -= 100 * (ch - '0'); - } - - ch = ipd/10; - if (ch) { - ch += '0'; - if (echo) - putc(ch); - *cp++ = ch; - ipd -= 10 * (ch - '0'); - } - - ch = ipd + '0'; - if (echo) - putc(ch); - *cp++ = ch; - - ch = '.'; - if (echo) - putc(ch); - *cp++ = ch; - } - - /* At the end of the string, remove the - * '.' and replace it with a ':'. - */ - *(cp - 1) = ':'; - if (echo) { - putc('\b'); putc(':'); - } - } - - /* At the end of the second string, remove the - * '.' from both the command line and the - * screen. - */ - --cp; - putc('\b'); putc(' '); putc('\b'); - } - } - *cmd_cp = cp; - return(retval); -} - -void -do_nfsroot(char **cmd_cp, char *dp) -{ - char *cp, *rp, *ep; - - /* The boot argument (i.e /sys/mbxroot/zImage) is stored - * at offset 0x0078 in NVRAM. We use this path name to - * construct the root file system path. - */ - cp = *cmd_cp; - - /* build command string. - */ - rp = nfsroot_string; - while (*rp != 0) - *cp++ = *rp++; - - /* Add the server address to the path. - */ - while (*dp != ' ') - *cp++ = *dp++; - *cp++ = ':'; - - rp = (char *)0xfa000078; - ep = strrchr(rp, '/'); - - if (ep != 0) { - while (rp < ep) - *cp++ = *rp++; - } - else { - rp = defroot_string; - while (*rp != 0) - *cp++ = *rp++; - } - - *cmd_cp = cp; -} - -size_t strlen(const char * s) -{ - const char *sc; - - for (sc = s; *sc != '\0'; ++sc) - /* nothing */; - return sc - s; -} - -int strncmp(const char * cs,const char * ct,size_t count) -{ - register signed char __res = 0; - - while (count) { - if ((__res = *cs - *ct++) != 0 || !*cs++) - break; - count--; - } - - return __res; -} - -char * strrchr(const char * s, int c) -{ - const char *p = s + strlen(s); - do { - if (*p == (char)c) - return (char *)p; - } while (--p >= s); - return NULL; -} - void puthex(unsigned long val) { unsigned char buf[10]; diff --git a/arch/ppc/mbxboot/pci.c b/arch/ppc/mbxboot/pci.c new file mode 100644 index 000000000000..72a8aa0e7c45 --- /dev/null +++ b/arch/ppc/mbxboot/pci.c @@ -0,0 +1,251 @@ +/* Stand alone funtions for QSpan Tundra support. + */ +#include +#include +#include + +/* To map PCI devices, you first write 0xffffffff into the device + * base address registers. When the register is read back, the + * number of most significant '1' bits describes the amount of address + * space needed for mapping. If the most significant bit is not set, + * either the device does not use that address register, or it has + * a fixed address that we can't change. After the address is assigned, + * the command register has to be written to enable the card. + */ +typedef struct { + u_char pci_bus; + u_char pci_devfn; + ushort pci_command; + uint pci_addrs[6]; +} pci_map_t; + +/* We should probably dynamically allocate these structures. +*/ +#define MAX_PCI_DEVS 32 +int pci_dev_cnt; +pci_map_t pci_map[MAX_PCI_DEVS]; + +void pci_conf_write(int bus, int device, int func, int reg, uint writeval); +void pci_conf_read(int bus, int device, int func, int reg, void *readval); +void probe_addresses(int bus, int devfn); +void map_pci_addrs(void); + +/* This is a really stripped version of PCI bus scan. All we are + * looking for are devices that exist. + */ +pci_scanner(int addr_probe) +{ + unsigned int devfn, l, max, class, bus_number; + unsigned char cmd, irq, tmp, hdr_type, is_multi; + int reg; + + is_multi = 0; + bus_number = 0; + for (devfn = 0; devfn < 0xff; ++devfn) { + /* The device numbers are comprised of upper 5 bits of + * device number and lower 3 bits of multi-function number. + */ + if ((devfn & 7) && !is_multi) { + /* Don't scan multifunction addresses if this is + * not a multifunction device. + */ + continue; + } + + /* Read the header to determine card type. + */ + qs_pci_read_config_byte(bus_number, devfn, PCI_HEADER_TYPE, + &hdr_type); + + /* If this is a base device number, check the header to + * determine if it is mulifunction. + */ + if ((devfn & 7) == 0) + is_multi = hdr_type & 0x80; + + /* Check to see if the board is really in the slot. + */ + qs_pci_read_config_dword(bus_number, devfn, PCI_VENDOR_ID, &l); + /* some broken boards return 0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || + l == 0xffff0000) { + /* Nothing there. + */ + is_multi = 0; + continue; + } + + /* If we are not performing an address probe, + * just simply print out some information. + */ + if (!addr_probe) { + qs_pci_read_config_dword(bus_number, devfn, + PCI_CLASS_REVISION, &class); + + class >>= 8; /* upper 3 bytes */ + +#if 0 + printf("Found (%3d:%d): vendor 0x%04x, device 0x%04x, class 0x%06x\n", + (devfn >> 3), (devfn & 7), + (l & 0xffff), (l >> 16) & 0xffff, class); +#else + puts("Found ("); puthex(devfn >> 3); + puts(":"); puthex(devfn & 7); + puts("): vendor "); puthex(l & 0xffff); + puts(", device "); puthex((l >> 16) & 0xffff); + puts(", class "); puthex(class); puts("\n"); +#endif + } + else { + /* If this is a "normal" device, build address list. + */ + if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) + probe_addresses(bus_number, devfn); + } + } + + /* Now map the boards. + */ + if (addr_probe) + map_pci_addrs(); +} + +/* Probe addresses for the specified device. This is a destructive + * operation because it writes the registers. + */ +void +probe_addresses(bus, devfn) +{ + int i; + uint pciaddr; + ushort pcicmd; + pci_map_t *pm; + + if (pci_dev_cnt >= MAX_PCI_DEVS) { + puts("Too many PCI devices\n"); + return; + } + + pm = &pci_map[pci_dev_cnt++]; + + pm->pci_bus = bus; + pm->pci_devfn = devfn; + + for (i=0; i<6; i++) { + qs_pci_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), -1); + qs_pci_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0 + (i * 4), + &pciaddr); + pm->pci_addrs[i] = pciaddr; + qs_pci_read_config_word(bus, devfn, PCI_COMMAND, &pcicmd); + pm->pci_command = pcicmd; + } +} + +/* Map the cards into the PCI space. The PCI has separate memory + * and I/O spaces. In addition, some memory devices require mapping + * below 1M. The least significant 4 bits of the address register + * provide information. If this is an I/O device, only the LS bit + * is used to indicate that, so I/O devices can be mapped to a two byte + * boundard. Memory addresses can be mapped to a 32 byte boundary. + * The QSpan implementations usually have a 1Gbyte space for each + * memory and I/O spaces. + * + * This isn't a terribly fancy algorithm. I just map the spaces from + * the top starting with the largest address space. When finished, + * the registers are written and the card enabled. + * + * While the Tundra can map a large address space on most boards, we + * need to be careful because it may overlap other devices (like IMMR). + */ +#define MEMORY_SPACE_SIZE 0x20000000 +#define IO_SPACE_SIZE 0x20000000 + +void +map_pci_addrs() +{ + uint pci_mem_top, pci_mem_low; + uint pci_io_top; + uint addr_mask, reg_addr, space; + int i, j; + pci_map_t *pm; + + pci_mem_top = MEMORY_SPACE_SIZE; + pci_io_top = IO_SPACE_SIZE; + pci_mem_low = (1 * 1024 * 1024); /* Below one meg addresses */ + + /* We can't map anything more than the maximum space, but test + * for it anyway to catch devices out of range. + */ + addr_mask = 0x80000000; + + do { + space = (~addr_mask) + 1; /* Size of the space */ + for (i=0; ipci_addrs[j]; + if ((reg_addr & 0x80000000) == 0) + continue; + if (reg_addr & PCI_BASE_ADDRESS_SPACE_IO) { + if ((reg_addr & PCI_BASE_ADDRESS_IO_MASK) != addr_mask) + continue; + if (pci_io_top < space) { + puts("Out of PCI I/O space\n"); + } + else { + pci_io_top -= space; + pm->pci_addrs[j] = pci_io_top; + pm->pci_command |= PCI_COMMAND_IO; + } + } + else { + if ((reg_addr & PCI_BASE_ADDRESS_MEM_MASK) != addr_mask) + continue; + + /* Memory space. Test if below 1M. + */ + if (reg_addr & PCI_BASE_ADDRESS_MEM_TYPE_1M) { + if (pci_mem_low < space) { + puts("Out of PCI 1M space\n"); + } + else { + pci_mem_low -= space; + pm->pci_addrs[j] = pci_mem_low; + } + } + else { + if (pci_mem_top < space) { + puts("Out of PCI Mem space\n"); + } + else { + pci_mem_top -= space; + pm->pci_addrs[j] = pci_mem_top; + } + } + pm->pci_command |= PCI_COMMAND_MEMORY; + } + } + } + addr_mask >>= 1; + addr_mask |= 0x80000000; + } while (addr_mask != 0xfffffffe); + + /* Now, run the list one more time and map everything. + */ + for (i=0; ipci_bus, pm->pci_devfn, + PCI_BASE_ADDRESS_0 + (j * 4), pm->pci_addrs[j]); + } + + /* Enable memory or address mapping. + */ + qs_pci_write_config_word(pm->pci_bus, pm->pci_devfn, PCI_COMMAND, + pm->pci_command); + } +} + diff --git a/arch/ppc/mbxboot/qspan_pci.c b/arch/ppc/mbxboot/qspan_pci.c new file mode 100644 index 000000000000..b4f332a9b7fa --- /dev/null +++ b/arch/ppc/mbxboot/qspan_pci.c @@ -0,0 +1,267 @@ +/* + * LinuxPPC arch/ppc/kernel/qspan_pci.c Dan Malek (dmalek@jlc.net) + * + * QSpan Motorola bus to PCI bridge. The config address register + * is located 0x500 from the base of the bridge control/status registers. + * The data register is located at 0x504. + * This is a two step operation. First, the address register is written, + * then the data register is read/written as required. + * I don't know what to do about interrupts (yet). + */ + +#include +#include +#include + +/* + * When reading the configuration space, if something does not respond + * the bus times out and we get a machine check interrupt. So, the + * good ol' exception tables come to mind to trap it and return some + * value. + * + * On an error we just return a -1, since that is what the caller wants + * returned if nothing is present. I copied this from __get_user_asm, + * with the only difference of returning -1 instead of EFAULT. + * There is an associated hack in the machine check trap code. + * + * The QSPAN is also a big endian device, that is it makes the PCI + * look big endian to us. This presents a problem for the Linux PCI + * functions, which assume little endian. For example, we see the + * first 32-bit word like this: + * ------------------------ + * | Device ID | Vendor ID | + * ------------------------ + * If we read/write as a double word, that's OK. But in our world, + * when read as a word, device ID is at location 0, not location 2 as + * the little endian PCI would believe. We have to switch bits in + * the PCI addresses given to us to get the data to/from the correct + * byte lanes. + * + * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5. + * It always forces the MS bit to zero. Therefore, dev_fn values + * greater than 128 are returned as "no device found" errors. + * + * The QSPAN can only perform long word (32-bit) configuration cycles. + * The "offset" must have the two LS bits set to zero. Read operations + * require we read the entire word and then sort out what should be + * returned. Write operations other than long word require that we + * read the long word, update the proper word or byte, then write the + * entire long word back. + * + * PCI Bridge hack. We assume (correctly) that bus 0 is the primary + * PCI bus from the QSPAN. If we are called with a bus number other + * than zero, we create a Type 1 configuration access that a downstream + * PCI bridge will interpret. + */ + +#define __get_pci_config(x, addr, op) \ + __asm__ __volatile__( \ + "1: "op" %0,0(%1)\n" \ + " eieio\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".text" \ + : "=r"(x) : "r"(addr)) + +#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500)) +#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504)) + +#define mk_config_addr(bus, dev, offset) \ + (((bus)<<16) | ((dev)<<8) | (offset & 0xfc)) + +#define mk_config_type1(bus, dev, offset) \ + mk_config_addr(bus, dev, offset) | 1; + +/* Initialize the QSpan device registers after power up. +*/ +qspan_init() +{ + uint *qptr; + + + + qptr = (uint *)PCI_CSR_ADDR; + + /* PCI Configuration/status. Upper bits written to clear + * pending interrupt or status. Lower bits enable QSPAN as + * PCI master, enable memory and I/O cycles, and enable PCI + * parity error checking. + * IMPORTANT: The last two bits of this word enable PCI + * master cycles into the QBus. The QSpan is broken and can't + * meet the timing specs of the PQ bus for this to work. Therefore, + * if you don't have external bus arbitration, you can't use + * this function. + */ +#ifdef EXTERNAL_PQ_ARB + qptr[1] = 0xf9000147; +#else + qptr[1] = 0xf9000144; +#endif + + /* PCI Misc configuration. Set PCI latency timer resolution + * of 8 cycles, set cache size to 4 x 32. + */ + qptr[3] = 0; + + /* Set up PCI Target address mapping. Enable, Posted writes, + * 2Gbyte space (processor memory controller determines actual size). + */ + qptr[64] = 0x8f000080; + + /* Map processor 0x80000000 to PCI 0x00000000. + * Processor address bit 1 determines I/O type access (0x80000000) + * or memory type access (0xc0000000). + */ + qptr[65] = 0x80000000; + + /* Enable error logging and clear any pending error status. + */ + qptr[80] = 0x90000000; + + qptr[512] = 0x000c0003; + + /* Set up Qbus slave image. + */ + qptr[960] = 0x01000000; + qptr[961] = 0x000000d1; + qptr[964] = 0x00000000; + qptr[965] = 0x000000d1; + +} + +/* Functions to support PCI bios-like features to read/write configuration + * space. If the function fails for any reason, a -1 (0xffffffff) value + * must be returned. + */ +#define DEVICE_NOT_FOUND (-1) +#define SUCCESSFUL 0 + +int qs_pci_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + uint temp; + u_char *cp; + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xff; + return DEVICE_NOT_FOUND; + } + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *val = *cp; + return SUCCESSFUL; +} + +int qs_pci_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + uint temp; + ushort *sp; + + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffff; + return DEVICE_NOT_FOUND; + } + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(temp, QS_CONFIG_DATA, "lwz"); + offset ^= 0x02; + + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *val = *sp; + return SUCCESSFUL; +} + +int qs_pci_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + if ((bus > 7) || (dev_fn > 127)) { + *val = 0xffffffff; + return DEVICE_NOT_FOUND; + } + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + __get_pci_config(*val, QS_CONFIG_DATA, "lwz"); + return SUCCESSFUL; +} + +int qs_pci_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + uint temp; + u_char *cp; + + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + qs_pci_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x03; + cp = ((u_char *)&temp) + (offset & 0x03); + *cp = val; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + + return SUCCESSFUL; +} + +int qs_pci_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + uint temp; + ushort *sp; + + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + qs_pci_read_config_dword(bus, dev_fn, offset, &temp); + + offset ^= 0x02; + sp = ((ushort *)&temp) + ((offset >> 1) & 1); + *sp = val; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *QS_CONFIG_DATA = temp; + + return SUCCESSFUL; +} + +int qs_pci_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + if ((bus > 7) || (dev_fn > 127)) + return DEVICE_NOT_FOUND; + + if (bus == 0) + *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset); + else + *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset); + *(unsigned int *)QS_CONFIG_DATA = val; + + return SUCCESSFUL; +} + diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 5240875413bc..aa4f97acd0cd 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -181,38 +181,6 @@ bad_page_fault(struct pt_regs *regs, unsigned long address) } #ifdef CONFIG_8xx -/* - * I need a va to pte function for the MPC8xx so I can set the cache - * attributes on individual pages used by the Communication Processor - * Module. - */ -pte_t *va_to_pte(struct task_struct *tsk, unsigned long address) -{ - pgd_t *dir; - pmd_t *pmd; - pte_t *pte; - - dir = pgd_offset(tsk->mm, address & PAGE_MASK); - if (dir) - { - pmd = pmd_offset(dir, address & PAGE_MASK); - if (pmd && pmd_present(*pmd)) - { - pte = pte_offset(pmd, address & PAGE_MASK); - if (pte && pte_present(*pte)) - { - return(pte); - } - } else - { - return (0); - } - } else - { - return (0); - } - return (0); -} unsigned long va_to_phys(unsigned long address) { diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 20296b4e2921..e407ab4c3557 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.183 1999/09/05 19:29:44 cort Exp $ + * $Id: init.c,v 1.188 1999/09/18 18:40:44 dmalek Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -73,7 +73,7 @@ unsigned long ioremap_base; unsigned long ioremap_bot; unsigned long avail_start; extern int num_memory; -extern struct mem_info memory[NUM_MEMINFO]; +extern struct mem_info memory[]; extern boot_infos_t *boot_infos; #ifndef __SMP__ struct pgtable_cache_struct quicklists; @@ -86,9 +86,9 @@ 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_MBX -unsigned long *mbx_find_end_of_memory(void); -#endif /* CONFIG_MBX */ +#ifdef CONFIG_8xx +unsigned long *m8xx_find_end_of_memory(void); +#endif /* CONFIG_8xx */ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); extern void die_if_kernel(char *,struct pt_regs *,long); @@ -997,9 +997,6 @@ void __init free_initmem(void) */ void __init MMU_init(void) { -#ifdef __SMP__ - if ( first_cpu_booted ) return; -#endif /* __SMP__ */ if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); #ifndef CONFIG_8xx if (have_of) @@ -1054,9 +1051,6 @@ void __init MMU_init(void) setbat(0, 0xfff00000, 0xfff00000, 0x00020000, RAM_PAGE); /* Map chip and ZorroII memory */ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE); - /* Note: a temporary hack in arch/ppc/amiga/setup.c - (kernel_map) remaps individual IO regions to - 0x90000000. */ break; case _MACH_gemini: setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE); @@ -1065,9 +1059,9 @@ void __init MMU_init(void) } ioremap_bot = ioremap_base; #else /* CONFIG_8xx */ -#ifdef CONFIG_MBX - end_of_DRAM = mbx_find_end_of_memory(); -#endif /* CONFIG_MBX */ + + end_of_DRAM = m8xx_find_end_of_memory(); + /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); @@ -1076,13 +1070,25 @@ void __init MMU_init(void) * All of this fits into the same 4Mbyte region, so it only * requires one page table page. */ + ioremap(IMAP_ADDR, IMAP_SIZE); +#ifdef CONFIG_MBX ioremap(NVRAM_ADDR, NVRAM_SIZE); ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE); - ioremap(IMAP_ADDR, IMAP_SIZE); ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); - /* ide needs to be able to get at PCI space -- Cort */ - ioremap(0x80000000, 0x4000); - ioremap(0x81000000, 0x4000); + + /* Map some of the PCI/ISA I/O space to get the IDE interface. + */ + ioremap(PCI_ISA_IO_ADDR, 0x4000); + ioremap(PCI_IDE_ADDR, 0x4000); +#endif +#ifdef CONFIG_RPXLITE + ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); + ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE); +#endif +#ifdef CONFIG_RPXCLASSIC + ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE); + ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE); +#endif #endif /* CONFIG_8xx */ if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); } @@ -1231,55 +1237,8 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem) mem_init_done = 1; } -#ifdef CONFIG_MBX -/* - * This is a big hack right now, but it may turn into something real - * someday. - * - * For the MBX860 (at this time anyway), there is nothing to initialize - * associated the PROM. Rather than include all of the prom.c - * functions in the image just to get prom_init, all we really need right - * now is the initialization of the physical memory region. - */ -unsigned long __init *mbx_find_end_of_memory(void) -{ - unsigned long kstart, ksize; - bd_t *binfo; - volatile memctl8xx_t *mcp; - unsigned long *ret; - - binfo = (bd_t *)res; - - /* - * The MBX does weird things with the mmaps for ram. - * If there's no DIMM, it puts the onboard DRAM at - * 0, if there is a DIMM it sticks it at 0 and puts - * the DRAM at the end of the DIMM. - * - * In fact, it might be the best idea to just read the DRAM - * config registers and set the mem areas accordingly. - */ - mcp = (memctl8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_memctl)); - append_mem_piece(&phys_mem, 0, binfo->bi_memsize); -#if 0 - phys_mem.regions[0].address = 0; - phys_mem.regions[0].size = binfo->bi_memsize; - phys_mem.n_regions = 1; -#endif - - ret = __va(phys_mem.regions[0].address+ - phys_mem.regions[0].size); - - phys_avail = phys_mem; - - kstart = __pa(_stext); /* should be 0 */ - ksize = PAGE_ALIGN(_end - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 0); - return ret; -} -#endif /* CONFIG_MBX */ - #ifndef CONFIG_8xx +#if defined(CONFIG_PMAC) || defined(CONFIG_PPC_ALL) /* * On systems with Open Firmware, collect information about * physical RAM and which pieces are already in use. @@ -1372,7 +1331,9 @@ unsigned long __init *pmac_find_end_of_memory(void) #undef RAM_LIMIT return __va(total); } +#endif /* defined(CONFIG_PMAC) || defined(CONFIG_PPC_ALL) */ +#if defined(CONFIG_PREP) || defined(CONFIG_PPC_ALL) /* * This finds the amount of physical ram and does necessary * setup for prep. This is pretty architecture specific so @@ -1404,7 +1365,10 @@ unsigned long __init *prep_find_end_of_memory(void) return (__va(total)); } +#endif /* defined(CONFIG_PREP) || defined(CONFIG_PPC_ALL) */ + +#if defined(CONFIG_GEMINI) || defined(CONFIG_PPC_ALL) unsigned long __init *gemini_find_end_of_memory(void) { unsigned long total, kstart, ksize, *ret; @@ -1425,6 +1389,7 @@ unsigned long __init *gemini_find_end_of_memory(void) remove_mem_piece( &phys_avail, kstart, ksize, 0 ); return ret; } +#endif /* defined(CONFIG_GEMINI) || defined(CONFIG_PPC_ALL) */ #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) @@ -1602,4 +1567,37 @@ static void __init hash_init(void) } if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205); } +#else /* CONFIG_8xx */ +/* + * This is a big hack right now, but it may turn into something real + * someday. + * + * For the 8xx boards (at this time anyway), there is nothing to initialize + * associated the PROM. Rather than include all of the prom.c + * functions in the image just to get prom_init, all we really need right + * now is the initialization of the physical memory region. + */ +unsigned long __init *m8xx_find_end_of_memory(void) +{ + unsigned long kstart, ksize; + bd_t *binfo; + unsigned long *ret; + extern unsigned char __res[]; + + binfo = (bd_t *)__res; + + 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); + + phys_avail = phys_mem; + + kstart = __pa(_stext); /* should be 0 */ + ksize = PAGE_ALIGN(_end - _stext); + remove_mem_piece(&phys_avail, kstart, ksize, 0); + return ret; +} #endif /* ndef CONFIG_8xx */ diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds index c1b89ef9812e..707c4ad2febf 100644 --- a/arch/ppc/vmlinux.lds +++ b/arch/ppc/vmlinux.lds @@ -88,6 +88,7 @@ SECTIONS __initcall_end = .; . = ALIGN(4096); __init_end = .; + . = ALIGN(4096); __pmac_begin = .; .text.pmac : { *(.text.pmac) } @@ -109,6 +110,13 @@ SECTIONS . = ALIGN(4096); __apus_end = .; + . = ALIGN(4096); + __apus_begin = .; + .text.apus : { *(.text.apus) } + .data.apus : { *(.data.apus) } + . = ALIGN(4096); + __apus_end = .; + . = ALIGN(4096); __openfirmware_begin = .; .text.openfirmware : { *(.text.openfirmware) } diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index 300659d98128..1b0fffd7128c 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -1,19 +1,26 @@ /* * Copyright (C) 1996 Paul Mackerras. */ +#include #include #include #include #include #include -#include +#include +#include #include +#include static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); +extern void map_bootx_text(void); +extern void drawchar(char); +extern void drawstring(const char *str); -static int console = 1; +static int console = 0; +static int use_screen = 0; void buf_access(void) { @@ -29,10 +36,21 @@ xmon_map_scc(void) if ( _machine == _MACH_Pmac ) { struct device_node *np; + extern boot_infos_t *boot_infos; + unsigned long addr; + +#ifdef CONFIG_BOOTX_TEXT + if (boot_infos != 0 && find_via_pmu()) { + printk(KERN_INFO "xmon uses screen and keyboard\n"); + use_screen = 1; + map_bootx_text(); + return; + } +#endif #ifdef CHRP_ESCC - unsigned long addr = 0xc1013020; + addr = 0xc1013020; #else - unsigned long addr = 0xf3013020; + addr = 0xf3013020; #endif TXRDY = 4; RXRDY = 1; @@ -73,11 +91,19 @@ xmon_write(void *handle, void *ptr, int nb) char *p = ptr; int i, ct; +#ifdef CONFIG_BOOTX_TEXT + if (use_screen) { + /* write it on the screen */ + for (i = 0; i < nb; ++i) + drawchar(*p++); + return nb; + } +#endif if (!scc_initialized) xmon_init_scc(); for (i = 0; i < nb; ++i) { while ((*sccc & TXRDY) == 0) - if (adb_hardware == ADB_VIAPMU) + if (sys_ctrler == SYS_CTRLER_PMU) pmu_poll(); buf_access(); if ( console && (*p != '\r')) @@ -92,17 +118,85 @@ xmon_write(void *handle, void *ptr, int nb) return i; } +int xmon_wants_key; +int xmon_pmu_keycode; + +#ifdef CONFIG_BOOTX_TEXT +static int xmon_pmu_shiftstate; + +static unsigned char xmon_keytab[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80o]" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static unsigned char xmon_shift_keytab[128] = + "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ + "YT!@#$^%+(&=*)}O" /* 0x10 - 0x1f */ + "U{IP\rLJ\"K:|" /* 0x20 - 0x2f */ + "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ + "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ + "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ + +static int +xmon_get_pmu_key(void) +{ + int k, t, on; + + xmon_wants_key = 1; + for (;;) { + xmon_pmu_keycode = -1; + t = 0; + on = 0; + do { + if (--t < 0) { + on = 1 - on; + drawchar(on? 0xdb: 0x20); + drawchar('\b'); + t = 200000; + } + pmu_poll(); + } while (xmon_pmu_keycode == -1); + k = xmon_pmu_keycode; + if (on) + drawstring(" \b"); + + /* test for shift keys */ + if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { + xmon_pmu_shiftstate = (k & 0x80) == 0; + continue; + } + if (k >= 0x80) + continue; /* ignore up transitions */ + k = (xmon_pmu_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; + if (k != 0) + break; + } + xmon_wants_key = 0; + return k; +} +#endif /* CONFIG_BOOTX_TEXT */ + int xmon_read(void *handle, void *ptr, int nb) { char *p = ptr; int i; +#ifdef CONFIG_BOOTX_TEXT + if (use_screen) { + for (i = 0; i < nb; ++i) + *p++ = xmon_get_pmu_key(); + return i; + } +#endif if (!scc_initialized) xmon_init_scc(); for (i = 0; i < nb; ++i) { while ((*sccc & RXRDY) == 0) - if (adb_hardware == ADB_VIAPMU) + if (sys_ctrler == SYS_CTRLER_PMU) pmu_poll(); buf_access(); #if 0 diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index cf8af1a7855c..ee4d1bb99690 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -146,14 +146,10 @@ if [ "$CONFIG_SCSI" != "n" ]; then if [ "$CONFIG_PCI" != "n" ]; then dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then - bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y - bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N - if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then - int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 - fi - bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N + bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8 bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N - int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15 + int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 fi dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 53a69e509380..10d9ccd811b0 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -207,10 +207,9 @@ CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_SUNESP=y CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set -# CONFIG_OVERRIDE_CMDS is not set -# CONFIG_AIC7XXX_PAGE_ENABLE is not set -# CONFIG_AIC7XXX_PROC_STATS is not set +# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set +# CONFIG_CMDS_PER_DEVICE is not set +CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=5 CONFIG_SCSI_NCR53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 1776e6d7e43d..c9e3681dd043 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -202,11 +202,6 @@ void pcibios_fixup_bus(struct pci_bus *pbus) { } -int pcibios_assign_resource(struct pci_dev *pdev, int resource) -{ - return 0; -} - char * __init pcibios_setup(char *str) { if (!strcmp(str, "onboardfirst")) { diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in index af401ed29ea5..c0112f839cd2 100644 --- a/drivers/atm/Config.in +++ b/drivers/atm/Config.in @@ -4,44 +4,44 @@ mainmenu_option next_comment comment 'ATM drivers' if [ "$CONFIG_INET" = "y" ]; then - tristate 'ATM over TCP' CONFIG_ATM_TCP y + tristate 'ATM over TCP' CONFIG_ATM_TCP fi if [ "$CONFIG_PCI" = "y" ]; then - tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI y - if [ ! "$CONFIG_ATM_ENI" = "n" ]; then - bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG n - bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST n - if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then - bool ' Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W n - bool ' Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W y - bool ' Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W n - bool ' Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W n - bool ' Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W n - bool ' Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W n - bool ' Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W y - bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W n - fi - fi - tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM y - if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then - bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG n - bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS y - fi -# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y -# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then -# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n -# fi - tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR - if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then - bool ' Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI - fi - tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR - if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then - bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG - fi - tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON y - if [ "$CONFIG_ATM_HORIZON" != "n" ]; then - bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG - fi + tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI + if [ ! "$CONFIG_ATM_ENI" = "n" ]; then + bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG + bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST + if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then + bool ' Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W + bool ' Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W + bool ' Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W + bool ' Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W + bool ' Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W + bool ' Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W + bool ' Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W + bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W + fi + fi + tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM + if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then + bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG + bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS + fi +# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y +# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then +# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n +# fi + tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR + if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then + bool ' Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI + fi + tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR + if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then + bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG + fi + tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON + if [ "$CONFIG_ATM_HORIZON" != "n" ]; then + bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG + fi fi endmenu diff --git a/drivers/char/defkeymap.c b/drivers/char/defkeymap.c index 42fae3568711..d8ac176c251d 100644 --- a/drivers/char/defkeymap.c +++ b/drivers/char/defkeymap.c @@ -233,7 +233,6 @@ struct kbdiacr accent_table[MAX_DIACR] = { {'A', 'A', '\305'}, {'a', 'a', '\345'}, {'A', 'E', '\306'}, {'a', 'e', '\346'}, {',', 'C', '\307'}, {',', 'c', '\347'}, - {'\'', 'C', '\307'}, {'\'', 'c', '\347'}, {'`', 'E', '\310'}, {'`', 'e', '\350'}, {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, {'^', 'E', '\312'}, {'^', 'e', '\352'}, @@ -260,4 +259,4 @@ struct kbdiacr accent_table[MAX_DIACR] = { {'s', 'z', '\337'}, {'i', 'j', '\377'}, }; -unsigned int accent_table_size = 70; +unsigned int accent_table_size = 68; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index ff3158e96c96..42ea12a2c736 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -50,7 +50,7 @@ extern void prom_con_init(void); #ifdef CONFIG_MDA_CONSOLE extern void mda_console_init(void); #endif -#if defined(CONFIG_PPC) || defined(CONFIG_MAC) +#if defined(CONFIG_ADB) extern void adbdev_init(void); #endif #ifdef CONFIG_USB @@ -667,7 +667,7 @@ int __init chr_dev_init(void) #ifdef CONFIG_VIDEO_BT848 i2c_init(); #endif -#if defined(CONFIG_PPC) || defined(CONFIG_MAC) +#if defined(CONFIG_ADB) adbdev_init(); #endif #ifdef CONFIG_VIDEO_DEV diff --git a/drivers/char/pms.c b/drivers/char/pms.c index 72653aa1975e..02212033a3bc 100644 --- a/drivers/char/pms.c +++ b/drivers/char/pms.c @@ -1024,21 +1024,11 @@ static int init_mediavision(void) return 0; } -static void shutdown_mediavision(void) -{ - release_region(io_port,3); - release_region(0x9A01, 1); -} - /* - * Module stuff + * Initialization and module stuff */ -#ifdef MODULE -int init_module(void) -#else -int init_pms_cards(struct video_init *v) -#endif +static int __init init_pms_cards(void) { printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n"); @@ -1057,15 +1047,21 @@ int init_pms_cards(struct video_init *v) return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER); } -#ifdef MODULE - MODULE_PARM(io_port,"i"); MODULE_PARM(mem_base,"i"); -void cleanup_module(void) +static void __exit shutdown_mediavision(void) +{ + release_region(io_port,3); + release_region(0x9A01, 1); +} + +static void __exit cleanup_pms_module(void) { shutdown_mediavision(); video_unregister_device((struct video_device *)&pms_device); } -#endif +module_init(init_pms_cards); +module_exit(cleanup_pms_module); + diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 9a5759fefecf..dc14d2ce67a6 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -13,13 +13,11 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) L_TARGET := macintosh.a +L_OBJS := M_OBJS := -ifndef CONFIG_MBX -L_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o -endif -ifeq ($(CONFIG_MAC_KEYBOARD),y) -LX_OBJS := adb.o +ifeq ($(CONFIG_PMAC_PBOOK),y) + L_OBJS += mediabay.o endif ifeq ($(CONFIG_MAC_SERIAL),y) @@ -38,8 +36,36 @@ else endif endif -ifdef CONFIG_MAC_KEYBOARD -L_OBJS += mac_keyb.o +ifdef CONFIG_ADB + LX_OBJS := adb.o +endif + +ifdef CONFIG_ADB_KEYBOARD + L_OBJS += mac_keyb.o +endif + +ifdef CONFIG_ADB_MACII + L_OBJS += via-macii.o +endif + +ifdef CONFIG_ADB_MACIISI + L_OBJS += via-maciisi.o +endif + +ifdef CONFIG_ADB_CUDA + L_OBJS += via-cuda.o +endif + +ifdef CONFIG_ADB_IOP + L_OBJS += adb-iop.o +endif + +ifdef CONFIG_ADB_PMU + L_OBJS += via-pmu.o +endif + +ifdef CONFIG_ADB_MACIO + L_OBJS += macio-adb.o endif include $(TOPDIR)/Rules.make diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index be5c45a6ca87..73a53a6f43ca 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -24,29 +24,59 @@ #include #include #include +#include +#include +#include +#include #include -#include -#include -#include -#include +#include #include +#ifdef CONFIG_PPC +#include #include -#include +#endif EXPORT_SYMBOL(adb_controller); EXPORT_SYMBOL(adb_client_list); -EXPORT_SYMBOL(adb_hardware); -struct adb_controller *adb_controller = NULL; +extern struct adb_driver via_macii_driver; +extern struct adb_driver via_maciisi_driver; +extern struct adb_driver via_cuda_driver; +extern struct adb_driver adb_iop_driver; +extern struct adb_driver via_pmu_driver; +extern struct adb_driver macio_adb_driver; + +static struct adb_driver *adb_driver_list[] = { +#ifdef CONFIG_ADB_MACII + &via_macii_driver, +#endif +#ifdef CONFIG_ADB_MACIISI + &via_maciisi_driver, +#endif +#ifdef CONFIG_ADB_CUDA + &via_cuda_driver, +#endif +#ifdef CONFIG_ADB_IOP + &adb_iop_driver, +#endif +#ifdef CONFIG_ADB_PMU + &via_pmu_driver, +#endif +#ifdef CONFIG_ADB_MACIO + &macio_adb_driver, +#endif + NULL +}; + +struct adb_driver *adb_controller; struct notifier_block *adb_client_list = NULL; -enum adb_hw adb_hardware = ADB_NONE; +static int adb_got_sleep = 0; #ifdef CONFIG_PMAC_PBOOK -static int adb_notify_sleep(struct notifier_block *, unsigned long, void *); -static struct notifier_block adb_sleep_notifier = { +static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier adb_sleep_notifier = { adb_notify_sleep, - NULL, - 0 + SLEEP_LEVEL_ADB, }; #endif @@ -108,6 +138,15 @@ static int adb_scan_bus(void) */ adb_request(&req, NULL, ADBREQ_SYNC, 3, (i<< 4) | 0xb, (highFree | 0x60), 0xfe); + /* + * See if anybody actually moved. This is suggested + * by HW TechNote 01: + * + * http://developer.apple.com/technotes/hw/hw_01.html + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + (highFree << 4) | 0xf); + if (req.reply_len <= 1) continue; /* * Test whether there are any device(s) left * at address i. @@ -159,49 +198,73 @@ static int adb_scan_bus(void) return devmask; } -void adb_init(void) +int __init adb_init(void) { + struct adb_driver *driver; + int i; + +#ifdef CONFIG_PPC if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return 0; +#endif +#ifdef CONFIG_MAC + if (!MACH_IS_MAC) + return 0; +#endif - via_cuda_init(); - via_pmu_init(); - macio_adb_init(); - - if (adb_controller == NULL) + adb_controller = NULL; + + i = 0; + while ((driver = adb_driver_list[i++]) != NULL) { + if (!driver->probe()) { + adb_controller = driver; + break; + } + } + if ((adb_controller == NULL) || adb_controller->init()) { printk(KERN_WARNING "Warning: no ADB interface detected\n"); - else - { - adb_hardware = adb_controller->kind; + } else { #ifdef CONFIG_PMAC_PBOOK - notifier_chain_register(&sleep_notifier_list, - &adb_sleep_notifier); + pmu_register_sleep_notifier(&adb_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ adb_reset_bus(); } + return 0; } +__initcall(adb_init); #ifdef CONFIG_PMAC_PBOOK /* * notify clients before sleep and reset bus afterwards */ int -adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x) +adb_notify_sleep(struct pmu_sleep_notifier *self, int when) { int ret; - switch (code) { - case PBOOK_SLEEP: - ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); - if (ret & NOTIFY_STOP_MASK) - return -EBUSY; - case PBOOK_WAKE: + switch (when) { + case PBOOK_SLEEP_REQUEST: + adb_got_sleep = 1; + ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); + if (ret & NOTIFY_STOP_MASK) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + if (adb_got_sleep) { + adb_got_sleep = 0; adb_reset_bus(); - break; + } + break; + + case PBOOK_SLEEP_NOW: + break; + case PBOOK_WAKE: + adb_reset_bus(); + break; } - return NOTIFY_DONE; + return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ @@ -277,6 +340,9 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *), req->data[i+1] = va_arg(list, int); va_end(list); + if (flags & ADBREQ_NOSEND) + return 0; + return adb_controller->send_request(req, flags & ADBREQ_SYNC); } @@ -413,7 +479,7 @@ static int adb_open(struct inode *inode, struct file *file) { struct adbdev_state *state; - if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/) + if (MINOR(inode->i_rdev) > 0 || adb_controller == NULL) return -ENXIO; state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); if (state == 0) @@ -540,6 +606,7 @@ static ssize_t adb_write(struct file *file, const char *buf, goto out; atomic_inc(&state->n_pending); + if (adb_controller == NULL) return -ENXIO; /* Special case for ADB_BUSRESET request, all others are sent to the controller */ @@ -582,8 +649,15 @@ static struct file_operations adb_fops = { void adbdev_init() { +#ifdef CONFIG_PPC if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return; +#endif +#ifdef CONFIG_MAC + if (!MACH_IS_MAC) + return; +#endif + if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); } diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index 76c118474679..93be8f08f55f 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -39,12 +39,13 @@ #include #include #include +#include #include -#include -#include -#include +#include +#include +#include #include #include @@ -239,7 +240,7 @@ static void init_trackball(int id); static void init_turbomouse(int id); static void init_microspeed(int id); -#ifdef CONFIG_ADBMOUSE +#ifdef CONFIG_ADB_MOUSE /* XXX: Hook for mouse driver */ void (*adb_mouse_interrupt_hook)(unsigned char *, int); int adb_emulate_buttons = 0; @@ -250,6 +251,7 @@ int adb_button3_keycode = 0x7c; /* right option key */ extern int console_loglevel; extern struct kbd_struct kbd_table[]; +extern wait_queue_head_t keypress_wait; extern void handle_scancode(unsigned char, int); @@ -334,7 +336,7 @@ input_keycode(int keycode, int repeat) if (!repeat) del_timer(&repeat_timer); -#ifdef CONFIG_ADBMOUSE +#ifdef CONFIG_ADB_MOUSE /* * XXX: Add mouse button 2+3 fake codes here if mouse open. * Keep track of 'button' states here as we only send @@ -364,7 +366,7 @@ input_keycode(int keycode, int repeat) } return; } -#endif /* CONFIG_ADBMOUSE */ +#endif /* CONFIG_ADB_MOUSE */ if (kbd->kbdmode != VC_RAW) { if (!up_flag && !dont_repeat[keycode]) { @@ -420,7 +422,7 @@ static void mac_put_queue(int ch) } } -#ifdef CONFIG_ADBMOUSE +#ifdef CONFIG_ADB_MOUSE static void mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { @@ -552,7 +554,7 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) } } } -#endif /* CONFIG_ADBMOUSE */ +#endif /* CONFIG_ADB_MOUSE */ /* XXX Needs to get rid of this, see comments in pmu.c */ extern int backlight_level; @@ -566,7 +568,11 @@ buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) */ /* Ignore data from register other than 0 */ +#if 0 if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2)) +#else + if ((data[0] & 0x3) || (nb < 2)) +#endif return; switch (data[1]&0xf ) @@ -592,22 +598,26 @@ buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) /* brightness decrease */ case 0xa: /* down event */ +#ifdef CONFIG_PPC if ( data[1] == (data[1]&0xf) ) { if (backlight_level > 2) pmu_set_brightness(backlight_level-2); else pmu_set_brightness(0); } +#endif break; /* brightness increase */ case 0x9: /* down event */ +#ifdef CONFIG_PPC if ( data[1] == (data[1]&0xf) ) { if (backlight_level < 0x1e) pmu_set_brightness(backlight_level+2); else pmu_set_brightness(0x1f); } +#endif break; } } @@ -672,8 +682,14 @@ static void leds_done(struct adb_request *req) void __init mackbd_init_hw(void) { +#ifdef CONFIG_PPC if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return; +#endif +#ifdef CONFIG_MAC + if (!MACH_IS_MAC) + return; +#endif /* setup key map */ memcpy(key_maps[0], macplain_map, sizeof(plain_map)); @@ -684,7 +700,7 @@ void __init mackbd_init_hw(void) memcpy(key_maps[8], macalt_map, sizeof(plain_map)); memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map)); -#ifdef CONFIG_ADBMOUSE +#ifdef CONFIG_ADB_MOUSE /* initialize mouse interrupt hook */ adb_mouse_interrupt_hook = NULL; #endif @@ -720,9 +736,9 @@ mackeyb_probe(void) struct adb_request req; int i; -#ifdef CONFIG_ADBMOUSE +#ifdef CONFIG_ADB_MOUSE adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input); -#endif /* CONFIG_ADBMOUSE */ +#endif /* CONFIG_ADB_MOUSE */ adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input); adb_register(0x07, 0x1F, &buttons_ids, buttons_input); diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 2a9fc5ad8d02..52fc92198adc 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -59,28 +59,38 @@ static volatile struct adb_regs *adb; static struct adb_request *current_req, *last_req; static unsigned char adb_rbuf[16]; +static int macio_probe(void); +static int macio_init(void); static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs); -static int macio_adb_send_request(struct adb_request *req, int sync); +static int macio_send_request(struct adb_request *req, int sync); static int macio_adb_autopoll(int devs); static void macio_adb_poll(void); static int macio_adb_reset_bus(void); static void completed(void); -static struct adb_controller macio_controller = { - ADB_MACIO, - macio_adb_send_request, +struct adb_driver macio_adb_driver = { + "MACIO", + macio_probe, + macio_init, + macio_send_request, + /*macio_write,*/ macio_adb_autopoll, - macio_adb_reset_bus, - macio_adb_poll + macio_adb_poll, + macio_adb_reset_bus }; -void macio_adb_init(void) +int macio_probe(void) +{ + return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV; +} + +int macio_init(void) { struct device_node *adbs; adbs = find_compatible_devices("adb", "chrp,adb0"); if (adbs == 0) - return; + return -ENXIO; #if 0 { int i; @@ -101,7 +111,7 @@ void macio_adb_init(void) 0, "ADB", (void *)0)) { printk(KERN_ERR "ADB: can't get irq %d\n", adbs->intrs[0].line); - return; + return -EAGAIN; } out_8(&adb->ctrl.r, 0); @@ -112,12 +122,7 @@ void macio_adb_init(void) out_8(&adb->autopoll.r, APE); out_8(&adb->intr_enb.r, DFB | TAG); - adb_controller = &macio_controller; -// adb_hardware = ADB_MACIO; - -// adb_send_request = macio_adb_send_request; -// adb_autopoll = macio_adb_autopoll; -// adb_reset_bus = macio_reset_bus; + return 0; } static int macio_adb_autopoll(int devs) @@ -143,7 +148,7 @@ static int macio_adb_reset_bus(void) } /* Send an ADB command */ -static int macio_adb_send_request(struct adb_request *req, int sync) +static int macio_send_request(struct adb_request *req, int sync) { unsigned long mflags; int i; diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 93fe07774b06..53590a42a4bd 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -36,14 +36,22 @@ #include #include #include -#include -#include +#include +#include #ifdef CONFIG_KGDB #include #endif #include "macserial.h" +#ifdef CONFIG_PMAC_PBOOK +static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier serial_sleep_notifier = { + serial_notify_sleep, + SLEEP_LEVEL_MISC, +}; +#endif + /* * It would be nice to dynamically allocate everything that * depends on NUM_SERIAL, so we could support any number of @@ -1909,6 +1917,10 @@ probe_sccs() } *pp = 0; zs_channels_found = n; +#ifdef CONFIG_PMAC_PBOOK + if (n) + pmu_register_sleep_notifier(&serial_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ } /* rs_init inits the driver */ @@ -2470,3 +2482,40 @@ void __init zs_kgdb_hook(int tty_num) set_debug_traps(); /* init stub */ } #endif /* ifdef CONFIG_KGDB */ + +#ifdef CONFIG_PMAC_PBOOK +/* + * notify clients before sleep and reset bus afterwards + */ +int +serial_notify_sleep(struct pmu_sleep_notifier *self, int when) +{ + int i; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + case PBOOK_SLEEP_REJECT: + break; + + case PBOOK_SLEEP_NOW: + for (i=0; iflags & ZILOG_INITIALIZED) { + shutdown(info); + info->flags |= ZILOG_SLEEPING; + } + } + break; + case PBOOK_WAKE: + for (i=0; iflags & ZILOG_SLEEPING) { + info->flags &= ~ZILOG_SLEEPING; + startup(info, 0); + } + } + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h index 135d5a9708fd..e2f137f73916 100644 --- a/drivers/macintosh/macserial.h +++ b/drivers/macintosh/macserial.h @@ -68,6 +68,7 @@ struct serial_struct { #define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ #define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ #define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ +#define ZILOG_SLEEPING 0x01000000 /* have shut it down for sleep */ /* Software state per channel */ diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 0936b8bfba4b..83fd1d140f92 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -26,7 +26,16 @@ #include #include #include +#include +#include +#ifdef CONFIG_PMAC_PBOOK +static int mb_notify_sleep(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier mb_sleep_notifier = { + mb_notify_sleep, + SLEEP_LEVEL_MEDIABAY, +}; +#endif #undef MB_USE_INTERRUPTS @@ -77,13 +86,13 @@ int media_bay_count = 0; * Hold the media-bay reset signal true for this many ticks * after a device is inserted before releasing it. */ -#define MB_RESET_COUNT 20 +#define MB_RESET_COUNT 40 /* * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted * (or until the device is ready) before registering the IDE interface. */ -#define MB_IDE_WAIT 1000 +#define MB_IDE_WAIT 1500 static void poll_media_bay(int which); static void set_media_bay(int which, int id); @@ -157,6 +166,10 @@ media_bay_init(void) { printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count); +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&mb_sleep_notifier); +#endif /* CONFIG_PMAC_PBOOK */ + kernel_thread(media_bay_task, NULL, 0); } } @@ -298,9 +311,16 @@ poll_media_bay(int which) int id = MB_CONTENTS(which); if (id == media_bays[which].last_value) { - if (id != media_bays[which].content_id - && ++media_bays[which].value_count >= MB_STABLE_COUNT) - set_media_bay(which, id); + if (id != media_bays[which].content_id + && ++media_bays[which].value_count >= MB_STABLE_COUNT) { + /* If the device type changes without going thru "MB_NO", we force + a pass by "MB_NO" to make sure things are properly reset */ + if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) { + set_media_bay(which, MB_NO); + udelay(500); + } + set_media_bay(which, id); + } } else { media_bays[which].last_value = id; media_bays[which].value_count = 0; @@ -319,27 +339,28 @@ set_media_bay(int which, int id) switch (id) { case MB_CD: - feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); feature_set(bay->dev_node, FEATURE_Mediabay_enable); - feature_set(bay->dev_node, FEATURE_CD_power); feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable); + udelay(500); + feature_set(bay->dev_node, FEATURE_CD_power); printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); break; case MB_FD: - feature_clear(bay->dev_node, FEATURE_CD_power); feature_set(bay->dev_node, FEATURE_Mediabay_enable); feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); feature_set(bay->dev_node, FEATURE_SWIM3_enable); printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); break; case MB_NO: - feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); feature_clear(bay->dev_node, FEATURE_CD_power); + feature_clear(bay->dev_node, FEATURE_Mediabay_enable); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable); + feature_clear(bay->dev_node, FEATURE_SWIM3_enable); + feature_set(bay->dev_node, FEATURE_Mediabay_reset); printk(KERN_INFO "media bay %d is empty\n", which); break; default: - feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_clear(bay->dev_node, FEATURE_CD_power); feature_set(bay->dev_node, FEATURE_Mediabay_enable); printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", which, id); @@ -348,3 +369,62 @@ set_media_bay(int which, int id) udelay(500); } + +#ifdef CONFIG_PMAC_PBOOK +/* + * notify clients before sleep and reset bus afterwards + */ +int __pmac +mb_notify_sleep(struct pmu_sleep_notifier *self, int when) +{ + volatile struct media_bay_info* bay; + int i; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + case PBOOK_SLEEP_REJECT: + break; + + case PBOOK_SLEEP_NOW: + for (i=0; idev_node, FEATURE_Mediabay_enable); + feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable); + feature_clear(bay->dev_node, FEATURE_SWIM3_enable); + feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_set(bay->dev_node, FEATURE_Mediabay_reset); + feature_clear(bay->dev_node, FEATURE_CD_power); + out_8(&media_bays[i].addr->contents, 0x70); + } + break; + case PBOOK_WAKE: + for (i=0; idev_node, FEATURE_Mediabay_enable); + /* I suppose this is enough delay to stabilize MB_CONTENT ... */ + mdelay(10); + /* We re-enable the bay using it's previous content only if + it did not change */ + if (MB_CONTENTS(i) == bay->content_id) { + set_media_bay(i, bay->content_id); + if (bay->content_id != MB_NO) { + mdelay(400); + /* Clear the bay reset */ + feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + /* This small delay makes sure the device has time + to assert the BUSY bit (used by IDE sleep) */ + udelay(100); + /* We reset the state machine timers in case we were in the + middle of a wait loop */ + if (bay->reset_timer) + bay->reset_timer = MB_RESET_COUNT; + if (bay->cd_timer) + bay->cd_timer = MB_IDE_WAIT; + } + } + } + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 1742b16206b2..2e2dbf66c13a 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -14,16 +14,31 @@ #include #include #include +#include +#include +#ifdef CONFIG_PPC #include -#include -#include +#include +#else +#include +#include +#include +#include +#endif #include -#include #include #include static volatile unsigned char *via; +#ifdef CONFIG_MAC +#define CUDA_IRQ IRQ_MAC_ADB +#define __openfirmware +#define eieio() +#else +#define CUDA_IRQ vias->intrs[0].line +#endif + /* VIA registers - spaced 0x200 bytes apart */ #define RS 0x200 /* skip between registers */ #define B 0 /* B-side data */ @@ -73,27 +88,38 @@ static unsigned char cuda_rbuf[16]; static unsigned char *reply_ptr; static int reading_reply; static int data_index; +#ifdef CONFIG_PPC static struct device_node *vias; +#endif static int cuda_fully_inited = 0; -static int init_via(void); +static int cuda_probe(void); +static int cuda_init(void); +static int cuda_init_via(void); static void cuda_start(void); -static void via_interrupt(int irq, void *arg, struct pt_regs *regs); +static void cuda_interrupt(int irq, void *arg, struct pt_regs *regs); static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); -static int cuda_adb_send_request(struct adb_request *req, int sync); +static int cuda_send_request(struct adb_request *req, int sync); static int cuda_adb_autopoll(int devs); -static int cuda_adb_reset_bus(void); -static int cuda_send_request(struct adb_request *req); - - -static struct adb_controller cuda_controller = { - ADB_VIACUDA, - cuda_adb_send_request, +void cuda_poll(void); +static int cuda_reset_adb_bus(void); +static int cuda_write(struct adb_request *req); + +int cuda_request(struct adb_request *req, + void (*done)(struct adb_request *), int nbytes, ...); + +struct adb_driver via_cuda_driver = { + "CUDA", + cuda_probe, + cuda_init, + cuda_send_request, + /*cuda_write,*/ cuda_adb_autopoll, - cuda_adb_reset_bus, - cuda_poll + cuda_poll, + cuda_reset_adb_bus }; +#ifdef CONFIG_PPC void find_via_cuda() { @@ -106,7 +132,7 @@ find_via_cuda() #if 0 { int i; - printk("via_cuda_init: node = %p, addrs =", vias->node); + printk("find_via_cuda: node = %p, addrs =", vias->node); for (i = 0; i < vias->n_addrs; ++i) printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size); printk(", intrs ="); @@ -124,31 +150,56 @@ find_via_cuda() via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); cuda_state = idle; + sys_ctrler = SYS_CTRLER_CUDA; +} +#endif /* CONFIG_PPC */ - if (!init_via()) { - printk(KERN_ERR "init_via failed\n"); - via = NULL; - } - - adb_controller = &cuda_controller; +static int +cuda_probe() +{ +#ifdef CONFIG_PPC + if (sys_ctrler != SYS_CTRLER_CUDA) + return -ENODEV; +#else + if (macintosh_config->adb_type != MAC_ADB_CUDA) + return -ENODEV; + via = via1; +#endif + return 0; } -void -via_cuda_init(void) +static int +cuda_init(void) { + int err; + if (via == NULL) - return; + return -ENODEV; - if (request_irq(vias->intrs[0].line, via_interrupt, 0, "VIA", (void *)0)) { - printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0].line); - return; + err = cuda_init_via(); + if (err) { + printk(KERN_ERR "cuda_probe: init_via() failed\n"); + via = NULL; + return err; } - /* Clear and enable interrupts */ + /* Clear and enable interrupts, but only on PPC. On 68K it's done */ + /* for us by the the main VIA driver in arch/m68k/mac/via.c */ + +#ifndef CONFIG_MAC via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */ +#endif + + if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { + printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); + return -EAGAIN; + } + + printk("adb: CUDA driver v0.5 for Unified ADB.\n"); cuda_fully_inited = 1; + return 0; } #define WAIT_FOR(cond, what) \ @@ -156,14 +207,14 @@ via_cuda_init(void) for (x = 1000; !(cond); --x) { \ if (x == 0) { \ printk("Timeout waiting for " what); \ - return 0; \ + return -ENXIO; \ } \ udelay(100); \ } \ } while (0) static int -init_via() +cuda_init_via() { int x; @@ -172,7 +223,9 @@ init_via() via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; /* SR data in */ eieio(); x = via[SR]; eieio(); /* clear any left-over data */ +#ifndef CONFIG_MAC via[IER] = 0x7f; eieio(); /* disable interrupts from VIA */ +#endif eieio(); /* delay 4ms and then clear any pending interrupt */ @@ -198,12 +251,12 @@ init_via() x = via[SR]; eieio(); via[B] |= TIP; eieio(); /* should be unnecessary */ - return 1; + return 0; } /* Send an ADB command */ static int -cuda_adb_send_request(struct adb_request *req, int sync) +cuda_send_request(struct adb_request *req, int sync) { int i; @@ -214,7 +267,7 @@ cuda_adb_send_request(struct adb_request *req, int sync) req->reply_expected = 1; - i = cuda_send_request(req); + i = cuda_write(req); if (i) return i; @@ -243,7 +296,7 @@ cuda_adb_autopoll(int devs) /* Reset adb bus - how do we do this?? */ static int -cuda_adb_reset_bus(void) +cuda_reset_adb_bus(void) { struct adb_request req; @@ -276,11 +329,11 @@ cuda_request(struct adb_request *req, void (*done)(struct adb_request *), req->data[i] = va_arg(list, int); va_end(list); req->reply_expected = 1; - return cuda_send_request(req); + return cuda_write(req); } static int -cuda_send_request(struct adb_request *req) +cuda_write(struct adb_request *req) { unsigned long flags; @@ -336,17 +389,17 @@ cuda_start() void cuda_poll() { - int ie; + unsigned long flags; - __save_flags(ie); - __cli(); + save_flags(flags); + cli(); if (via[IFR] & SR_INT) - via_interrupt(0, 0, 0); - __restore_flags(ie); + cuda_interrupt(0, 0, 0); + restore_flags(flags); } static void -via_interrupt(int irq, void *arg, struct pt_regs *regs) +cuda_interrupt(int irq, void *arg, struct pt_regs *regs) { int x, status; struct adb_request *req; @@ -355,7 +408,7 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs) return; status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio(); - /* printk("via_interrupt: state=%d status=%x\n", cuda_state, status); */ + /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */ switch (cuda_state) { case idle: /* CUDA has sent us the first byte of data - unsolicited */ @@ -469,7 +522,7 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs) break; default: - printk("via_interrupt: unknown cuda_state %d?\n", cuda_state); + printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state); } } @@ -490,9 +543,3 @@ cuda_input(unsigned char *buf, int nb, struct pt_regs *regs) printk("\n"); } } - -int -cuda_present(void) -{ - return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via); -} diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 94cc546359b9..cff3f5cb7d96 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -21,10 +21,12 @@ #include #include #include +#include +#include +#include +#include #include -#include -#include -#include +#include #include #include #include @@ -32,6 +34,7 @@ #include #include #include +#include /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -70,6 +73,7 @@ static volatile unsigned char *via; #define IER_SET 0x80 /* set bits in IER */ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ +#define CB2_INT 0x08 #define CB1_INT 0x10 /* transition on CB1 input */ static enum pmu_state { @@ -98,11 +102,13 @@ static int pmu_fully_inited = 0; int asleep; struct notifier_block *sleep_notifier_list; +static int pmu_probe(void); +static int pmu_init(void); static int init_pmu(void); static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); -static int pmu_adb_send_request(struct adb_request *req, int sync); +static int pmu_send_request(struct adb_request *req, int sync); static int pmu_adb_autopoll(int devs); static int pmu_adb_reset_bus(void); static void send_byte(int x); @@ -112,15 +118,31 @@ static void pmu_done(struct adb_request *req); static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); static void set_volume(int level); +#ifdef CONFIG_PMAC_PBOOK +static void pmu_pass_intr(unsigned char *data, int len); +#endif -static struct adb_controller pmu_controller = { - ADB_VIAPMU, - pmu_adb_send_request, +struct adb_driver via_pmu_driver = { + "PMU", + pmu_probe, + pmu_init, + pmu_send_request, + /*pmu_queue_request,*/ pmu_adb_autopoll, - pmu_adb_reset_bus, - pmu_poll + pmu_poll, + pmu_adb_reset_bus }; +extern void low_sleep_handler(void); +extern void sleep_save_intrs(int); +extern void sleep_restore_intrs(void); + +extern int grackle_pcibios_read_config_word(unsigned char bus, + unsigned char dev_fn, unsigned char offset, unsigned short *val); + +extern int grackle_pcibios_write_config_word(unsigned char bus, + unsigned char dev_fn, unsigned char offset, unsigned short val); + /* * This table indicates for each PMU opcode: * - the number of data bytes to be sent with the command, or -1 @@ -164,13 +186,21 @@ static s8 pmu_data_len[256][2] __openfirmwaredata = { /*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1}, }; +static char *pbook_type[] = { + "Unknown PowerBook", + "PowerBook 2400/3400/3500(G3)", + "PowerBook G3 Series", + "1999 PowerBook G3", +}; -void __openfirmware +int __openfirmware find_via_pmu() { + if (via != 0) + return 1; vias = find_devices("via-pmu"); if (vias == 0) - return; + return 0; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); @@ -179,7 +209,7 @@ find_via_pmu() #if 0 { int i; - printk("via_pmu_init: node = %p, addrs =", vias->node); + printk("find_via_pmu: node = %p, addrs =", vias->node); for (i = 0; i < vias->n_addrs; ++i) printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size); printk(", intrs ="); @@ -192,12 +222,14 @@ find_via_pmu() printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n", vias->n_addrs, vias->n_intrs); if (vias->n_addrs < 1 || vias->n_intrs < 1) - return; + return 0; } if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) pmu_kind = PMU_OHARE_BASED; + else if (device_is_compatible(vias->parent, "paddington")) + pmu_kind = PMU_PADDINGTON_BASED; else if (device_is_compatible(vias->parent, "heathrow")) pmu_kind = PMU_HEATHROW_BASED; else @@ -209,23 +241,28 @@ find_via_pmu() pmu_state = idle; - if (!init_pmu()) + if (!init_pmu()) { via = NULL; + return 0; + } - adb_controller = &pmu_controller; + printk(KERN_INFO "PMU driver initialized for %s\n", + pbook_type[pmu_kind]); + sys_ctrler = SYS_CTRLER_PMU; + return 1; +} - if (via) - printk(KERN_INFO "PMU driver initialized for %s\n", - (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" : - ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" : - "Unknown PowerBook")); +static int __openfirmware +pmu_probe() +{ + return vias == NULL? -ENODEV: 0; } -void __openfirmware -via_pmu_init(void) +static int __openfirmware +pmu_init(void) { if (vias == NULL) - return; + return -ENXIO; bright_req_1.complete = 1; bright_req_2.complete = 1; @@ -235,7 +272,7 @@ via_pmu_init(void) (void *)0)) { printk(KERN_ERR "VIA-PMU: can't get irq %d\n", vias->intrs[0].line); - return; + return -ENXIO; } /* Enable interrupts */ @@ -245,6 +282,8 @@ via_pmu_init(void) /* Enable backlight */ pmu_enable_backlight(1); + + return 0; } static int __openfirmware @@ -292,20 +331,19 @@ pmu_get_model(void) /* Send an ADB command */ static int __openfirmware -pmu_adb_send_request(struct adb_request *req, int sync) +pmu_send_request(struct adb_request *req, int sync) { - int i, ret; + int i, ret; + + if ((vias == NULL) || (!pmu_fully_inited)) { + req->complete = 1; + return -ENXIO; + } - if ((vias == NULL) || (!pmu_fully_inited)) - { - req->complete = 1; - return -ENXIO; - } + ret = -EINVAL; - ret = -EINVAL; - - switch (req->data[0]) { - case PMU_PACKET: + switch (req->data[0]) { + case PMU_PACKET: for (i = 0; i < req->nbytes - 1; ++i) req->data[i] = req->data[i+1]; --req->nbytes; @@ -316,7 +354,7 @@ pmu_adb_send_request(struct adb_request *req, int sync) req->reply_len = 0; ret = pmu_queue_request(req); break; - case CUDA_PACKET: + case CUDA_PACKET: switch (req->data[1]) { case CUDA_GET_TIME: if (req->nbytes != 2) @@ -344,7 +382,7 @@ pmu_adb_send_request(struct adb_request *req, int sync) break; } break; - case ADB_PACKET: + case ADB_PACKET: for (i = req->nbytes - 1; i > 1; --i) req->data[i+2] = req->data[i]; req->data[3] = req->nbytes - 2; @@ -356,19 +394,17 @@ pmu_adb_send_request(struct adb_request *req, int sync) req->reply_len = 0; ret = pmu_queue_request(req); break; - } - if (ret) - { - req->complete = 1; - return ret; - } - - if (sync) { - while (!req->complete) - pmu_poll(); - } + } + if (ret) { + req->complete = 1; + return ret; + } - return 0; + if (sync) + while (!req->complete) + pmu_poll(); + + return 0; } /* Enable/disable autopolling */ @@ -513,19 +549,25 @@ pmu_queue_request(struct adb_request *req) static void __openfirmware send_byte(int x) { - out_8(&via[ACR], 0x1c); - out_8(&via[SR], x); - out_8(&via[B], via[B] & ~0x10); /* assert TREQ */ + volatile unsigned char *v = via; + + out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT); + out_8(&v[SR], x); + out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */ } static void __openfirmware recv_byte() { - out_8(&via[ACR], 0x0c); - in_8(&via[SR]); /* resets SR */ - out_8(&via[B], via[B] & ~0x10); + volatile unsigned char *v = via; + + out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT); + in_8(&v[SR]); /* resets SR */ + out_8(&v[B], in_8(&v[B]) & ~0x10); } +static int disable_poll; + static void __openfirmware pmu_start() { @@ -545,7 +587,9 @@ pmu_start() data_len = pmu_data_len[req->data[0]][0]; /* set the shift register to shift out and send a byte */ + ++disable_poll; send_byte(req->data[0]); + --disable_poll; out: restore_flags(flags); @@ -554,13 +598,15 @@ out: void __openfirmware pmu_poll() { - int ie; + unsigned long flags; - __save_flags(ie); - __cli(); + if (disable_poll) + return; + save_flags(flags); + cli(); if (via[IFR] & (SR_INT | CB1_INT)) via_pmu_interrupt(0, 0, 0); - __restore_flags(ie); + restore_flags(flags); } static void __openfirmware @@ -569,6 +615,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) int intr; int nloop = 0; + ++disable_poll; while ((intr = in_8(&via[IFR])) != 0) { if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " @@ -580,11 +627,9 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) else if (intr & CB1_INT) { adb_int_pending = 1; out_8(&via[IFR], CB1_INT); - } else - { - /* -- Disabled printk, will happen _really_ often on - PowerBooks ((CB2 interrupts) -- - printk(KERN_DEBUG "PMU: spurrious interrupt intr=%x\n", intr); */ + } + intr &= ~(SR_INT | CB1_INT); + if (intr != 0) { out_8(&via[IFR], intr); } } @@ -597,6 +642,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) pmu_start(); } } + --disable_poll; } static void __openfirmware @@ -605,17 +651,17 @@ pmu_sr_intr(struct pt_regs *regs) struct adb_request *req; int bite, timeout; + if (via[B] & TREQ) { + printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); + out_8(&via[IFR], SR_INT); + return; + } if (via[B] & TACK) - printk(KERN_DEBUG "PMU: sr_intr but ack still high! (%x)\n", + printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n", via[B]); - /* if reading grab the byte, and reset the interrupt */ - if ((via[ACR] & SR_OUT) == 0) - bite = in_8(&via[SR]); - out_8(&via[IFR], SR_INT); - /* reset TREQ and wait for TACK to go high */ - out_8(&via[B], via[B] | TREQ); + out_8(&via[B], in_8(&via[B]) | TREQ); timeout = 3200; while ((in_8(&via[B]) & TACK) == 0) { if (--timeout < 0) { @@ -625,6 +671,11 @@ pmu_sr_intr(struct pt_regs *regs) udelay(10); } + /* if reading grab the byte, and reset the interrupt */ + if (pmu_state == reading || pmu_state == reading_intr) + bite = in_8(&via[SR]); + out_8(&via[IFR], SR_INT); + switch (pmu_state) { case sending: req = current_req; @@ -707,8 +758,6 @@ pmu_done(struct adb_request *req) static void __openfirmware pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) { - static int show_pmu_ints = 1; - asleep = 0; if (len < 1) { adb_int_pending = 0; @@ -730,21 +779,34 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) } pmu_done(req); } else { - adb_input(data+1, len-1, regs, 1); +#ifdef CONFIG_XMON + if (len == 4 && data[1] == 0x2c) { + extern int xmon_wants_key, xmon_pmu_keycode; + if (xmon_wants_key) { + xmon_pmu_keycode = data[2]; + return; + } + } +#endif /* CONFIG_XMON */ + /* + * XXX On the [23]400 the PMU gives us an up + * event for keycodes 0x74 or 0x75 when the PC + * card eject buttons are released, so we + * ignore those events. + */ + if (!(pmu_kind == PMU_OHARE_BASED && len == 4 + && data[1] == 0x2c && data[3] == 0xff + && (data[2] & ~1) == 0xf4)) + adb_input(data+1, len-1, regs, 1); } + } else if (data[0] == 0x08 && len == 3) { + /* sound/brightness buttons pressed */ + pmu_set_brightness(data[1] >> 3); + set_volume(data[2]); } else { - if (data[0] == 0x08 && len == 3) { - /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); - set_volume(data[2]); - } else if (show_pmu_ints - && !(data[0] == PMU_INT_TICK && len == 1)) { - int i; - printk(KERN_DEBUG "pmu intr"); - for (i = 0; i < len; ++i) - printk(" %.2x", data[i]); - printk("\n"); - } +#ifdef CONFIG_PMAC_PBOOK + pmu_pass_intr(data, len); +#endif } } @@ -759,38 +821,46 @@ pmu_enable_backlight(int on) struct adb_request req; if (vias == NULL) - return ; + return; - if (on) { - /* first call: get current backlight value */ - if (backlight_level < 0) { - switch(pmu_kind) { - case PMU_OHARE_BASED: + /* first call: get current backlight value */ + if (on && backlight_level < 0) { + switch (pmu_kind) { + case PMU_OHARE_BASED: pmu_request(&req, NULL, 2, 0xd9, 0); while (!req.complete) pmu_poll(); backlight_level = req.reply[1] >> 3; - printk(KERN_DEBUG "pmu: controls returned bright: %d\n", (int)req.reply[1]); break; - case PMU_HEATHROW_BASED: + case PMU_HEATHROW_BASED: + /* We cannot use nvram_read_byte here (not yet initialized) */ pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); while (!req.complete) pmu_poll(); - printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]); backlight_level = req.reply[1]; + printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level); + break; + case PMU_PADDINGTON_BASED: + /* the G3 PB 1999 has a backlight node + and chrp-structured nvram */ + /* XXX should read macos's "blkt" property in nvram + for this node. For now this ensures that the + backlight doesn't go off as soon as linux boots. */ + backlight_level = 20; break; - default: + default: backlight_enabled = 0; return; } - } - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - LEVEL_TO_BRIGHT(backlight_level)); - while (!req.complete) - pmu_poll(); + } + if (on) { + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, + LEVEL_TO_BRIGHT(backlight_level)); + while (!req.complete) + pmu_poll(); } pmu_request(&req, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); + PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); while (!req.complete) pmu_poll(); backlight_enabled = on; @@ -847,7 +917,7 @@ pmu_restart(void) { struct adb_request req; - __cli(); + cli(); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | PMU_INT_TICK ); @@ -866,7 +936,7 @@ pmu_shutdown(void) { struct adb_request req; - __cli(); + cli(); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB | PMU_INT_TICK ); @@ -881,13 +951,69 @@ pmu_shutdown(void) ; } +#ifdef CONFIG_PMAC_PBOOK + +static LIST_HEAD(sleep_notifiers); + int -pmu_present(void) +pmu_register_sleep_notifier(struct pmu_sleep_notifier *n) { - return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias); + struct list_head *list; + struct pmu_sleep_notifier *current; + + for (list = sleep_notifiers.next; list != &sleep_notifiers; + list = list->next) { + current = list_entry(list, struct pmu_sleep_notifier, list); + if (n->priority > current->priority) + break; + } + __list_add(&n->list, list->prev, list); + return 0; } -#ifdef CONFIG_PMAC_PBOOK +int +pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) +{ + if (n->list.next == 0) + return -ENOENT; + list_del(&n->list); + n->list.next = 0; + return 0; +} + +/* Sleep is broadcast last-to-first */ +static int +broadcast_sleep(int when, int can_cancel) +{ + int ret = PBOOK_SLEEP_OK; + struct list_head *list; + struct pmu_sleep_notifier *current; + + for (list = sleep_notifiers.prev; list != &sleep_notifiers; + list = list->prev) { + current = list_entry(list, struct pmu_sleep_notifier, list); + ret = current->notifier_call(current, when); + if (can_cancel && (ret != PBOOK_SLEEP_OK)) + return ret; + } + return ret; +} + +/* Wake is broadcast first-to-last */ +static int +broadcast_wake(void) +{ + int ret = PBOOK_SLEEP_OK; + struct list_head *list; + struct pmu_sleep_notifier *current; + + for (list = sleep_notifiers.next; list != &sleep_notifiers; + list = list->next) { + current = list_entry(list, struct pmu_sleep_notifier, list); + current->notifier_call(current, PBOOK_WAKE); + } + return ret; +} /* * This struct is used to store config register values for @@ -897,10 +1023,11 @@ static struct pci_save { u16 command; u16 cache_lat; u16 intr; + u32 rom_address; } *pbook_pci_saves; static int n_pbook_pci_saves; -static inline void __openfirmware +static void __openfirmware pbook_pci_save(void) { int npci; @@ -922,12 +1049,13 @@ pbook_pci_save(void) pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); + pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); ++ps; --npci; } } -static inline void __openfirmware +static void __openfirmware pbook_pci_restore(void) { u16 cmd; @@ -948,7 +1076,7 @@ pbook_pci_restore(void) PCI_BASE_ADDRESS_0 + j*4, pd->resource[j].start); pci_write_config_dword(pd, PCI_ROM_ADDRESS, - pd->resource[PCI_ROM_RESOURCE].start); + ps->rom_address); pci_write_config_word(pd, PCI_CACHE_LINE_SIZE, ps->cache_lat); pci_write_config_word(pd, PCI_INTERRUPT_LINE, @@ -963,43 +1091,147 @@ pbook_pci_restore(void) /* * Put the powerbook to sleep. */ -#define IRQ_ENABLE ((unsigned int *)0xf3000024) -#define MEM_CTRL ((unsigned int *)0xf8000070) + +#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38)) +#define GRACKLE_PM (1<<7) +#define GRACKLE_DOZE (1<<5) +#define GRACKLE_NAP (1<<4) +#define GRACKLE_SLEEP (1<<3) + +int __openfirmware powerbook_sleep_G3(void) +{ + int ret; + unsigned long save_l2cr; + unsigned long save_fcr; + unsigned long wait; + unsigned short pmcr1; + struct adb_request sleep_req; + struct device_node *macio; + unsigned long macio_base = 0; + + macio = find_devices("mac-io"); + if (macio != 0 && macio->n_addrs > 0) + macio_base = (unsigned long) + ioremap(macio->addrs[0].address, 0x40); -int __openfirmware powerbook_sleep(void) + /* Sync the disks. */ + /* XXX It would be nice to have some way to ensure that + * nobody is dirtying any new buffers while we wait. */ + fsync_dev(0); + + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1); + if (ret != PBOOK_SLEEP_OK) { + broadcast_sleep(PBOOK_SLEEP_REJECT, 0); + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + broadcast_sleep(PBOOK_SLEEP_NOW, 0); + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); + + /* Disable all interrupts except pmu */ + sleep_save_intrs(vias->intrs[0].line); + + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); +#if 0 + /* Save the state of PCI config space for some slots */ + pbook_pci_save(); +#endif + /* For 750, save backside cache setting and disable it */ + save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ + if (save_l2cr) + _set_L2CR(0); + + if (macio_base != 0) { + save_fcr = in_le32(FEATURE_CTRL(macio_base)); + /* Check if this is still valid on older powerbooks */ + out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL)); + } + + if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + grackle_pcibios_read_config_word(0,0,0x70,&pmcr1); + /* Apparently, MacOS uses NAP mode for Grackle ??? */ + pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP); + pmcr1 |= GRACKLE_PM|GRACKLE_NAP; + grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); + + /* Ask the PMU to put us to sleep */ + pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!sleep_req.complete) + mb(); + + cli(); + while (pmu_state != idle) + pmu_poll(); + + /* Call low-level ASM sleep handler */ + low_sleep_handler(); + + /* We're awake again, stop grackle PM */ + grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1); + pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); + grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); + + sti(); +#if 0 + /* According to someone from Apple, this should not be needed, + at least not for all devices. Let's keep it for now until we + have something that works. */ + pbook_pci_restore(); +#endif + set_context(current->mm->context); + + /* Restore L2 cache */ + if (save_l2cr) + _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + + /* reenable interrupts */ + sleep_restore_intrs(); + + /* Notify drivers */ + broadcast_wake(); + + return 0; +} + +#define PB3400_MEM_CTRL ((unsigned int *)0xf8000070) + +int __openfirmware powerbook_sleep_3400(void) { int ret, i, x; - static int save_backlight; - static unsigned int save_irqen; unsigned long msr; unsigned int hid0; unsigned long p, wait; struct adb_request sleep_req; - /* Notify device drivers */ - ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL); - if (ret & NOTIFY_STOP_MASK) - return -EBUSY; - /* Sync the disks. */ /* XXX It would be nice to have some way to ensure that * nobody is dirtying any new buffers while we wait. */ fsync_dev(0); - /* Turn off the display backlight */ - save_backlight = backlight_enabled; - if (save_backlight) - pmu_enable_backlight(0); + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1); + if (ret != PBOOK_SLEEP_OK) { + broadcast_sleep(PBOOK_SLEEP_REJECT, 0); + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + broadcast_sleep(PBOOK_SLEEP_NOW, 0); /* Give the disks a little time to actually finish writing */ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) mb(); /* Disable all interrupts except pmu */ - save_irqen = in_le32(IRQ_ENABLE); - for (i = 0; i < 32; ++i) - if (i != vias->intrs[0].line && (save_irqen & (1 << i))) - disable_irq(i); + sleep_save_intrs(vias->intrs[0].line); + + /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); /* Save the state of PCI config space for some slots */ @@ -1008,9 +1240,9 @@ int __openfirmware powerbook_sleep(void) /* Set the memory controller to keep the memory refreshed while we're asleep */ for (i = 0x403f; i >= 0x4000; --i) { - out_be32(MEM_CTRL, i); + out_be32(PB3400_MEM_CTRL, i); do { - x = (in_be32(MEM_CTRL) >> 16) & 0x3ff; + x = (in_be32(PB3400_MEM_CTRL) >> 16) & 0x3ff; } while (x == 0); if (x >= 0x100) break; @@ -1020,6 +1252,7 @@ int __openfirmware powerbook_sleep(void) pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); while (!sleep_req.complete) mb(); + /* displacement-flush the L2 cache - necessary? */ for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) i = *(volatile int *)p; @@ -1035,7 +1268,7 @@ int __openfirmware powerbook_sleep(void) udelay(10); /* OK, we're awake again, start restoring things */ - out_be32(MEM_CTRL, 0x3f); + out_be32(PB3400_MEM_CTRL, 0x3f); pbook_pci_restore(); /* wait for the PMU interrupt sequence to complete */ @@ -1043,21 +1276,10 @@ int __openfirmware powerbook_sleep(void) mb(); /* reenable interrupts */ - for (i = 0; i < 32; ++i) - if (i != vias->intrs[0].line && (save_irqen & (1 << i))) - enable_irq(i); + sleep_restore_intrs(); /* Notify drivers */ - notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); - - /* reenable ADB autopoll */ - pmu_adb_autopoll(adb_dev_map); - - /* Turn on the screen backlight, if it was on before */ - if (save_backlight) - pmu_enable_backlight(1); - - /* Wait for the hard disk to spin up */ + broadcast_wake(); return 0; } @@ -1065,15 +1287,112 @@ int __openfirmware powerbook_sleep(void) /* * Support for /dev/pmu device */ +#define RB_SIZE 10 +struct pmu_private { + struct list_head list; + int rb_get; + int rb_put; + struct rb_entry { + unsigned short len; + unsigned char data[16]; + } rb_buf[RB_SIZE]; + wait_queue_head_t wait; + spinlock_t lock; +}; + +static LIST_HEAD(all_pmu_pvt); +static spinlock_t all_pvt_lock = SPIN_LOCK_UNLOCKED; + +static void pmu_pass_intr(unsigned char *data, int len) +{ + struct pmu_private *pp; + struct list_head *list; + int i; + unsigned long flags; + + if (len > sizeof(pp->rb_buf[0].data)) + len = sizeof(pp->rb_buf[0].data); + spin_lock_irqsave(&all_pvt_lock, flags); + for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) { + pp = list_entry(list, struct pmu_private, list); + i = pp->rb_put + 1; + if (i >= RB_SIZE) + i = 0; + if (i != pp->rb_get) { + struct rb_entry *rp = &pp->rb_buf[pp->rb_put]; + rp->len = len; + memcpy(rp->data, data, len); + pp->rb_put = i; + wake_up_interruptible(&pp->wait); + } + } + spin_unlock_irqrestore(&all_pvt_lock, flags); +} + static int __openfirmware pmu_open(struct inode *inode, struct file *file) { + struct pmu_private *pp; + unsigned long flags; + + pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL); + if (pp == 0) + return -ENOMEM; + pp->rb_get = pp->rb_put = 0; + spin_lock_init(&pp->lock); + init_waitqueue_head(&pp->wait); + spin_lock_irqsave(&all_pvt_lock, flags); + list_add(&pp->list, &all_pmu_pvt); + spin_unlock_irqrestore(&all_pvt_lock, flags); + file->private_data = pp; return 0; } static ssize_t __openfirmware pmu_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - return 0; + struct pmu_private *pp = file->private_data; + DECLARE_WAITQUEUE(wait, current); + int ret; + + if (count < 1 || pp == 0) + return -EINVAL; + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + add_wait_queue(&pp->wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + for (;;) { + ret = -EAGAIN; + spin_lock(&pp->lock); + if (pp->rb_get != pp->rb_put) { + int i = pp->rb_get; + struct rb_entry *rp = &pp->rb_buf[i]; + ret = rp->len; + if (ret > count) + ret = count; + if (ret > 0 && copy_to_user(buf, rp->data, ret)) + ret = -EFAULT; + if (++i >= RB_SIZE) + i = 0; + pp->rb_get = i; + } + spin_unlock(&pp->lock); + if (ret >= 0) + break; + + if (file->f_flags & O_NONBLOCK) + break; + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&pp->wait, &wait); + + return ret; } static ssize_t __openfirmware pmu_write(struct file *file, const char *buf, @@ -1082,26 +1401,65 @@ static ssize_t __openfirmware pmu_write(struct file *file, const char *buf, return 0; } +static unsigned int pmu_fpoll(struct file *filp, poll_table *wait) +{ + struct pmu_private *pp = filp->private_data; + unsigned int mask = 0; + + if (pp == 0) + return 0; + poll_wait(filp, &pp->wait, wait); + spin_lock(&pp->lock); + if (pp->rb_get != pp->rb_put) + mask |= POLLIN; + spin_unlock(&pp->lock); + return mask; +} + +static int pmu_release(struct inode *inode, struct file *file) +{ + struct pmu_private *pp = file->private_data; + unsigned long flags; + + if (pp != 0) { + file->private_data = 0; + spin_lock_irqsave(&all_pvt_lock, flags); + list_del(&pp->list); + spin_unlock_irqrestore(&all_pvt_lock, flags); + kfree(pp); + } + return 0; +} + /* Note: removed __openfirmware here since it causes link errors */ -static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp, +static int pmu_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { int error; __u32 value; switch (cmd) { - case PMU_IOC_SLEEP: - if (pmu_kind != PMU_OHARE_BASED) - return -ENOSYS; - return powerbook_sleep(); - case PMU_IOC_GET_BACKLIGHT: + case PMU_IOC_SLEEP: + switch (pmu_kind) { + case PMU_OHARE_BASED: + error = powerbook_sleep_3400(); + break; + case PMU_HEATHROW_BASED: + case PMU_PADDINGTON_BASED: + error = powerbook_sleep_G3(); + break; + default: + error = ENOSYS; + } + return error; + case PMU_IOC_GET_BACKLIGHT: return put_user(backlight_level, (__u32 *)arg); - case PMU_IOC_SET_BACKLIGHT: + case PMU_IOC_SET_BACKLIGHT: error = get_user(value, (__u32 *)arg); if (!error) pmu_set_brightness(value); return error; - case PMU_IOC_GET_MODEL: + case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); } return -EINVAL; @@ -1112,12 +1470,12 @@ static struct file_operations pmu_device_fops = { pmu_read, pmu_write, NULL, /* no readdir */ - NULL, /* no poll yet */ + pmu_fpoll, pmu_ioctl, NULL, /* no mmap */ pmu_open, NULL, /* flush */ - NULL /* no release */ + pmu_release, }; static struct miscdevice pmu_device = { diff --git a/drivers/misc/Config.in b/drivers/misc/Config.in index 9467c5e45597..5b793e2149e6 100644 --- a/drivers/misc/Config.in +++ b/drivers/misc/Config.in @@ -4,13 +4,6 @@ mainmenu_option next_comment comment 'Misc devices' -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Generic ACPI support' CONFIG_ACPI -fi - -# PIIX4 ACPI requires PCI for setup and a hardcoded TSC for timing -if [ "$CONFIG_PCI" = "y" -a "$CONFIG_X86_TSC" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'PIIX4 ACPI support' CONFIG_PIIX4_ACPI -fi +tristate 'Generic ACPI support' CONFIG_ACPI endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8368614adf1c..6183d1231e75 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -26,10 +26,6 @@ else endif endif -ifdef CONFIG_PIIX4_ACPI -O_OBJS += piix4_acpi.o -endif - include $(TOPDIR)/Rules.make fastdep: diff --git a/drivers/misc/acpi.c b/drivers/misc/acpi.c index 27137fa40dbd..1337ff8e8f06 100644 --- a/drivers/misc/acpi.c +++ b/drivers/misc/acpi.c @@ -18,6 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * See http://www.geocities.com/SiliconValley/Hardware/3165/ + * for the user-level ACPI stuff + */ + #include #include #include @@ -252,6 +257,7 @@ static int __init acpi_map_tables(void) */ static void acpi_unmap_tables(void) { + acpi_idle = NULL; acpi_dsdt_addr = 0; acpi_facp_addr = 0; acpi_unmap_table((struct acpi_table *) acpi_facp); @@ -355,6 +361,48 @@ static struct miscdevice acpi_device = NULL }; +/* Make it impossible to enter L2/L3 until after we've initialized */ +static unsigned long acpi_p_lvl2_lat = ~0UL; +static unsigned long acpi_p_lvl3_lat = ~0UL; + +/* Initialize to guaranteed harmless port read */ +static u16 acpi_p_lvl2 = 0x80; +static u16 acpi_p_lvl3 = 0x80; + +static void acpi_idle_handler(void) +{ + unsigned long time; + static int sleep_level = 1; + + time = inl(acpi_facp->pm_tmr); + switch (sleep_level) { + case 1: + __asm__ __volatile__("sti ; hlt": : :"memory"); + break; + case 2: + inb(acpi_p_lvl2); + break; + case 3: + /* Disable PCI arbitration while sleeping, to avoid DMA corruption? */ + if (acpi_facp->pm2_cnt) { + unsigned int port = acpi_facp->pm2_cnt; + outb(inb(port) | ACPI_ARB_DIS, port); + inb(acpi_p_lvl3); + outb(inb(port) & ~ACPI_ARB_DIS, port); + break; + } + inb(acpi_p_lvl3); + } + time = (inl(acpi_facp->pm_tmr) - time) & ACPI_TMR_MASK; + + if (time > acpi_p_lvl3_lat) + sleep_level = 3; + else if (time > acpi_p_lvl2_lat) + sleep_level = 2; + else + sleep_level = 1; +} + /* * Initialize and enable ACPI */ @@ -376,6 +424,17 @@ static int __init acpi_init(void) if (misc_register(&acpi_device)) { printk(KERN_ERR "ACPI: misc. register failed\n"); } + + /* + * Set up the ACPI idle function. Note that we can't really + * do this with multiple CPU's, we'd need a per-CPU ACPI + * device.. + */ +#ifdef __SMP__ + if (smp_num_cpus > 1) + return 0; +#endif + acpi_idle = acpi_idle_handler; return 0; } diff --git a/drivers/misc/piix4_acpi.c b/drivers/misc/piix4_acpi.c deleted file mode 100644 index 9cd3625b9aaf..000000000000 --- a/drivers/misc/piix4_acpi.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * linux/drivers/misc/piix4_acpi.c - * - * (C) Copyright 1999 Linus Torvalds - * - * A PM driver for the ACPI portion of the Intel PIIX4 - * chip. - * - * This has been known to occasionally work on some laptops. - * - * It probably only works on Intel PII machines that support - * the STPCLK protocol. - */ - -#include -#include -#include - -#include - -extern void (*acpi_idle)(void); - -/* - * This first part should be common to all ACPI - * CPU sleep functionality. Assuming we get the - * timing heuristics in a better shape than "none" ;) - */ - -typedef void (*sleep_fn_t)(void); - -/* - * Our "sleep mode" is a fixed point number - * with two binary places, ranging between - * [0 .. 3[ - */ -#define Cx_SHIFT 2 -#define MAXMODE ((3 << Cx_SHIFT)-1) - -/* - * NOTE! - * - * Right now this always defaults to C3, which is just broken. - * The exit latency is usually too high for much busy IO activity, - * and generally it's not always the best thing to do. - * - * We should just read the cycle counter around all the cases, - * and if we pause for a long time we go to a deeper sleep, while - * a short wait makes us go into a lighter sleep. - */ -static void common_acpi_idle(sleep_fn_t *sleep) -{ - int mode = MAXMODE; - - while (1) { - while (!current->need_resched) { - unsigned int time; - - time = get_cycles(); - sleep[(mode) >> Cx_SHIFT](); - time = get_cycles() - time; - - /* - * Yeah, yeah, yeah. - * if (time > Large && mode < MAXMODE) mode++; - * if (time < Small && mode > 0) mode--; - * Yadda-yadda-yadda. - * - * "Large" is on the order of half a timer tick. - * "Small" is on the order of Large >> 2 or so. - * - * Somebody should _really_ look at the exact - * details. The ACPI bios would give some made-up - * numbers, they might be useful (or maybe not: - * they are probably tuned for whatever Windows - * does, so don't take them for granted). - */ - } - schedule(); - check_pgt_cache(); - } -} - -/* Ok, here starts the magic PIIX4 knowledge */ - -/* - * Ehh.. We "know" about the northbridge - * bus arbitration stuff. Maybe somebody - * should actually verify this some day? - */ -#define NORTHBRIDGE_CONTROL 0x22 -#define NB_ARBITRATE 0x01 - -/* - * PIIX4 ACPI IO offsets and defines - */ -#define PMEN 0x02 -#define PMCNTRL 0x04 -#define PMTMR 0x08 -#define GPSTS 0x0c -#define GPEN 0x0E - -#define PCNTRL 0x10 -#define CC_EN 0x0200 -#define BST_EN 0x0400 -#define SLEEP_EN 0x0800 -#define STPCLK_EN 0x1000 -#define CLKRUN_EN 0x2000 - -#define PLVL2 0x14 -#define PLVL3 0x15 - -/* - * PIIX4 ACPI PCI configurations offsets and defines - */ -#define DEVACTB 0x58 -#define BRLD_EN_IRQ0 0x01 -#define BRLD_EN_IRQ 0x02 - -#define PMREGMISC 0x80 -#define PMIOSE 0x01 - -static unsigned int piix4_base_address = 0; - -static void piix4_c1_sleep(void) -{ - asm volatile("sti ; hlt" : : : "memory"); -} - -static void piix4_c2_sleep(void) -{ - outl(CLKRUN_EN | CC_EN, piix4_base_address + PCNTRL); - inb(piix4_base_address + PLVL2); -} - -static void piix4_c3_sleep(void) -{ - __cli(); - outl(CLKRUN_EN | CC_EN | STPCLK_EN | SLEEP_EN, piix4_base_address + PCNTRL); - outb(NB_ARBITRATE, NORTHBRIDGE_CONTROL); - inb(piix4_base_address + PLVL3); - outb(0, NORTHBRIDGE_CONTROL); - __sti(); -} - -static sleep_fn_t piix4_sleep[] = { - piix4_c1_sleep, /* low-latency C1 (ie "sti ; hlt") */ - piix4_c2_sleep, /* medium latency C2 (ie LVL2 stopckl) */ - piix4_c3_sleep /* high-latency C3 (ie LVL3 sleep) */ -}; - -static void piix4_acpi_idle(void) -{ - common_acpi_idle(piix4_sleep); -} - -static int __init piix4_acpi_init(void) -{ - /* This is the PIIX4 ACPI device */ - struct pci_dev *dev; - u32 base, val; - u16 cmd; - u8 pmregmisc; - -#ifdef __SMP__ - /* - * We can't really do idle things with multiple CPU's, I'm - * afraid. We'd need a per-CPU ACPI device. - */ - if (smp_num_cpus > 1) - return -1; -#endif - dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); - - if (!dev) - return -1; - - /* - * Read the IO base value, and verify that it makes sense - * - * We could enable this if it wasn't enabled before, but - * let's walk before we run.. - */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_IO)) - return -1; - - pci_read_config_byte(dev, PMREGMISC, &pmregmisc); - if (!(pmregmisc & PMIOSE)) - return -1; - - pci_read_config_dword(dev, 0x40, &base); - if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) - return -1; - - base &= PCI_BASE_ADDRESS_IO_MASK; - if (!base) - return -1; - - printk("Found PIIX4 ACPI device at %04x\n", base); - piix4_base_address = base; - - /* Enable stopcklock, sleep and bursts, along with clock control */ - outl(CLKRUN_EN | CC_EN | STPCLK_EN | SLEEP_EN, piix4_base_address + PCNTRL); - - /* Make all unmasked interrupts be BREAK events */ - pci_read_config_dword(dev, DEVACTB, &val); - pci_write_config_dword(dev, DEVACTB, val | BRLD_EN_IRQ0 | BRLD_EN_IRQ); - - /* Set up the new idle handler.. */ - acpi_idle = piix4_acpi_idle; - return 0; -} - -__initcall(piix4_acpi_init); diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c index 8af63739cfe2..81bba9e60b8f 100644 --- a/drivers/net/pcmcia/ray_cs.c +++ b/drivers/net/pcmcia/ray_cs.c @@ -57,21 +57,17 @@ left out. If you compile with PCMCIA_DEBUG=0, the debug code will be present but disabled -- but it can then be enabled for specific modules at load time with a 'pc_debug=#' option to insmod. - - I found that adding -DPCMCIA_DEBUG to the compile options during - the 'make config' resulted in cardmgr not finding any sockets. - Therefore, this module uses RAYLINK_DEBUG instead. - The module option to use is ray_debug=# - where # is 1 for modest output - 2 for more output - ... */ #ifdef RAYLINK_DEBUG -static int ray_debug = RAYLINK_DEBUG; -MODULE_PARM(ray_debug, "i"); -/* #define DEBUG(n, args...) if (ray_debug>(n)) printk(KERN_DEBUG args); */ -#define DEBUG(n, args...) if (ray_debug>(n)) printk(args); +#define PCMCIA_DEBUG RAYLINK_DEBUG +#endif +#ifdef PCMCIA_DEBUG +static int ray_debug = 0; +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +/* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */ +#define DEBUG(n, args...) if (pc_debug>(n)) printk(args); #else #define DEBUG(n, args...) #endif @@ -137,7 +133,6 @@ void start_net(u_long local); /* void start_net(ray_dev_t *local); */ int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare); - /* Create symbol table for registering with kernel in init_module */ EXPORT_SYMBOL(ray_dev_ioctl); EXPORT_SYMBOL(ray_rx); @@ -147,40 +142,30 @@ EXPORT_SYMBOL(ray_rx); /* Bit map of interrupts to choose from */ /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ static u_long irq_mask = 0xdeb8; -MODULE_PARM(irq_mask,"i"); /* ADHOC=0, Infrastructure=1 */ static int net_type = ADHOC; -MODULE_PARM(net_type,"i"); /* Hop dwell time in Kus (1024 us units defined by 802.11) */ static int hop_dwell = 128; -MODULE_PARM(hop_dwell,"i"); /* Beacon period in Kus */ static int beacon_period = 256; -MODULE_PARM(beacon_period,"i"); /* power save mode (0 = off, 1 = save power) */ static int psm = 0; -MODULE_PARM(psm,"i"); /* String for network's Extended Service Set ID. 32 Characters max */ static char *essid = NULL; -MODULE_PARM(essid,"s"); /* Default to encapsulation unless translation requested */ static int translate = 1; -MODULE_PARM(translate,"i"); static int country = USA; -MODULE_PARM(country,"i"); static int sniffer = 0; -MODULE_PARM(sniffer,"i"); static int bc = 0; -MODULE_PARM(bc,"i"); /* 48 bit physical card address if overriding card's real physical * address is required. Since IEEE 802.11 addresses are 48 bits @@ -193,7 +178,6 @@ MODULE_PARM(bc,"i"); * things will happen if it is not 0 in a card address. */ static char *phy_addr = NULL; -MODULE_PARM(phy_addr,"s"); /* The dev_info variable is the "key" that is used to match up this @@ -214,7 +198,22 @@ static dev_link_t *dev_list = NULL; 'priv' pointer in a dev_link_t structure can be used to point to a device-specific private data structure, like this. */ -static const unsigned int ray_mem_speed = 0x2A; +static unsigned int ray_mem_speed = 0x2A; + +MODULE_AUTHOR("Corey Thomas "); +MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); +MODULE_PARM(irq_mask,"i"); +MODULE_PARM(net_type,"i"); +MODULE_PARM(hop_dwell,"i"); +MODULE_PARM(beacon_period,"i"); +MODULE_PARM(psm,"i"); +MODULE_PARM(essid,"s"); +MODULE_PARM(translate,"i"); +MODULE_PARM(country,"i"); +MODULE_PARM(sniffer,"i"); +MODULE_PARM(bc,"i"); +MODULE_PARM(phy_addr,"s"); +MODULE_PARM(ray_mem_speed, "i"); static UCHAR b5_default_startup_parms[] = { 0, 0, /* Adhoc station */ @@ -284,7 +283,7 @@ static UCHAR b4_default_startup_parms[] = { /*===========================================================================*/ static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0}; -static char rcsid[] = " $Id: ray_cs.c,v 1.60 1999/09/01 20:58:45 corey Exp $ - Corey Thomas corey@world.std.com"; +static char rcsid[] = "Raylink/WebGear wireless LAN - Corey "; #ifdef CONFIG_PROC_FS struct proc_dir_entry ray_cs_proc_entry = { @@ -358,7 +357,7 @@ dev_link_t *ray_attach(void) local->finder = link; link->dev = &local->node; local->card_status = CARD_INSERTED; - local->authentication_state = UNAUTHENTICATED; + local->authentication_state = UNAUTHENTICATED; local->num_multi = 0; DEBUG(2,"ray_attach link = %p, dev = %p, local = %p, intr = %p\n", link,dev,local,&ray_interrupt); @@ -442,8 +441,6 @@ void ray_detach(dev_link_t *link) if (link->state & DEV_CONFIG) { ray_release((u_long)link); if(link->state & DEV_STALE_CONFIG) { - DEBUG(0,"ray_cs: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); link->state |= DEV_STALE_LINK; return; } @@ -472,7 +469,7 @@ void ray_detach(dev_link_t *link) =============================================================================*/ #define CS_CHECK(fn, args...) \ while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed -#define MAX_TUPLE_SIZE 80 +#define MAX_TUPLE_SIZE 128 void ray_config(dev_link_t *link) { client_handle_t handle = link->handle; @@ -480,7 +477,7 @@ void ray_config(dev_link_t *link) cisparse_t parse; int last_fn, last_ret; int i; - u_char buf[80]; + u_char buf[MAX_TUPLE_SIZE]; win_req_t req; memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; @@ -499,6 +496,19 @@ void ray_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; + /* Determine card type and firmware version */ + buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = buf; + tuple.TupleDataMax = MAX_TUPLE_SIZE; + tuple.TupleOffset = 2; + CS_CHECK(GetTupleData, handle, &tuple); + + for (i=0; istate |= DEV_CONFIG; @@ -562,7 +572,10 @@ void ray_config(dev_link_t *link) } link->state &= ~DEV_CONFIG_PENDING; - DEBUG(0, "ray_cs device loaded\n"); + printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", + dev->name, dev->irq); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); return; @@ -594,7 +607,8 @@ int ray_init(struct net_device *dev) /* Check Power up test status and get mac address from card */ if (local->startup_res.startup_word != 0x80) { -DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word); + printk(KERN_INFO "ray_init ERROR card status = %2x\n", + local->startup_res.startup_word); local->card_status = CARD_INIT_ERROR; return -1; } @@ -619,16 +633,12 @@ DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word); if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) { p = local->sparm.b4.a_mac_addr; - DEBUG(1,"ray_cs phy address overridden = %2x %2x %2x %2x %2x %2x\n",\ - p[0],p[1],p[2],p[3],p[4],p[5]); } else { memcpy(&local->sparm.b4.a_mac_addr, &local->startup_res.station_addr, ADDRLEN); p = local->sparm.b4.a_mac_addr; - DEBUG(1,"ray_cs phy addr= %2x %2x %2x %2x %2x %2x\n",\ - p[0],p[1],p[2],p[3],p[4],p[5]); } clear_interrupt(local); /* Clear any interrupt from the card */ @@ -647,7 +657,7 @@ int dl_startup_params(struct net_device *dev) DEBUG(1,"dl_startup_params entered\n"); if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs dl_startup_params - device not present\n"); + DEBUG(2,"ray_cs dl_startup_params - device not present\n"); return -1; } @@ -661,14 +671,15 @@ int dl_startup_params(struct net_device *dev) /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) == -1) return -1; + if ((ccsindex = get_free_ccs(local)) < 0) return -1; local->dl_param_ccs = ccsindex; pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); /* Interrupt the firmware to process the command */ if (interrupt_ecf(local, ccsindex)) { - DEBUG(0,"ray dl_startup_params failed - ECF not ready for intr\n"); + printk(KERN_INFO "ray dl_startup_params failed - " + "ECF not ready for intr\n"); local->card_status = CARD_DL_PARAM_ERROR; writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); return -2; @@ -723,11 +734,11 @@ void init_startup_params(ray_dev_t *local) local->sparm.b4.a_curr_country_code = country; local->sparm.b4.a_hop_pattern_length = hop_pattern_length[(int)country] - 1; - if (bc) - { - local->sparm.b4.a_ack_timeout = 0x50; - local->sparm.b4.a_sifs = 0x3f; - } + if (bc) + { + local->sparm.b4.a_ack_timeout = 0x50; + local->sparm.b4.a_sifs = 0x3f; + } } else { /* Version 5 uses real kus values */ memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, @@ -756,30 +767,29 @@ void verify_dl_startup(u_long data) ray_dev_t *local = (ray_dev_t *)data; struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs; UCHAR status; -/* UCHAR *p = local->sram + HOST_TO_ECF_BASE; */ dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs verify_dl_startup - device not present\n"); + DEBUG(2,"ray_cs verify_dl_startup - device not present\n"); return; } -#ifdef RAYLINK_DEBUG - { - int i; - DEBUG(2,"verify_dl_startup parameters sent via ccs %d:\n",\ - local->dl_param_ccs); - for (i=0; isram + HOST_TO_ECF_BASE + i)); +#ifdef PCMCIA_DEBUG + if (pc_debug > 2) { + int i; + printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n", + local->dl_param_ccs); + for (i=0; isram + HOST_TO_ECF_BASE + i)); } - DEBUG(1,"\n"); + printk("\n"); } #endif status = readb(&pccs->buffer_status); if (status!= CCS_BUFFER_FREE) { - DEBUG(0,"Download startup params failed. Status = %d\n",status); + printk(KERN_INFO "Download startup params failed. Status = %d\n", + status); local->card_status = CARD_DL_PARAM_ERROR; return; } @@ -799,11 +809,11 @@ void start_net(u_long data) int ccsindex; dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs start_net - device not present\n"); + DEBUG(2,"ray_cs start_net - device not present\n"); return; } /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) == -1) return; + if ((ccsindex = get_free_ccs(local)) < 0) return; pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; writeb(CCS_START_NETWORK, &pccs->cmd); writeb(0, &pccs->var.start_network.update_param); @@ -827,11 +837,11 @@ void join_net(u_long data) dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs join_net - device not present\n"); + DEBUG(2,"ray_cs join_net - device not present\n"); return; } /* Fill in the CCS fields for the ECF */ - if ((ccsindex = get_free_ccs(local)) == -1) return; + if ((ccsindex = get_free_ccs(local)) < 0) return; pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; writeb(CCS_JOIN_NETWORK, &pccs->cmd); writeb(0, &pccs->var.join_network.update_param); @@ -867,7 +877,7 @@ void ray_release(u_long arg) link->state |= DEV_STALE_CONFIG; return; } - del_timer(&local->timer); + del_timer(&local->timer); if (link->dev != '\0') unregister_netdev(dev); /* Unlink the device chain */ link->dev = NULL; @@ -962,13 +972,14 @@ int ray_dev_init(struct net_device *dev) DEBUG(1,"ray_dev_init(dev=%p)\n",dev); if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_dev_init - device not present\n"); + DEBUG(2,"ray_dev_init - device not present\n"); return -1; } /* Download startup parameters */ if ( (i = dl_startup_params(dev)) < 0) { - DEBUG(0,"ray_dev_init dl_startup_params failed - returns 0x%x/n",i); + printk(KERN_INFO "ray_dev_init dl_startup_params failed - " + "returns 0x%x/n",i); return -1; } @@ -976,15 +987,6 @@ int ray_dev_init(struct net_device *dev) memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); memset(dev->broadcast, 0xff, ETH_ALEN); -#ifdef RAYLINK_DEBUG - { - UCHAR *p; - p = (UCHAR *)(local->startup_res.station_addr); - DEBUG(1,"ray_dev_init card hardware mac addr = %2x %2x %2x %2x %2x %2x\n",\ - p[0],p[1],p[2],p[3],p[4],p[5]); - } -#endif - DEBUG(2,"ray_dev_init ending\n"); return 0; } @@ -996,7 +998,7 @@ int ray_dev_config(struct net_device *dev, struct ifmap *map) /* Dummy routine to satisfy device structure */ DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_dev_config - device not present\n"); + DEBUG(2,"ray_dev_config - device not present\n"); return -1; } @@ -1010,13 +1012,13 @@ int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) short length; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_dev_start_xmit - device not present\n"); + DEBUG(2,"ray_dev_start_xmit - device not present\n"); return -1; } DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev); if (dev->tbusy) { - DEBUG(2,"ray_dev_start_xmit busy\n"); + printk(KERN_NOTICE "ray_dev_start_xmit busy\n"); return 1; } if (local->authentication_state == NEED_TO_AUTH) { @@ -1031,7 +1033,7 @@ int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) { case XMIT_NO_CCS: - case XMIT_NEED_AUTH: + case XMIT_NEED_AUTH: dev->tbusy = 1; return 1; case XMIT_NO_INTR: @@ -1058,15 +1060,20 @@ int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) { - DEBUG(0,"ray_hw_xmit packet to large %d bytes\n",len); + printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len); return XMIT_MSG_BAD; } - if ((ccsindex = get_free_tx_ccs(local)) == -1) - { - DEBUG(2,"ray_hw_xmit - No free tx ccs\n"); + switch (ccsindex = get_free_tx_ccs(local)) { + case ECCSBUSY: + DEBUG(2,"ray_hw_xmit tx_ccs table busy\n"); + case ECCSFULL: + DEBUG(2,"ray_hw_xmit No free tx ccs\n"); + case ECARDGONE: dev->tbusy = 1; return XMIT_NO_CCS; - } + default: + break; + } addr = TX_BUF_BASE + (ccsindex << 11); if (msg_type == DATA_TYPE) { @@ -1186,7 +1193,7 @@ int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) int err = 0; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_dev_ioctl - device not present\n"); + DEBUG(2,"ray_dev_ioctl - device not present\n"); return -1; } DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd); @@ -1258,16 +1265,14 @@ void ray_reset(struct net_device *dev) { int interrupt_ecf(ray_dev_t *local, int ccs) { int i = 50; -/* UCHAR *p = (local->amem + CIS_OFFSET + ECF_INTR_OFFSET); */ dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs interrupt_ecf - device not present\n"); + DEBUG(2,"ray_cs interrupt_ecf - device not present\n"); return -1; } DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs); -/* while ( i && (*p & ECF_INTR_SET)) i--; */ while ( i && (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET)) i--; @@ -1275,8 +1280,8 @@ int interrupt_ecf(ray_dev_t *local, int ccs) DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n"); return -1; } - - *(local->sram + SCB_BASE) = ccs; + /* Fill the mailbox, then kick the card */ + writeb(ccs, local->sram + SCB_BASE); writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); return 0; } /* interrupt_ecf */ @@ -1290,19 +1295,26 @@ int get_free_tx_ccs(ray_dev_t *local) dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs get_free_tx_ccs - device not present\n"); - return -1; + DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n"); + return ECARDGONE; } + if (test_and_set_bit(0,&local->tx_ccs_lock)) { + DEBUG(1,"ray_cs tx_ccs_lock busy\n"); + return ECCSBUSY; + } + for (i=0; i < NUMBER_OF_TX_CCS; i++) { if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); writeb(CCS_END_LIST, &(pccs+i)->link); + local->tx_ccs_lock = 0; return i; } } - DEBUG(1,"ray_cs ERROR no free tx CCS for raylink card\n"); - return -1; + local->tx_ccs_lock = 0; + DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n"); + return ECCSFULL; } /* get_free_tx_ccs */ /*===========================================================================*/ /* Get next free CCS */ @@ -1314,25 +1326,33 @@ int get_free_ccs(ray_dev_t *local) dev_link_t *link = local->finder; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs get_free_ccs - device not present\n"); - return -1; + DEBUG(2,"ray_cs get_free_ccs - device not present\n"); + return ECARDGONE; } + if (test_and_set_bit(0,&local->ccs_lock)) { + DEBUG(1,"ray_cs ccs_lock busy\n"); + return ECCSBUSY; + } + for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); writeb(CCS_END_LIST, &(pccs+i)->link); + local->ccs_lock = 0; return i; } } + local->ccs_lock = 0; DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n"); - return -1; + return ECCSFULL; } /* get_free_ccs */ /*===========================================================================*/ void authenticate_timeout(u_long data) { ray_dev_t *local = (ray_dev_t *)data; del_timer(&local->timer); - DEBUG(0,"ray_cs Authentication with access point failed - timeout\n"); + printk(KERN_INFO "ray_cs Authentication with access point failed" + " - timeout\n"); join_net((u_long)local); } /*===========================================================================*/ @@ -1381,26 +1401,26 @@ struct enet_statistics *ray_get_stats(struct net_device *dev) dev_link_t *link = local->finder; struct status *p = (struct status *)(local->sram + STATUS_BASE); if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_cs enet_statistics - device not present\n"); + DEBUG(2,"ray_cs enet_statistics - device not present\n"); return &local->stats; } - if (p->mrx_overflow_for_host) + if (readb(&p->mrx_overflow_for_host)) { - local->stats.rx_over_errors += ntohs(p->mrx_overflow); - p->mrx_overflow = 0; - p->mrx_overflow_for_host = 0; + local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow)); + writeb(0,&p->mrx_overflow); + writeb(0,&p->mrx_overflow_for_host); } - if (p->mrx_checksum_error_for_host) + if (readb(&p->mrx_checksum_error_for_host)) { - local->stats.rx_crc_errors += ntohs(p->mrx_checksum_error); - p->mrx_checksum_error = 0; - p->mrx_checksum_error_for_host = 0; + local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error)); + writeb(0,&p->mrx_checksum_error); + writeb(0,&p->mrx_checksum_error_for_host); } - if (p->rx_hec_error_for_host) + if (readb(&p->rx_hec_error_for_host)) { - local->stats.rx_frame_errors += ntohs(p->rx_hec_error); - p->rx_hec_error = 0; - p->rx_hec_error_for_host = 0; + local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error)); + writeb(0,&p->rx_hec_error); + writeb(0,&p->rx_hec_error_for_host); } return &local->stats; } @@ -1414,11 +1434,11 @@ void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) struct ccs *pccs; if (!(link->state & DEV_PRESENT)) { - DEBUG(0,"ray_update_parm - device not present\n"); + DEBUG(2,"ray_update_parm - device not present\n"); return; } - if ((ccsindex = get_free_ccs(local)) == -1) + if ((ccsindex = get_free_ccs(local)) < 0) { DEBUG(0,"ray_update_parm - No free ccs\n"); return; @@ -1449,12 +1469,12 @@ static void ray_update_multi_list(struct net_device *dev, int all) UCHAR *p = local->sram + HOST_TO_ECF_BASE; if (!(link->state & DEV_PRESENT)) { - DEBUG(1,"ray_update_multi_list - device not present\n"); + DEBUG(2,"ray_update_multi_list - device not present\n"); return; } else - DEBUG(1,"ray_update_multi_list(%p)\n",dev); - if ((ccsindex = get_free_ccs(local)) == -1) + DEBUG(2,"ray_update_multi_list(%p)\n",dev); + if ((ccsindex = get_free_ccs(local)) < 0) { DEBUG(1,"ray_update_multi - No free ccs\n"); return; @@ -1491,7 +1511,7 @@ static void set_multicast_list(struct net_device *dev) ray_dev_t *local = (ray_dev_t *)dev->priv; UCHAR promisc; - DEBUG(1,"ray_cs set_multicast_list(%p)\n",dev); + DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev); if (dev->flags & IFF_PROMISC) { @@ -1534,30 +1554,23 @@ void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) UCHAR cmd; UCHAR status; - if (dev == NULL) { - link = dev_list; - dev = (struct net_device *)link->priv; - DEBUG(4,"ray_cs interrupt dev = %p, link = %p\n",dev,link); - if (dev->irq != irq) - { - DEBUG(0,"ray_cs interrupt irq %d for unknown device.\n", irq); - return; - } - } + if ((dev == NULL) || !dev->start) + return; + DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); - if (dev->interrupt) { + if (test_and_set_bit(0,&dev->interrupt)) { printk("ray_cs Reentering interrupt handler not allowed\n"); return; } - dev->interrupt = 1; + local = (ray_dev_t *)dev->priv; link = (dev_link_t *)local->finder; if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { - DEBUG(1,"ray_cs interrupt from device not present or suspended.\n"); + DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); return; } - rcsindex = ((struct scb *)(local->sram))->rcs_index; + rcsindex = readb(&((struct scb *)(local->sram))->rcs_index); if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { @@ -1602,7 +1615,7 @@ void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) case CCS_JOIN_NETWORK: if (status == CCS_COMMAND_COMPLETE) { if (readb(&pccs->var.start_network.net_initiated) == 1) { - DEBUG(0,"ray_cs interrupt network \"%s\"started\n",\ + DEBUG(0,"ray_cs interrupt network \"%s\" started\n",\ local->sparm.b4.a_current_ess_id); } else { @@ -1741,16 +1754,16 @@ void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) switch(readb(pmsg)) { case DATA_TYPE: - DEBUG(4,"ray_rx data type\n"); + DEBUG(4,"ray_rx data type\n"); rx_data(dev, prcs, pkt_addr, rx_len); break; case AUTHENTIC_TYPE: - DEBUG(4,"ray_rx authentic type\n"); + DEBUG(4,"ray_rx authentic type\n"); if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); else rx_authenticate(local, prcs, pkt_addr, rx_len); break; case DEAUTHENTIC_TYPE: - DEBUG(4,"ray_rx deauth type\n"); + DEBUG(4,"ray_rx deauth type\n"); if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); else rx_deauthenticate(local, prcs, pkt_addr, rx_len); break; @@ -1758,7 +1771,7 @@ void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) DEBUG(3,"ray_cs rx NULL msg\n"); break; case BEACON_TYPE: - DEBUG(4,"ray_rx beacon type\n"); + DEBUG(4,"ray_rx beacon type\n"); if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, @@ -1909,19 +1922,24 @@ void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) struct ethhdr *peth; UCHAR srcaddr[ADDRLEN]; UCHAR destaddr[ADDRLEN]; - int i; - if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA) + if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA) memcpy(destaddr, pmac->addr_3, ADDRLEN); else memcpy(destaddr, pmac->addr_1, ADDRLEN); memcpy(srcaddr, pmac->addr_2, ADDRLEN); - DEBUG(3,"skb->data before untranslate"); +#ifdef PCMCIA_DEBUG + if (pc_debug > 3) { + int i; + printk(KERN_DEBUG "skb->data before untranslate"); for (i=0;i<64;i++) - DEBUG(3,"%02x ",skb->data[i]); - DEBUG(3,"\ntype = %08x, xsap = %08x, org = %08x\n",type,xsap,org); - DEBUG(3,"untranslate skb->data = %p\n",skb->data); + printk("%02x ",skb->data[i]); + printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n", + type,xsap,org); + printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data); + } +#endif if ( xsap != SNAP_ID) { /* not a snap type so leave it alone */ @@ -1971,10 +1989,15 @@ void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data); memcpy(peth->h_dest, destaddr, ADDRLEN); memcpy(peth->h_source, srcaddr, ADDRLEN); - DEBUG(3,"skb->data after untranslate:"); - for (i=0;i<64;i++) - DEBUG(3,"%02x ",skb->data[i]); - DEBUG(3,"\n"); +#ifdef PCMCIA_DEBUG + if (pc_debug > 3) { + int i; + printk(KERN_DEBUG "skb->data after untranslate:"); + for (i=0;i<64;i++) + printk("%02x ",skb->data[i]); + printk("\n"); + } +#endif } /* end untranslate */ /*===========================================================================*/ /* Copy data from circular receive buffer to PC memory. @@ -2020,7 +2043,7 @@ void authenticate(ray_dev_t *local) dev_link_t *link = local->finder; DEBUG(0,"ray_cs Starting authentication.\n"); if (!(link->state & DEV_PRESENT)) { - DEBUG(1,"ray_cs authenticate - device not present\n"); + DEBUG(2,"ray_cs authenticate - device not present\n"); return; } @@ -2046,37 +2069,37 @@ void rx_authenticate(ray_dev_t *local, struct rcs *prcs, del_timer(&local->timer); copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); - /* if we are trying to get authenticated */ + /* if we are trying to get authenticated */ if (local->sparm.b4.a_network_type == ADHOC) { - DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]); - if (msg->var[2] == 1) { + DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]); + if (msg->var[2] == 1) { DEBUG(0,"ray_cs Sending authentication response.\n"); if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { local->authentication_state = NEED_TO_AUTH; memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN); } - } - } - else /* Infrastructure network */ - { - if (local->authentication_state == AWAITING_RESPONSE) { - /* Verify authentication sequence #2 and success */ - if (msg->var[2] == 2) { - if ((msg->var[3] | msg->var[4]) == 0) { - DEBUG(1,"Authentication successful\n"); - local->card_status = CARD_AUTH_COMPLETE; - associate(local); - local->authentication_state = AUTHENTICATED; - } - else { - DEBUG(0,"Authentication refused\n"); - local->card_status = CARD_AUTH_REFUSED; - join_net((u_long)local); - local->authentication_state = UNAUTHENTICATED; - } - } - } - } + } + } + else /* Infrastructure network */ + { + if (local->authentication_state == AWAITING_RESPONSE) { + /* Verify authentication sequence #2 and success */ + if (msg->var[2] == 2) { + if ((msg->var[3] | msg->var[4]) == 0) { + DEBUG(1,"Authentication successful\n"); + local->card_status = CARD_AUTH_COMPLETE; + associate(local); + local->authentication_state = AUTHENTICATED; + } + else { + DEBUG(0,"Authentication refused\n"); + local->card_status = CARD_AUTH_REFUSED; + join_net((u_long)local); + local->authentication_state = UNAUTHENTICATED; + } + } + } + } } /* end rx_authenticate */ /*===========================================================================*/ @@ -2087,11 +2110,11 @@ void associate(ray_dev_t *local) struct net_device *dev = link->priv; int ccsindex; if (!(link->state & DEV_PRESENT)) { - DEBUG(1,"ray_cs associate - device not present\n"); + DEBUG(2,"ray_cs associate - device not present\n"); return; } /* If no tx buffers available, return*/ - if ((ccsindex = get_free_ccs(local)) == -1) + if ((ccsindex = get_free_ccs(local)) < 0) { /* TBD should never be here but... what if we are? */ DEBUG(1,"ray_cs associate - No free ccs\n"); @@ -2125,7 +2148,7 @@ void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, struct rx_msg *msg = (struct rx_msg *)buff; */ DEBUG(0,"Deauthentication frame received\n"); - local->authentication_state = UNAUTHENTICATED; + local->authentication_state = UNAUTHENTICATED; /* Need to reauthenticate or rejoin depending on reason code */ /* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); */ @@ -2256,9 +2279,8 @@ int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) int ccsindex; /* If no tx buffers available, return */ - if ((ccsindex = get_free_tx_ccs(local)) == -1) + if ((ccsindex = get_free_tx_ccs(local)) < 0) { -/* TBD should never be here but... what if we are? */ DEBUG(1,"ray_cs send authenticate - No free tx ccs\n"); return -1; } diff --git a/drivers/net/pcmcia/ray_cs.h b/drivers/net/pcmcia/ray_cs.h index 28502954eb0e..ae28bc71aecd 100644 --- a/drivers/net/pcmcia/ray_cs.h +++ b/drivers/net/pcmcia/ray_cs.h @@ -17,9 +17,14 @@ struct beacon_rx { + sizeof(struct tim_element)]; }; +/* Return values for get_free{,_tx}_ccs */ +#define ECCSFULL (-1) +#define ECCSBUSY (-2) +#define ECARDGONE (-3) + typedef struct ray_dev_t { int card_status; - int authentication_state; + int authentication_state; dev_node_t node; window_handle_t amem_handle; /* handle to window for attribute memory */ window_handle_t rmem_handle; /* handle to window for rx buffer on card */ @@ -28,6 +33,8 @@ typedef struct ray_dev_t { UCHAR *rmem; /* pointer to receive buffer window */ dev_link_t *finder; /* pointer back to dev_link_t for card */ struct timer_list timer; + int tx_ccs_lock; + int ccs_lock; int dl_param_ccs; union { struct b4_startup_params b4; diff --git a/drivers/net/pcmcia/rayctl.h b/drivers/net/pcmcia/rayctl.h index a301b0bd2873..49d9b267bc0f 100644 --- a/drivers/net/pcmcia/rayctl.h +++ b/drivers/net/pcmcia/rayctl.h @@ -142,8 +142,6 @@ struct adhoc_beacon }; /*****************************************************************************/ /*****************************************************************************/ - - /* #define C_MAC_HDR_2_WEP 0x40 */ /* TX/RX CCS constants */ #define TX_HEADER_LENGTH 0x1C @@ -151,6 +149,9 @@ struct adhoc_beacon #define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6) #define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) #define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) +#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2) +#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) +#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) #define FCS_LEN 4 #define ADHOC 0 @@ -324,17 +325,23 @@ struct adhoc_beacon #define CARD_ASSOC_COMPLETE (6) #define CARD_ASSOC_FAILED (16) -/*** Values for authentication_state */ +/*** Values for authentication_state ***********************************/ #define UNAUTHENTICATED (0) #define AWAITING_RESPONSE (1) #define AUTHENTICATED (2) #define NEED_TO_AUTH (3) -/*** Values for authentication type */ +/*** Values for authentication type ************************************/ #define OPEN_AUTH_REQUEST (1) #define OPEN_AUTH_RESPONSE (2) - - +#define BROADCAST_DEAUTH (0xc0) +/*** Values for timer functions ****************************************/ +#define TODO_NOTHING (0) +#define TODO_VERIFY_DL_START (-1) +#define TODO_START_NET (-2) +#define TODO_JOIN_NET (-3) +#define TODO_AUTHENTICATE_TIMEOUT (-4) +#define TODO_SEND_CCS (-5) /***********************************************************************/ /* Parameter passing structure for update/report parameter CCS's */ struct object_id { diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 5a29ff4594b6..1bc4b2db1afe 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -161,15 +161,15 @@ static void parport_ieee1284_terminate (struct parport *port) /* Terminate from EPP mode. */ /* Event 68: Set nInit low */ - parport_frob_control (port, - PARPORT_CONTROL_INIT, - PARPORT_CONTROL_INIT); + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); udelay (50); /* Event 69: Set nInit high, nSelectIn low */ parport_frob_control (port, - PARPORT_CONTROL_SELECT, - PARPORT_CONTROL_SELECT); + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT, + PARPORT_CONTROL_SELECT + | PARPORT_CONTROL_INIT); break; default: diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index 41780752cf2f..4d460a58d6f9 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -9,8 +9,10 @@ * Note: Make no assumptions about hardware or architecture in this file! * * Author: Tim Waugh + * Fixed AUTOFD polarity in ecp_forward_to_reverse(). Fred Barnes, 1999 */ + #include #include #include @@ -336,7 +338,7 @@ int ecp_forward_to_reverse (struct parport *port) /* Event 38: Set nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, - 0); + PARPORT_CONTROL_AUTOFD); parport_data_reverse (port); udelay (5); @@ -524,12 +526,12 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port, if (count && dev->port->irq != PARPORT_IRQ_NONE) { parport_release (dev); current->state = TASK_INTERRUPTIBLE; - schedule_timeout ((HZ + 99) / 25); + schedule_timeout ((HZ + 24) / 25); parport_claim_or_block (dev); } else /* We must have the device claimed here. */ - parport_wait_event (port, (HZ + 99) / 25); + parport_wait_event (port, (HZ + 24) / 25); /* Is there a signal pending? */ if (signal_pending (current)) @@ -610,10 +612,11 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port, count += rle_count; DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n", port->name, rle_count); - } - else + } else { /* Normal data byte. */ - *buf++ = byte, count++; + *buf = byte; + buf++, count++; + } } out: diff --git a/drivers/parport/init.c b/drivers/parport/init.c index 7874519c7d3d..8f30d60c1aed 100644 --- a/drivers/parport/init.c +++ b/drivers/parport/init.c @@ -209,6 +209,8 @@ EXPORT_SYMBOL(parport_device_coords); EXPORT_SYMBOL(parport_daisy_deselect_all); EXPORT_SYMBOL(parport_daisy_select); EXPORT_SYMBOL(parport_daisy_init); +EXPORT_SYMBOL(parport_find_device); +EXPORT_SYMBOL(parport_find_class); #endif void inc_parport_count(void) diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 3b5d1812730a..efa644f8010a 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -10,6 +10,7 @@ * * Cleaned up include files - Russell King * DMA support - Bert De Jonghe + * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 */ /* This driver should work with any hardware that is broadly compatible @@ -73,7 +74,12 @@ static void frob_econtrol (struct parport *pb, unsigned char m, unsigned char v) { - outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb)); + unsigned char ectr = inb (ECONTROL (pb)); +#ifdef DEBUG_PARPORT + printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", + m, v, ectr, (ectr & ~m) ^ v); +#endif + outb ((ectr & ~m) ^ v, ECONTROL (pb)); } #ifdef CONFIG_PARPORT_PC_FIFO @@ -94,11 +100,8 @@ static int change_mode(struct parport *p, int m) oecr = inb (ecr); mode = (oecr >> 5) & 0x7; if (mode == m) return 0; - if (mode && m) - /* We have to go through mode 000 */ - change_mode (p, ECR_SPP); - if (m < 2 && !(parport_read_control (p) & 0x20)) { + if (mode >= 2 && !(priv->ctr & 0x20)) { /* This mode resets the FIFO, so we may * have to wait for it to drain first. */ long expire = jiffies + p->physport->cad->timeout; @@ -127,6 +130,13 @@ static int change_mode(struct parport *p, int m) } } + if (mode >= 2 && m >= 2) { + /* We have to go through mode 001 */ + oecr &= ~(7 << 5); + oecr |= ECR_PS2 << 5; + outb (oecr, ecr); + } + /* Set the mode. */ oecr &= ~(7 << 5); oecr |= m << 5; @@ -160,11 +170,11 @@ static int get_fifo_residue (struct parport *p) residue); /* Reset the FIFO. */ - frob_econtrol (p, 0xe0, 0x20); + frob_econtrol (p, 0xe0, ECR_PS2 << 5); parport_frob_control (p, PARPORT_CONTROL_STROBE, 0); /* Now change to config mode and clean up. FIXME */ - frob_econtrol (p, 0xe0, 0xe0); + frob_econtrol (p, 0xe0, ECR_CNF << 5); cnfga = inb (CONFIGA (p)); printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); @@ -177,7 +187,7 @@ static int get_fifo_residue (struct parport *p) * PWord != 1 byte. */ /* Back to PS2 mode. */ - frob_econtrol (p, 0xe0, 0x20); + frob_econtrol (p, 0xe0, ECR_PS2 << 5); return residue; } @@ -209,9 +219,9 @@ static int clear_epp_timeout(struct parport *pb) /* * Access functions. * - * These aren't static because they may be used by the parport_xxx_yyy - * macros. extern __inline__ versions of several of these are in - * parport_pc.h. + * Most of these aren't static because they may be used by the + * parport_xxx_yyy macros. extern __inline__ versions of several + * of these are in parport_pc.h. */ static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -229,21 +239,6 @@ unsigned char parport_pc_read_data(struct parport *p) return inb (DATA (p)); } -unsigned char __frob_control (struct parport *p, unsigned char mask, - unsigned char val) -{ - const unsigned char wm = (PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_INIT | - PARPORT_CONTROL_SELECT); - struct parport_pc_private *priv = p->physport->private_data; - unsigned char ctr = priv->ctr; - ctr = (ctr & ~mask) ^ val; - ctr &= priv->ctr_writable; /* only write writable bits. */ - outb (ctr, CONTROL (p)); - return priv->ctr = ctr & wm; /* update soft copy */ -} - void parport_pc_write_control(struct parport *p, unsigned char d) { const unsigned char wm = (PARPORT_CONTROL_STROBE | @@ -253,18 +248,22 @@ void parport_pc_write_control(struct parport *p, unsigned char d) /* Take this out when drivers have adapted to the newer interface. */ if (d & 0x20) { - printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", - p->name, p->cad->name); - parport_pc_data_reverse (p); + printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", + p->name, p->cad->name); + parport_pc_data_reverse (p); } - __frob_control (p, wm, d & wm); + __parport_pc_frob_control (p, wm, d & wm); } unsigned char parport_pc_read_control(struct parport *p) { + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); const struct parport_pc_private *priv = p->physport->private_data; - return priv->ctr; /* Use soft copy */ + return priv->ctr & wm; /* Use soft copy */ } unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, @@ -277,16 +276,20 @@ unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask, /* Take this out when drivers have adapted to the newer interface. */ if (mask & 0x20) { - printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", - p->name, p->cad->name); + printk (KERN_DEBUG "%s (%s): use data_%s for this!\n", + p->name, p->cad->name, + (val & 0x20) ? "reverse" : "forward"); + if (val & 0x20) parport_pc_data_reverse (p); + else + parport_pc_data_forward (p); } /* Restrict mask and val to control lines. */ mask &= wm; val &= wm; - return __frob_control (p, mask, val); + return __parport_pc_frob_control (p, mask, val); } unsigned char parport_pc_read_status(struct parport *p) @@ -296,22 +299,22 @@ unsigned char parport_pc_read_status(struct parport *p) void parport_pc_disable_irq(struct parport *p) { - __frob_control (p, 0x10, 0); + __parport_pc_frob_control (p, 0x10, 0); } void parport_pc_enable_irq(struct parport *p) { - __frob_control (p, 0x10, 0x10); + __parport_pc_frob_control (p, 0x10, 0x10); } void parport_pc_data_forward (struct parport *p) { - __frob_control (p, 0x20, 0); + __parport_pc_frob_control (p, 0x20, 0); } void parport_pc_data_reverse (struct parport *p) { - __frob_control (p, 0x20, 0x20); + __parport_pc_frob_control (p, 0x20, 0x20); } void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) @@ -469,7 +472,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port, frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ /* Forward mode. */ - parport_pc_data_forward (port); + parport_pc_data_forward (port); /* Must be in PS2 mode */ while (left) { unsigned char byte; @@ -559,7 +562,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port, frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ /* Forward mode. */ - parport_pc_data_forward (port); + parport_pc_data_forward (port); /* Must be in PS2 mode */ while (left) { long expire = jiffies + port->physport->cad->timeout; @@ -656,8 +659,8 @@ size_t parport_pc_compat_write_block_pio (struct parport *port, length, flags); /* Set up parallel port FIFO mode.*/ + parport_pc_data_forward (port); /* Must be in PS2 mode */ change_mode (port, ECR_PPF); /* Parallel port FIFO */ - parport_pc_data_forward (port); port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; /* Write the data to the FIFO. */ @@ -687,8 +690,8 @@ size_t parport_pc_compat_write_block_pio (struct parport *port, outb (0, FIFO (port)); } - /* Reset the FIFO. */ - frob_econtrol (port, 0xe0, 0); + /* Reset the FIFO and return to PS2 mode. */ + frob_econtrol (port, 0xe0, ECR_PS2 << 5); /* De-assert strobe. */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); @@ -727,8 +730,8 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, } /* Set up ECP parallel port mode.*/ + parport_pc_data_forward (port); /* Must be in PS2 mode */ change_mode (port, ECR_ECP); /* ECP FIFO */ - parport_pc_data_forward (port); port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; /* Write the data to the FIFO. */ @@ -758,17 +761,20 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, outb (0, FIFO (port)); } - /* Reset the FIFO. */ - frob_econtrol (port, 0xe0, 0); + /* Reset the FIFO and return to PS2 mode. */ + frob_econtrol (port, 0xe0, ECR_PS2 << 5); + + /* De-assert strobe. */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); /* Host transfer recovery. */ + parport_pc_data_reverse (port); /* Must be in PS2 mode */ + udelay (5); + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); - parport_pc_data_reverse (port); - parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); - parport_frob_control (port, PARPORT_CONTROL_INIT, 0); parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); @@ -819,21 +825,21 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); - parport_pc_data_reverse (port); + parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); /* Event 39: Set nInit low to initiate bus reversal */ parport_frob_control (port, PARPORT_CONTROL_INIT, - PARPORT_CONTROL_INIT); + 0); /* Event 40: PError goes low */ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); } /* Set up ECP parallel port mode.*/ + parport_pc_data_reverse (port); /* Must be in PS2 mode */ change_mode (port, ECR_ECP); /* ECP FIFO */ - parport_pc_data_reverse (port); port->ieee1284.phase = IEEE1284_PH_REV_DATA; /* Do the transfer. */ @@ -1054,7 +1060,6 @@ static int __maybe_init parport_ECR_present(struct parport *pb) struct parport_pc_private *priv = pb->private_data; unsigned char r = 0xc; - priv->ecr = 0; outb (r, CONTROL (pb)); if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) { outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */ @@ -1120,9 +1125,9 @@ static int __maybe_init parport_PS2_supported(struct parport *pb) /* cancel input mode */ parport_pc_data_forward (pb); - if (ok) + if (ok) { pb->modes |= PARPORT_MODE_TRISTATE; - else { + } else { struct parport_pc_private *priv = pb->private_data; priv->ctr_writable &= ~0x20; } @@ -1180,8 +1185,8 @@ static int __maybe_init parport_ECP_supported(struct parport *pb) priv->writeIntrThreshold = i; /* Find out readIntrThreshold */ - frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */ - parport_pc_data_reverse (pb); + frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO and enable PS2 */ + parport_pc_data_reverse (pb); /* Must be in PS2 mode */ frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */ frob_econtrol (pb, 1<<2, 1<<2); frob_econtrol (pb, 1<<2, 0); @@ -1544,12 +1549,10 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, if (base_hi && !check_region(base_hi,3)) { parport_ECR_present(p); parport_ECP_supported(p); - parport_ECPPS2_supported(p); } if (base != 0x3bc) { if (!check_region(base+0x3, 5)) { - parport_EPP_supported(p); - if (!(p->modes & PARPORT_MODE_EPP)) + if (!parport_EPP_supported(p)) parport_ECPEPP_supported(p); } } @@ -1558,8 +1561,10 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, kfree (priv); return NULL; } - - parport_PS2_supported (p); + if (priv->ecr) + parport_ECPPS2_supported(p); + else + parport_PS2_supported (p); if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops))) { @@ -1672,9 +1677,10 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, /* Done probing. Now put the port into a sensible start-up state. * SELECT | INIT also puts IEEE1284-compliant devices into * compatibility mode. */ - if (p->modes & PARPORT_MODE_ECP) + if (priv->ecr) /* * Put the ECP detected port in PS2 mode. + * Do this also for ports that have ECR but don't do ECP. */ outb (0x34, ECONTROL (p)); diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 45197e4c35df..4511040eee84 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -25,6 +25,10 @@ ifdef CONFIG_PROC_FS L_OBJS += proc.o endif -L_OBJS += compat.o quirks.o names.o syscall.o setup.o +L_OBJS += compat.o quirks.o names.o + +ifndef CONFIG_X86 +L_OBJS += syscall.o setup.o +endif include $(TOPDIR)/Rules.make diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 51c229c258a3..5cf99152198e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -17,7 +17,6 @@ #include #include -#include #include #undef DEBUG @@ -125,26 +124,20 @@ pci_find_parent_resource(struct pci_dev *dev, struct resource *res) int i; struct resource *best = NULL; - while (bus) { - for(i=0; i<4; i++) { - struct resource *r = bus->resource[i]; - if (!r) - continue; - if (res->start && !(res->start >= r->start && res->end <= r->end)) - continue; /* Not contained */ - if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) - continue; /* Wrong type */ - if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) - return r; /* Exact match */ - if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH)) - best = r; /* Approximating prefetchable by non-prefetchable */ - } - if (best) - return best; - bus = bus->parent; + for(i=0; i<4; i++) { + struct resource *r = bus->resource[i]; + if (!r) + continue; + if (res->start && !(res->start >= r->start && res->end <= r->end)) + continue; /* Not contained */ + if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) + continue; /* Wrong type */ + if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) + return r; /* Exact match */ + if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH)) + best = r; /* Approximating prefetchable by non-prefetchable */ } - printk(KERN_ERR "PCI: Bug: Parent resource not found!\n"); - return NULL; + return best; } @@ -193,46 +186,17 @@ pci_set_master(struct pci_dev *dev) pci_read_config_word(dev, PCI_COMMAND, &cmd); if (! (cmd & PCI_COMMAND_MASTER)) { - printk("PCI: Enabling bus mastering for device %s\n", dev->name); + printk("PCI: Enabling bus mastering for device %s\n", dev->slot_name); cmd |= PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, cmd); } pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); if (lat < 16) { - printk("PCI: Increasing latency timer of device %s to 64\n", dev->name); + printk("PCI: Increasing latency timer of device %s to 64\n", dev->slot_name); pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); } } -/* - * Assign new address to PCI resource. We hope our resource information - * is complete. On the PC, we don't re-assign resources unless we are - * forced to do so or the driver asks us to. - * - * Expects start=0, end=size-1, flags=resource type. - */ -int __init pci_assign_resource(struct pci_dev *dev, int i) -{ - struct resource *r = &dev->resource[i]; - struct resource *pr = pci_find_parent_resource(dev, r); - unsigned long size = r->end + 1; - - if (!pr) - return -EINVAL; - if (r->flags & IORESOURCE_IO) { - if (size > 0x100) - return -EFBIG; - if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) - return -EBUSY; - } else { - if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) - return -EBUSY; - } - if (i < 6) - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start); - return 0; -} - /* * Translate the low bits of the PCI base * to the resource type @@ -296,7 +260,7 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) res->end = res->start + (((unsigned long) ~l) << 32); #else if (l) { - printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->name); + printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name); res->start = 0; res->flags = 0; continue; @@ -305,6 +269,7 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } } if (rom) { + dev->rom_base_reg = rom; res = &dev->resource[PCI_ROM_RESOURCE]; pci_read_config_dword(dev, rom, &l); pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE); @@ -324,8 +289,9 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) pci_write_config_word(dev, PCI_COMMAND, cmd); } -void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child) +void __init pci_read_bridge_bases(struct pci_bus *child) { + struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi; u32 mem_base_hi, mem_limit_hi; @@ -333,6 +299,9 @@ void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child) struct resource *res; int i; + if (!dev) /* It's a host bus, nothing to read */ + return; + for(i=0; i<3; i++) child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; @@ -425,31 +394,27 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) dev_cache = NULL; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; - sprintf(dev->name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); + sprintf(dev->slot_name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); pci_name_device(dev); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); class >>= 8; /* upper 3 bytes */ dev->class = class; class >>= 8; - dev->hdr_type = hdr_type; + dev->hdr_type = hdr_type & 0x7f; - switch (hdr_type & 0x7f) { /* header type */ + switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ if (class == PCI_CLASS_BRIDGE_PCI) goto bad; /* - * If the card generates interrupts, read IRQ number - * (some architectures change it during pcibios_fixup()) + * Read interrupt line and base address registers. + * The architecture-dependent code can tweak these, of course. */ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq); if (irq) pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); dev->irq = irq; - /* - * read base address registers, again pcibios_fixup() can - * tweak these - */ pci_read_bases(dev, 6, PCI_ROM_ADDRESS); pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); @@ -468,8 +433,8 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) break; default: /* unknown header */ bad: - printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n", - bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type); + printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n", + dev->slot_name, hdr_type); continue; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ec8fcb7a8bb3..d25a0ed293a8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -31,7 +31,7 @@ static void __init quirk_passive_release(struct pci_dev *dev) while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->name); + printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } @@ -99,7 +99,7 @@ static void pci_do_fixups(struct pci_dev *dev, int pass, struct pci_fixup *f) (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG - printk("PCI: Calling quirk %p for %s\n", f->hook, dev->name); + printk("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name); #endif f->hook(dev); } diff --git a/drivers/pci/setup.c b/drivers/pci/setup.c index 53bf9f58271d..9c752d0defa8 100644 --- a/drivers/pci/setup.c +++ b/drivers/pci/setup.c @@ -16,7 +16,6 @@ #include #include -#include #define DEBUG_CONFIG 0 @@ -108,9 +107,12 @@ pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem) (ie. do not respond to memory space writes) when it is left enabled. A good example are QlogicISP adapters. */ - pci_read_config_dword(dev, PCI_ROM_ADDRESS, ®); - reg &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg); + if (dev->rom_base_reg) { + pci_read_config_dword(dev, dev->rom_base_reg, ®); + reg &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, dev->rom_base_reg, reg); + dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE; + } /* All of these (may) have I/O scattered all around and may not use I/O base address registers at all. So we just have to diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx index d5fbbd59a2d7..d543e51996dc 100644 --- a/drivers/scsi/ChangeLog.ncr53c8xx +++ b/drivers/scsi/ChangeLog.ncr53c8xx @@ -1,3 +1,33 @@ +Sat Sep 11 18:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2c + - Handle correctly (hopefully) jiffies wrap-around. + - Restore the entry used to detect 875 until revision 0xff. + (I removed it inadvertently, it seems :) ) + - Replace __initfunc() which is deprecated stuff by __init which + is not yet so. ;-) + - Add support of some 'resource handling' for linux-2.3.13. + Basically the BARs have been changed to something more complex + in the pci_dev structure. + - Remove some deprecated code. + +Sat May 10 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision pre-3.2b-1 + - Support for the 53C895A by Pamela Delaney + The 53C895A contains all of the features of the 896 but has only + one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing + using dual cycle PCI data transfers. + - Miscellaneous minor fixes. + - Some additions to the README.ncr53c8xx file. + +Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) + * revision 3.2a + - Add 'hostid:#id' boot option. This option allows to change the + default SCSI id the driver uses for controllers. + - Remove nvram layouts and driver set-up structures from the C source, + and use the one defined in sym53c8xx_defs.h file. + (shared by both drivers). + - Set for now MAX LUNS to 16 (instead of 8). + Thu Mar 11 23:00 1999 Gerard Roudier (groudier@club-internet.fr) * revision 3.2 (8xx-896 driver bundle) - Only define the host template in ncr53c8xx.h and include the diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx index 98656d35974a..260c6b5aa519 100644 --- a/drivers/scsi/ChangeLog.sym53c8xx +++ b/drivers/scsi/ChangeLog.sym53c8xx @@ -1,3 +1,132 @@ +Sat Sep 11 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5e + - New linux-2.3.13 __setup scheme support added. + - Cleanup of the extended error status handling: + Use 1 bit per error type. + - Also save the extended error status prior to auto-sense. + - Add the FE_DIFF chip feature bit to indicate support of + diff probing from GPIO3 (825/825A/876/875). + - Remove the quirk handling that has been useless since day one. + - Work-around PCI chips being reported twice on some platforms. + - Add some redundant PCI reads in order to deal with common + bridge misbehaviour regarding posted write flushing. + - Add some other conditionnal code for people who have to deal + with really broken bridges (they will have to edit a source + file to try these options). + - Handle correctly (hopefully) jiffies wrap-around. + - Restore the entry used to detect 875 until revision 0xff. + (I removed it inadvertently, it seems :) ) + - Replace __initfunc() which is deprecated stuff by __init which + is not yet so. ;-) + - Rewrite the MESSAGE IN scripts more generic by using a MOVE + table indirect. Extended messages of any size are accepted now. + (Size is limited to 8 for now, but a constant is just to be + increased if necessary) + - Fix some bug in the fully untested MDP handling:) and share + some code between MDP handling and residual calculation. + - Calculate the data transfer residual as the 2's complement + integer (A positive value in returned on data overrun, and + a negative one on underrun). + - Add support of some 'resource handling' for linux-2.3.13. + Basically the BARs have been changed to something more complex + in the pci_dev structure. + - Remove some deprecated code. + +Sat Jun 5 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5c + - Donnot negotiate on auto-sense if we are currently using 8 bit + async transfer for the target. + - Only check for SISL/RAID on i386 platforms. + (A problem has been reported on PPC with that code). + - On MSG REJECT for a negotiation, the driver attempted to restart + the SCRIPT processor when this one was already running. + +Sat May 29 12:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5b + - Force negotiation prior auto-sense. + This ensures that the driver will be able to grab the sense data + from a device that has received a BUS DEVICE RESET message from + another initiator. + - Complete all disconnected CCBs for a logical UNIT if we are told + about a UNIT ATTENTION for a RESET condition by this target. + - Add the control command 'cleardev' that allows to send a ABORT + message to a logical UNIT (for test purpose). + +Tue May 25 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5a + - Add support for task abort and bus device reset SCSI message + and implement proper synchonisation with SCRIPTS to handle + correctly task abortion without races. + - Send an ABORT message (if untagged) or ABORT TAG message (if tagged) + when the driver is told to abort a command that is disconnected and + complete the command with appropriate error. + If the aborted command is not yet started, remove it from the start + queue and complete it with error. + - Add the control command 'resetdev' that allows to send a BUS + DEVICE RESET message to a target (for test purpose). + - Clean-up some unused or useless code. + +Fri May 21 23:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5 + - Add support for CHMOV with Wide controllers. + - Handling of the SWIDE (low byte residue at the end of a CHMOV + in DATA IN phase with WIDE transfer when the byte count gets odd). + - Handling of the IGNORE WIDE RESIDUE message. + Handled from SCRIPTS as possible with some optimizations when both + a wide device and the controller are odd at the same time (SWIDE + present and IGNORE WIDE RESIDUE message on the BUS at the same time). + - Check against data OVERRUN/UNDERRUN condition at the end of a data + transfer, whatever a SWIDE is present (OVERRUN in DATA IN phase) + or the SODL is full (UNDERRUN in DATA out phase). + - Handling of the MODIFY DATA POINTER message. + This one cannot be handled from SCRIPTS, but hopefully it will not + happen very often. :) + - Large rewrite of the SCSI MESSAGE handling. + +Sun May 9 11:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.4 + - Support for IMMEDIATE ARBITRATION. + See the README file for detailed information about this feature. + Requires both a compile option and a boot option. + - Minor SCRIPTS optimization in reselection pattern for LUN 0. + - Simpler algorithm to deal with SCSI command starvation. + Just use 2 tag counters in flip/flop and switch to the other + one every 3 seconds. + - Do some work in SCRIPTS after the SELECT instruction and prior + to testing for a PHASE. SYMBIOS say this feature is working fine. + (Btw, only problems with Toshiba 3401B had been reported). + - Measure the PCI clock speed and donnot attach controllers if + result is greater than 37 MHz. Since the precision of the + algorithm (from Stefan Esser) is better than 2%, this should + be fine. + - Fix the misdetection of SYM53C875E (was detected as a 876). + - Fix the misdetection of SYM53C810 not A (was detected as a 810A). + - Support for up to 256 TAGS per LUN (CMD_PER_LUN). + Currently limited to 255 due to Linux limitation. :) + - Support for up to 508 active commands (CAN_QUEUE). + - Support for the 53C895A by Pamela Delaney + The 53C895A contains all of the features of the 896 but has only + one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing + using dual cycle PCI data transfers. + - Miscellaneous minor fixes. + - Some additions to the README.ncr53c8xx file. + +Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3e + - Support for any number of LUNs (64) (SPI2-compliant). + (Btw, this may only be ever usefull under linux-2.2 ;-)) + +Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.3d + - Add 'hostid:#id' boot option. This option allows to change the + default SCSI id the driver uses for controllers. + - Make SCRIPTS not use self-mastering for PCI. + There were still 2 places the driver used this feature of the + 53C8XX family. + - Move some data structures (nvram layouts and driver set-up) to + the sym53c8xx_defs.h file. So, the both drivers will share them. + - Set MAX LUNS to 16 (instead of 8). + Sat Mar 20 21:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3b - Add support for NCR PQS PDS. diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index ae7a42c48fb5..323e077caeb0 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -129,6 +129,14 @@ else endif endif +ifeq ($(CONFIG_SCSI_SIM710),y) +L_OBJS += sim710.o +else + ifeq ($(CONFIG_SCSI_SIM710),m) + M_OBJS += sim710.o + endif +endif + ifeq ($(CONFIG_A4000T_SCSI),y) L_OBJS += amiga7xx.o 53c7xx.o else @@ -681,6 +689,17 @@ include $(TOPDIR)/Rules.make 53c7xx.o : 53c7xx_d.h +sim710_d.h: sim710.scr script_asm.pl + ln -sf sim710.scr fake7.c + $(CPP) -traditional -DCHIP=710 fake7.c | grep -v '^#' | perl -s script_asm.pl -ncr7x0_family + mv script.h sim710_d.h + mv scriptu.h sim710_u.h + rm fake7.c + +sim710_u.h: sim710_d.h + +sim710.o : sim710_d.h + initio.o: ini9100u.c i91uscsi.c $(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx index 0497bbb10f11..100f9ff959b4 100644 --- a/drivers/scsi/README.aic7xxx +++ b/drivers/scsi/README.aic7xxx @@ -20,11 +20,13 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD AHA-2920C AHA-2930 AHA-2930U + AHA-2930CU AHA-2930U2 AHA-2940 AHA-2940W AHA-2940U AHA-2940UW + AHA-2940UW-PRO AHA-2940AU AHA-2940U2W AHA-2940U2 @@ -37,6 +39,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD AHA-2950U2 AHA-2950U2W AHA-2950U2B + AHA-29160M AHA-3940 AHA-3940U AHA-3940W @@ -45,6 +48,8 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD AHA-3940U2W AHA-3950U2B AHA-3950U2D + AHA-3960D + AHA-39160M AHA-3985 AHA-3985U AHA-3985W @@ -159,6 +164,12 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD on your controller. This helps those people who have cards without a SEEPROM make sure that linux and all other operating systems think the same way about your hard drives. + + "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to + give the card more hardware SCB slots. This allows the driver to use + that SCB RAM. Without this option, the driver won't touch the SCB + RAM because it is known to cause problems on a few cards out there + (such as 3985 class cards). "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel to use the correct IRQ type for your card. This only applies to EISA @@ -464,10 +475,9 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD FTP sites ------------------------------ ftp://ftp.redhat.com/pub/aic/ - - Primary site for Doug Ledford developed driver releases - ftp://ftp.dialnet.net/pub/linux/aic7xxx - - Temporary mirror of the redhat.com ftp site while people - get used to the new address + - Out of date. I used to keep stuff here, but too many people + complained about having a hard time getting into Red Hat's ftp + server. So use the web site below instead. ftp://ftp.pcnet.com/users/eischen/Linux/ - Dan Eischen's driver distribution area ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/ @@ -475,10 +485,8 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD Web sites ------------------------------ - http://developer.redhat.com/aic7xxx/ - - Primary web site maintained by Doug Ledford. I haven't actually - put anything up yet....but I'm planning on it. This information - is put here as an add for the vapor page :) + http://people.redhat.com/dledford/aic7xxx.html + - Primary web site maintained by Doug Ledford. Dean W. Gehnert deang@teleport.com diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx index 2fa1956a2889..858673c3368f 100644 --- a/drivers/scsi/README.ncr53c8xx +++ b/drivers/scsi/README.ncr53c8xx @@ -1,10 +1,10 @@ -The Linux NCR53C8XX driver README file +The Linux NCR53C8XX/SYM53C8XX drivers README file Written by Gerard Roudier 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -10 March 1999 +29 May 1999 =============================================================================== 1. Introduction @@ -25,14 +25,39 @@ Written by Gerard Roudier 8.6 Clear profile counters 8.7 Set flag (no_disc) 8.8 Set verbose level + 8.9 Reset all logical units of a target + 8.10 Abort all tasks of all logical units of a target 9. Configuration parameters 10. Boot setup commands 10.1 Syntax 10.2 Available arguments + 10.2.1 Master parity checking + 10.2.2 Scsi parity checking + 10.2.3 Scsi disconnections + 10.2.4 Special features + 10.2.5 Ultra SCSI support + 10.2.6 Default number of tagged commands + 10.2.7 Default synchronous period factor + 10.2.8 Negotiate synchronous with all devices + 10.2.9 Verbosity level + 10.2.10 Debug mode + 10.2.11 Burst max + 10.2.12 LED support + 10.2.13 Max wide + 10.2.14 Differential mode + 10.2.15 IRQ mode + 10.2.16 Reverse probe + 10.2.17 Fix up PCI configuration space + 10.2.18 Serial NVRAM + 10.2.19 Check SCSI BUS + 10.2.20 Exclude a host from being attached + 10.2.21 Suggest a default SCSI id for hosts + 10.2.22 Enable use of IMMEDIATE ARBITRATION 10.3 Advised boot setup commands 10.4 PCI configuration fix-up boot option 10.5 Serial NVRAM support boot option 10.6 SCSI BUS checking boot option + 10.7 IMMEDIATE ARBITRATION boot option 11. Some constants and flags of the ncr53c8xx.h header file 12. Installation 13. Architecture dependent features @@ -43,6 +68,8 @@ Written by Gerard Roudier 14.4 Possible data corruption during a Memory Write and Invalidate 14.5 IRQ sharing problems 15. SCSI problem troubleshooting + 15.1 Problem tracking + 15.2 Understanding hardware error reports 16. Synchonous transfer negotiation tables 16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers 16.2 Synchronous timings for fast SCSI-2 53C8XX controllers @@ -69,11 +96,12 @@ The original driver has been written for 386bsd and FreeBSD by: It is now available as a bundle of 2 drivers: - ncr53c8xx generic driver that supports all the SYM53C8XX family including - the ealiest 810 rev. 1 and the latest 896 2 channels LVD SCSI controller. + the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and + the new 895A (1 channel LVD SCSI controller). - sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest chips in order to gain advantage of new features, as LOAD/STORE intructions available since the 810A and hardware phase mismatch available with the - latest 896. + 896 and the 895A. You can find technical information about the NCR 8xx family in the PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by @@ -95,15 +123,17 @@ Usefull SCSI tools written by Eric Youngdale are available at tsx-11: These tools are not ALPHA but quite clean and work quite well. It is essential you have the 'scsiinfo' package. -This short documentation only describes the features of the NCR53C8XX -driver, configuration parameters and control commands available -through the proc SCSI file system read / write operations. +This short documentation describes the features of the generic and enhanced +drivers, configuration parameters and control commands available through +the proc SCSI file system read / write operations. This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC. Latest driver version and patches are available at: ftp://ftp.tux.org/pub/people/gerard-roudier +or + ftp://ftp.symbios.com/mirror/ftp.tux.org/pub/tux/roudier/drivers I am not a native speaker of English and there are probably lots of mistakes in this README file. Any help will be welcome. @@ -136,6 +166,7 @@ Chip SDMS BIOS Wide SCSI std. Max. sync driver driver 875 Y Y FAST20 40 MB/s Y Y 876 Y Y FAST20 40 MB/s Y Y 895 Y Y FAST40 80 MB/s Y Y +895A Y Y FAST40 80 MB/s Y Y 896 Y Y FAST40 80 MB/s Y Y @@ -156,21 +187,25 @@ Serial NVRAM: Symbios and Tekram formats 3.1 Optimized SCSI SCRIPTS. -The 810A, 825A, 875, 895 and newest 896 support new SCSI SCRIPTS instructions -named LOAD and STORE that allow to move 1 DWORD from/to an IO register to/from -memory much faster that the MOVE MEMORY instruction that is supported by the -53c7xx and 53c8xx family. The LOAD/STORE instructions support absolute and -DSA relative addressing modes. The SCSI SCRIPTS had been entirely rewritten -using LOAD/STORE instead of MOVE MEMORY instructions. +The 810A, 825A, 875, 895, 896 and 895A support new SCSI SCRIPTS instructions +named LOAD and STORE that allow to move up to 1 DWORD from/to an IO register +to/from memory much faster that the MOVE MEMORY instruction that is supported +by the 53c7xx and 53c8xx family. +The LOAD/STORE instructions support absolute and DSA relative addressing +modes. The SCSI SCRIPTS had been entirely rewritten using LOAD/STORE instead +of MOVE MEMORY instructions. 3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller) -The 896 allows to handle the phase mismatch context saving from SCRIPTS -(avoids the phase mismatch interrupt that stops the SCSI processor +The 896 and the 895A allows handling of the phase mismatch context from +SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor until the C code has saved the context of the transfer). Implementing this without using LOAD/STORE instructions would be painfull -and I did'nt even try it. This chip also supports 64 bit PCI transactions -and addressing. The SCRIPTS processor is not true 64 bit, but uses segment +and I did'nt even want to try it. + +The 896 chip supports 64 bit PCI transactions and addressing, while the +895A supports 32 bit PCI transactions and 64 bit addressing. +The SCRIPTS processor of these chips is not true 64 bit, but uses segment registers for bit 32-63. Another interesting feature is that LOAD/STORE instructions that address the on-chip RAM (8k) remain internal to the chip. @@ -219,9 +254,13 @@ The maximum number of simultaneous tagged commands queued to a device is currently set to 8 by default. This value is suitable for most SCSI disks. With large SCSI disks (>= 2GB, cache >= 512KB, average seek time <= 10 ms), using a larger value may give better performances. -The driver supports up to 64 commands per device, but using more than -32 is generally not worth it, unless you are using a very large disk -or disk array. + +The sym53c8xx driver supports up to 255 commands per device, and the +generic ncr53c8xx driver supports up to 64, but using more than 32 is +generally not worth-while, unless you are using a very large disk or disk +array. It is noticeable that most of recent hard disks seem not to accept +more than 64 simultaneous commands. So, using more than 64 queued commands +is probably just resource wasting. If your controller does not have NVRAM or if it is managed by the SDMS BIOS/SETUP, you can configure tagged queueing feature and device queue @@ -491,6 +530,24 @@ Available commands: The driver default verbose level is 1. This command allows to change th driver verbose level after boot-up. +8.9 Reset all logical units of a target + + resetdev + + target: target number + The driver will try to send a BUS DEVICE RESET message to the target. + (Only supported by the SYM53C8XX driver and provided for test purpose) + +8.10 Abort all tasks of all logical units of a target + + cleardev + + target: target number + The driver will try to send a ABORT message to all the logical units + of the target. + (Only supported by the SYM53C8XX driver and provided for test purpose) + + 9. Configuration parameters If the firmware of all your devices is perfect enough, all the @@ -566,10 +623,11 @@ CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT Setup commands can be passed to the driver either at boot time or as a string variable using 'insmod'. -A boot setup command for the ncr53c8xx driver begins with the driver name -"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of -integers separated with comma followed by an optionnal list of comma- -separated strings. Example of boot setup command under lilo prompt: +A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the +driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects +an optionnal list of integers separated with comma followed by an optional +list of comma-separated strings. Example of boot setup command under lilo +prompt: lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200 @@ -582,7 +640,7 @@ Since comma seems not to be allowed when defining a string variable using The following command will install driver module with the same options as above. -insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200" + insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200" For the moment, the integer list of arguments is discarded by the driver. It will be used in the future in order to allow a per controller setup. @@ -590,40 +648,53 @@ It will be used in the future in order to allow a per controller setup. Each string argument must be specified as "keyword:value". Only lower-case characters and digits are allowed. +In a system that contains multiple 53C8xx adapters insmod will install the +specified driver on each adapter. To exclude a chip use the 'excl' keyword. + +The sequence of commands, + + insmod sym53c8xx sym53c8xx=excl:0x1400 + insmod ncr53c8xx + +installs the sym53c8xx driver on all adapters except the one at IO port +address 0x1400 and then installs the ncr53c8xx driver to the adapter at IO +port address 0x1400. + + 10.2 Available arguments -Master parity checking - mpar:y enabled - mpar:n disabled +10.2.1 Master parity checking + mpar:y enabled + mpar:n disabled -Scsi parity checking - spar:y enabled - spar:n disabled +10.2.2 Scsi parity checking + spar:y enabled + spar:n disabled -Scsi disconnections - disc:y enabled - disc:n disabled +10.2.3 Scsi disconnections + disc:y enabled + disc:n disabled -Special features +10.2.4 Special features Only apply to 810A, 825A, 860, 875 and 895 controllers. Have no effect with other ones. - specf:y (or 1) enabled - specf:n (or 0) disabled - specf:3 enabled except Memory Write And Invalidate + specf:y (or 1) enabled + specf:n (or 0) disabled + specf:3 enabled except Memory Write And Invalidate The default driver setup is 'specf:3'. As a consequence, option 'specf:y' must be specified in the boot setup command to enable Memory Write And Invalidate. -Ultra SCSI support +10.2.5 Ultra SCSI support Only apply to 860, 875 and 895 controllers. Have no effect with other ones. - ultra:2 Ultra2 enabled - ultra:1 Ultra enabled - ultra:n disabled + ultra:2 Ultra2 enabled + ultra:1 Ultra enabled + ultra:n disabled -Default number of tagged commands - tags:0 (or tags:1 ) tagged command queuing disabled - tags:#tags (#tags > 1) tagged command queuing enabled +10.2.6 Default number of tagged commands + tags:0 (or tags:1 ) tagged command queuing disabled + tags:#tags (#tags > 1) tagged command queuing enabled #tags will be truncated to the max queued commands configuration parameter. This option also allows to specify a command queue depth for each device that support tagged command queueing. @@ -635,9 +706,9 @@ Default number of tagged commands - controller #1 target #1 logical unit #2 -> 32 commands, - all other logical units (all targets, all controllers) -> 10 commands. -Default synchronous period factor - sync:255 disabled (asynchronous transfer mode) - sync:#factor +10.2.7 Default synchronous period factor + sync:255 disabled (asynchronous transfer mode) + sync:#factor #factor = 10 Ultra-2 SCSI 40 Mega-transfers / second #factor = 11 Ultra-2 SCSI 33 Mega-transfers / second #factor < 25 Ultra SCSI 20 Mega-transfers / second @@ -646,19 +717,19 @@ Default synchronous period factor In all cases, the driver will use the minimum transfer period supported by controllers according to NCR53C8XX chip type. -Negotiate synchronous with all devices - (force sync nego) - fsn:y enabled - fsn:n disabled +10.2.8 Negotiate synchronous with all devices + (force sync nego) + fsn:y enabled + fsn:n disabled -Verbosity level - verb:0 minimal - verb:1 normal - verb:2 too much +10.2.9 Verbosity level + verb:0 minimal + verb:1 normal + verb:2 too much -Debug mode - debug:0 clear debug flags - debug:#x set debug flags +10.2.10 Debug mode + debug:0 clear debug flags + debug:#x set debug flags #x is an integer value combining the following power-of-2 values: DEBUG_ALLOC 0x1 DEBUG_PHASE 0x2 @@ -677,10 +748,10 @@ Debug mode You can play safely with DEBUG_NEGO. However, some of these flags may generate bunches of syslog messages. -Burst max - burst:0 burst disabled - burst:255 get burst length from initial IO register settings. - burst:#x burst enabled (1<<#x burst transfers max) +10.2.11 Burst max + burst:0 burst disabled + burst:255 get burst length from initial IO register settings. + burst:#x burst enabled (1<<#x burst transfers max) #x is an integer value which is log base 2 of the burst transfers max. The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7). Other chips only support up to 16 (#x = 4). @@ -688,42 +759,42 @@ Burst max and revision ids. By default the driver uses the maximum value supported by the chip. -LED support - led:1 enable LED support - led:0 disable LED support +10.2.12 LED support + led:1 enable LED support + led:0 disable LED support Donnot enable LED support if your scsi board does not use SDMS BIOS. (See 'Configuration parameters') -Max wide - wide:1 wide scsi enabled - wide:0 wide scsi disabled +10.2.13 Max wide + wide:1 wide scsi enabled + wide:0 wide scsi disabled Some scsi boards use a 875 (ultra wide) and only supply narrow connectors. If you have connected a wide device with a 50 pins to 68 pins cable converter, any accepted wide negotiation will break further data transfers. In such a case, using "wide:0" in the bootup command will be helpfull. -Differential mode - diff:0 never set up diff mode - diff:1 set up diff mode if BIOS set it - diff:2 always set up diff mode - diff:3 set diff mode if GPIO3 is not set +10.2.14 Differential mode + diff:0 never set up diff mode + diff:1 set up diff mode if BIOS set it + diff:2 always set up diff mode + diff:3 set diff mode if GPIO3 is not set -IRQ mode - irqm:0 always open drain - irqm:1 same as initial settings (assumed BIOS settings) - irqm:2 always totem pole - irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq - irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq +10.2.15 IRQ mode + irqm:0 always open drain + irqm:1 same as initial settings (assumed BIOS settings) + irqm:2 always totem pole + irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq + irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq (Bits 0x10 and 0x20 can be combined with hardware irq mode option) -Reverse probe - revprob:n probe chip ids from the PCI configuration in this order: - 810, 815, 820, 860, 875, 885, 895, 896 - revprob:y probe chip ids in the reverse order. +10.2.16 Reverse probe + revprob:n probe chip ids from the PCI configuration in this order: + 810, 815, 820, 860, 875, 885, 895, 896 + revprob:y probe chip ids in the reverse order. -Fix up PCI configuration space - pcifix: