From ccb5ba85b2a5aec5882f4be3d39f096c11f4272a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:38:48 -0500 Subject: [PATCH] Linux 2.4.0-test9pre2 - scsi fixes - network updates - PCI bridge scanning fix: assign numbers properly - sparc updates - Riel VM update - disallow re-mounting same filesystem in same place multiple times. Too confusing. And /etc/mtab gets strange. - PPC updates (including PPC-related drivers etc) - more initcall updates - various net drvr updates and fixes - "extern inline" -> "static inline". It doesn't matter right now, but it's proactive for future gcc versions. --- Documentation/Configure.help | 92 +- Documentation/kbuild/00-INDEX | 2 + Documentation/kbuild/makefiles.txt | 1086 +++++++++++++++ Documentation/networking/8139too.txt | 36 +- Documentation/pci.txt | 5 + Makefile | 4 +- arch/i386/kernel/acpi.c | 60 +- arch/ppc/8260_io/Config.in | 15 +- arch/ppc/8260_io/Makefile | 4 +- arch/ppc/8260_io/commproc.c | 34 +- arch/ppc/8260_io/enet.c | 21 +- arch/ppc/8260_io/fcc_enet.c | 1600 +++++++++++++++++++++++ arch/ppc/8260_io/uart.c | 23 +- arch/ppc/8xx_io/enet.c | 11 +- arch/ppc/8xx_io/fec.c | 9 +- arch/ppc/chrpboot/Makefile | 6 +- arch/ppc/chrpboot/addnote.c | 13 +- arch/ppc/coffboot/Makefile | 2 +- arch/ppc/coffboot/chrpmain.c | 65 +- arch/ppc/config.in | 57 +- arch/ppc/configs/common_defconfig | 207 ++- arch/ppc/configs/est8260_defconfig | 70 +- arch/ppc/configs/gemini_defconfig | 93 +- arch/ppc/configs/rpxcllf_defconfig | 68 +- arch/ppc/defconfig | 210 ++- arch/ppc/kernel/Makefile | 6 +- arch/ppc/kernel/apus_setup.c | 16 +- arch/ppc/kernel/chrp_pci.c | 95 +- arch/ppc/kernel/chrp_setup.c | 144 +- arch/ppc/kernel/chrp_time.c | 49 +- arch/ppc/kernel/entry.S | 49 +- arch/ppc/kernel/feature.c | 175 ++- arch/ppc/kernel/gemini_setup.c | 3 +- arch/ppc/kernel/hashtable.S | 6 + arch/ppc/kernel/head.S | 180 ++- arch/ppc/kernel/head_8xx.S | 45 + arch/ppc/kernel/idle.c | 1 + arch/ppc/kernel/irq.c | 28 +- arch/ppc/kernel/m8260_setup.c | 23 +- arch/ppc/kernel/m8xx_setup.c | 62 +- arch/ppc/kernel/misc.S | 103 +- arch/ppc/kernel/mol.h | 68 + arch/ppc/kernel/oak_setup.c | 3 +- arch/ppc/kernel/open_pic.c | 12 +- arch/ppc/kernel/pci.c | 427 +++--- arch/ppc/kernel/pmac_backlight.c | 18 +- arch/ppc/kernel/pmac_nvram.c | 14 +- arch/ppc/kernel/pmac_pci.c | 32 +- arch/ppc/kernel/pmac_pic.c | 9 +- arch/ppc/kernel/pmac_setup.c | 83 +- arch/ppc/kernel/pmac_time.c | 65 +- arch/ppc/kernel/ppc_ksyms.c | 43 +- arch/ppc/kernel/prep_setup.c | 107 +- arch/ppc/kernel/prep_time.c | 45 +- arch/ppc/kernel/process.c | 24 +- arch/ppc/kernel/prom.c | 230 ++-- arch/ppc/kernel/setup.c | 14 +- arch/ppc/kernel/signal.c | 11 +- arch/ppc/kernel/smp.c | 341 +++-- arch/ppc/kernel/syscalls.c | 24 +- arch/ppc/kernel/time.c | 325 +++-- arch/ppc/kernel/traps.c | 144 +- arch/ppc/kernel/walnut_setup.c | 3 +- arch/ppc/kernel/xics.c | 2 +- arch/ppc/lib/string.S | 246 ++-- arch/ppc/mbxboot/misc.c | 5 + arch/ppc/mm/extable.c | 47 +- arch/ppc/mm/fault.c | 4 +- arch/ppc/mm/init.c | 322 ++--- arch/ppc/xmon/start.c | 66 +- arch/ppc/xmon/xmon.c | 180 ++- arch/sparc/kernel/time.c | 2 +- arch/sparc64/kernel/sys_sparc32.c | 8 +- arch/sparc64/kernel/time.c | 2 +- arch/sparc64/mm/fault.c | 4 +- drivers/Makefile | 2 +- drivers/acpi/include/acenv.h | 1 - drivers/block/lvm-snap.c | 6 +- drivers/block/lvm.c | 12 +- drivers/block/swim3.c | 7 + drivers/cdrom/mcd.c | 4 +- drivers/char/Config.in | 4 +- drivers/char/drm/picker.c | 2 +- drivers/char/mem.c | 6 - drivers/i2o/i2o_proc.c | 15 +- drivers/isdn/avmb1/capi.c | 20 +- drivers/isdn/avmb1/capidrv.c | 18 +- drivers/macintosh/Makefile | 103 +- drivers/macintosh/adb.c | 9 + drivers/macintosh/adbhid.c | 875 +++++++++++++ drivers/macintosh/mac_hid.c | 492 +++++++ drivers/macintosh/mac_keyb.c | 80 +- drivers/macintosh/macio-adb.c | 2 + drivers/macintosh/macserial.c | 14 +- drivers/macintosh/mediabay.c | 11 +- drivers/macintosh/nvram.c | 26 + drivers/macintosh/rtc.c | 158 +++ drivers/macintosh/via-cuda.c | 124 +- drivers/macintosh/via-pmu.c | 563 +++++--- drivers/media/video/bttv-driver.c | 8 +- drivers/media/video/bttv.h | 5 - drivers/net/3c507.c | 6 +- drivers/net/3c509.c | 16 +- drivers/net/8139too.c | 297 +++-- drivers/net/Makefile | 2 +- drivers/net/arcnet/arcnet.c | 3 - drivers/net/arcnet/com20020-isa.c | 2 +- drivers/net/arcnet/com20020-pci.c | 4 +- drivers/net/auto_irq.c | 5 + drivers/net/declance.c | 7 +- drivers/net/eexpress.c | 1 + drivers/net/gmac.c | 253 +++- drivers/net/gmac.h | 31 +- drivers/net/irda/toshoboe.c | 1 - drivers/net/lne390.c | 48 +- drivers/net/net_init.c | 19 +- drivers/net/pcmcia/xircom_tulip_cb.c | 5 +- drivers/net/pppox.c | 4 +- drivers/net/rtl8129.c | 52 +- drivers/net/setup.c | 4 + drivers/net/sunlance.c | 1 + drivers/net/wan/Makefile | 1 + drivers/parport/ChangeLog | 5 + drivers/parport/parport_pc.c | 6 +- drivers/pci/pci.c | 175 +-- drivers/scsi/Makefile | 5 +- drivers/scsi/pci2220i.c | 2 +- drivers/scsi/qlogicfas.c | 2 + drivers/scsi/scsi.c | 73 +- drivers/scsi/scsi.h | 1 + drivers/scsi/scsi_lib.c | 45 +- drivers/scsi/scsi_queue.c | 2 +- drivers/scsi/seagate.c | 128 +- drivers/scsi/seagate.h | 4 - drivers/scsi/sg.c | 131 +- drivers/scsi/sym53c8xx.c | 3 + drivers/scsi/sym53c8xx_comm.h | 2 +- drivers/sound/ac97_codec.c | 21 +- drivers/sound/adlib_card.c | 6 - drivers/sound/cs46xx.c | 6 - drivers/sound/dmasound/awacs_defs.h | 5 + drivers/sound/dmasound/dmasound_awacs.c | 49 +- drivers/sound/emu10k1/emu_wrapper.h | 5 - drivers/sound/emu10k1/main.c | 6 +- drivers/sound/gus_card.c | 4 +- drivers/sound/opl3.c | 42 +- drivers/sound/uart6850.c | 24 +- drivers/sound/wf_midi.c | 3 +- drivers/telephony/Makefile | 36 +- drivers/telephony/ixj.c | 23 +- drivers/telephony/phonedev.c | 22 +- drivers/usb/storage/freecom.c | 1 - drivers/usb/storage/transport.c | 1 + drivers/usb/storage/usb.c | 2 +- drivers/usb/usb-core.c | 1 - drivers/video/Makefile | 3 + drivers/video/aty.h | 11 +- drivers/video/aty128.h | 11 +- drivers/video/aty128fb.c | 95 +- drivers/video/atyfb.c | 133 +- drivers/video/chipsfb.c | 15 +- drivers/video/controlfb.c | 52 +- drivers/video/offb.c | 106 +- drivers/video/sisfb.c | 5 +- drivers/video/valkyriefb.c | 2 + fs/bfs/inode.c | 2 +- fs/block_dev.c | 36 +- fs/buffer.c | 24 +- fs/dcache.c | 2 +- fs/namei.c | 4 +- fs/partitions/acorn.c | 1 + fs/partitions/mac.c | 10 +- fs/proc/proc_misc.c | 6 +- fs/ramfs/inode.c | 2 +- fs/super.c | 59 +- include/asm-i386/semaphore.h | 24 +- include/asm-ppc/atomic.h | 8 +- include/asm-ppc/backlight.h | 2 +- include/asm-ppc/bitops.h | 4 + include/asm-ppc/bootx.h | 1 - include/asm-ppc/cpm_8260.h | 191 ++- include/asm-ppc/fcntl.h | 12 + include/asm-ppc/feature.h | 7 +- include/asm-ppc/hardirq.h | 7 + include/asm-ppc/heathrow.h | 5 + include/asm-ppc/highmem.h | 121 ++ include/asm-ppc/ide.h | 2 - include/asm-ppc/immap_8260.h | 8 +- include/asm-ppc/io.h | 80 +- include/asm-ppc/irq.h | 3 + include/asm-ppc/keylargo.h | 103 ++ include/asm-ppc/kmap_types.h | 10 + include/asm-ppc/machdep.h | 4 +- include/asm-ppc/mbx.h | 1 + include/asm-ppc/mman.h | 4 +- include/asm-ppc/nvram.h | 13 +- include/asm-ppc/pci-bridge.h | 9 +- include/asm-ppc/pgtable.h | 2 +- include/asm-ppc/processor.h | 1 + include/asm-ppc/prom.h | 3 + include/asm-ppc/serial.h | 11 - include/asm-ppc/smp.h | 7 +- include/asm-ppc/spinlock.h | 1 + include/asm-ppc/time.h | 81 +- include/asm-ppc/uaccess.h | 8 +- include/asm-ppc/uninorth.h | 83 ++ include/asm-ppc/unistd.h | 8 +- include/asm-sparc/io.h | 6 +- include/asm-sparc64/io.h | 6 +- include/linux/adb.h | 2 +- include/linux/arcdevice.h | 1 - include/linux/blk.h | 2 +- include/linux/cuda.h | 3 +- include/linux/fs.h | 3 +- include/linux/mount.h | 3 +- include/linux/pci.h | 48 +- include/linux/pmu.h | 64 +- include/linux/raid/md_compatible.h | 6 +- include/linux/signal.h | 26 +- include/linux/sysctl.h | 13 +- include/linux/usb.h | 12 +- include/linux/vt_buffer.h | 10 +- include/linux/wait.h | 6 +- include/linux/zftape.h | 4 +- include/net/addrconf.h | 18 +- include/net/checksum.h | 2 +- include/net/dn_route.h | 6 +- include/net/x25.h | 2 +- kernel/exit.c | 1 + kernel/ksyms.c | 2 - mm/slab.c | 8 - mm/swap.c | 12 +- mm/vmscan.c | 73 +- net/core/sock.c | 2 +- net/ipv4/af_inet.c | 3 +- net/ipv4/ip_sockglue.c | 38 +- net/ipv4/netfilter/ip_nat_ftp.c | 5 +- net/ipv4/netfilter/ip_nat_standalone.c | 1 + net/ipv4/netfilter/iptable_mangle.c | 1 + net/ipv4/sysctl_net_ipv4.c | 23 +- net/ipv4/tcp_input.c | 5 +- net/ipv6/af_inet6.c | 51 +- net/ipv6/ip6_fib.c | 6 +- net/x25/af_x25.c | 9 +- net/x25/x25_dev.c | 6 +- net/x25/x25_link.c | 6 +- net/x25/x25_out.c | 13 +- scripts/ver_linux | 2 + 248 files changed, 10607 insertions(+), 3184 deletions(-) create mode 100644 Documentation/kbuild/makefiles.txt create mode 100644 arch/ppc/8260_io/fcc_enet.c create mode 100644 arch/ppc/kernel/mol.h create mode 100644 drivers/macintosh/adbhid.c create mode 100644 drivers/macintosh/mac_hid.c create mode 100644 drivers/macintosh/rtc.c create mode 100644 include/asm-ppc/highmem.h create mode 100644 include/asm-ppc/keylargo.h create mode 100644 include/asm-ppc/kmap_types.h create mode 100644 include/asm-ppc/uninorth.h diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 676b70a83971..708e3e1d8ae0 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1088,22 +1088,25 @@ CONFIG_BLK_DEV_IDEDOUBLER Support for PowerMac IDE devices (must also enable IDE) CONFIG_BLK_DEV_IDE_PMAC - No help for CONFIG_BLK_DEV_IDE_PMAC + This driver provides support for the built-in IDE controller on most + of the recent Apple Power Macintoshes and PowerBooks. + If unsure, say Y. PowerMac IDE DMA support CONFIG_BLK_DEV_IDEDMA_PMAC - No help for CONFIG_BLK_DEV_IDEDMA_PMAC + This option allows the driver for the built-in IDE controller on + Power Macintoshes and PowerBooks to use DMA (direct memory access) + to transfer data to and from memory. Saying Y is safe and improves + performance. Use DMA by default -CONFIG_IDEDMA_PMAC_AUTO - Prior to kernel version 2.1.112, Linux used to automatically use - DMA for IDE drives and chipsets which support it. Due to concerns - about a couple of cases where buggy hardware may have caused damage, - the default is now to NOT use DMA automatically. To revert to the - previous behaviour, say Y to this question. - - If you suspect your hardware is at all flakey, say N here. - Do NOT email the IDE kernel people regarding this issue! +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO + This option allows the driver for the built-in IDE controller on + Power Macintoshes and PowerBooks to use DMA automatically, without + it having to be explicitly enabled. This option is provided because + of concerns about a couple of cases where using DMA on buggy PC + hardware may have caused damage. Saying Y should be safe on all + Apple machines. Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -9984,10 +9987,24 @@ CONFIG_USB_WMFORCE The module will be called wmforce.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Use input layer for ADB devices +CONFIG_INPUT_ADBHID + Say Y here if you want to have ADB (Apple Desktop Bus) HID devices + such as keyboards, mice, joysticks, or graphic tablets handled by the + input layer. If you say Y here, make sure to say Y to the + corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV), + "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + If you say N here, you still have the option of using the old ADB + keyboard and mouse drivers. + + If unsure, say Y. + Keyboard support CONFIG_INPUT_KEYBDEV - Say Y here if you want your USB HID keyboard to be able to serve as - a system keyboard. + Say Y here if you want your USB HID keyboard (or an ADB keyboard + handled by the input layer) to be able to serve as a system keyboard. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9996,10 +10013,11 @@ CONFIG_INPUT_KEYBDEV Mouse support CONFIG_INPUT_MOUSEDEV - Say Y here if you want your USB HID mouse to be accessible as - char devices 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice - as an emulated PS/2 mouse. That way, all user space programs will - be able to use your mouse. + Say Y here if you want your USB HID mouse (or ADB mouse handled by + the input layer) to be accessible as char devices 13:32+ - + /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2 + mouse. That way, all user space programs will be able to use your + mouse. If unsure, say Y. @@ -10034,8 +10052,8 @@ CONFIG_INPUT_JOYDEV Event interface support CONFIG_INPUT_EVDEV - Say Y here if you want your USB HID device events be accessible - under char device 13:64+ - /dev/inputX in a generic way. + Say Y here if you want your USB or ADB HID device events be accessible + under char device 13:64+ - /dev/input/eventX in a generic way. This is the future ... USB Scanner support @@ -15430,6 +15448,42 @@ CONFIG_PMAC_PBOOK have it autoloaded. The act of removing the module shuts down the sound hardware for more power savings. +Mac-on-Linux support +CONFIG_MOL + This option enables low-level support for Mac-on-Linux. + MOL lets you run MacOS and Linux simultaneously. Please + visit for more information. + If unsure, say Y. + +ADB raw keycode support +CONFIG_MAC_ADBKEYCODES + This provides support for sending raw ADB keycodes to console + devices. This is the default up to 2.4.0, but in future this may be + phased out in favor of generic Linux keycodes. If you say Y here, you + can dynamically switch via the + /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes + sysctl and with the "keyboard_sends_linux_keycodes=" kernel argument. + + If unsure, say Y here. + +Mouse button 2+3 emulation support +CONFIG_MAC_EMUMOUSEBTN + This provides generic support for emulating the 2nd and 3rd mouse + button with keypresses. If you say Y here, the emulation is still + disabled by default. The emulation is controlled by these sysctl entries: + /proc/sys/dev/mac_hid/mouse_button_emulation + /proc/sys/dev/mac_hid/mouse_button2_keycode + /proc/sys/dev/mac_hid/mouse_button3_keycode + +Enhanced Real Time Clock Support +CONFIG_PPC_RTC + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + into your computer. + + If unsure, say Y here. + Support for Open Firmware device tree in /proc CONFIG_PROC_DEVICETREE This option adds a device-tree directory under /proc which contains diff --git a/Documentation/kbuild/00-INDEX b/Documentation/kbuild/00-INDEX index b72963abb8f7..398393455c76 100644 --- a/Documentation/kbuild/00-INDEX +++ b/Documentation/kbuild/00-INDEX @@ -6,3 +6,5 @@ commands.txt - overview of kbuild commands config-language.txt - specification of Config Language, the language in Config.in files +makefiles.txt + - developer information for linux kernel makefiles diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt new file mode 100644 index 000000000000..976f4d435db5 --- /dev/null +++ b/Documentation/kbuild/makefiles.txt @@ -0,0 +1,1086 @@ +Linux Kernel Makefiles +16 August 2000 +Michael Elizabeth Chastain, + + + +=== Introduction + +This document describes the Linux kernel Makefiles. + +The Makefiles have five parts: + + Makefile: the top Makefile. + .config: the kernel configuration file. + arch/*/Makefile: the arch Makefiles. + Subdirectory Makefiles: there are about 300 of these. + Rules.make: the common rules for all subdirectory Makefiles. + +The top Makefile reads the .config file, which comes from the +kernel configuration process. + +The top Makefile is responsible for building two major products: vmlinux +(the resident kernel image) and modules (any module files). It builds +these targets by recursively descending into the subdirectories of the +kernel source tree. The list of subdirectories which are visited depends +upon the kernel configuration. + +The top Makefile textually includes an arch Makefile with the name +arch/$(ARCH)/Makefile. The arch Makefile supplies architecture-specific +information to the top Makefile. + +Each subdirectory has a Makefile which carries out the commands passed +down from above. The subdirectory Makefile uses information from the +.config file to construct various file lists, and then it textually +includes the common rules in Rules.make. + +Rules.make defines rules which are common to all the subdirectory +Makefiles. It has a public interface in the form of certain variable +lists. It then declares rules based on those lists. + + + +=== Who does what + +People have four different relationships with the kernel Makefiles. + +*Users* are people who build kernels. These people type commands such as +"make menuconfig" or "make bzImage". They usually do not read or edit +any kernel Makefiles (or any other source files). + +*Normal developers* are people who work on features such as device +drivers, file systems, and network protocols. These people need to +maintain the subdirectory Makefiles for the subsystem that they are +working on. In order to do this effectively, they need some overall +knowledge about the kernel Makefiles, plus detailed knowledge about the +public interface for Rules.make. + +*Arch developers* are people who work on an entire architecture, such +as sparc or ia64. Arch developers need to know about the arch Makefiles +as well as subdirectory Makefiles. + +*Kbuild developers* are people who work on the kernel build system itself. +These people need to know about all aspects of the kernel Makefiles. + +This document is aimed towards normal developers and arch developers. + + + +=== Makefile language + +The kernel Makefiles are designed to run with Gnu Make. The Makefiles +use only the documented features of Gnu Make, but they do use many +Gnu extensions. + +Gnu Make supports elementary list-processing functions. The kernel +Makefiles use a novel style of list building and manipulation with few +"if" statements. + +Gnu Make has two assignment operators, ":=" and "=". ":=" performs +immediate evaluation of the right-hand side and stores an actual string +into the left-hand side. "=" is like a formula definition; it stores the +right-hand side in an unevaluated form and then evaluates this form each +time the left-hand side is used. + +There are some cases where "=" is appropriate. Usually, though, ":=" +is the right choice. + +All of the examples in this document were drawn from actual kernel +sources. The examples have been reformatted (white space changed, lines +split), but are otherwise exactly the same. + + + +=== Variables passed down from the top + +The top Makefile exports the following variables: + + VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION + + These variables define the current kernel version. A few arch + Makefiles actually use these values directly; they should use + $(KERNELRELEASE) instead. + + $(VERSION), $(PATCHLEVEL), and $(SUBLEVEL) define the basic + three-part version number, such as "2", "4", and "0". These three + values are always numeric. + + $(EXTRAVERSION) defines an even tinier sublevel for pre-patches + or additional patches. It is usually some non-numeric string + such as "-pre4", and is often blank. + + KERNELRELEASE + + $(KERNELRELEASE) is a single string such as "2.4.0-pre4", suitable + for constructing installation directory names or showing in + version strings. Some arch Makefiles use it for this purpose. + + ARCH + + This variable defines the target architecture, such as "i386", + "arm", or "sparc". Many subdirectory Makefiles test $(ARCH) + to determine which files to compile. + + By default, the top Makefile sets $(ARCH) to be the same as the + host system system architecture. For a cross build, a user may + override the value of $(ARCH) on the command line: + + make ARCH=m68k ... + + TOPDIR, HPATH + + $(TOPDIR) is the path to the top of the kernel source tree. + Subdirectory Makefiles need this so that they can include + $(TOPDIR)/Rules.make. + + $(HPATH) is equal to $(TOPDIR)/include. A few arch Makefiles + need to use this to do special things using include files. + + SUBDIRS + + $(SUBDIRS) is a list of directories which the top Makefile + enters in order to build either vmlinux or modules. The actual + directories in $(SUBDIRS) depend on the kernel configuration. + The top Makefile defines this variable, and the arch Makefile + extends it. + + HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS + LINKFLAGS + + $(HEAD), $(CORE_FILES), $(NETWORKS), $(DRIVERS), and $(LIBS) + specify lists of object files and libraries to be linked into + vmlinux. + + The files in $(HEAD) are linked first in vmlinux. + + $(LINKFLAGS) specifies the flags to build vmlinux. + + The top Makefile and the arch Makefile jointly define these + variables. The top Makefile defines $(CORE_FILES), $(NETWORKS), + $(DRIVERS), and $(LIBS). The arch Makefile defines $(HEAD) + and $(LINKFLAGS), and extends $(CORE_FILES) and $(LIBS). + + Note: there are more names here than necessary. $(NETWORKS), + $(DRIVERS), and even $(LIBS) could be subsumed into $(CORE_FILES). + + CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP + CPPFLAGS, CFLAGS, CFLAGS_KERNEL, MODFLAGS, AFLAGS, LDFLAGS + PERL + GENKSYMS + + These variables specify the commands and flags that Rules.make + uses to build target files from source files. + + $(CFLAGS_KERNEL) contains extra C compiler flags used to compile + resident kernel code. + + $(MODFLAGS) contains extra C compiler flags used to compile code + for loadable kernel modules. In the future, this flag may be + renamed to the more regular name $(CFLAGS_MODULE). + + $(AFLAGS) contains assembler flags. + + $(GENKSYMS) contains the command used to generate kernel symbol + signatures when CONFIG_MODVERSIONS is enabled. The genksyms + command comes from the modutils package. + + CROSS_COMPILE + + This variable is a prefix path for other variables such as $(CC), + $(AS), and $(LD). The arch Makefiles sometimes use and set this + variable explicitly. Subdirectory Makefiles don't need to worry + about it. + + The user may override $(CROSS_COMPILE) on the command line if + desired. + + HOSTCC, HOSTCFLAGS + + These variables define the C compiler and C compiler flags to + be used for compiling host side programs. These are separate + variables because the target architecture can be different from + the host architecture. + + If your Makefile compiles and runs a program that is executed + during the course of building the kernel, then it should use + $(HOSTCC) and $(HOSTCFLAGS). + + For example, the subdirectory drivers/pci has a helper program + named gen-devlist.c. This program reads a list of PCI ID's and + generates C code in the output files classlist.h and devlist.h. + + Suppose that a user has an i386 computer and wants to build a + kernel for an ia64 machine. Then the user would use an ia64 + cross-compiler for most of the compilation, but would use a + native i386 host compiler to compile drivers/pci/gen-devlist.c. + + For another example, kbuild helper programs such as + scripts/mkdep.c and scripts/lxdialog/*.c are compiled with + $(HOSTCC) rather than $(CC). + + ROOT_DEV, SVGA_MODE, RAMDISK + + End users edit these variables to specify certain information + about the configuration of their kernel. These variables + are ancient! They are also specific to the i386 architecture. + They really should be replaced with CONFIG_* options. + + MAKEBOOT + + This variable is defined and used only inside the main arch + Makefiles. The top Makefile should not export it. + + INSTALL_PATH + + This variable defines a place for the arch Makefiles to install + the resident kernel image and System.map file. + + INSTALL_MOD_PATH, MODLIB + + $(INSTALL_MOD_PATH) specifies a prefix to $(MODLIB) for module + installation. This variable is not defined in the Makefile but + may be passed in by the user if desired. + + $(MODLIB) specifies the directory for module installation. + The top Makefile defines $(MODLIB) to + $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE). The user may + override this value on the command line if desired. + + CONFIG_SHELL + + This variable is private between Makefile and Rules.make. + Arch makefiles and subdirectory Makefiles should never use this. + + MODVERFILE + + An internal variable. This doesn't need to be exported, as it + is never used outside of the top Makefile. + + MAKE, MAKEFILES + + Some variables internal to Gnu Make. + + $(MAKEFILES) in particular is used to force the arch Makefiles + and subdirectory Makefiles to read $(TOPDIR)/.config without + including it explicitly. (This was an implementation hack and + could be fixed). + + + +=== The structure of an arch Makefile + +The top Makefile includes one arch Makefile file, arch/$(ARCH)/Makefile. +This section describes the functions of the arch Makefile. + +An arch Makefile extends some of the top Makefile's variables with +architecture-specific values. + + SUBDIRS + + The top Makefile defines $(SUBDIRS). The arch Makefile extends + $(SUBDIRS) with a list of architecture-specific directories. + + Example: + + # arch/alpha/Makefile + + SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm \ + arch/alpha/lib arch/alpha/math-emu + + This list may depend on the configuration: + + # arch/arm/Makefile + + ifeq ($(CONFIG_ARCH_ACORN),y) + SUBDIRS += drivers/acorn + ... + endif + + CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP + CPPFLAGS, CFLAGS, CFLAGS_KERNEL, MODFLAGS, AFLAGS, LDFLAGS + + The top Makefile defines these variables, and the arch Makefile + extends them. + + Many arch Makefiles dynamically run the target C compiler to + probe what options it supports: + + # arch/i386/Makefile + + # only work around strength reduction bug(s) on older gcc versions + CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-fno-strength-reduce"; fi) + + # prevent gcc from keeping the stack 16 byte aligned + CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 \ + -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ + then echo "-mpreferred-stack-boundary=2"; fi) + + And, of course, $(CFLAGS) can depend on the configuration: + + # arch/i386/Makefile + + ifdef CONFIG_M386 + CFLAGS += $(shell if $(CC) -march=i386 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-march=i386"; else echo "-m386"; fi) + endif + + ifdef CONFIG_M486 + CFLAGS += $(shell if $(CC) -march=i486 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-march=i486"; else echo "-m486"; fi) + endif + + ifdef CONFIG_M586 + CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-march=i586"; fi) + endif + + Some arch Makefiles redefine the compilation commands in order + to add architecture-specific flags: + + # arch/s390/Makefile + + LD=$(CROSS_COMPILE)ld -m elf_s390 + OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S + +An arch Makefile co-operates with the top Makefile to define variables +which specify how to build the vmlinux file. Note that there is no +corresponding arch-specific section for modules; the module-building +machinery is all architecture-independent. + + HEAD, CORE_FILES, LIBS + LINKFLAGS + + The top Makefile defines the architecture-independent core of + thse variables, and the arch Makefile extends them. Note that the + arch Makefile defines (not just extends) $(HEAD) and $(LINKFLAGS). + + Example: + + # arch/m68k/Makefile + + ifndef CONFIG_SUN3 + LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds + else + LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N + endif + + ... + + ifndef CONFIG_SUN3 + HEAD := arch/m68k/kernel/head.o + else + HEAD := arch/m68k/kernel/sun3-head.o + endif + + SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib + CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) + LIBS += arch/m68k/lib/lib.a + +An arch Makefile specifies targets that take the vmlinux file, compress +it, wrap it in bootstrapping code, and copy the resulting files somewhere. +This includes various kinds of installation commands. + +These post-vmlinux targets are not standardized across different +architectures. Here is a list of these targets and the architectures +that support each of them (as of kernel version 2.4.0-test6-pre5): + + balo mips + bootimage alpha + bootpfile alpha, ia64 + bzImage i386, m68k + bzdisk i386 + bzlilo i386 + compressed i386, m68k, mips, mips64, sh + dasdfmt s390 + Image arm + image s390 + install arm, i386 + lilo m68k + msb alpha, ia64 + my-special-boot alpha, ia64 + orionboot mips + rawboot alpha + silo s390 + srmboot alpha + tftpboot.img sparc, sparc64 + vmlinux.64 mips64 + vmlinux.aout sparc64 + zImage arm, i386, m68k, mips, mips64, ppc, sh + zImage.initrd ppc + zdisk i386, mips, mips64, sh + zinstall arm + zlilo i386 + znetboot.initrd ppc + +An arch Makefile must define the following auxiliary targets. These +targets provide arch-specific actions for the corresponding targets +in the top Makefile: + + archclean clean + archdep dep + archmrproper mrproper + + + +=== The structure of a subdirectory Makefile + +A subdirectory Makefile has five sections. + +The first section is a comment header. Just write what you would +write if you were editing a C source file, but use "# ..." instead of +"/* ... */". Historically, many anonymous people have edited kernel +Makefiles without leaving any change histories in the header; comments +from them would have been valuable. + +The second section is a bunch of definitions that are the heart of the +subdirectory Makefile. These lines define the files to be built, any +special compilation options, and any subdirectories to be recursively +entered. The declarations in these lines depend heavily on the kernel +configuration variables (CONFIG_* symbols). + +In some Makefiles ("old-style Makefiles"), the second section looks +like this: + + # drivers/parport/Makefile + ifeq ($(CONFIG_PARPORT_PC),y) + LX_OBJS += parport_pc.o + else + ifeq ($(CONFIG_PARPORT_PC),m) + MX_OBJS += parport_pc.o + endif + endif + +In most Makefiles ("new-style Makefiles"), the second section looks +like this: + + # drivers/block/Makefile + obj-$(CONFIG_MAC_FLOPPY) += swim3.o + obj-$(CONFIG_BLK_DEV_FD) += floppy.o + obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o + obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o + +The new-style Makefiles are more compact and easier to get correct +for certain features (such as CONFIG_* options that enable more than +one file). If you have a choice, please write a new-style Makefile. + +The third section is an adapter section. In old-style Makefiles, this +third section is not present. In new-style Makefiles, the third section +contains boilerplate code which converts from new-style variables to +old-style variables. This is because Rules.make processes only the +old-style variables. + +The fourth section is the single line: + + include $(TOPDIR)/Rules.make + +The fifth section contains any special Makefile rules needed that are +not available through the common rules in Rules.make. + + + +=== Rules.make variables + +The public interface of Rules.make consists of the following variables: + + ALL_SUB_DIRS, SUB_DIRS, MOD_IN_SUB_DIRS, MOD_SUB_DIRS + + $(ALL_SUB_DIRS) is an unconditional list of *all* the + subdirectories in a given directory. This list should not depend + on the kernel configuration. + + $(SUB_DIRS) is a list of subdirectories which may contribute code + to vmlinux. This list may depend on the kernel configuration. + + $(MOD_SUB_DIRS) and $(MOD_IN_SUB_DIRS) are lists of subdirectories + which may build kernel modules. Both names have exactly the + same meaning. (In version 2.2 and earlier kernels, these + variables had different meanings -- hence the different names). + + For new code, $(MOD_SUB_DIRS) is recommended and $(MOD_IN_SUB_DIRS) + is deprecated. + + Example: + + # fs/Makefile + ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs \ + umsdos ntfs hpfs sysv smbfs ncpfs ufs efs affs \ + romfs autofs hfs lockd nfsd nls devpts devfs \ + adfs partitions qnx4 udf bfs cramfs openpromfs \ + autofs4 ramfs jffs + SUB_DIRS := + + ... + + ifeq ($(CONFIG_EXT2_FS),y) + SUB_DIRS += ext2 + else + ifeq ($(CONFIG_EXT2_FS),m) + MOD_SUB_DIRS += ext2 + endif + endif + + ifeq ($(CONFIG_CRAMFS),y) + SUB_DIRS += cramfs + else + ifeq ($(CONFIG_CRAMFS),m) + MOD_SUB_DIRS += cramfs + endif + endif + + Example: + + # drivers/net/Makefile + SUB_DIRS := + MOD_SUB_DIRS := + MOD_IN_SUB_DIRS := + ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring \ + wan sk98lin arcnet skfp tulip appletalk + + ... + + ifeq ($(CONFIG_IRDA),y) + SUB_DIRS += irda + MOD_IN_SUB_DIRS += irda + else + ifeq ($(CONFIG_IRDA),m) + MOD_IN_SUB_DIRS += irda + endif + endif + + ifeq ($(CONFIG_TR),y) + SUB_DIRS += tokenring + MOD_IN_SUB_DIRS += tokenring + else + ifeq ($(CONFIG_TR),m) + MOD_IN_SUB_DIRS += tokenring + endif + endif + + O_TARGET, O_OBJS, OX_OBJS + + The subdirectory Makefile specifies object files for vmlinux in + the lists $(O_OBJS) and $(OX_OBJS). These lists depend on the + kernel configuration. + + The "X" in "OX_OBJS" stands for "eXport". Files in $(OX_OBJS) + may use the EXPORT_SYMBOL macro to define public symbols which + loadable kernel modules can see. Files in $(O_OBJS) may not use + EXPORT_SYMBOL (and you will get a funky error message if you try). + + [Yes, it's kludgy to do this by hand. Yes, you can define all + your objects as $(OX_OBJS) whether they define symbols or not; + but then you will notice a lot of extra compiles when you edit + any source file. Blame CONFIG_MODVERSIONS for this.] + + Rules.make compiles all the $(O_OBJS) and $(OX_OBJS) files. + It then calls "$(LD) -r" to merge these files into one .o file + with the name $(O_TARGET). This $(O_TARGET) name also appears + in the top Makefile. + + The order of files in $(O_OBJS) and $(OX_OBJS) is significant. + All $(OX_OBJS) files come first, in the order listed, followed by + all $(O_OBJS) files, in the order listed. Duplicates in the lists + are allowed: the first instance will be linked into $(O_TARGET) + and succeeding instances will be ignored. (Note: Rules.make may + emit warning messages for duplicates, but this is harmless). + + Example: + + # arch/alpha/kernel/Makefile + O_TARGET := kernel.o + O_OBJS := entry.o traps.o process.o osf_sys.o irq.o \ + irq_alpha.o signal.o setup.o ptrace.o time.o \ + semaphore.o + OX_OBJS := alpha_ksyms.o + + ifdef CONFIG_SMP + O_OBJS += smp.o irq_smp.o + endif + + ifdef CONFIG_PCI + O_OBJS += pci.o pci_iommu.o + endif + + Even if a subdirectory Makefile has an $(O_TARGET), the .config + options still control whether or not its $(O_TARGET) goes into + vmlinux. See the $(M_OBJS) example below. + + + + L_TARGET, L_OBJS, LX_OBJS + + These names are similar to the O_* names. Once again, $(L_OBJS) + and $(LX_OBJS) specify object files for the resident kernel; + once again, the lists depend on the current configuration; and + once again, the files that call EXPORT_SYMBOL go on the "X" list. + + The difference is that "L" stands for "Library". After making + $(L_OBJS) and $(LX_OBJS), Rules.make uses the "$(AR) rcs" command + to put these files into an archive file (a library) with the + name $(L_TARGET). This name also appears in the top Makefile. + + Example: + + # arch/i386/lib/Makefile + L_TARGET = lib.a + L_OBJS = checksum.o old-checksum.o delay.o \ + usercopy.o getuser.o putuser.o iodebug.o + + ifdef CONFIG_X86_USE_3DNOW + L_OBJS += mmx.o + endif + + ifdef CONFIG_HAVE_DEC_LOCK + L_OBJS += dec_and_lock.o + endif + + The order of files in $(L_OBJS) and $(LX_OBJS) is not significant. + Duplicates in the lists are allowed. (Note: Rules.make may emit + warning messages for duplicates, but this is harmless). + + A subdirectory Makefile can specify either an $(O_TARGET), + an $(L_TARGET), or both. Here is a discussion of the differences. + + All of the files in an $(O_TARGET) are guaranteed to appear in + the resident vmlinux image. In an $(L_TARGET), only the files + that satisfy undefined symbol references from other files will + appear in vmlinux. + + In a conventional link process, the linker processes some + object files and creates a list of unresolved external symbols. + The linker then looks in a set of libraries to resolve these + symbols. Indeed, the Linux kernel used to be linked this way, + with the bulk of the code stored in libraries. + + But vmlinux contains two types of object files that cannot be + fetched out of libraries this way: + + (1) object files that are purely EXPORT_SYMBOL definitions + (2) object files that use module_init or __initcall initializers + (instead of an initialization routine called externally) + + These files contain autonomous initializer sections which provide + code and data without being explicitly called. If these files + were stored in $(L_TARGET) libraries, the linker would fail + to include them in vmlinux. Thus, most subdirectory Makefiles + specify an $(O_TARGET) and do not use $(L_TARGET). + + Other considerations: $(O_TARGET) leads to faster re-link times + during development activity, but $(L_TARGET) gives better error + messages for unresolved symbols. + + M_OBJS, MX_OBJS + + $(M_OBJS) and $(MX_OBJS) specify object files which are built + as loadable kernel modules. As usual, the "X" in $(MX_OBJS) + stands for "eXport"; source files that use EXPORT_SYMBOL must + appear on an $(MX_OBJS) list. + + A module may be built from one source file or several source + files. In the case of one source file, the subdirectory + Makefile simply adds the file to either $(M_OBJS) or $(MX_OBJS), + as appropriate. + + Example: + + # drivers/net/irda/Makefile + ifeq ($(CONFIG_IRTTY_SIR),y) + L_OBJS += irtty.o + else + ifeq ($(CONFIG_IRTTY_SIR),m) + M_OBJS += irtty.o + endif + endif + + ifeq ($(CONFIG_IRPORT_SIR),y) + LX_OBJS += irport.o + else + ifeq ($(CONFIG_IRPORT_SIR),m) + MX_OBJS += irport.o + endif + endif + + If a kernel module is built from several source files, there + are two ways to specify the set of source files. One way is to + build a single module for the entire subdirectory. This way is + popular in the file system and network protocol stacks. + + Example: + + # fs/ext2/Makefile + O_TARGET := ext2.o + O_OBJS := acl.o balloc.o bitmap.o dir.o file.o fsync.o \ + ialloc.o inode.o ioctl.o namei.o super.o symlink.o \ + truncate.o + M_OBJS := $(O_TARGET) + + In this example, the module name will be ext2.o. Because this + file has the same name has $(O_TARGET), Rules.make will use + the $(O_TARGET) rule to build ext2.o: it will run "$(LD) -r" + on the list of $(O_OBJS) files. + + Note that this subdirectory Makefile defines both an $(O_TARGET) + and an $(M_OBJS). The control code, up in fs/Makefile, will + select between these two. If CONFIG_EXT2_FS=y, then fs/Makefile + will build $(O_TARGET); and if CONFIG_EXT_FS=m, then fs/Makefile + will build $(M_OBJS) instead. (Yes, this is a little delicate + and a little confusing). + + MI_OBJS, MIX_OBJS + + Some kernel modules are composed of several object files + linked together, but do not include every object file in their + subdirectory. $(MI_OBJS) and $(MIX_OBJS) are for this case. + + "M" stands for Module. + "I" stands for Intermediate. + "X", as usual, stands for "eXport symbol". + + Example: + + # drivers/sound/Makefile + gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o + pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + sb-objs := sb_card.o + + gus.o: $(gus-objs) + $(LD) -r -o $@ $(gus-objs) + + pas2.o: $(pas2-objs) + $(LD) -r -o $@ $(pas2-objs) + + sb.o: $(sb-objs) + $(LD) -r -o $@ $(sb-objs) + + The kernel modules gus.o, pas2.o, and sb.o are the *composite + files*. The object files gus_card.o, gus_midi.o, gus_vol.o, + gus_wave.o, ics2101.o, pas2_card.o, pas2_midi.o, pas2_mixer.o, + pas2_pcm.o, and sb_card.o are *component files*. The component + files are also called *intermediate files*. + + In another part of drivers/sound/Makefile (not shown), all of + the component files are split out. For the resident drivers: + the component object files go onto $(O_OBJS) and $(OX_OBJS) + lists, depending on whether they export symbols or not; and the + composite files are never built. For the kernel modules: the + component object files go onto $(MI_OBJS) and $(MIX_OBJS); + the composite files go onto $(M_OBJS). + + The subdirectory Makefile must also specify the linking rule + for a multi-object-file module: + + # drivers/sound/Makefile + + gus.o: $(gus-objs) + $(LD) -r -o $@ $(gus-objs) + + pas2.o: $(pas2-objs) + $(LD) -r -o $@ $(pas2-objs) + + sb.o: $(sb-objs) + $(LD) -r -o $@ $(sb-objs) + + IGNORE_FLAGS_OBJS + + $(IGNORE_FLAGS_OBJS) is a list of object files which will not have + their flag dependencies automatically tracked. This is a hackish + feature, used to kludge around a problem in the implementation + of flag dependencies. (The problem is that flag dependencies + assume that a %.o file is built from a matching %.S or %.c file. + This is sometimes not true). + + EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS + + $(EXTRA_CFLAGS) specifies options for compiling C files with + $(CC). The options in this variable apply to all $(CC) commands + for files in the current directory. + + Example: + + # drivers/sound/emu10k1/Makefile + EXTRA_CFLAGS += -I. + ifdef DEBUG + EXTRA_CFLAGS += -DEMU10K1_DEBUG + endif + + $(EXTRA_CFLAGS) does not apply to subdirectories of the current + directory. Also, it does not apply to files compiled with + $(HOSTCC). + + This variable is necessary because the top Makefile owns the + variable $(CFLAGS) and uses it for compilation flags for the + entire tree. + + $(EXTRA_AFLAGS) is a similar string for per-directory options + when compiling assembly language source. + + Example: at the time of writing, there were no examples of + $(EXTRA_AFLAGS) in the kernel corpus. + + $(EXTRA_LDFLAGS) and $(EXTRA_ARFLAGS) are similar strings for + per-directory options to $(LD) and $(AR). + + Example: at the time of writing, there were no examples of + $(EXTRA_LDFLAGS) or $(EXTRA_ARFLAGS) in the kernel corpus. + + CFLAGS_$@, AFLAGS_$@ + + $(CFLAGS_$@) specifies per-file options for $(CC). The $@ + part has a literal value which specifies the file that it's for. + + Example: + + # drivers/scsi/Makefile + CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF + CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ + -DGDTH_STATISTICS + CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM + + These three lines specify compilation flags for aha152x.o, + gdth.o, and seagate.o + + $(AFLAGS_$@) is a similar feature for source files in assembly + languages. + + Example: + + # arch/arm/kernel/Makefile + AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional + AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional + + Rules.make has a feature where an object file depends on the + value of $(CFLAGS_$@) that was used to compile it. (It also + depends on the values of $(CFLAGS) and $(EXTRA_CFLAGS)). Thus, + if you change the value of $(CFLAGS_$@) for a file, either by + editing the Makefile or overriding the value some other way, + Rules.make will do the right thing and re-compile your source + file with the new options. + + Note: because of a deficiency in Rules.make, assembly language + files do not have flag dependencies. If you edit $(AFLAGS_$@) + for such a file, you will have to remove the object file in order + to re-build from source. + + USE_STANDARD_AS_RULE + + This is a transition variable. If $(USE_STANDARD_AS_RULE) + is defined, then Rules.make will provide standard rules for + assembling %.S files into %.o files or %.s files (%.s files + are useful only to developers). + + If $(USE_STANDARD_AS_RULE) is not defined, then Rules.make + will not provide these standard rules. In this case, the + subdirectory Makefile must provide its own private rules for + assembling %.S files. + + In the past, all Makefiles provided private %.S rules. Newer + Makefiles should define USE_STANDARD_AS_RULE and use the standard + Rules.make rules. As soon as all the Makefiles across all + architectures have been converted to USE_STANDARD_AS_RULE, then + Rules.make can drop the conditional test on USE_STANDARD_AS_RULE. + After that, all the other Makefiles can drop the definition of + USE_STANDARD_AS_RULE. + + + +=== New-style variables + +The "new-style variables" are simpler and more powerful than the +"old-style variables". As a result, many subdirectory Makefiles shrank +more than 60%. This author hopes that, in time, all arch Makefiles and +subdirectory Makefiles will convert to the new style. + +Rules.make does not understand new-style variables. Thus, each new-style +Makefile has a section of boilerplate code that converts the new-style +variables into old-style variables. There is also some mixing, where +people define most variables using "new style" but then fall back to +"old style" for a few lines. + + obj-y obj-m obj-n obj- + + These variables replace $(O_OBJS), $(OX_OBJS), $(M_OBJS), + and $(MX_OBJS). + + Example: + + # drivers/block/Makefile + obj-$(CONFIG_MAC_FLOPPY) += swim3.o + obj-$(CONFIG_BLK_DEV_FD) += floppy.o + obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o + obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o + + Notice the use of $(CONFIG_...) substitutions on the left hand + side of an assignment operator. This gives Gnu Make the power + of associative indexing! Each of these assignments replaces + eight lines of code in an old-style Makefile. + + After executing all of the assignments, the subdirectory + Makefile has built up four lists: $(obj-y), $(obj-m), $(obj-n), + and $(obj-). + + $(obj-y) is a list of files to include in vmlinux. + $(obj-m) is a list of files to build as single-file modules. + $(obj-n) and $(obj-) are ignored. + + Each list may contain duplicates items; duplicates are + automatically removed later. Also, if a file appears in both + $(obj-y) and $(obj-m), it will automatically be removed from + the $(obj-m) list. + + Example: + + # drivers/net/Makefile + + ... + obj-$(CONFIG_OAKNET) += oaknet.o 8390.o + ... + obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o + ... + obj-$(CONFIG_STNIC) += stnic.o 8390.o + ... + obj-$(CONFIG_MAC8390) += daynaport.o 8390.o + ... + + In this example, four different drivers require the code in + 8390.o. If one or more of these four drivers are built into + vmlinux, then 8390.o will also be built into vmlinux, and will + *not* be built as a module -- even if another driver which needs + 8390.o is built as a module. (The modular driver is able to + use services of the 8390.o code in the resident vmlinux image). + + export-objs + + $(export-objs) is a list of all the files in the subdirectory + which potentially export symbols. The canonical way to construct + this list is: + + grep -l EXPORT_SYMBOL *.c + + (but watch out for sneaky files that call EXPORT_SYMBOL from an + included header file!) + + This is a potential list, independent of the kernel configuration. + All files that export symbols go into $(export-objs). The + boilerplate code then uses the $(export-objs) list to separate + the real file lists into $(*_OBJS) and $(*X_OBJS). + + Experience has shown that maintaining the proper X's in an + old-style Makefile is difficult and error-prone. Maintaining the + $(export-objs) list in a new-style Makefile is simpler and easier + to audit. + + list-multi + $(foo)-objs + + Some kernel modules are composed of multiple object files linked + together. $(list-multi) is a list of such kernel modules. + This is a static list; it does not depend on the configuration. + + For each kernel module in $(list-multi) there is another list + of all the object files which make up that module. For a kernel + module named foo.o, its object file list is foo-objs. + + Example: + + # drivers/scsi/Makefile + list-multi := scsi_mod.o sr_mod.o initio.o a100u2w.o + + ... + + scsi_mod-objs := hosts.o scsi.o scsi_ioctl.o constants.o \ + scsicam.o scsi_proc.o scsi_error.o \ + scsi_obsolete.o scsi_queue.o scsi_lib.o \ + scsi_merge.o scsi_dma.o scsi_scan.o \ + scsi_syms.o + sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o + initio-objs := ini9100u.o i91uscsi.o + a100u2w-objs := inia100.o i60uscsi.o + + The subdirectory Makefile puts the modules onto obj-* lists in + the usual configuration-dependent way: + + obj-$(CONFIG_SCSI) += scsi_mod.o + obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o + obj-$(CONFIG_SCSI_INITIO) += initio.o + obj-$(CONFIG_SCSI_INIA100) += a100u2w.o + + Suppose that CONFIG_SCSI=y. Then vmlinux needs to link in all + 14 components of scsi_mod.o, so these components will go onto + $(O_OBJS) and $(OX_OBJS). The composite file scsi_mod.o will + never be created. The boilerplate conversion code produces this + result with a few lines of list processing commands. + + Suppose that CONFIG_BLK_DEV_SR=m. Then the 3 components + of sr_mod.o will linked together with "$(LD) -r" to make the + kernel module sr_mod.o, so these 3 components need to go onto + the $(MI_OBJS) and $(MIX_OBJS) lists; the composite file sr_mod.o + goes onto $(M_OBJS). The boilerplate conversion code takes care + of this, too. + + And suppose CONFIG_SCSI_INITIO=n. Then initio.o goes onto the + $(obj-n) list and that's the end of it. Its component files + are not compiled, and the composite file is not created. + + Finally, the subdirectory Makefile needs to define rules to + build each multi-object kernel module from its component list. + Example: + + # drivers/scsi/Makefile + + scsi_mod.o: $(scsi_mod-objs) + $(LD) -r -o $@ $(scsi_mod-objs) + + sr_mod.o: $(sr_mod-objs) + $(LD) -r -o $@ $(sr_mod-objs) + + initio.o: $(initio-objs) + $(LD) -r -o $@ $(initio-objs) + + a100u2w.o: $(a100u2w-objs) + $(LD) -r -o $@ $(a100u2w-objs) + + These rules are very regular; it would be nice for the boilerplate + code or Rules.make to synthesize these rules automatically. + But until that happens, the subdirectory Makefile needs to define + these rules explicitly. + + + +=== Compatibility with Linux Kernel 2.2 + +Most of the information in this document also applies to 2.2, although +there is no indication of which things have changed when. Here are some +hints for writing subdirectory Makefiles that are compatible with Linux +kernel 2.2. + +You can write either an old-style Makefile or a new-style Makefile +with a boilerplate adapter section. See the 2.2 version of +drivers/sound/Makefile for a copy of the boilerplate code. + +In 2.2, Rules.make makes a distinction between $(MOD_SUB_DIRS) +and $(MOD_IN_SUB_DIRS). If you have a single directory with no +subdirectories, this will not matter to you. If you have a whole +tree, then you need to know the difference between $(MOD_SUB_DIRS) +and $(MOD_IN_SUB_DIRS). For example code: $(MOD_SUB_DIRS) is used +extensively in fs/Makefile; $(MOD_IN_SUB_DIRS) is used extensively in +drivers/net/Makefile. + +If you are already using MOD_LIST_NAME, go ahead and keep using it. +If you don't already have a MOD_LIST_NAME, go ahead and keep not using +one; your module will be a 'misc' module in 2.2. + +Assembly language rules were a mess in 2.2. If you have assembly language +files, this author recommends that you write your own explicit rules +for each file by name. + + + +=== Credits + +Thanks to the members of the linux-kbuild mailing list for reviewing +drafts of this document, with particular thanks to Peter Samuelson. diff --git a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt index 92dcf1393523..1c5c8afc903d 100644 --- a/Documentation/networking/8139too.txt +++ b/Documentation/networking/8139too.txt @@ -131,6 +131,8 @@ James Fidell, Taso Hatzi, Peter K - intrepid test team And thanks to every supporter free software. +(see top of 8139too.c for further credits and kudos) + Submitting Bug Reports @@ -157,38 +159,42 @@ the list, please report it. That's why we do beta releases, after all... 1) Work with Donald to merge fixes and updates into his driver. -2) 2.2.x COMPATIBILITY SUPPORT IS BROKEN. DO NOT USE IT. -It is included only for enterprising hackers willing to help fix it. +2) ethtool support -3) PPC platform has stability problems. +3) PPC platform has stability problems. (XXX: verify this is still true) 4) Sparc64 platform not tested at all. -5) Identify and fix "rx wedge" when ping flooded. (WIP) - -7) N-Way auto-negotiation is known to fail in some cases. This problem -also occurs in the rtl8139 driver in kernels 2.2.x/2.3.x. Solution: -Following technique in sunhme and sunbmac, use a kernel timer to -manually perform autonegotiation in case the network or card cannot do -it automatically. (patches welcome) - 8) Much improved command line / module parameter setup. (patches and suggestions welcome) (WIP) 9) Better documentation. (patches welcome) -10) (rtl8139-diag modified from Becker version, DONE) -User-mode (or maybe optional /proc) diagnostics program. - 11) RTL8139C support untested. -12) 10base-T support flaky or slow +12) 10base-T support flaky or slow (todo: verify this is still true) Change History -------------- + +Version 0.9.10 - September 12, 2000 + +* Never wrap an Rx packet (faster Rx interrupt handling) +* Clear all TxAborted conditions (bug fix) +* Correct copyright +* More credits +* Update NWay doc URL +* Clean up commonly used ifdef switches +* Reorg info displayed at bootup/modprobe time +* Remove some unneeded spinlocks +* Misc cosmetic code cleanup +* Always print interrupt status for abnormal interrupts +* Use RealTek-recommended FIFO and DMA burst settings (1024 bytes) + + Version 0.9.9 - September 9, 2000 * Fix oops-able bug in Rx ring wrap calculation (David Ford) diff --git a/Documentation/pci.txt b/Documentation/pci.txt index b96f6c48fec5..2b9041d3eec9 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -188,6 +188,11 @@ pci_find_capability() Find specified capability in device's capability list. pci_module_init() Inline helper function for ensuring correct pci_driver initialization and error handling. +pci_resource_start() Returns bus start address for a given PCI region +pci_resource_end() Returns bus end address for a given PCI region +pci_resource_len() Returns the byte length of a PCI region +pci_set_drvdata() Set private driver data pointer for a pci_dev +pci_get_drvdata() Return private driver data pointer for a pci_dev 7. Miscellaneous hints diff --git a/Makefile b/Makefile index 08ca5dc848d8..5e5646f51322 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus.a DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/zorro.a DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a -DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o +DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a @@ -174,7 +174,7 @@ DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o -DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.a +DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o DRIVERS-$(CONFIG_ACPI_INTERPRETER) += drivers/acpi/acpi.o DRIVERS += $(DRIVERS-y) diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 9993d83319ce..211a6ce50d9e 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -21,6 +21,12 @@ /* * See http://www.geocities.com/SiliconValley/Hardware/3165/ * for the user-level ACPI stuff + * + * Changes: + * Arnaldo Carvalho de Melo - 2000/08/31 + * - check copy*user return + * - get rid of check_region + * - get rid of verify_area */ #include @@ -135,8 +141,7 @@ static int acpi_do_stat(ctl_table *ctl, *len = 0; return 0; } - copy_to_user(buffer, str, size); - return 0; + return copy_to_user(buffer, str, size) ? -EFAULT : 0; } static void cx_statistics(unsigned int x, unsigned long time) @@ -1283,11 +1288,9 @@ static void acpi_power_off(void) */ static int acpi_claim(unsigned long start, unsigned long size) { - if (start && size) { - if (check_region(start, size)) + if (start && size) + if (!request_region(start, size, "acpi")) return -EBUSY; - request_region(start, size, "acpi"); - } return 0; } @@ -1391,7 +1394,8 @@ static int acpi_do_ulong(ctl_table *ctl, val = *(unsigned long*) ctl->data; size = sprintf(str, "0x%08lx\n", val); if (*len >= size) { - copy_to_user(buffer, str, size); + if (copy_to_user(buffer, str, size)) + return -EFAULT; *len = size; } else @@ -1404,7 +1408,8 @@ static int acpi_do_ulong(ctl_table *ctl, size = sizeof(str) - 1; if (size > *len) size = *len; - copy_from_user(str, buffer, size); + if (copy_from_user(str, buffer, size)) + return -EFAULT; str[size] = '\0'; val = simple_strtoul(str, &strend, 0); if (strend == str) @@ -1423,22 +1428,22 @@ static int acpi_verify_table(void *buffer, size_t size, struct acpi_table_info *info) { + struct acpi_table hdr; + size_t table_size; + if (size < sizeof(struct acpi_table)) return -EINVAL; - else if (verify_area(VERIFY_READ, buffer, size)) + + if (copy_from_user(&hdr, buffer, sizeof(hdr))) return -EFAULT; - else { - struct acpi_table hdr; - size_t table_size; - copy_from_user(&hdr, buffer, sizeof(hdr)); - table_size = (size_t) hdr.length; - if (hdr.signature != info->expected_signature - || table_size < size - || (info->expected_size - && table_size != info->expected_size)) - return -EINVAL; - } + table_size = (size_t) hdr.length; + if (hdr.signature != info->expected_signature + || table_size < size + || (info->expected_size + && table_size != info->expected_size)) + return -EINVAL; + return 0; } @@ -1496,7 +1501,8 @@ static int acpi_do_table(ctl_table *ctl, error = acpi_verify_table(buffer, *len, info); if (error) return error; - copy_from_user(&hdr, buffer, sizeof(hdr)); + if (copy_from_user(&hdr, buffer, sizeof(hdr))) + return -EFAULT; table_size = (size_t) hdr.length; write_lock(&acpi_do_table_lock); @@ -1517,7 +1523,8 @@ static int acpi_do_table(ctl_table *ctl, error = -ENOMEM; } if (data) - copy_from_user(data, buffer, size); + if (copy_from_user(data, buffer, size)) + error = -EFAULT; write_unlock(&acpi_do_table_lock); } @@ -1565,7 +1572,8 @@ static int acpi_do_event_reg(ctl_table *ctl, size = sprintf(str, "0x%08x\n", val); if (*len >= size) { - copy_to_user(buffer, str, size); + if (copy_to_user(buffer, str, size)) + return -EFAULT; *len = size; } else @@ -1580,7 +1588,8 @@ static int acpi_do_event_reg(ctl_table *ctl, size = sizeof(str) - 1; if (size > *len) size = *len; - copy_from_user(str, buffer, size); + if (copy_from_user(str, buffer, size)) + return -EFAULT; str[size] = '\0'; val = (u32) simple_strtoul(str, &strend, 0); if (strend == str) @@ -1682,7 +1691,8 @@ static int acpi_do_event(ctl_table *ctl, pm1_status, gpe_status, event_state); - copy_to_user(buffer, str, size); + if (copy_to_user(buffer, str, size)) + return -EFAULT; *len = size; file->f_pos += size; diff --git a/arch/ppc/8260_io/Config.in b/arch/ppc/8260_io/Config.in index 8cdd8c6152b7..4db16a068a75 100644 --- a/arch/ppc/8260_io/Config.in +++ b/arch/ppc/8260_io/Config.in @@ -11,12 +11,15 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then bool 'Ethernet on SCC2' CONFIG_SCC2_ENET fi fi - bool 'FCC Ethernet' CONFIG_FCC_ENET - if [ "$CONFIG_FCC_ENET" = "y" ]; then - bool 'Ethernet on FCC1' CONFIG_FCC1_ENET - if [ "$CONFIG_FCC1_ENET" != "y" ]; then - bool 'Ethernet on FCC2' CONFIG_FCC2_ENET - fi +# +# CONFIG_FEC_ENET is only used to get netdevices to call our init +# function. Any combination of FCC1,2,3 are supported. +# + bool 'FCC Ethernet' CONFIG_FEC_ENET + if [ "$CONFIG_FEC_ENET" = "y" ]; then + bool 'Ethernet on FCC1' CONFIG_FCC1_ENET + bool 'Ethernet on FCC2' CONFIG_FCC2_ENET + bool 'Ethernet on FCC3' CONFIG_FCC3_ENET fi endmenu fi diff --git a/arch/ppc/8260_io/Makefile b/arch/ppc/8260_io/Makefile index 240a85628c2f..8de47b144a77 100644 --- a/arch/ppc/8260_io/Makefile +++ b/arch/ppc/8260_io/Makefile @@ -10,8 +10,8 @@ O_TARGET := 8260_io.a O_OBJS = commproc.o uart.o -ifdef CONFIG_FCC_ENET -O_OBJS += fcc.o +ifdef CONFIG_FEC_ENET +O_OBJS += fcc_enet.o endif ifdef CONFIG_SCC_ENET O_OBJS += enet.o diff --git a/arch/ppc/8260_io/commproc.c b/arch/ppc/8260_io/commproc.c index 8642fa4206fb..b7c13b167ee8 100644 --- a/arch/ppc/8260_io/commproc.c +++ b/arch/ppc/8260_io/commproc.c @@ -69,17 +69,27 @@ m8260_cpm_reset(void) cpmp = (cpm8260_t *)commproc; } -/* Allocate some memory from the dual ported ram. We may want to - * enforce alignment restrictions, but right now everyone is a good - * citizen. +/* Allocate some memory from the dual ported ram. + * To help protocols with object alignment restrictions, we do that + * if they ask. */ uint -m8260_cpm_dpalloc(uint size) +m8260_cpm_dpalloc(uint size, uint align) { uint retloc; + uint align_mask, off; + uint savebase; - if ((dp_alloc_base + size) >= dp_alloc_top) + align_mask = align - 1; + savebase = dp_alloc_base; + + if ((off = (dp_alloc_base & align_mask)) != 0) + dp_alloc_base += (align - off); + + if ((dp_alloc_base + size) >= dp_alloc_top) { + dp_alloc_base = savebase; return(CPM_DP_NOSPACE); + } retloc = dp_alloc_base; dp_alloc_base += size; @@ -91,12 +101,22 @@ m8260_cpm_dpalloc(uint size) * UART "fifos" and the like. */ uint -m8260_cpm_hostalloc(uint size) +m8260_cpm_hostalloc(uint size, uint align) { uint retloc; + uint align_mask, off; + uint savebase; - if ((host_buffer + size) >= host_end) + align_mask = align - 1; + savebase = host_buffer; + + if ((off = (host_buffer & align_mask)) != 0) + host_buffer += (align - off); + + if ((host_buffer + size) >= host_end) { + host_buffer = savebase; return(0); + } retloc = host_buffer; host_buffer += size; diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c index 4c8c672fdcfb..e1ff3c09248e 100644 --- a/arch/ppc/8260_io/enet.c +++ b/arch/ppc/8260_io/enet.c @@ -466,8 +466,11 @@ for (;;) { cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. - */ - skb = dev_alloc_skb(pkt_len); + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -475,10 +478,10 @@ for (;;) { } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } @@ -549,10 +552,10 @@ static void set_multicast_list(struct net_device *dev) /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->sccp->scc_pmsr |= SCC_PMSR_PRO; + cep->sccp->scc_pmsr |= SCC_PSMR_PRO; } else { - cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO; + cep->sccp->scc_pmsr &= ~SCC_PSMR_PRO; if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the @@ -678,11 +681,11 @@ int __init scc_enet_init(void) * These are relative offsets in the DP ram address space. * Initialize base addresses for the buffer descriptors. */ - i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE); + i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); ep->sen_genscc.scc_rbase = i; cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; - i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE); + i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); ep->sen_genscc.scc_tbase = i; cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; @@ -816,7 +819,7 @@ int __init scc_enet_init(void) /* Set processing mode. Use Ethernet CRC, catch broadcast, and * start frame search 22 bit times after RENA. */ - sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_NIB22); + sccp->scc_pmsr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c new file mode 100644 index 000000000000..5c7b61cf9cfe --- /dev/null +++ b/arch/ppc/8260_io/fcc_enet.c @@ -0,0 +1,1600 @@ +/* + * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * This version of the driver is a combination of the 8xx fec and + * 8260 SCC Ethernet drivers. People seem to be choosing common I/O + * configurations, so this driver will work on the EST8260 boards and + * others yet to be announced. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* The transmitter timeout + */ +#define TX_TIMEOUT (2*HZ) + +/* The number of Tx and Rx buffers. These are allocated from the page + * pool. The code may assume these are power of two, so it it best + * to keep them that size. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#define FCC_ENET_RX_PAGES 16 +#define FCC_ENET_RX_FRSIZE 2048 +#define FCC_ENET_RX_FRPPG (PAGE_SIZE / FCC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES) +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ + +/* The FCC stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 + +/* Maximum input DMA size. Must be a should(?) be a multiple of 4. +*/ +#define PKT_MAXDMA_SIZE 1520 + +/* Maximum input buffer size. Must be a multiple of 32. +*/ +#define PKT_MAXBLR_SIZE 1536 + +static int fcc_enet_open(struct net_device *dev); +static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int fcc_enet_rx(struct net_device *dev); +static void fcc_enet_mii(struct net_device *dev); +static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static int fcc_enet_close(struct net_device *dev); +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void restart_fcc(struct net_device *dev); + +/* These will be configurable for the FCC choice. + * Multiple ports can be configured. There is little choice among the + * I/O pins to the PHY, except the clocks. We will need some board + * dependent clock selection. + * Why in the hell did I put these inside #ifdef's? I dunno, maybe to + * help show what pins are used for each device. + */ + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL ((uint)0x00000001) +#define PA1_CRS ((uint)0x00000002) +#define PA1_TXER ((uint)0x00000004) +#define PA1_TXEN ((uint)0x00000008) +#define PA1_RXDV ((uint)0x00000010) +#define PA1_RXER ((uint)0x00000020) +#define PA1_TXDAT ((uint)0x00003c00) +#define PA1_RXDAT ((uint)0x0003c000) +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + +/* CLK12 is receive, CLK11 is transmit. These are board specific. +*/ +#define PC_F1RXCLK ((uint)0x00000800) +#define PC_F1TXCLK ((uint)0x00000400) +#define CMX1_CLK_ROUTE ((uint)0x3e000000) +#define CMX1_CLK_MASK ((uint)0xff000000) + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER ((uint)0x00000001) +#define PB2_RXDV ((uint)0x00000002) +#define PB2_TXEN ((uint)0x00000004) +#define PB2_RXER ((uint)0x00000008) +#define PB2_COL ((uint)0x00000010) +#define PB2_CRS ((uint)0x00000020) +#define PB2_TXDAT ((uint)0x000003c0) +#define PB2_RXDAT ((uint)0x00003c00) +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + +/* CLK13 is receive, CLK14 is transmit. These are board dependent. +*/ +#define PC_F2RXCLK ((uint)0x00001000) +#define PC_F2TXCLK ((uint)0x00002000) +#define CMX2_CLK_ROUTE ((uint)0x00250000) +#define CMX2_CLK_MASK ((uint)0x00ff0000) + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV ((uint)0x00004000) +#define PB3_RXER ((uint)0x00008000) +#define PB3_TXER ((uint)0x00010000) +#define PB3_TXEN ((uint)0x00020000) +#define PB3_COL ((uint)0x00040000) +#define PB3_CRS ((uint)0x00080000) +#define PB3_TXDAT ((uint)0x0f000000) +#define PB3_RXDAT ((uint)0x00f00000) +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 (0) +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) + +/* CLK15 is receive, CLK16 is transmit. These are board dependent. +*/ +#define PC_F3RXCLK ((uint)0x00004000) +#define PC_F3TXCLK ((uint)0x00008000) +#define CMX3_CLK_ROUTE ((uint)0x00003700) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +/* MII status/control serial interface. +*/ +#define PC_MDIO ((uint)0x00400000) +#define PC_MDCK ((uint)0x00200000) + +/* A table of information for supporting FCCs. This does two things. + * First, we know how many FCCs we have and they are always externally + * numbered from zero. Second, it holds control register and I/O + * information that could be different among board designs. + */ +typedef struct fcc_info { + uint fc_fccnum; + uint fc_cpmblock; + uint fc_cpmpage; + uint fc_proff; + uint fc_interrupt; + uint fc_trxclocks; + uint fc_clockroute; + uint fc_clockmask; + uint fc_mdio; + uint fc_mdck; +} fcc_info_t; + +static fcc_info_t fcc_ports[] = { +#ifdef CONFIG_FCC1_ENET + { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1, + (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +#ifdef CONFIG_FCC2_ENET + { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2, + (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +#ifdef CONFIG_FCC3_ENET + { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3, + (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +}; + +/* The FCC buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct fcc_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + volatile fcc_t *fccp; + volatile fcc_enet_t *ep; + struct net_device_stats stats; + uint tx_full; + spinlock_t lock; + uint phy_address; + uint phy_type; + uint phy_duplex; + fcc_info_t *fip; +}; + +static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile immap_t *immap); +static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev); +static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, + volatile immap_t *immap); +static void init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile immap_t *immap); + +/* MII processing. We keep this as simple as possible. Requests are + * placed on the list (if there is room). When the request is finished + * by the MII, an optional function may be called. + */ +typedef struct mii_list { + uint mii_regval; + void (*mii_func)(uint val, struct net_device *dev); + struct mii_list *mii_next; +} mii_list_t; + +#define NMII 20 +mii_list_t mii_cmds[NMII]; +mii_list_t *mii_free; +mii_list_t *mii_head; +mii_list_t *mii_tail; + +static int phyaddr; +static uint phytype; + +static int mii_queue(int request, void (*func)(uint, struct net_device *)); +static void mii_startup_cmds(void); +static uint mii_send_receive(fcc_info_t *fip, uint cmd); + +/* Make MII read/write commands for the FCC. +*/ + +#define mk_mii_phyaddr(ADDR) (0x60020000 | ((ADDR) << 23) | (2 << 18)) + +#define mk_mii_read(REG) (0x60020000 | ((phyaddr << 23) | \ + (REG & 0x1f) << 18)) + +#define mk_mii_write(REG, VAL) (0x50020000 | ((phyaddr << 23) | \ + (REG & 0x1f) << 18) | \ + (VAL & 0xffff)) + + +static int +fcc_enet_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; /* Always succeed */ +} + +static int +fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + volatile cbd_t *bdp; + + + /* Fill in a Tx ring entry */ + bdp = cep->cur_tx; + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since cep->tx_full should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } +#endif + + /* Clear all of the status flags. + */ + bdp->cbd_sc &= ~BD_ENET_TX_STATS; + + /* If the frame is short, tell CPM to pad it. + */ + if (skb->len <= ETH_ZLEN) + bdp->cbd_sc |= BD_ENET_TX_PAD; + else + bdp->cbd_sc &= ~BD_ENET_TX_PAD; + + /* Set buffer length and buffer pointer. + */ + bdp->cbd_datlen = skb->len; + bdp->cbd_bufaddr = __pa(skb->data); + + /* Save skb pointer. + */ + cep->tx_skbuff[cep->skb_cur] = skb; + + cep->stats.tx_bytes += skb->len; + cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; + + spin_lock_irq(&cep->lock); + + /* Send it on its way. Tell CPM its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + +#if 0 + /* Errata says don't do this. + */ + cep->fccp->fcc_ftodr = 0x8000; +#endif + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, start at the beginning again. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + if (bdp->cbd_sc & BD_ENET_TX_READY) { + netif_stop_queue(dev); + cep->tx_full = 1; + } + + cep->cur_tx = (cbd_t *)bdp; + + spin_unlock_irq(&cep->lock); + + return 0; +} + + +static void +fcc_enet_timeout(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + cep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", + cep->cur_tx, cep->tx_full ? " (full)" : "", + cep->cur_rx); + bdp = cep->tx_bd_base; + printk(" Tx @base %p :\n", bdp); + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp = cep->rx_bd_base; + printk(" Rx @base %p :\n", bdp); + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + } +#endif + if (!cep->tx_full) + netif_wake_queue(dev); +} + +/* The interrupt handler. + */ +static void +fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + volatile struct fcc_enet_private *cep; + volatile cbd_t *bdp; + ushort int_events; + int must_restart; + + cep = (struct fcc_enet_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->fccp->fcc_fcce; + cep->fccp->fcc_fcce = int_events; + must_restart = 0; + + /* Handle receive event in its own function. + */ + if (int_events & FCC_ENET_RXF) + fcc_enet_rx(dev_id); + + /* Check for a transmit error. The manual is a little unclear + * about this, so the debug code until I get it figured out. It + * appears that if TXE is set, then TXB is not set. However, + * if carrier sense is lost during frame transmission, the TXE + * bit is set, "and continues the buffer transmission normally." + * I don't know if "normally" implies TXB is set when the buffer + * descriptor is closed.....trial and error :-). + */ + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + */ + if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { + spin_lock(&cep->lock); + bdp = cep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { + if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) + break; + + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + cep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + cep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + cep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + cep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + cep->stats.tx_carrier_errors++; + + + /* No heartbeat or Lost carrier are not really bad errors. + * The others require a restart transmit command. + */ + if (bdp->cbd_sc & + (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + must_restart = 1; + cep->stats.tx_errors++; + } + + cep->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->cbd_sc & BD_ENET_TX_DEF) + cep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); + cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + /* I don't know if we can be held off from processing these + * interrupts for more than one frame time. I really hope + * not. In such a case, we would now want to check the + * currently available BD (cur_tx) and determine if any + * buffers between the dirty_tx and cur_tx have also been + * sent. We would want to process anything in between that + * does not have BD_ENET_TX_READY set. + */ + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (cep->tx_full) { + cep->tx_full = 0; + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + } + + cep->dirty_tx = (cbd_t *)bdp; + } + + if (must_restart) { + volatile cpm8260_t *cp; + + /* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. + */ + + cp = cpmp; + cp->cp_cpcr = + mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, + 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + spin_unlock(&cep->lock); + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. + */ + if (int_events & FCC_ENET_BSY) { + cep->stats.rx_dropped++; + } + return; +} + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int +fcc_enet_rx(struct net_device *dev) +{ + struct fcc_enet_private *cep; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + + cep = (struct fcc_enet_private *)dev->priv; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = cep->cur_rx; + +for (;;) { + if (bdp->cbd_sc & BD_ENET_RX_EMPTY) + break; + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, both + * the first and last indicators should be set. + */ + if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != + (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) + printk("CPM ENET: rcv is not first+last\n"); +#endif + + /* Frame too long or too short. + */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + cep->stats.rx_length_errors++; + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + cep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + cep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + cep->stats.rx_crc_errors++; + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (bdp->cbd_sc & BD_ENET_RX_CL) { + cep->stats.rx_frame_errors++; + } + else { + + /* Process the incoming frame. + */ + cep->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + cep->stats.rx_bytes += pkt_len; + + /* This does 16 byte alignment, much more than we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + else { + skb->dev = dev; + skb_put(skb,pkt_len-4); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len-4, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + } + + /* Clear the status flags for this buffer. + */ + bdp->cbd_sc &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. + */ + bdp->cbd_sc |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. + */ + if (bdp->cbd_sc & BD_ENET_RX_WRAP) + bdp = cep->rx_bd_base; + else + bdp++; + + } + cep->cur_rx = (cbd_t *)bdp; + + return 0; +} + +static int +fcc_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + netif_stop_queue(dev); + + return 0; +} + +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + return &cep->stats; +} + +/* The MII is simulated from the 8xx FEC implementation. The FCC + * is not responsible for the MII control/status interface. + */ +static void +fcc_enet_mii(struct net_device *dev) +{ + struct fcc_enet_private *fep; + mii_list_t *mip; + uint mii_reg; + + fep = (struct fcc_enet_private *)dev->priv; +#if 0 + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + mii_reg = ep->fec_mii_data; +#endif + + if ((mip = mii_head) == NULL) { + printk("MII and no head!\n"); + return; + } + + if (mip->mii_func != NULL) + (*(mip->mii_func))(mii_reg, dev); + + mii_head = mip->mii_next; + mip->mii_next = mii_free; + mii_free = mip; + +#if 0 + if ((mip = mii_head) != NULL) + ep->fec_mii_data = mip->mii_regval; +#endif +} + +static int +mii_queue(int regval, void (*func)(uint, struct net_device *)) +{ + unsigned long flags; + mii_list_t *mip; + int retval; + + retval = 0; + + save_flags(flags); + cli(); + + if ((mip = mii_free) != NULL) { + mii_free = mip->mii_next; + mip->mii_regval = regval; + mip->mii_func = func; + mip->mii_next = NULL; + if (mii_head) { + mii_tail->mii_next = mip; + mii_tail = mip; + } + else { + mii_head = mii_tail = mip; +#if 0 + (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval; +#endif + } + } + else { + retval = 1; + } + + restore_flags(flags); + + return(retval); +} + +static volatile uint full_duplex; + +static void +mii_status(uint mii_reg, struct net_device *dev) +{ + volatile uint prev_duplex; + + if (((mii_reg >> 18) & 0x1f) == 1) { + /* status register. + */ + printk("fec: "); + if (mii_reg & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_reg & 0x0010) + printk(",remote fault"); + if (mii_reg & 0x0020) + printk(",auto complete"); + printk("\n"); + } + if (((mii_reg >> 18) & 0x1f) == 0x14) { + /* Extended chip status register. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_reg & 0x0800) + printk("100 Mbps"); + else + printk("10 Mbps"); + + if (mii_reg & 0x1000) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } +#if 0 + if (prev_duplex != full_duplex) + restart_fec(dev); +#endif + } + if (((mii_reg >> 18) & 0x1f) == 31) { + /* QS6612 PHY Control/Status. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + + mii_reg = (mii_reg >> 2) & 7; + + if (mii_reg & 1) + printk("10 Mbps"); + else + printk("100 Mbps"); + + if (mii_reg > 4) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + +#if 0 + if (prev_duplex != full_duplex) + restart_fec(dev); +#endif + } +} + +static uint phyno; + +static void +mii_discover_phy3(uint mii_reg, struct net_device *dev) +{ + phytype <<= 16; + phytype |= (mii_reg & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", phyno, phytype); + mii_startup_cmds(); +} + +static void +mii_discover_phy(uint mii_reg, struct net_device *dev) +{ + if (phyno < 32) { + if ((phytype = (mii_reg & 0xffff)) != 0xffff) { + phyaddr = phyno; + mii_queue(mk_mii_read(3), mii_discover_phy3); + } + else { + phyno++; + mii_queue(mk_mii_phyaddr(phyno), mii_discover_phy); + } + } + else { + printk("FEC: No PHY device found.\n"); + } +} + +static void +mii_discover_phy_poll(fcc_info_t *fip) +{ + uint rv; + int i; + + for (i=0; i<32; i++) { + rv = mii_send_receive(fip, mk_mii_phyaddr(i)); + if ((phytype = (rv & 0xffff)) != 0xffff) { + phyaddr = i; + rv = mii_send_receive(fip, mk_mii_read(3)); + phytype <<= 16; + phytype |= (rv & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", phyaddr, phytype); + } + } +} + +static void +mii_startup_cmds(void) +{ + +#if 1 + /* Level One PHY. + */ + + /* Read status registers to clear any pending interrupt. + */ + mii_queue(mk_mii_read(1), mii_status); + mii_queue(mk_mii_read(18), mii_status); + + /* Read extended chip status register. + */ + mii_queue(mk_mii_read(0x14), mii_status); + + /* Set default operation of 100-TX....for some reason + * some of these bits are set on power up, which is wrong. + */ + mii_queue(mk_mii_write(0x13, 0), NULL); + + /* Enable Link status change interrupts. + */ + mii_queue(mk_mii_write(0x11, 0x0002), NULL); + + /* Don't advertize Full duplex. + mii_queue(mk_mii_write(0x04, 0x0021), NULL); + */ +#endif + +} + +/* This supports the mii_link interrupt below. + * We should get called three times. Once for register 1, once for + * register 18, and once for register 20. + */ +static uint mii_saved_reg1; + +static void +mii_relink(uint mii_reg, struct net_device *dev) +{ + volatile uint prev_duplex; + unsigned long flags; + + if (((mii_reg >> 18) & 0x1f) == 1) { + /* Just save the status register and get out. + */ + mii_saved_reg1 = mii_reg; + return; + } + if (((mii_reg >> 18) & 0x1f) == 18) { + /* Not much here, but has to be read to clear the + * interrupt condition. + */ + if ((mii_reg & 0x8000) == 0) + printk("fec: re-link and no IRQ?\n"); + if ((mii_reg & 0x4000) == 0) + printk("fec: no PHY power?\n"); + } + if (((mii_reg >> 18) & 0x1f) == 20) { + /* Extended chip status register. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + if (mii_reg & 0x0800) + printk(", 100 Mbps"); + else + printk(", 10 Mbps"); + + if (mii_reg & 0x1000) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + if (prev_duplex != full_duplex) { + save_flags(flags); + cli(); +#if 0 + restart_fec(dev); +#endif + restore_flags(flags); + } + } + if (((mii_reg >> 18) & 0x1f) == 31) { + /* QS6612 PHY Control/Status. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + mii_reg = (mii_reg >> 2) & 7; + + if (mii_reg & 1) + printk(", 10 Mbps"); + else + printk(", 100 Mbps"); + + if (mii_reg > 4) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + +#if 0 + if (prev_duplex != full_duplex) { + save_flags(flags); + cli(); + restart_fec(dev); + restore_flags(flags); + } +#endif + } +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ +static void +set_multicast_list(struct net_device *dev) +{ + struct fcc_enet_private *cep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile fcc_enet_t *ep; + int i, j; + + cep = (struct fcc_enet_private *)dev->priv; + +return; + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)dev->base_addr; + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO; + } else { + + cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->fen_gaddrh = 0xffffffff; + ep->fen_gaddrl = 0xffffffff; + } + else { + /* Clear filter and add the addresses in the list. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + + dmi = dev->mc_list; + + for (i=0; imc_count; i++) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u_char *)dmi->dmi_addr + 5; + tdptr = (u_char *)&ep->fen_taddrh; + for (j=0; j<6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage, + cep->fip->fc_cpmblock, 0x0c, + CPM_CR_SET_GADDR) | CPM_CR_FLG; + udelay(10); + while (cpmp->cp_cpcr & CPM_CR_FLG); + } + } + } +} + +/* Initialize the CPM Ethernet on FCC. + */ +int __init fec_enet_init(void) +{ + struct net_device *dev; + struct fcc_enet_private *cep; + fcc_info_t *fip; + int i, np; + volatile immap_t *immap; + volatile iop8260_t *io; + + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + io = &immap->im_ioport; + + np = sizeof(fcc_ports) / sizeof(fcc_info_t); + fip = fcc_ports; + + while (np-- > 0) { + + /* Allocate some private information. + */ + cep = (struct fcc_enet_private *) + kmalloc(sizeof(*cep), GFP_KERNEL); + __clear_user(cep,sizeof(*cep)); + spin_lock_init(&cep->lock); + cep->fip = fip; + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + dev->priv = cep; + + init_fcc_shutdown(fip, cep, immap); + init_fcc_ioports(fip, io, immap); + init_fcc_param(fip, dev, immap); + + dev->base_addr = (unsigned long)(cep->ep); + + /* The CPM Ethernet specific entries in the device + * structure. + */ + dev->open = fcc_enet_open; + dev->hard_start_xmit = fcc_enet_start_xmit; + dev->tx_timeout = fcc_enet_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = fcc_enet_close; + dev->get_stats = fcc_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + init_fcc_startup(fip, dev); + + printk("%s: FCC ENET Version 0.2, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + /* This is just a hack for now that works only on the EST + * board, or anything else that has MDIO/CK configured. + * It is mainly to test the MII software clocking. + */ + mii_discover_phy_poll(fip); + + fip++; + } + + return 0; +} + +/* Make sure the device is shut down during initialization. +*/ +static void __init +init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile immap_t *immap) +{ + volatile fcc_enet_t *ep; + volatile fcc_t *fccp; + + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]); + + /* And another to the FCC register area. + */ + fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]); + cep->fccp = fccp; /* Keep the pointers handy */ + cep->ep = ep; + + /* Disable receive and transmit in case someone left it running. + */ + fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* Initialize the I/O pins for the FCC Ethernet. +*/ +static void __init +init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, + volatile immap_t *immap) +{ + + /* FCC1 pins are on port A/C. FCC2/3 are port B/C. + */ + if (fip->fc_proff == PROFF_FCC1) { + /* Configure port A and C pins for FCC1 Ethernet. + */ + io->iop_pdira &= ~PA1_DIRA0; + io->iop_pdira |= PA1_DIRA1; + io->iop_psora &= ~PA1_PSORA0; + io->iop_psora |= PA1_PSORA1; + io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1); + } + if (fip->fc_proff == PROFF_FCC2) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB2_DIRB0; + io->iop_pdirb |= PB2_DIRB1; + io->iop_psorb &= ~PB2_PSORB0; + io->iop_psorb |= PB2_PSORB1; + io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1); + } + if (fip->fc_proff == PROFF_FCC3) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB3_DIRB0; + io->iop_pdirb |= PB3_DIRB1; + io->iop_psorb &= ~PB3_PSORB0; + io->iop_psorb |= PB3_PSORB1; + io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1); + } + + /* Port C has clocks...... + */ + io->iop_psorc &= ~(fip->fc_trxclocks); + io->iop_pdirc &= ~(fip->fc_trxclocks); + io->iop_pparc |= fip->fc_trxclocks; + + /* ....and the MII serial clock/data. + */ + io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_podrc |= fip->fc_mdio; + io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck); + + /* Configure Serial Interface clock routing. + * First, clear all FCC bits to zero, + * then set the ones we want. + */ + immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask); + immap->im_cpmux.cmx_fcr |= fip->fc_clockroute; +} + +static void __init +init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile immap_t *immap) +{ + unsigned char *eap; + unsigned long mem_addr; + bd_t *bd; + int i, j; + struct fcc_enet_private *cep; + volatile fcc_enet_t *ep; + volatile cbd_t *bdp; + volatile cpm8260_t *cp; + + cep = (struct fcc_enet_private *)(dev->priv); + ep = cep->ep; + cp = cpmp; + + bd = (bd_t *)__res; + + /* Zero the whole thing.....I must have missed some individually. + * It works when I do this. + */ + memset((char *)ep, 0, sizeof(fcc_enet_t)); + + /* Allocate space for the buffer descriptors in the DP ram. + * These are relative offsets in the DP ram address space. + * Initialize base addresses for the buffer descriptors. + */ +#if 0 + /* I really want to do this, but for some reason it doesn't + * work with the data cache enabled, so I allocate from the + * main memory instead. + */ + i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i]; + cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; + + i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i]; + cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; +#else + cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base); + cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base); +#endif + + cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; + cep->cur_rx = cep->rx_bd_base; + + ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + + /* Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; + + /* Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. + */ + mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128); + ep->fen_genfcc.fcc_riptr = mem_addr; + ep->fen_genfcc.fcc_tiptr = mem_addr+32; + ep->fen_padptr = mem_addr+64; + memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32); + + ep->fen_genfcc.fcc_rbptr = 0; + ep->fen_genfcc.fcc_tbptr = 0; + ep->fen_genfcc.fcc_rcrc = 0; + ep->fen_genfcc.fcc_tcrc = 0; + ep->fen_genfcc.fcc_res1 = 0; + ep->fen_genfcc.fcc_res2 = 0; + + ep->fen_camptr = 0; /* CAM isn't used in this driver */ + + /* Set CRC preset and mask. + */ + ep->fen_cmask = 0xdebb20e3; + ep->fen_cpres = 0xffffffff; + + ep->fen_crcec = 0; /* CRC Error counter */ + ep->fen_alec = 0; /* alignment error counter */ + ep->fen_disfc = 0; /* discard frame counter */ + ep->fen_retlim = 15; /* Retry limit threshold */ + ep->fen_pper = 0; /* Normal persistence */ + + /* Clear hash filter tables. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + ep->fen_iaddrh = 0; + ep->fen_iaddrl = 0; + + /* Clear the Out-of-sequence TxBD. + */ + ep->fen_tfcstat = 0; + ep->fen_tfclen = 0; + ep->fen_tfcptr = 0; + + ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ + + /* Set Ethernet station address. + * + * This is supplied in the board information structure, so we + * copy that into the controller. + * So, far we have only been given one Ethernet address. We make + * it unique by setting a few bits in the upper byte of the + * non-static part of the address. + */ + eap = (unsigned char *)&(ep->fen_paddrh); + for (i=5; i>=0; i--) { + if (i == 3) { + dev->dev_addr[i] = bd->bi_enetaddr[i]; + dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum)); + *eap++ = dev->dev_addr[i]; + } + else { + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; + } + } + + ep->fen_taddrh = 0; + ep->fen_taddrm = 0; + ep->fen_taddrl = 0; + + ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */ + ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */ + + /* Clear stat counters, in case we ever enable RMON. + */ + ep->fen_octc = 0; + ep->fen_colc = 0; + ep->fen_broc = 0; + ep->fen_mulc = 0; + ep->fen_uspc = 0; + ep->fen_frgc = 0; + ep->fen_ospc = 0; + ep->fen_jbrc = 0; + ep->fen_p64c = 0; + ep->fen_p65c = 0; + ep->fen_p128c = 0; + ep->fen_p256c = 0; + ep->fen_p512c = 0; + ep->fen_p1024c = 0; + + ep->fen_rfthr = 0; /* Suggested by manual */ + ep->fen_rfcnt = 0; + ep->fen_cftype = 0; + + /* Now allocate the host memory pages and initialize the + * buffer descriptors. + */ + bdp = cep->tx_bd_base; + for (i=0; icbd_sc = 0; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + bdp = cep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FCC_ENET_RX_FRSIZE; + bdp++; + } + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + cep->skb_cur = cep->skb_dirty = 0; +} + +/* Let 'er rip. +*/ +static void __init +init_fcc_startup(fcc_info_t *fip, struct net_device *dev) +{ + volatile fcc_t *fccp; + struct fcc_enet_private *cep; + + cep = (struct fcc_enet_private *)(dev->priv); + fccp = cep->fccp; + + fccp->fcc_fcce = 0xffff; /* Clear any pending events */ + + /* Enable interrupts for transmit error, complete frame + * received, and any transmit buffer we have also set the + * interrupt flag. + */ + fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); + + /* Install our interrupt handler. + */ + if (request_8xxirq(fip->fc_interrupt, fcc_enet_interrupt, 0, + "fenet", dev) < 0) + printk("Can't get FCC IRQ %d\n", fip->fc_interrupt); + + /* Set GFMR to enable Ethernet operating mode. + */ + fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); + + /* Set sync/delimiters. + */ + fccp->fcc_fdsr = 0xd555; + + /* Set protocol specific processing mode for Ethernet. + * This has to be adjusted for Full Duplex operation after we can + * determine how to detect that. + */ + fccp->fcc_fpsmr = FCC_PSMR_ENCRC; + + /* And last, enable the transmit and receive processing. + */ + fccp->fcc_gfmr |= (FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* MII command/status interface. + * I'm not going to describe all of the details. You can find the + * protocol definition in many other places, including the data sheet + * of most PHY parts. + * I wonder what "they" were thinking (maybe weren't) when they leave + * the I2C in the CPM but I have to toggle these bits...... + */ +static uint +mii_send_receive(fcc_info_t *fip, uint cmd) +{ + unsigned long flags; + uint retval; + int read_op, i; + volatile immap_t *immap; + volatile iop8260_t *io; + + immap = (immap_t *)IMAP_ADDR; + io = &immap->im_ioport; + + /* When we get here, both clock and data are high, outputs. + * Output is open drain. + * Data transitions on high->low clock, is valid on low->high clock. + * Spec says edge transitions no closer than 160 nSec, minimum clock + * cycle 400 nSec. I could only manage about 500 nSec edges with + * an XOR loop, so I won't worry about delays yet. + * I disable interrupts during bit flipping to ensure atomic + * updates of the registers. I do lots of interrupt disable/enable + * to ensure we don't hang out too long with interrupts disabled. + */ + + /* First, crank out 32 1-bits as preamble. + * This is 64 transitions to clock the bits, with clock/data + * left high. + */ + save_flags(flags); + cli(); + for (i=0; i<64; i++) { + io->iop_pdatc ^= fip->fc_mdck; + udelay(0); + } + restore_flags(flags); + + read_op = ((cmd & 0xf0000000) == 0x60000000); + + /* We return the command word on a write op, or the command portion + * plus the new data on a read op. This is what the 8xx FEC does, + * and it allows the functions to simply look at the returned value + * and know the PHY/register as well. + */ + if (read_op) + retval = cmd; + else + retval = (cmd >> 16); + + /* Clock out the first 16 MS bits of the command. + */ + save_flags(flags); + cli(); + for (i=0; i<16; i++) { + io->iop_pdatc &= ~(fip->fc_mdck); + if (cmd & 0x80000000) + io->iop_pdatc |= fip->fc_mdio; + else + io->iop_pdatc &= ~(fip->fc_mdio); + cmd <<= 1; + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + } + + /* Do the turn-around. If read op, we make the IO and input. + * If write op, do the 1/0 thing. + */ + io->iop_pdatc &= ~(fip->fc_mdck); + if (read_op) + io->iop_pdirc &= ~(fip->fc_mdio); + else + io->iop_pdatc |= fip->fc_mdio; + io->iop_pdatc |= fip->fc_mdck; + + /* I do this mainly to get just a little delay. + */ + restore_flags(flags); + save_flags(flags); + cli(); + io->iop_pdatc &= ~(fip->fc_mdck); + io->iop_pdirc &= ~(fip->fc_mdio); + io->iop_pdatc |= fip->fc_mdck; + + restore_flags(flags); + save_flags(flags); + cli(); + + /* For read, clock in 16 bits. For write, clock out + * rest of command. + */ + if (read_op) { + io->iop_pdatc &= ~(fip->fc_mdck); + udelay(0); + for (i=0; i<16; i++) { + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + retval <<= 1; + if (io->iop_pdatc & fip->fc_mdio) + retval |= 1; + io->iop_pdatc &= ~(fip->fc_mdck); + udelay(0); + } + } + else { + for (i=0; i<16; i++) { + io->iop_pdatc &= ~(fip->fc_mdck); + if (cmd & 0x80000000) + io->iop_pdatc |= fip->fc_mdio; + else + io->iop_pdatc &= ~(fip->fc_mdio); + cmd <<= 1; + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + } + io->iop_pdatc &= ~(fip->fc_mdck); + } + restore_flags(flags); + + /* Some diagrams show two 1 bits for "idle". I don't know if + * this is really necessary or if it was just to indicate nothing + * is going to happen for a while. + * Make the data pin an output, set the data high, and clock it. + */ + save_flags(flags); + cli(); + io->iop_pdatc |= fip->fc_mdio; + io->iop_pdirc |= fip->fc_mdio; + for (i=0; i<3; i++) + io->iop_pdatc ^= fip->fc_mdck; + restore_flags(flags); + + /* We exit with the same conditions as entry. + */ + return(retval); +} diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c index caa5ca8b0835..97c4cb880884 100644 --- a/arch/ppc/8260_io/uart.c +++ b/arch/ppc/8260_io/uart.c @@ -977,8 +977,7 @@ static int rs_8xx_write(struct tty_struct * tty, int from_user, } if (from_user) { - if (c != - copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { + if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { if (!ret) ret = -EFAULT; break; @@ -2396,10 +2395,10 @@ int __init rs_8xx_init(void) io->iop_pdird &= ~0x00800000; io->iop_psord &= ~0x00c00000; #if USE_SMC2 - io->iop_ppara |= 0x01800000; - io->iop_pdira |= 0x00800000; - io->iop_pdira &= ~0x01000000; - io->iop_psora &= ~0x01800000; + io->iop_ppara |= 0x00c00000; + io->iop_pdira |= 0x00400000; + io->iop_pdira &= ~0x00800000; + io->iop_psora &= ~0x00c00000; #endif /* Configure SCC2 and SCC3. Be careful about the fine print. @@ -2473,11 +2472,11 @@ int __init rs_8xx_init(void) * descriptors from dual port ram, and a character * buffer area from host mem. */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); + mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -2506,11 +2505,11 @@ int __init rs_8xx_init(void) sup->scc_genscc.scc_rbase = dp_addr; } - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); + mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -2716,11 +2715,11 @@ static int __init serial_console_setup(struct console *co, char *options) /* Allocate space for two buffer descriptors in the DP ram. */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2, 8); /* Allocate space for two 2 byte FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(4); + mem_addr = m8260_cpm_hostalloc(4, 1); /* Set the physical address of the host memory buffers in * the buffer descriptors. diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index 730453bbb8f2..b77cf32da5e4 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -484,8 +484,11 @@ for (;;) { cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. - */ - skb = dev_alloc_skb(pkt_len); + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -493,10 +496,10 @@ for (;;) { } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c index f69d0dfbdc14..45f10b6359b4 100644 --- a/arch/ppc/8xx_io/fec.c +++ b/arch/ppc/8xx_io/fec.c @@ -669,18 +669,21 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { #endif /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. */ - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); fep->stats.rx_dropped++; } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile index 48750982e781..f7ea3a3fa6b2 100644 --- a/arch/ppc/chrpboot/Makefile +++ b/arch/ppc/chrpboot/Makefile @@ -67,11 +67,13 @@ initrd.o: ramdisk.image.gz piggyback zImage: $(OBJS) no_initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) - ./addnote $@ + cp $@ $@.rs6k + ./addnote $@.rs6k zImage.initrd: $(OBJS) initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) - ./addnote $@ + cp $@ $@.rs6k + ./addnote $@.rs6k else znetboot: diff --git a/arch/ppc/chrpboot/addnote.c b/arch/ppc/chrpboot/addnote.c index 5f0934f6ef60..b2374df7c1d9 100644 --- a/arch/ppc/chrpboot/addnote.c +++ b/arch/ppc/chrpboot/addnote.c @@ -22,12 +22,23 @@ char arch[] = "PowerPC"; #define N_DESCR 6 unsigned int descr[N_DESCR] = { +#if 1 + /* values for IBM RS/6000 machines */ 0xffffffff, /* real-mode = true */ 0x00c00000, /* real-base, i.e. where we expect OF to be */ 0xffffffff, /* real-size */ 0xffffffff, /* virt-base */ 0xffffffff, /* virt-size */ 0x4000, /* load-base */ +#else + /* values for longtrail CHRP */ + 0, /* real-mode = false */ + 0xffffffff, /* real-base */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x00600000, /* load-base */ +#endif }; unsigned char buf[512]; @@ -63,7 +74,7 @@ unsigned char buf[512]; unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; -main(int ac, char **av) +int main(int ac, char **av) { int fd, n, i; int ph, ps, np; diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile index 23afda4a87d4..494026e42d80 100644 --- a/arch/ppc/coffboot/Makefile +++ b/arch/ppc/coffboot/Makefile @@ -8,7 +8,7 @@ HOSTCFLAGS = -O -I$(TOPDIR)/include CFLAGS = $(CPPFLAGS) -O -fno-builtin OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x00400000 +CHRP_LD_ARGS = -Ttext 0x01000000 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o diff --git a/arch/ppc/coffboot/chrpmain.c b/arch/ppc/coffboot/chrpmain.c index 4d994d17ee88..08b238b16156 100644 --- a/arch/ppc/coffboot/chrpmain.c +++ b/arch/ppc/coffboot/chrpmain.c @@ -22,13 +22,18 @@ void stop_imac_usb(void); #define get_16be(x) (*(unsigned short *)(x)) #define get_32be(x) (*(unsigned *)(x)) -#define RAM_START 0x00000000 -#define RAM_END (8<<20) +#define RAM_END (16 << 20) #define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) char *avail_ram; -char *end_avail; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; extern char _end[]; extern char image_data[]; @@ -60,29 +65,30 @@ boot(int a1, int a2, void *prom) im = image_data; len = image_len; /* claim 3MB starting at PROG_START */ - claim(PROG_START, 3 << 20, 0); + claim(PROG_START, PROG_SIZE, 0); dst = (void *) PROG_START; if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim 512kB for scratch space */ - avail_ram = (char *) claim(0, 512 << 10, 0x10); - end_avail = avail_ram + (512 << 10); - printf("avail_ram = %x\n", avail_ram); + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 3 << 20, im, &len); + gunzip(dst, PROG_SIZE, im, &len); printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); } else { memmove(dst, im, len); } flush_cache(dst, len); - stop_imac_ethernet(); - stop_imac_usb(); make_bi_recs((unsigned long) dst + len); sa = (unsigned long)PROG_START; printf("start address = 0x%x\n", sa); - (*(void (*)())sa)(0, 0, prom, a1, a2); + (*(void (*)())sa)(a1, a2, prom); printf("returned?\n"); @@ -122,6 +128,7 @@ void make_bi_recs(unsigned long addr) rec = (struct bi_record *)((unsigned long)rec + rec->size); } +#if 0 #define eieio() asm volatile("eieio"); void stop_imac_ethernet(void) @@ -172,14 +179,35 @@ void stop_imac_usb(void) *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ eieio(); } +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; void *zalloc(void *x, unsigned items, unsigned size) { - void *p = avail_ram; + void *p; + struct memchunk **mpp, *mp; size *= items; size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; if (avail_ram > end_avail) { printf("oops... out of memory\n"); pause(); @@ -189,6 +217,17 @@ void *zalloc(void *x, unsigned items, unsigned size) void zfree(void *x, void *addr, unsigned nb) { + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; } #define HEAD_CRC 2 diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 950118eb2390..21c02082e549 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -88,11 +88,15 @@ fi if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then bool 'Math emulation' CONFIG_MATH_EMULATION fi + endmenu mainmenu_option next_comment comment 'General setup' +bool 'High memory support (experimental)' CONFIG_HIGHMEM +bool 'Mac-on-Linux support' CONFIG_MOL + define_bool CONFIG_ISA n define_bool CONFIG_SBUS n @@ -140,20 +144,6 @@ if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC fi - bool 'Power management support for PowerBooks' CONFIG_PMAC_PBOOK - bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY - tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL - if [ "$CONFIG_MAC_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE - fi - bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB - if [ "$CONFIG_ADB" = "y" ]; then - bool ' Include CUDA ADB driver' CONFIG_ADB_CUDA - bool ' Include MacIO ADB driver' CONFIG_ADB_MACIO - bool ' Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU - bool 'Support for ADB keyboard' CONFIG_ADB_KEYBOARD - bool 'Support for ADB mouse' CONFIG_ADBMOUSE - fi tristate 'Support for /dev/rtc' CONFIG_PPC_RTC bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -192,7 +182,6 @@ endmenu source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in -#source drivers.new/Config.in if [ "$CONFIG_NET" = "y" ]; then source net/Config.in @@ -262,6 +251,43 @@ comment 'Console drivers' source drivers/video/Config.in endmenu +source drivers/input/Config.in + +mainmenu_option next_comment +comment 'Macintosh device drivers' + +if [ "$CONFIG_ALL_PPC" = "y" ]; then + # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU + bool 'Support for CUDA based PowerMacs' CONFIG_ADB_CUDA + bool 'Support for PMU based PowerMacs' CONFIG_ADB_PMU + if [ "$CONFIG_ADB_PMU" = "y" ]; then + bool ' Power management support for PowerBooks' CONFIG_PMAC_PBOOK + # made a separate option since backlight may end up beeing used + # on non-powerbook machines (but only on PMU based ones AFAIK) + bool ' Backlight control for LCD screens' CONFIG_PMAC_BACKLIGHT + fi + bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY + tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL + if [ "$CONFIG_MAC_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + fi + bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB + if [ "$CONFIG_ADB" = "y" ]; then + bool ' Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO + fi +fi +if [ "$CONFIG_ADB" = "y" ]; then + dep_bool ' Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT + if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then + define_bool CONFIG_MAC_HID y + bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES + bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN + else + bool ' Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD + fi +fi +endmenu + source drivers/char/Config.in source drivers/media/Config.in @@ -287,7 +313,6 @@ source arch/ppc/8260_io/Config.in fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index 68e49c148fa3..a9ae80db0ec2 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -8,13 +8,21 @@ # CONFIG_EXPERIMENTAL=y +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + # # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y @@ -24,16 +32,10 @@ CONFIG_ALL_PPC=y # CONFIG_SMP is not set CONFIG_ALTIVEC=y -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - # # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set CONFIG_PCI=y @@ -44,8 +46,8 @@ CONFIG_SYSVIPC=y CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -57,20 +59,17 @@ CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_ADBMOUSE=y +CONFIG_PPC_RTC=y CONFIG_PROC_DEVICETREE=y CONFIG_BOOTX_TEXT=y # CONFIG_MOTOROLA_HOTSWAP is not set # CONFIG_CMDLINE_BOOL is not set +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + # # Plug and Play configuration # @@ -90,8 +89,11 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -109,22 +111,24 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -145,26 +149,42 @@ CONFIG_IDE=y # IDE, ATA and ATAPI Block devices # CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -173,37 +193,40 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set +CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set -# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -211,6 +234,10 @@ CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -296,6 +323,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -327,8 +355,9 @@ CONFIG_DE4X5=y # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set # CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -347,11 +376,13 @@ CONFIG_DE4X5=y # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_DEFLATE=y # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -404,12 +435,13 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y @@ -420,6 +452,7 @@ CONFIG_FB_MATROX_G100=y CONFIG_FB_ATY=y CONFIG_FB_ATY128=y CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -436,6 +469,32 @@ CONFIG_FONT_SUN12x22=y # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_HID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y + # # Character devices # @@ -459,7 +518,6 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -469,19 +527,19 @@ CONFIG_PSMOUSE=y # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -490,26 +548,31 @@ CONFIG_NVRAM=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y +# CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -519,7 +582,8 @@ CONFIG_ISO9660_FS=y # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set @@ -571,12 +635,14 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -593,6 +659,10 @@ CONFIG_NLS=y # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -605,6 +675,7 @@ CONFIG_NLS=y # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Sound @@ -614,6 +685,7 @@ CONFIG_DMASOUND_AWACS=y CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -622,6 +694,7 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -647,24 +720,39 @@ CONFIG_SOUND_CS4232=m # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # CONFIG_USB=y CONFIG_USB_DEBUG=y -# CONFIG_USB_DEVICEFS is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -679,15 +767,13 @@ CONFIG_USB_OHCI=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# USB Human Interface Devices (HID) +# CONFIG_USB_HID=y # CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set # # Kernel hacking @@ -695,4 +781,3 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y - diff --git a/arch/ppc/configs/est8260_defconfig b/arch/ppc/configs/est8260_defconfig index 972820d213df..d317c851747b 100644 --- a/arch/ppc/configs/est8260_defconfig +++ b/arch/ppc/configs/est8260_defconfig @@ -8,13 +8,19 @@ # CONFIG_EXPERIMENTAL=y +# +# Loadable module support +# +# CONFIG_MODULES is not set + # # Platform support # CONFIG_PPC=y # CONFIG_6xx is not set # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set CONFIG_8260=y # CONFIG_8xx is not set CONFIG_6xx=y @@ -28,14 +34,10 @@ CONFIG_EST8260=y # CONFIG_ALTIVEC is not set CONFIG_MACH_SPECIFIC=y -# -# Loadable module support -# -# CONFIG_MODULES is not set - # # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set # CONFIG_PCI is not set @@ -56,14 +58,16 @@ CONFIG_KERNEL_ELF=y # CONFIG_PARPORT is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set -# CONFIG_PMAC_PBOOK is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADB is not set +# CONFIG_PPC_RTC is not set # CONFIG_PROC_DEVICETREE is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_MOTOROLA_HOTSWAP is not set +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + # # Plug and Play configuration # @@ -84,8 +88,10 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -105,17 +111,11 @@ CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -126,9 +126,9 @@ CONFIG_SKB_LARGE=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -164,6 +164,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -244,6 +245,15 @@ CONFIG_NET_ETHERNET=y # # CONFIG_FB is not set +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Macintosh device drivers +# + # # Character devices # @@ -269,19 +279,19 @@ CONFIG_UNIX98_PTY_COUNT=256 # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -290,9 +300,13 @@ CONFIG_UNIX98_PTY_COUNT=256 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -310,6 +324,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set @@ -369,6 +384,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set @@ -382,7 +398,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y -# CONFIG_FCC_ENET is not set +# CONFIG_FEC_ENET is not set # # USB support diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig index e141e8f54c8e..522bd5d5dabd 100644 --- a/arch/ppc/configs/gemini_defconfig +++ b/arch/ppc/configs/gemini_defconfig @@ -14,14 +14,12 @@ CONFIG_EXPERIMENTAL=y CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set -# CONFIG_82xx is not set +# CONFIG_PPC64 is not set +# CONFIG_8260 is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set # CONFIG_ALL_PPC is not set CONFIG_GEMINI=y +# CONFIG_EST8260 is not set # CONFIG_APUS is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -37,7 +35,8 @@ CONFIG_KMOD=y # # General setup # -# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_SBUS is not set CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y @@ -47,8 +46,12 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# # CONFIG_PARPORT is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set @@ -57,7 +60,6 @@ CONFIG_KERNEL_ELF=y # CONFIG_MAC_SERIAL is not set # CONFIG_ADB is not set # CONFIG_PROC_DEVICETREE is not set -# CONFIG_TOTALMP is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_MOTOROLA_HOTSWAP is not set @@ -70,22 +72,16 @@ CONFIG_KERNEL_ELF=y # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# Additional Block Devices # -# CONFIG_BLK_DEV_HD_ONLY is not set -# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -137,6 +133,13 @@ CONFIG_SKB_LARGE=y # # CONFIG_NET_SCHED is not set +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + # # SCSI support # @@ -148,7 +151,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set -CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 @@ -171,7 +173,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -184,43 +185,22 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_NCR53C7xx_sync is not set +# CONFIG_SCSI_NCR53C7xx_FAST is not set +# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_MESH is not set # CONFIG_SCSI_MAC53C94 is not set -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set # # Network device support @@ -232,6 +212,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -249,12 +230,10 @@ CONFIG_NCR885E=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # @@ -274,7 +253,7 @@ CONFIG_NCR885E=y # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -291,6 +270,11 @@ CONFIG_NCR885E=y # # CONFIG_HAMRADIO is not set +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + # # ISDN subsystem # @@ -361,12 +345,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_AGP is not set # -# USB support -# -# CONFIG_USB is not set - -# -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set @@ -378,12 +357,14 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set @@ -397,6 +378,7 @@ CONFIG_EXT2_FS=y # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -415,6 +397,11 @@ CONFIG_MSDOS_PARTITION=y # # CONFIG_SOUND is not set +# +# USB support +# +# CONFIG_USB is not set + # # Kernel hacking # diff --git a/arch/ppc/configs/rpxcllf_defconfig b/arch/ppc/configs/rpxcllf_defconfig index 9aaa80530c20..4dda3d93f867 100644 --- a/arch/ppc/configs/rpxcllf_defconfig +++ b/arch/ppc/configs/rpxcllf_defconfig @@ -8,19 +8,28 @@ # CONFIG_EXPERIMENTAL=y +# +# Loadable module support +# +# CONFIG_MODULES is not set + # # Platform support # CONFIG_PPC=y # CONFIG_6xx is not set # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set CONFIG_8xx=y CONFIG_SERIAL_CONSOLE=y # CONFIG_RPXLITE is not set CONFIG_RPXCLASSIC=y # CONFIG_BSEIP is not set +# CONFIG_TQM8xxL is not set +# CONFIG_TQM860L is not set +# CONFIG_TQM860 is not set # CONFIG_MBX is not set # CONFIG_WINCEPT is not set # CONFIG_ALL_PPC is not set @@ -28,14 +37,10 @@ CONFIG_RPXCLASSIC=y CONFIG_MACH_SPECIFIC=y CONFIG_MATH_EMULATION=y -# -# Loadable module support -# -# CONFIG_MODULES is not set - # # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set # CONFIG_PCI is not set @@ -55,6 +60,11 @@ CONFIG_KERNEL_ELF=y # # CONFIG_PARPORT is not set +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + # # Plug and Play configuration # @@ -75,8 +85,10 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -96,17 +108,11 @@ CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -117,9 +123,9 @@ CONFIG_SKB_LARGE=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -155,6 +161,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -235,6 +242,15 @@ CONFIG_NET_ETHERNET=y # # CONFIG_FB is not set +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Macintosh device drivers +# + # # Character devices # @@ -260,19 +276,19 @@ CONFIG_UNIX98_PTY_COUNT=256 # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -281,9 +297,13 @@ CONFIG_UNIX98_PTY_COUNT=256 # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -301,6 +321,7 @@ CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set @@ -360,6 +381,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set @@ -374,7 +396,9 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y CONFIG_FEC_ENET=y +CONFIG_ENET_BIG_BUFFERS=y CONFIG_8xxSMC2=y +# CONFIG_8xx_ALTSMC2 is not set CONFIG_8xxSCC=y # diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index e1854fad66cf..9b3d88212ec5 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -8,13 +8,21 @@ # CONFIG_EXPERIMENTAL=y +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + # # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y @@ -24,16 +32,10 @@ CONFIG_ALL_PPC=y # CONFIG_SMP is not set CONFIG_ALTIVEC=y -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - # # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set CONFIG_PCI=y @@ -44,8 +46,8 @@ CONFIG_SYSVIPC=y CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -57,20 +59,17 @@ CONFIG_VGA_CONSOLE=y CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_ADBMOUSE=y +CONFIG_PPC_RTC=y CONFIG_PROC_DEVICETREE=y CONFIG_BOOTX_TEXT=y # CONFIG_MOTOROLA_HOTSWAP is not set # CONFIG_CMDLINE_BOOL is not set +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + # # Plug and Play configuration # @@ -90,8 +89,11 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -109,22 +111,24 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -145,26 +149,42 @@ CONFIG_IDE=y # IDE, ATA and ATAPI Block devices # CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -173,37 +193,40 @@ CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set +CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set -# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -211,6 +234,10 @@ CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -296,6 +323,7 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -327,8 +355,9 @@ CONFIG_DE4X5=y # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set # CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -347,11 +376,13 @@ CONFIG_DE4X5=y # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_DEFLATE=y # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -404,12 +435,13 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y @@ -420,6 +452,7 @@ CONFIG_FB_MATROX_G100=y CONFIG_FB_ATY=y CONFIG_FB_ATY128=y CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -436,6 +469,32 @@ CONFIG_FONT_SUN12x22=y # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_HID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y + # # Character devices # @@ -459,7 +518,6 @@ CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -469,19 +527,19 @@ CONFIG_PSMOUSE=y # Joysticks # # CONFIG_JOYSTICK is not set + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set CONFIG_NVRAM=y # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -490,26 +548,31 @@ CONFIG_NVRAM=y # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y +# CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -519,7 +582,7 @@ CONFIG_ISO9660_FS=y # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set +CONFIG_DEVFS_FS=y # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y @@ -572,12 +635,14 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -594,6 +659,10 @@ CONFIG_NLS=y # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -606,6 +675,7 @@ CONFIG_NLS=y # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Sound @@ -615,6 +685,7 @@ CONFIG_DMASOUND_AWACS=y CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -623,6 +694,7 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -648,24 +720,39 @@ CONFIG_SOUND_CS4232=m # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # CONFIG_USB=y CONFIG_USB_DEBUG=y -# CONFIG_USB_DEVICEFS is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -680,15 +767,18 @@ CONFIG_USB_OHCI=y # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# USB Human Interface Devices (HID) +# CONFIG_USB_HID=y # CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set + +# +# Mac-on-Linux (MOL) support +# +# CONFIG_MOL is not set # # Kernel hacking diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 0369ad800b9f..a539083bd19d 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -99,8 +99,10 @@ endif ifeq ($(CONFIG_ALL_PPC),y) O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \ chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \ - prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o \ - pmac_backlight.o + prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o + ifeq ($(CONFIG_PMAC_BACKLIGHT),y) + O_OBJS += pmac_backlight.o + endif OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index b93bd81937ed..d75663be5044 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -304,7 +304,7 @@ __apus void apus_calibrate_decr(void) { #ifdef CONFIG_APUS - int freq, divisor; + unsigned long freq; /* This algorithm for determining the bus speed was contributed by Ralph Schmidt. */ @@ -335,8 +335,8 @@ void apus_calibrate_decr(void) bus_speed = 60; freq = 15000000; } else if ((bus_speed >= 63) && (bus_speed < 69)) { - bus_speed = 66; - freq = 16500000; + bus_speed = 67; + freq = 16666667; } else { printk ("APUS: Unable to determine bus speed (%d). " "Defaulting to 50MHz", bus_speed); @@ -375,12 +375,10 @@ void apus_calibrate_decr(void) } - freq *= 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); __bus_speed = bus_speed; __speed_test_failed = speed_test_failed; diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index c43296c4239b..43b678861ca2 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -284,13 +284,38 @@ hydra_init(void) return 1; } +#ifdef CONFIG_POWER4 +static void +power4_fixup_dev(struct pci_dev *dev) +{ + int i; + unsigned long offset; + + for (i = 0; i < 6; ++i) { + if (dev->resource[i].start == 0) + continue; + offset = pci_address_offset(dev->bus->number, + dev->resource[i].flags); + if (offset) { + dev->resource[i].start += offset; + dev->resource[i].end += offset; + printk("device %x.%x[%d] now [%lx..%lx]\n", + dev->bus->number, dev->devfn, i, + dev->resource[i].start, + dev->resource[i].end); + } + /* zap the 2nd function of the winbond chip */ + if (dev->resource[i].flags & IORESOURCE_IO + && dev->bus->number == 0 && dev->devfn == 0x81) + dev->resource[i].flags &= ~IORESOURCE_IO; + } +} +#endif /* CONFIG_POWER4 */ + void __init chrp_pcibios_fixup(void) { struct pci_dev *dev; -#ifdef CONFIG_POWER4 - int i; -#endif int *brp; struct device_node *np; extern struct pci_ops generic_pci_ops; @@ -316,10 +341,8 @@ chrp_pcibios_fixup(void) /* PCI interrupts are controlled by the OpenPIC */ pci_for_each_dev(dev) { np = find_pci_device_OFnode(dev->bus->number, dev->devfn); - if ( (np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) + if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) dev->irq = np->intrs[0].line; - if ( dev->irq ) - dev->irq = openpic_to_irq( dev->irq ); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { @@ -337,25 +360,7 @@ chrp_pcibios_fixup(void) dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } #ifdef CONFIG_POWER4 - for (i = 0; i < 6; ++i) { - unsigned long offset; - if (dev->resource[i].start == 0) - continue; - offset = pci_address_offset(dev->bus->number, - dev->resource[i].flags); - if (offset) { - dev->resource[i].start += offset; - dev->resource[i].end += offset; - printk("device %x.%x[%d] now [%lx..%lx]\n", - dev->bus->number, dev->devfn, i, - dev->resource[i].start, - dev->resource[i].end); - } - /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - } + power4_fixup_dev(dev); #else if (dev->bus->number > 0 && python_busnr > 0) dev->resource[0].start += dev->bus->number*0x01000000; @@ -363,6 +368,40 @@ chrp_pcibios_fixup(void) } } +static struct { + /* parent is iomem */ + struct resource ram, pci_mem, isa_mem, pci_io, pci_cfg, rom_exp, flash; + /* parent is isa_mem */ + struct resource nvram; +} gg2_resources = { + ram: { "RAM", 0x00000000, 0xbfffffff, IORESOURCE_MEM }, + pci_mem: { "GG2 PCI mem", 0xc0000000, 0xf6ffffff, IORESOURCE_MEM }, + isa_mem: { "GG2 ISA mem", 0xf7000000, 0xf7ffffff }, + pci_io: { "GG2 PCI I/O", 0xf8000000, 0xf8ffffff }, + pci_cfg: { "GG2 PCI cfg", 0xfec00000, 0xfec7ffff }, + rom_exp: { "ROM exp", 0xff000000, 0xff7fffff, }, + flash: { "Flash ROM", 0xfff80000, 0xffffffff }, + nvram: { "NVRAM", 0xf70e0000, 0xf70e7fff }, +}; + +static void __init gg2_pcibios_fixup(void) +{ + int i; + extern unsigned long *end_of_DRAM; + + chrp_pcibios_fixup(); + gg2_resources.ram.end = (unsigned long)end_of_DRAM-PAGE_OFFSET; + for (i = 0; i < 7; i++) + request_resource(&iomem_resource, + &((struct resource *)&gg2_resources)[i]); + request_resource(&gg2_resources.isa_mem, &gg2_resources.nvram); +} + +static void __init gg2_pcibios_fixup_bus(struct pci_bus *bus) +{ + bus->resource[1] = &gg2_resources.pci_mem; +} + decl_config_access_method(grackle); decl_config_access_method(indirect); decl_config_access_method(rtas); @@ -372,6 +411,7 @@ chrp_setup_pci_ptrs(void) { struct device_node *py; + ppc_md.pcibios_fixup = chrp_pcibios_fixup; #ifdef CONFIG_POWER4 set_config_access_method(rtas); pci_dram_offset = 0; @@ -428,16 +468,17 @@ chrp_setup_pci_ptrs(void) } else { + /* LongTrail */ pci_dram_offset = 0; isa_mem_base = 0xf7000000; isa_io_base = 0xf8000000; set_config_access_method(gg2); + ppc_md.pcibios_fixup = gg2_pcibios_fixup; + ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; } } } #endif /* CONFIG_POWER4 */ - - ppc_md.pcibios_fixup = chrp_pcibios_fixup; } #ifdef CONFIG_PPC64BRIDGE diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 8d6649231edb..ccc6621deeaa 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -62,11 +62,13 @@ extern volatile unsigned char *chrp_int_ack_special; unsigned long chrp_get_rtc_time(void); int chrp_set_rtc_time(unsigned long nowtime); void chrp_calibrate_decr(void); -void chrp_time_init(void); +long chrp_time_init(void); void chrp_setup_pci_ptrs(void); -extern void chrp_progress(char *, unsigned short); void chrp_event_scan(void); +void rtas_display_progress(char *, unsigned short); +void rtas_indicator_progress(char *, unsigned short); +void bootx_text_progress(char *, unsigned short); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); @@ -91,6 +93,8 @@ extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; extern unsigned long loops_per_sec; +extern int bootx_text_mapped; +static int max_width; unsigned long empty_zero_page[1024]; @@ -252,13 +256,6 @@ chrp_setup_arch(void) #endif ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ printk("Boot arguments: %s\n", cmd_line); - - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); #ifndef CONFIG_PPC64BRIDGE /* PCI bridge config space access area - @@ -446,11 +443,43 @@ void __init chrp_init_IRQ(void) void __init chrp_init2(void) { +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) + struct device_node *kbd; +#endif #ifdef CONFIG_NVRAM pmac_nvram_init(); #endif + + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + if (ppc_md.progress) ppc_md.progress(" Have fun! ", 0x7777); + +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) + if (kbd->parent && kbd->parent->type + && strcmp(kbd->parent->type, "adb") == 0) + break; + if (kbd) { + ppc_md.kbd_setkeycode = mackbd_setkeycode; + ppc_md.kbd_getkeycode = mackbd_getkeycode; + ppc_md.kbd_translate = mackbd_translate; + ppc_md.kbd_unexpected_up = mackbd_unexpected_up; + ppc_md.kbd_leds = mackbd_leds; + ppc_md.kbd_init_hw = mackbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif /* CONFIG_MAGIC_SYSRQ */ + } +#endif /* CONFIG_VT && CONFIG_ADB_KEYBOARD */ } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) @@ -598,40 +627,40 @@ void __init ppc_md.calibrate_decr = chrp_calibrate_decr; #ifdef CONFIG_VT -#ifdef CONFIG_MAC_KEYBOARD - if (adb_driver == NULL) - { -#endif /* CONFIG_MAC_KEYBOAD */ - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; - SYSRQ_KEY = 0x54; -#endif /* CONFIG_MAGIC_SYSRQ */ -#ifdef CONFIG_MAC_KEYBOARD - } - else - { - ppc_md.kbd_setkeycode = mackbd_setkeycode; - ppc_md.kbd_getkeycode = mackbd_getkeycode; - ppc_md.kbd_translate = mackbd_translate; - ppc_md.kbd_unexpected_up = mackbd_unexpected_up; - ppc_md.kbd_leds = mackbd_leds; - ppc_md.kbd_init_hw = mackbd_init_hw; + /* these are adjusted in chrp_init2 if we have an ADB keyboard */ + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; - SYSRQ_KEY = 0x69; + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif /* CONFIG_MAGIC_SYSRQ */ - } -#endif /* CONFIG_MAC_KEYBOARD */ #endif /* CONFIG_VT */ - if ( rtas_data ) - ppc_md.progress = chrp_progress; - + + if (rtas_data) { + struct device_node *rtas; + unsigned int *p; + + rtas = find_devices("rtas"); + if (rtas != NULL) { + if (get_property(rtas, "display-character", NULL)) { + ppc_md.progress = rtas_display_progress; + p = (unsigned int *) get_property + (rtas, "ibm,display-line-length", NULL); + if (p) + max_width = *p; + } else if (get_property(rtas, "set-indicator", NULL)) + ppc_md.progress = rtas_indicator_progress; + } + } +#ifdef CONFIG_BOOTX_TEXT + if (ppc_md.progress == NULL && bootx_text_mapped) + ppc_md.progress = bootx_text_progress; +#endif + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = chrp_ide_insw; ppc_ide_md.outsw = chrp_ide_outsw; @@ -653,30 +682,13 @@ void __init } void __chrp -chrp_progress(char *s, unsigned short hex) +rtas_display_progress(char *s, unsigned short hex) { - extern unsigned int rtas_data; - int max_width, width; - struct device_node *root; + int width; char *os = s; - unsigned long *p; - if ( (root = find_path_device("/rtas")) && - (p = (unsigned long *)get_property(root, - "ibm,display-line-length", - NULL)) ) - max_width = *p; - else - max_width = 0x10; - - if ( (_machine != _MACH_chrp) || !rtas_data ) - return; if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) - { - /* assume no display-character RTAS method - use hex display */ - call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); return; - } width = max_width; while ( *os ) @@ -696,3 +708,17 @@ chrp_progress(char *s, unsigned short hex) call_rtas( "display-character", 1, 1, NULL, ' ' ); } +void __chrp +rtas_indicator_progress(char *s, unsigned short hex) +{ + call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); +} + +#ifdef CONFIG_BOOTX_TEXT +void +bootx_text_progress(char *s, unsigned short hex) +{ + prom_print(s); + prom_print("\n"); +} +#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c index c74b7b36db8e..67325c685e49 100644 --- a/arch/ppc/kernel/chrp_time.c +++ b/arch/ppc/kernel/chrp_time.c @@ -33,18 +33,20 @@ static int nvram_as1 = NVRAM_AS1; static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -void __init chrp_time_init(void) +long __init chrp_time_init(void) { struct device_node *rtcs; int base; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); if (rtcs == NULL || rtcs->addrs == NULL) - return; + return 0; base = rtcs->addrs[0].address; nvram_as1 = 0; nvram_as0 = base; nvram_data = base + 1; + + return 0; } int __chrp chrp_cmos_clock_read(int addr) @@ -116,28 +118,34 @@ int __chrp chrp_set_rtc_time(unsigned long nowtime) unsigned long __chrp chrp_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; + int uip, i; /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); sec = chrp_cmos_clock_read(RTC_SECONDS); min = chrp_cmos_clock_read(RTC_MINUTES); hour = chrp_cmos_clock_read(RTC_HOURS); day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); mon = chrp_cmos_clock_read(RTC_MONTH); year = chrp_cmos_clock_read(RTC_YEAR); - } while (sec != chrp_cmos_clock_read(RTC_SECONDS)); + uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); @@ -156,8 +164,7 @@ unsigned long __chrp chrp_get_rtc_time(void) void __init chrp_calibrate_decr(void) { struct device_node *cpu; - int *fp, divisor; - unsigned long freq; + unsigned int freq, *fp; if (via_calibrate_decr()) return; @@ -169,15 +176,13 @@ void __init chrp_calibrate_decr(void) freq = 16666000; /* hardcoded default */ cpu = find_type_devices("cpu"); if (cpu != 0) { - fp = (int *) get_property(cpu, "timebase-frequency", NULL); + fp = (unsigned int *) + get_property(cpu, "timebase-frequency", NULL); if (fp != 0) freq = *fp; } - freq *= 30; - divisor = 30; - printk("time_init: decrementer frequency = %lu/%d (%ld MHz)\n", freq, - divisor, (freq/divisor)>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index d40a54cf141e..627cd7a2a912 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -30,6 +30,7 @@ #include #include #include +#include "mol.h" #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -85,7 +86,7 @@ _GLOBAL(DoSyscall) beq- 10f cmpi 0,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */ beq- 16f - lwz r10,TASK_FLAGS(r2) + lwz r10,TASK_PTRACE(r2) andi. r10,r10,PT_TRACESYS bne- 50f cmpli 0,r0,NR_syscalls @@ -241,6 +242,13 @@ _GLOBAL(_switch) /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */ lwz r9,PGDIR(r4) /* cache the page table root */ tophys(r9,r9) /* convert to phys addr */ +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + li r5, 0x3980 + stw r5, 8(r6) + lwz r5, 8(r6) +#endif mtspr M_TWB,r9 /* Update MMU base address */ tlbia SYNC @@ -349,21 +357,18 @@ ret_to_user_hook: beq+ restore li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD + MOL_HOOK_MMU(8,r8) bl do_signal .globl do_signal_ret do_signal_ret: -restore: - lwz r3,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r3 - mtlr r0 +restore: lwz r3,_XER(r1) mtspr XER,r3 - REST_10GPRS(3, r1) - REST_10GPRS(13, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - + REST_10GPRS(9,r1) + REST_10GPRS(19,r1) + REST_2GPRS(29,r1) + REST_GPR(31,r1) + /* make sure we hard disable here, even if rtl is active, to protect * SRR[01] and SPRG2 -- Cort */ @@ -376,12 +381,28 @@ restore: lwz r0,_MSR(r1) andi. r0,r0,MSR_PR beq+ 1f +#ifdef CONFIG_ALTIVEC + mfpvr r8 /* check if we are on a G4 */ + srwi r8,r8,16 + cmpwi r8,PVR_7400@h + bne 2f + lwz r0,THREAD+THREAD_VRSAVE(r2) + mtspr SPRN_VRSAVE,r0 /* if so, restore VRSAVE reg */ +2: +#endif /* CONFIG_ALTIVEC */ addi r0,r1,INT_FRAME_SIZE /* size of frame */ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ - tophys(r2,r1) - CLR_TOP32(r2) - mtspr SPRG2,r2 /* phys exception stack pointer */ + tophys(r8,r1) + CLR_TOP32(r8) + MOL_HOOK_MMU(9, r4) /* mod. r0,r2-r7, lr, ctr */ + mtspr SPRG2,r8 /* phys exception stack pointer */ 1: + lwz r3,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r3 + mtlr r0 + REST_4GPRS(3, r1) + REST_2GPRS(7, r1) lwz r0,_MSR(r1) FIX_SRR1(r0,r2) mtspr SRR1,r0 diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index 4b63d5dc0f0b..57599917ae85 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,6 +36,20 @@ #define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) +/* Keylargo reg. access. */ +#define KL_FCR(r) (keylargo_base + ((r) >> 2)) +#define KL_IN(r) (in_le32(KL_FCR(r))) +#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v))) +#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v))) +#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v))) + +/* Uni-N reg. access. Note that Uni-N regs are big endian */ +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + typedef struct feature_bit { int reg; /* reg. offset from mac-io base */ unsigned int polarity; /* 0 = normal, 1 = inverse */ @@ -74,10 +90,44 @@ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_Airport_reset */ }; -/* Those bits are from a PowerBook. It's possible that desktop machines - * based on heathrow need a different definition or some bits removed +/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed + * the SCC related bits and init them once. They have proven to occasionally cause + * problems with the desktop units. */ static fbit feature_bits_heathrow[] = { + {0x38,0,0}, /* FEATURE_null */ + {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,0}, /* FEATURE_Serial_enable */ + {0x38,0,0}, /* FEATURE_Serial_IO_A */ + {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,0}, /* FEATURE_Mediabay_reset */ + {0x38,1,0}, /* FEATURE_Mediabay_power */ + {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ + {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ + {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ + {0x38,1,0}, /* FEATURE_Modem_power */ + {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,1,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ + {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ +}; + +/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet). + * Heathrow-based desktop macs (Beige G3s) are _not_ handled here + */ +static fbit feature_bits_wallstreet[] = { {0x38,0,0}, /* FEATURE_null */ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ @@ -145,32 +195,32 @@ static fbit feature_bits_paddington[] = { */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ - {0x38,0,0x00000054}, /* FEATURE_Serial_enable */ - {0x38,0,0}, /* FEATURE_Serial_IO_A */ - {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */ + {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */ + {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ {0x3c,0,0}, /* FEATURE_IDE0_enable */ - {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */ + {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ - {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */ + {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x40,1,0x02000000}, /* FEATURE_Modem_power */ + {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */ - {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */ + {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ + {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ - {0x40,1,0x08000000}, /* FEATURE_Airport_reset */ + {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; /* definition of a feature controller object */ @@ -190,6 +240,8 @@ feature_lookup_controller(struct device_node *device); static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); static void heathrow_wakeup(struct feature_controller* ctrler); +static void keylargo_init(void); +static void uninorth_init(void); static void core99_prepare_for_sleep(struct feature_controller* ctrler); static void core99_wake_up(struct feature_controller* ctrler); @@ -228,8 +280,15 @@ feature_init(void) } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + } else if (machine_is_compatible("AAPL,PowerBook1998")) { + feature_add_controller(np, feature_bits_wallstreet); } else { - feature_add_controller(np, feature_bits_heathrow); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_heathrow); + if (ctrler) + out_le32(FREG(ctrler,HEATHROW_FEATURE_REG), + in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS); + } np = np->next; } @@ -249,14 +308,17 @@ feature_init(void) np = find_devices("uni-n"); if (np && np->n_addrs > 0) { uninorth_base = ioremap(np->addrs[0].address, 0x1000); - rev = (u32 *)get_property(np, "device-rev", NULL); - if (rev) - uninorth_rev = *rev; + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); } if (uninorth_base && keylargo_base) printk("Uni-N revision: %d, KeyLargo revision: %d\n", uninorth_rev, keylargo_rev); + if (uninorth_base) + uninorth_init(); + if (keylargo_base) + keylargo_init(); + if (controller_count) printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); @@ -440,14 +502,21 @@ feature_set_gmac_power(struct device_node* device, int power) if (!uninorth_base) return; if (power) - out_le32(uninorth_base + 0x20/4, - in_le32(uninorth_base + 0x20/4) | 0x02000000); + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); else - out_le32(uninorth_base + 0x20/4, - in_le32(uninorth_base + 0x20/4) & ~0x02000000); + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); udelay(20); } +void +feature_set_gmac_phy_reset(struct device_node* device, int reset) +{ + if (!keylargo_base) + return; + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); +} + /* Pass the node of the correct controller, please */ void feature_set_usb_power(struct device_node* device, int power) @@ -460,6 +529,53 @@ feature_set_firewire_power(struct device_node* device, int power) { } +/* Initialize the Core99 UniNorth host bridge and memory controller + */ +static void +uninorth_init(void) +{ + struct device_node* gmac; + unsigned long actrl; + + /* Set the arbitrer QAck delay according to what Apple does + */ + actrl = in_be32(UN_REG(UNI_N_ARB_CTRL)) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) + << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + + /* + * Turns OFF the gmac clock. The gmac driver will turn + * it back ON when the interface is enabled. This save + * power on portables. + * + * Note: We could also try to turn OFF the PHY. Since this + * has to be done by both the gmac driver and this code, + * I'll probably end-up moving some of this out of the + * modular gmac driver into a non-modular stub containing + * some basic PHY management and power management stuffs + */ + gmac = find_devices("ethernet"); + + while(gmac) { + if (device_is_compatible(gmac, "gmac")) + break; + gmac = gmac->next; + } + if (gmac) + feature_set_gmac_power(gmac, 0); +} + +/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure + * OpenPIC is enabled + */ +static void +keylargo_init(void) +{ + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); +} + +#ifdef CONFIG_PMAC_PBOOK void feature_prepare_for_sleep(void) { @@ -506,27 +622,28 @@ feature_wake_up(void) } } -static u32 save_fcr0; -//static u32 save_fcr1; -//static u32 save_fcr2; +static u32 save_fcr[5]; static u32 save_mbcr; static void heathrow_prepare_for_sleep(struct feature_controller* ctrler) { save_mbcr = in_le32(FREG(ctrler, 0x34)); - save_fcr0 = in_le32(FREG(ctrler, 0x38)); + save_fcr[0] = in_le32(FREG(ctrler, 0x38)); + save_fcr[1] = in_le32(FREG(ctrler, 0x3c)); - out_le32(FREG(ctrler, 0x38), save_fcr0 & ~HRW_IOBUS_ENABLE); + out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE); } static void heathrow_wakeup(struct feature_controller* ctrler) { - out_le32(FREG(ctrler, 0x38), save_fcr0); + out_le32(FREG(ctrler, 0x38), save_fcr[0]); + out_le32(FREG(ctrler, 0x3c), save_fcr[1]); out_le32(FREG(ctrler, 0x34), save_mbcr); - - out_le32(FREG(ctrler, 0x38), save_fcr0 | HRW_IOBUS_ENABLE); + mdelay(1); + out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE); + mdelay(1); } static void @@ -540,4 +657,4 @@ core99_wake_up(struct feature_controller* ctrler) { /* Not yet implemented */ } - +#endif /* CONFIG_PMAC_PBOOK */ diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c index f2c4f1d0b9c0..a01ff9eca080 100644 --- a/arch/ppc/kernel/gemini_setup.c +++ b/arch/ppc/kernel/gemini_setup.c @@ -336,7 +336,7 @@ void __init gemini_init_IRQ(void) #define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) /* ensure that the RTC is up and running */ -void __init gemini_time_init(void) +long __init gemini_time_init(void) { unsigned char reg; @@ -347,6 +347,7 @@ void __init gemini_time_init(void) gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); } + return 0; } #undef DEBUG_RTC diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S index be86a1503bc1..1129dd40e5ba 100644 --- a/arch/ppc/kernel/hashtable.S +++ b/arch/ppc/kernel/hashtable.S @@ -27,6 +27,7 @@ #include #include #include +#include "mol.h" /* * Load a PTE into the hash table, if possible. @@ -593,6 +594,11 @@ _GLOBAL(flush_hash_segments) * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) +#ifdef CONFIG_MOL + mflr r10 + MOL_HOOK_MMU(10, r6) + mtlr r10 +#endif lis r6,Hash@ha lwz r6,Hash@l(r6) /* hash table base */ cmpwi 0,r6,0 /* hash table in use? */ diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 067581f5dc03..5d26e2917a6b 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -31,6 +31,7 @@ #include #include #include +#include "mol.h" #ifdef CONFIG_APUS #include @@ -78,7 +79,7 @@ CACHELINE_WORDS = 32 mtspr DBAT##n##L,RB; \ 1: #endif /* CONFIG_PPC64BRIDGE */ - + .text .globl _stext _stext: @@ -162,8 +163,8 @@ __start: /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ -__after_prom_start: bl mmu_off +__after_mmu_off: bl clear_bats bl flush_tlbs #endif @@ -202,15 +203,7 @@ __after_prom_start: mr r26,r3 addis r4,r3,KERNELBASE@h /* current address of _start */ cmpwi 0,r4,0 /* are we already running at 0? */ - beq 2f /* assume it's OK if so */ - li r3,0 - mfmsr r0 - andi. r0,r0,MSR_DR /* MMU enabled? */ - beq relocate_kernel - lis r3,KERNELBASE@h /* if so, are we */ - cmpw 0,r4,r3 /* already running at KERNELBASE? */ bne relocate_kernel -2: #endif /* CONFIG_APUS */ /* * we now have the 1st 16M of ram mapped with the bats. @@ -300,6 +293,17 @@ label: \ .long hdlr; \ .long ret_from_except +#define STD_MOL_EXCEPTION(n, label, hdlr, hook) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + MOL_HOOK(hook); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,MSR_KERNEL; \ + bl transfer_to_handler; \ + .long hdlr; \ + .long ret_from_except + /* System reset */ #ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ #ifdef CONFIG_GEMINI @@ -324,6 +328,7 @@ DataAccessCont: DataAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ + MOL_HOOK(0) mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -366,6 +371,7 @@ InstructionAccessCont: InstructionAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ + MOL_HOOK(1) andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ @@ -430,6 +436,7 @@ Alignment: . = 0x700 ProgramCheck: EXCEPTION_PROLOG + MOL_HOOK(2) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ @@ -441,6 +448,7 @@ ProgramCheck: . = 0x800 FPUnavailable: EXCEPTION_PROLOG + MOL_HOOK_RESTORE(3) bne load_up_fpu /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -450,6 +458,7 @@ FPUnavailable: . = 0x900 Decrementer: EXCEPTION_PROLOG + MOL_HOOK(4) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler @@ -473,12 +482,9 @@ SystemCall: .long ret_from_except /* Single step - not used on 601 */ - STD_EXCEPTION(0xd00, SingleStep, SingleStepException) - + STD_MOL_EXCEPTION(0xd00, SingleStep, SingleStepException, 5) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) -#ifndef CONFIG_ALTIVEC - STD_EXCEPTION(0xf00, Trap_0f, UnknownException) -#else + /* * The Altivec unavailable trap is at 0x0f20. Foo. * We effectively remap it to 0x3000. @@ -493,15 +499,20 @@ trap_0f_cont: .long ret_from_except . = 0xf20 +#ifdef CONFIG_ALTIVEC b AltiVecUnavailable -#endif /* CONFIG_ALTIVEC */ - +#endif +Trap_0f: + EXCEPTION_PROLOG + b trap_0f_cont + /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. */ . = 0x1000 InstructionTLBMiss: + MOL_HOOK_TLBMISS( 14 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -568,6 +579,7 @@ InstructionAddressInvalid: */ . = 0x1100 DataLoadTLBMiss: + MOL_HOOK_TLBMISS( 15 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -633,6 +645,7 @@ DataAddressInvalid: */ . = 0x1200 DataStoreTLBMiss: + MOL_HOOK_TLBMISS( 16 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -674,7 +687,7 @@ DataStoreTLBMiss: mtcrf 0x80,r3 rfi - STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) + STD_MOL_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, 11) STD_EXCEPTION(0x1400, SMI, SMIException) STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -687,7 +700,7 @@ DataStoreTLBMiss: STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) - STD_EXCEPTION(0x2000, RunMode, RunModeException) + STD_MOL_EXCEPTION(0x2000, RunMode, RunModeException, 5) STD_EXCEPTION(0x2100, Trap_21, UnknownException) STD_EXCEPTION(0x2200, Trap_22, UnknownException) STD_EXCEPTION(0x2300, Trap_23, UnknownException) @@ -709,16 +722,12 @@ DataStoreTLBMiss: #ifdef CONFIG_ALTIVEC AltiVecUnavailable: EXCEPTION_PROLOG + MOL_HOOK_RESTORE(12) bne load_up_altivec /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ .long KernelAltiVec .long ret_from_except - -/* here are the bits of trap 0xf00 which got displaced */ -Trap_0f: - EXCEPTION_PROLOG - b trap_0f_cont #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_PPC64BRIDGE @@ -753,6 +762,14 @@ transfer_to_handler: beq 2f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) +#ifdef CONFIG_ALTIVEC + mfpvr r24 /* check if we are on a G4 */ + srwi r24,r24,16 + cmpwi r24,PVR_7400@h + bne 2f + mfspr r22,SPRN_VRSAVE /* if so, save vrsave register value */ + stw r22,THREAD_VRSAVE(r23) +#endif /* CONFIG_ALTIVEC */ 2: addi r2,r23,-THREAD /* set r2 to current */ tovirt(r2,r2) mflr r23 @@ -771,6 +788,7 @@ transfer_to_handler: lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ FIX_SRR1(r20,r22) + MOL_HOOK(6) mtspr SRR0,r24 mtspr SRR1,r20 mtlr r23 @@ -981,6 +999,11 @@ KernelAltiVec: .globl giveup_altivec giveup_altivec: +#ifdef CONFIG_MOL + mflr r4 + MOL_HOOK_MMU(13, r5) + mtlr r4 +#endif mfmsr r5 oris r5,r5,MSR_VEC@h SYNC @@ -1017,6 +1040,11 @@ giveup_altivec: */ .globl giveup_fpu giveup_fpu: +#ifdef CONFIG_MOL + mflr r4 + MOL_HOOK_MMU(7, r5) + mtlr r4 +#endif mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1048,19 +1076,10 @@ giveup_fpu: * the kernel image to physical address 0. */ relocate_kernel: -#if 0 /* Is this still needed ? I don't think so. It breaks new - * boot-with-mmu-off stuff - */ - lis r9,0x426f /* if booted from BootX, don't */ - addi r9,r9,0x6f58 /* translate source addr */ - cmpw r31,r9 /* (we have to on chrp) */ - beq 7f - rlwinm r4,r4,0,8,31 /* translate source address */ - add r4,r4,r3 /* to region mapped with BATs */ -#endif -7: addis r9,r26,klimit@ha /* fetch klimit */ + addis r9,r26,klimit@ha /* fetch klimit */ lwz r25,klimit@l(r9) addis r25,r25,-KERNELBASE@h + li r3,0 /* Destination base address */ li r6,0 /* Destination offset */ li r5,0x4000 /* # bytes of memory to copy */ bl copy_and_flush /* copy the first 0x4000 bytes */ @@ -1307,7 +1326,7 @@ enable_caches: mfspr r9,PVR rlwinm r9,r9,16,16,31 cmpi 0,r9,1 - beq 4f /* not needed for 601 */ + beq 6f /* not needed for 601 */ mfspr r11,HID0 andi. r0,r11,HID0_DCE ori r11,r11,HID0_ICE|HID0_DCE @@ -1323,26 +1342,33 @@ enable_caches: isync cmpi 0,r9,4 /* check for 604 */ cmpi 1,r9,9 /* or 604e */ - cmpi 2,r9,10 /* or mach5 */ + cmpi 2,r9,10 /* or mach5 / 604r */ cmpi 3,r9,8 /* check for 750 (G3) */ cmpi 4,r9,12 /* or 7400 (G4) */ cror 2,2,6 cror 2,2,10 bne 4f - ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ + ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e|r], enable */ bne 2,5f - ori r11,r11,HID0_BTCD + ori r11,r11,HID0_BTCD /* superscalar exec & br history tbl */ b 5f 4: cror 14,14,18 bne 3,6f - /* We should add ABE here if we want to use Store Gathering - * and other nifty bridge features + /* for G3/G4: + * enable Store Gathering (SGE), Address Brodcast (ABE), + * Branch History Table (BHTE), Branch Target ICache (BTIC) */ - ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC /* for g3/g4, enable */ + ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ + li r3,HID0_SPD + andc r11,r11,r3 /* clear SPD: enable speculative */ li r3,0 - mtspr ICTC,r3 -5: mtspr HID0,r11 /* superscalar exec & br history tbl */ + mtspr ICTC,r3 /* Instruction Cache Throttling off */ +5: isync + mtspr HID0,r11 + sync + isync 6: blr /* @@ -1548,12 +1574,11 @@ flush_tlbs: blr mmu_off: - addi r4, r3, __after_prom_start - _start + addi r4, r3, __after_mmu_off - _start mfmsr r3 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ beqlr - ori r3,r3,MSR_DR|MSR_IR - xori r3,r3,MSR_DR|MSR_IR + andc r3,r3,r0 mtspr SRR0,r4 mtspr SRR1,r3 sync @@ -1617,23 +1642,19 @@ setup_disp_bat: mflr r8 bl reloc_offset mtlr r8 - lis r8, disp_BATL@h - ori r8, r8, disp_BATL@l - add r8, r3, r8 - lwz r8, 0(r8) - lis r11, disp_BATU@h - ori r11, r11, disp_BATU@l - add r11, r3, r11 - lwz r11, 0(r11) - mtspr IBAT3L,r8 - mtspr IBAT3U,r11 + addis r8,r3,disp_BAT@ha + addi r8,r8,disp_BAT@l + lwz r11,0(r8) + lwz r8,4(r8) mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpi 0,r9,1 beq 1f mtspr DBAT3L,r8 mtspr DBAT3U,r11 -1: + blr +1: mtspr IBAT3L,r8 + mtspr IBAT3U,r11 blr #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ @@ -1649,18 +1670,43 @@ setup_disp_bat: */ .globl m8260_gorom m8260_gorom: - li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SRR0,r6 - mtspr SRR1,r5 - rfi + mfmsr r0 + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + sync + mtmsr r0 + sync + mfspr r11, HID0 + lis r10, 0 + ori r10,r10,HID0_ICE|HID0_DCE + andc r11, r11, r10 + mtspr HID0, r11 + isync + li r5, MSR_ + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SRR0,r6 + mtspr SRR1,r5 + isync + sync + rfi 2: - mtlr r4 - blr + mtlr r4 + blr +#endif + +#ifdef CONFIG_MOL +/* + * Mac-on-linux hook_table. Don't put this in the data section - + * the base address must be within the first 32KB of RAM. + */ + .globl mol_interface +mol_interface: + .long MOL_INTERFACE_VERSION + .fill 24,4,0 /* space for 24 hooks */ #endif + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S index a35f6e2a1d07..40579ce63052 100644 --- a/arch/ppc/kernel/head_8xx.S +++ b/arch/ppc/kernel/head_8xx.S @@ -874,6 +874,13 @@ start_here: lis r6, swapper_pg_dir@h tophys(r6,r6) ori r6, r6, swapper_pg_dir@l +#ifdef CONFIG_8xx_CPU6 + lis r4, cpu6_errata_word@h + ori r4, r4, cpu6_errata_word@l + li r3, 0x3980 + stw r3, 12(r4) + lwz r3, 12(r4) +#endif mtspr M_TWB, r6 lis r4,2f@h ori r4,r4,2f@l @@ -940,9 +947,23 @@ start_here: * ASID compare register with the new "context". */ _GLOBAL(set_context) +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + tophys (r4, r4) + li r7, 0x3980 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr M_TWB, r4 /* Update MMU base address */ + li r7, 0x3380 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr M_CASID, r3 /* Update context */ +#else mtspr M_CASID,r3 /* Update context */ tophys (r4, r4) mtspr M_TWB, r4 /* and pgd */ +#endif tlbia SYNC blr @@ -966,6 +987,24 @@ m8xx_gorom: 2: mtlr r4 blr + +#ifdef CONFIG_8xx_CPU6 +/* It's here because it is unique to the 8xx. + * It is important we get called with interrupts disabled. I used to + * do that, but it appears that all code that calls this already had + * interrupt disabled. + */ + .globl set_dec_cpu6 +set_dec_cpu6: + lis r7, cpu6_errata_word@h + ori r7, r7, cpu6_errata_word@l + li r4, 0x2c00 + stw r4, 8(r7) + lwz r4, 8(r7) + mtspr 22, r3 /* Update Decrementer */ + SYNC + blr +#endif /* * We put a few things here that have to be page-aligned. @@ -991,3 +1030,9 @@ swapper_pg_dir: cmd_line: .space 512 +#ifdef CONFIG_8xx_CPU6 + .globl cpu6_errata_word +cpu6_errata_word: + .space 16 +#endif + diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index d29f7bd20b0b..a363a0e34720 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -286,6 +286,7 @@ void power_save(void) case 6: /* 603e */ case 7: /* 603ev */ case 8: /* 750 */ + case 12: /* 7400 */ save_flags(msr); __cli(); if (!current->need_resched) { diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index 64ef4b4dc623..eef89f352ddc 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -137,17 +137,21 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) if (!handler) { /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - irq_kfree(action); - return 0; - } - return -ENOENT; + p = &irq_desc[irq].action; + while ((action = *p) != NULL && action->dev_id != dev_id) + p = &action->next; + if (action == NULL) + return -ENOENT; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (irq_desc[irq].action == NULL) + disable_irq(irq); + restore_flags(flags); + irq_kfree(action); + return 0; } action = (struct irqaction *) @@ -300,7 +304,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) } } -asmlinkage int do_IRQ(struct pt_regs *regs, int isfake) +int do_IRQ(struct pt_regs *regs, int isfake) { int cpu = smp_processor_id(); int irq; diff --git a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c index 891b0ca44fbc..6e006a8677f5 100644 --- a/arch/ppc/kernel/m8260_setup.c +++ b/arch/ppc/kernel/m8260_setup.c @@ -112,11 +112,10 @@ void __init m8260_calibrate_decr(void) bd_t *binfo = (bd_t *)__res; int freq, divisor; - freq = (binfo->bi_intfreq * 1000000); - divisor = 16; - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + freq = (binfo->bi_busfreq * 1000000); + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); } /* The 8260 has an internal 1-second timer update register that @@ -143,8 +142,20 @@ void m8260_restart(char *cmd) { extern void m8260_gorom(bd_t *bi, uint addr); + uint startaddr; - m8260_gorom(NULL, 0xff000100); + /* Most boot roms have a warmstart as the second instruction + * of the reset vector. If that doesn't work for you, change this + * or the reboot program to send a proper address. + */ + startaddr = 0xff000104; + + if (cmd != NULL) { + if (!strncmp(cmd, "startaddr=", 10)) + startaddr = simple_strtoul(&cmd[10], NULL, 0); + } + + m8260_gorom((uint)__pa(__res), startaddr); } void diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c index a00a8c452371..7dc408a13116 100644 --- a/arch/ppc/kernel/m8xx_setup.c +++ b/arch/ppc/kernel/m8xx_setup.c @@ -135,6 +135,13 @@ abort(void) machine_restart(NULL); } +/* A place holder for time base interrupts, if they are ever enabled. +*/ +void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) +{ + printk("timebase_interrupt()\n"); +} + /* The decrementer counts at the system (internal) clock frequency divided by * sixteen, or external oscillator divided by four. We force the processor * to use system clock divided by sixteen. @@ -160,35 +167,14 @@ void __init m8xx_calibrate_decr(void) freq = fp*60; /* try to make freq/1e6 an integer */ divisor = 60; printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; -} - -/* A place holder for time base interrupts, if they are ever enabled. -*/ -void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) -{ - printk("timebase_interrupt()\n"); -} - -/* The RTC on the MPC8xx is an internal register. - * We want to protect this during power down, so we need to unlock, - * modify, and re-lock. - */ -static int -m8xx_set_rtc_time(unsigned long time) -{ - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; - return(0); -} - -unsigned long __init -m8xx_get_rtc_time(void) -{ - /* First, unlock all of the registers we are going to modify. + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); + + /* Perform some more timer/timebase initialization. This used + * to be done elsewhere, but other changes caused it to get + * called more than once....that is a bad thing. + * + * First, unlock all of the registers we are going to modify. * To protect them from corruption during power down, registers * that are maintained by keep alive power are "locked". To * modify these registers we have to write the key value to @@ -219,9 +205,27 @@ m8xx_get_rtc_time(void) ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr = ((mk_int_int_mask(DEC_INTERRUPT) << 8) | (TBSCR_TBF | TBSCR_TBE)); + if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) panic("Could not allocate timer IRQ!"); +} +/* The RTC on the MPC8xx is an internal register. + * We want to protect this during power down, so we need to unlock, + * modify, and re-lock. + */ +static int +m8xx_set_rtc_time(unsigned long time) +{ + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; + return(0); +} + +unsigned long __init +m8xx_get_rtc_time(void) +{ /* Get time from the RTC. */ return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc)); diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 081dda7f35ac..e3826293bf9e 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -24,12 +24,15 @@ #if defined(CONFIG_4xx) || defined(CONFIG_8xx) #define CACHE_LINE_SIZE 16 #define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 #elif !defined(CONFIG_PPC64BRIDGE) #define CACHE_LINE_SIZE 32 #define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 #else #define CACHE_LINE_SIZE 128 #define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 #endif /* CONFIG_4xx || CONFIG_8xx */ .text @@ -339,7 +342,15 @@ _GLOBAL(__flush_icache_page) _GLOBAL(clear_page) li r0,4096/CACHE_LINE_SIZE mtctr r0 +#ifdef CONFIG_8xx + li r4, 0 +1: stw r4, 0(r3) + stw r4, 4(r3) + stw r4, 8(r3) + stw r4, 12(r3) +#else 1: dcbz 0,r3 +#endif addi r3,r3,CACHE_LINE_SIZE bdnz 1b blr @@ -361,12 +372,31 @@ _GLOBAL(clear_page) stwu r9,16(r3) _GLOBAL(copy_page) - li r0,4096/CACHE_LINE_SIZE - mtctr r0 addi r3,r3,-4 addi r4,r4,-4 li r5,4 -1: dcbz r5,r3 + +#ifndef CONFIG_8xx +#if MAX_COPY_PREFETCH > 1 + li r0,MAX_COPY_PREFETCH + li r11,4 + mtctr r0 +11: dcbt r11,r4 + addi r11,r11,CACHE_LINE_SIZE + bdnz 11b +#else /* MAX_COPY_PREFETCH == 1 */ + dcbt r5,r4 + li r11,CACHE_LINE_SIZE+4 +#endif /* MAX_COPY_PREFETCH */ +#endif /* CONFIG_8xx */ + + li r0,4096/CACHE_LINE_SIZE + mtctr r0 +1: +#ifndef CONFIG_8xx + dcbt r11,r4 + dcbz r5,r3 +#endif COPY_16_BYTES #if CACHE_LINE_SIZE >= 32 COPY_16_BYTES @@ -484,7 +514,7 @@ _GLOBAL(atomic_dec_and_test) stwcx. r5,0,r3 /* Update with new value */ bne- 10b /* Retry if "reservation" (i.e. lock) lost */ cntlzw r3,r5 - srwi r3,r3,5 + srwi r3,r3,5 blr #endif /* 0 */ _GLOBAL(atomic_clear_mask) @@ -629,48 +659,59 @@ _GLOBAL(_outsl_ns) blr /* - * Extended precision shifts + * Extended precision shifts. + * + * Updated to be valid for shift counts from 0 to 63 inclusive. + * -- Gabriel * * R3/R4 has 64 bit value * R5 has shift count * result in R3/R4 * - * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ - * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000 - * lshrdi3: XXXYYY/ZZZAAA -> 000XXX/YYYZZZ + * ashrdi3: arithmetic right shift (sign propagation) + * lshrdi3: logical right shift + * ashldi3: left shift */ _GLOBAL(__ashrdi3) - li r6,32 - sub r6,r6,r5 - slw r7,r3,r6 /* isolate YYY */ - srw r4,r4,r5 /* isolate ZZZ */ - or r4,r4,r7 /* YYYZZZ */ - sraw r3,r3,r5 /* SSSXXX */ + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 + sraw r7,r3,r7 # t2 = MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 + sraw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 blr _GLOBAL(__ashldi3) - li r6,32 - sub r6,r6,r5 - srw r7,r4,r6 /* isolate ZZZ */ - slw r4,r4,r5 /* AAA000 */ - slw r3,r3,r5 /* YYY--- */ - or r3,r3,r7 /* YYYZZZ */ + subfic r6,r5,32 + slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count + addi r7,r5,32 # could be xori, or addi with -32 + srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) + slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) + or r3,r3,r6 # MSW |= t1 + slw r4,r4,r5 # LSW = LSW << count + or r3,r3,r7 # MSW |= t2 blr _GLOBAL(__lshrdi3) - li r6,32 - sub r6,r6,r5 - slw r7,r3,r6 /* isolate YYY */ - srw r4,r4,r5 /* isolate ZZZ */ - or r4,r4,r7 /* YYYZZZ */ - srw r3,r3,r5 /* 000XXX */ + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + srw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 blr _GLOBAL(abs) - cmpi 0,r3,0 - bge 10f - neg r3,r3 -10: blr + srawi r4,r3,31 + xor r3,r3,r4 + sub r3,r3,r4 + blr _GLOBAL(_get_SP) mr r3,r1 /* Close enough */ @@ -1217,6 +1258,6 @@ _GLOBAL(sys_call_table) .long sys_pciconfig_iobase /* 200 */ .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ .long sys_getdents64 /* 202 */ - .rept NR_syscalls-201 + .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr diff --git a/arch/ppc/kernel/mol.h b/arch/ppc/kernel/mol.h new file mode 100644 index 000000000000..6105867e1c22 --- /dev/null +++ b/arch/ppc/kernel/mol.h @@ -0,0 +1,68 @@ +/* + * arch/ppc/kernel/mol.h + * + * + * + * Mac-on-Linux hook macros + * + * + * Copyright (C) 2000 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _PPC_KERNEL_MOL +#define _PPC_KERNEL_MOL + +#include + +#ifdef CONFIG_MOL +#define MOL_INTERFACE_VERSION 3 + +#define MOL_HOOK(hook_num) \ + lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ + cmpwi cr1,r0,0; \ + beq+ cr1,777f; \ + mtctr r0; \ + bctrl; \ +777: lwz r0,GPR0(r21) + +#define MOL_HOOK_RESTORE(hook_num) \ + mfcr r2; \ + MOL_HOOK(hook_num); \ + mtcrf 0x80,r2; \ + lwz r2,_CTR(r21); \ + mtctr r2; \ + lwz r2,GPR2(r21) + +#define MOL_HOOK_MMU(hook_num, scr) \ + lis scr,(mol_interface + 4 * hook_num + 4)@ha; \ + lwz scr,(mol_interface + 4 * hook_num + 4)@l(scr); \ + cmpwi cr1,scr,0; \ + beq+ cr1,778f; \ + mtctr scr; \ + bctrl; \ +778: + +#define MOL_HOOK_TLBMISS(hook_num) \ + lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ + cmpwi r0,0; \ + beq+ 779f; \ + mflr r3; \ + mtlr r0; \ + blrl; \ + mtlr r3; \ +779: + +#else +#define MOL_HOOK(num) +#define MOL_HOOK_RESTORE(num) +#define MOL_HOOK_MMU(num, scr) +#define MOL_HOOK_TLBMISS(num) +#endif + + +#endif /* _PPC_KERNEL_MOL */ diff --git a/arch/ppc/kernel/oak_setup.c b/arch/ppc/kernel/oak_setup.c index 09e6e6e6f837..ef5a7a0fe766 100644 --- a/arch/ppc/kernel/oak_setup.c +++ b/arch/ppc/kernel/oak_setup.c @@ -231,10 +231,11 @@ oak_halt(void) /* * Document me. */ -void __init +long __init oak_time_init(void) { /* XXX - Implement me */ + return 0; } /* diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index 41613793438f..5ca365b1c7bc 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -100,7 +100,7 @@ struct hw_interrupt_type open_pic = { #ifdef CONFIG_SMP void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { - smp_message_recv(cpl-OPENPIC_VEC_IPI); + smp_message_recv(cpl-OPENPIC_VEC_IPI, regs); } #endif /* CONFIG_SMP */ @@ -262,11 +262,11 @@ void __init openpic_init(int main_pic) int j, pri; pri = strcmp(np->name, "programmer-switch") ? 2 : 7; for (j=0;jn_intrs;j++) { - openpic_initirq( np->intrs[j].line, - pri, - np->intrs[j].line, - 0, - np->intrs[j].sense); + openpic_initirq(np->intrs[j].line, + pri, + np->intrs[j].line, + 0, + np->intrs[j].sense); if (np->intrs[j].sense) irq_desc[np->intrs[j].line].status = IRQ_LEVEL; } diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 6233e5f9b28a..84faa0e1df9e 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -25,7 +25,13 @@ #include "pci.h" -static void __init pcibios_claim_resources(struct list_head *); +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; @@ -70,59 +76,280 @@ struct pci_ops generic_pci_ops = generic_pcibios_write_dword }; -void __init pcibios_init(void) -{ - printk("PCI: Probing PCI hardware\n"); - pci_scan_bus(0, &generic_pci_ops, NULL); - if (ppc_md.pcibios_fixup) - ppc_md.pcibios_fixup(); - pcibios_claim_resources(&pci_root_buses); -} -void __init -pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) { - ranges->io_start -= bus->resource[0]->start; - ranges->io_end -= bus->resource[0]->start; - ranges->mem_start -= bus->resource[1]->start; - ranges->mem_end -= bus->resource[1]->start; + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } } -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +void +pcibios_align_resource(void *data, struct resource *res, unsigned long size) { - return start; + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } } -static void __init pcibios_claim_resources(struct list_head *bus_list) + +/* + * Handle resources of PCI devices. If the world were perfect, we could + * just allocate all the resource regions and do nothing more. It isn't. + * On the other hand, we cannot just re-allocate all devices, as it would + * require us to know lots of host bridge internals. So we attempt to + * keep as much of the original configuration as possible, but tweak it + * when it's found to be wrong. + * + * Known BIOS problems we have to work around: + * - I/O or memory regions not configured + * - regions configured, but not enabled in the command register + * - bogus I/O addresses above 64K used + * - expansion ROMs left enabled (this may sound harmless, but given + * the fact the PCI specs explicitly allow address decoders to be + * shared between expansion ROMs and other resource regions, it's + * at least dangerous) + * + * Our solution: + * (1) Allocate resources for all buses behind PCI-to-PCI bridges. + * This gives us fixed barriers on where we can allocate. + * (2) Allocate resources for all enabled devices. If there is + * a collision, just mark the resource as unallocated. Also + * disable expansion ROMs during this step. + * (3) Try to allocate resources for disabled devices. If the + * resources were assigned correctly, everything goes well, + * if they weren't, they won't disturb allocation of other + * resources. + * (4) Assign new addresses to resources which were either + * not configured at all or misconfigured. If explicitly + * requested by the user, configure expansion ROM address + * as well. + */ + +static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { - struct list_head *ln, *dn; + struct list_head *ln; struct pci_bus *bus; struct pci_dev *dev; int idx; + struct resource *r, *pr; + /* Depth-First Search on bus tree */ for (ln=bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); - for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) { - dev = pci_dev_b(dn); - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) - { - struct resource *r = &dev->resource[idx]; - struct resource *pr; + if ((dev = bus->self)) { + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + r = &dev->resource[idx]; if (!r->start) continue; pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) - { - printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); - /* We probably should disable the region, shouldn't we? */ + printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name); + } + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +static void __init pcibios_allocate_resources(int pass) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r, *pr; + + pci_for_each_dev(dev) { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (r->parent) /* Already allocated */ + continue; + if (!r->start) /* Address not assigned at all */ + continue; + if (r->end == 0xffffffff) { + /* LongTrail OF quirk: unassigned */ + DBG("PCI: Resource %08lx-%08lx was unassigned\n", r->start, r->end); + r->end -= r->start; + r->start = 0; + continue; + } + + if (r->flags & IORESOURCE_IO) + disabled = !(command & PCI_COMMAND_IO); + else + disabled = !(command & PCI_COMMAND_MEMORY); + if (pass == disabled) { + DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", + r->start, r->end, r->flags, disabled, pass); + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name); + /* We'll assign a new address later */ + r->end -= r->start; + r->start = 0; } } } - pcibios_claim_resources(&bus->children); + if (!pass) { + r = &dev->resource[PCI_ROM_RESOURCE]; + if (r->flags & PCI_ROM_ADDRESS_ENABLE) { + /* Turn the ROM off, leave the resource region, but keep it unregistered. */ + u32 reg; + DBG("PCI: Switching off ROM of %s\n", dev->slot_name); + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, dev->rom_base_reg, ®); + pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); + } + } + } +} + +static void __init pcibios_assign_resources(void) +{ + struct pci_dev *dev; + int idx; + struct resource *r; + + pci_for_each_dev(dev) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) + continue; + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end) + pci_assign_resource(dev, idx); + } + + if (0) { /* don't assign ROMs */ + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pci_assign_resource(dev, PCI_ROM_RESOURCE); + } } } + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + + +void __init pcibios_init(void) +{ + printk("PCI: Probing PCI hardware\n"); + pci_scan_bus(0, &generic_pci_ops, NULL); + if (ppc_md.pcibios_fixup) + ppc_md.pcibios_fixup(); + pcibios_allocate_bus_resources(&pci_root_buses); + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); + pcibios_assign_resources(); +} + +void __init +pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; +} + void __init pcibios_fixup_bus(struct pci_bus *bus) { if ( ppc_md.pcibios_fixup_bus ) @@ -134,21 +361,7 @@ char __init *pcibios_setup(char *str) return str; } -/* the next two are stolen from the alpha port... */ -void __init -pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) -{ - unsigned long where, size; - u32 reg; - - where = PCI_BASE_ADDRESS_0 + (resource * 4); - size = res->end - res->start; - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); -} - +/* the next one is stolen from the alpha port... */ void __init pcibios_update_irq(struct pci_dev *dev, int irq) { @@ -156,11 +369,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq) /* XXX FIXME - update OF device tree node interrupt property */ } -void __init -pcibios_align_resource(void *data, struct resource *res, unsigned long size) -{ -} - int pcibios_enable_device(struct pci_dev *dev) { u16 cmd, old_cmd; @@ -188,114 +396,26 @@ int pcibios_enable_device(struct pci_dev *dev) return 0; } -/* - * Those syscalls are derived from the Alpha versions, they - * allow userland apps to retreive the per-device iobase and - * mem-base. They also provide wrapper for userland to do - * config space accesses. - * The "host_number" returns the number of the Uni-N sub bridge - */ - -asmlinkage int -sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, buf); - break; - case 2: - err = pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, (unsigned short *)buf); - break; - case 4: - err = pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, (unsigned int *)buf); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -asmlinkage int -sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = get_user(ubyte, buf); - if (err) - break; - err = pcibios_write_config_byte(bus, dfn, off, ubyte); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 2: - err = get_user(ushort, (unsigned short *)buf); - if (err) - break; - err = pcibios_write_config_word(bus, dfn, off, ushort); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 4: - err = get_user(uint, (unsigned int *)buf); - if (err) - break; - err = pcibios_write_config_dword(bus, dfn, off, uint); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - void * -pci_dev_io_base(unsigned char bus, unsigned char devfn) +pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) { - /* Defaults to old way */ - if (!ppc_md.pci_dev_io_base) - return pci_io_base(bus); - return ppc_md.pci_dev_io_base(bus, devfn); + if (!ppc_md.pci_dev_io_base) { + /* Please, someone fix this for non-pmac machines, we + * need either the virtual or physical PCI IO base + */ + return 0; + } + return ppc_md.pci_dev_io_base(bus, devfn, physical); } void * pci_dev_mem_base(unsigned char bus, unsigned char devfn) { /* Default memory base is 0 (1:1 mapping) */ - if (!ppc_md.pci_dev_mem_base) + if (!ppc_md.pci_dev_mem_base) { + /* Please, someone fix this for non-pmac machines.*/ return 0; + } return ppc_md.pci_dev_mem_base(bus, devfn); } @@ -318,15 +438,20 @@ pci_dev_root_bridge(unsigned char bus, unsigned char devfn) asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) { + long result = -EOPNOTSUPP; + switch (which) { case IOBASE_BRIDGE_NUMBER: return (long)pci_dev_root_bridge(bus, devfn); case IOBASE_MEMORY: return (long)pci_dev_mem_base(bus, devfn); case IOBASE_IO: - return (long)pci_dev_io_base(bus, devfn); + result = (long)pci_dev_io_base(bus, devfn, 1); + if (result == 0) + result = -EOPNOTSUPP; + break; } - return -EOPNOTSUPP; + return result; } diff --git a/arch/ppc/kernel/pmac_backlight.c b/arch/ppc/kernel/pmac_backlight.c index 8c6244632456..30ad5f416797 100644 --- a/arch/ppc/kernel/pmac_backlight.c +++ b/arch/ppc/kernel/pmac_backlight.c @@ -41,16 +41,16 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c #ifdef CONFIG_ADB_PMU /* Special case for the old PowerBook since I can't test on it */ - if ((machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500") - || machine_is_compatible("AAPL,PowerBook1998") - || machine_is_compatible("AAPL,PowerBook1999")) - && !strcmp(type, "pmu")) + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) valid = 1; - else #endif - { - if (bk_node) - prop = get_property(bk_node, "backlight-control", NULL); + if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); if (prop && !strncmp(prop, type, strlen(type))) valid = 1; } @@ -70,8 +70,6 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c } #ifdef CONFIG_ADB_PMU - backlight_autosave = machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500"); if (backlight_autosave) { struct adb_request req; pmu_request(&req, NULL, 2, 0xd9, 0); diff --git a/arch/ppc/kernel/pmac_nvram.c b/arch/ppc/kernel/pmac_nvram.c index d8de113ec966..1c4c1eea1de9 100644 --- a/arch/ppc/kernel/pmac_nvram.c +++ b/arch/ppc/kernel/pmac_nvram.c @@ -312,17 +312,18 @@ pmac_nvram_update(void) __openfirmware unsigned char nvram_read_byte(int addr) { - struct adb_request req; - switch (nvram_naddrs) { #ifdef CONFIG_ADB_PMU - case -1: + case -1: { + struct adb_request req; + if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, (addr >> 8) & 0xff, addr & 0xff)) break; while (!req.complete) pmu_poll(); return req.reply[1]; + } #endif case 1: if (is_core_99) @@ -339,17 +340,18 @@ unsigned char nvram_read_byte(int addr) __openfirmware void nvram_write_byte(unsigned char val, int addr) { - struct adb_request req; - switch (nvram_naddrs) { #ifdef CONFIG_ADB_PMU - case -1: + case -1: { + struct adb_request req; + if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, (addr >> 8) & 0xff, addr & 0xff, val)) break; while (!req.complete) pmu_poll(); break; + } #endif case 1: if (is_core_99) { diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index ced0297222ec..8f7b3d7c231c 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -35,6 +35,7 @@ struct uninorth_data { volatile unsigned int* cfg_addr; volatile unsigned int* cfg_data; void* iobase; + unsigned long iobase_phys; }; static struct uninorth_data uninorth_bridges[3]; @@ -133,15 +134,20 @@ pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn) __pmac void * -pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn) +pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) { - int bridge; - if (uninorth_count == 0) - return pci_io_base(bus); - bridge = pmac_pci_dev_root_bridge(bus, devfn); - if (bridge == -1) - return pci_io_base(bus); - return uninorth_bridges[bridge].iobase; + int bridge = -1; + if (uninorth_count != 0) + bridge = pmac_pci_dev_root_bridge(bus, devfn); + if (bridge == -1) { + struct bridge_data *bp; + + if (bus > max_bus || (bp = bridges[bus]) == 0) + return 0; + return physical ? (void *) bp->io_base_phys : bp->io_base; + } + return physical ? (void *) uninorth_bridges[bridge].iobase_phys + : uninorth_bridges[bridge].iobase; } __pmac @@ -649,7 +655,9 @@ static void __init add_bridges(struct device_node *dev) uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000); uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000); uninorth_bridges[i].node = dev; - uninorth_bridges[i].iobase = (void *)addr->address; + uninorth_bridges[i].iobase_phys = addr->address; + /* is 0x10000 enough for io space ? */ + uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000); /* XXX This is the bridge with the PCI expansion bus. This is also the * address of the bus that will receive type 1 config accesses and io * accesses. Appears to be correct for iMac DV and G4 Sawtooth too. @@ -667,14 +675,15 @@ static void __init add_bridges(struct device_node *dev) if (device_is_compatible(dev, "uni-north")) { bp->cfg_addr = 0; bp->cfg_data = 0; - /* is 0x10000 enough for io space ? */ - bp->io_base = (void *)ioremap(addr->address, 0x10000); + bp->io_base = uninorth_bridges[uninorth_count-1].iobase; + bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ bp->cfg_addr = (volatile unsigned int *) ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); + bp->io_base_phys = 0xfe000000; bp->io_base = (void *) ioremap(0xfe000000, 0x20000); if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(bp, 1); @@ -687,6 +696,7 @@ static void __init add_bridges(struct device_node *dev) ioremap(addr->address + 0x800000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); + bp->io_base_phys = addr->address; bp->io_base = (void *) ioremap(addr->address, 0x10000); } if (isa_io_base == 0) diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index e0e654305562..efd7674826f3 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -204,17 +204,12 @@ pmac_get_irq(struct pt_regs *regs) unsigned long bits = 0; #ifdef CONFIG_SMP - void pmac_smp_message_recv(void); + void pmac_smp_message_recv(struct pt_regs *); /* IPI's are a hack on the powersurge -- Cort */ if ( smp_processor_id() != 0 ) { -#ifdef CONFIG_XMON - static int xmon_2nd; - if (xmon_2nd) - xmon(regs); -#endif - pmac_smp_message_recv(); + pmac_smp_message_recv(regs); return -2; /* ignore, already handled */ } #endif /* CONFIG_SMP */ diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 658d7c22688d..b5bf03abc34e 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -68,7 +68,7 @@ #undef SHOW_GATWICK_IRQS -extern void pmac_time_init(void); +extern long pmac_time_init(void); extern unsigned long pmac_get_rtc_time(void); extern int pmac_set_rtc_time(unsigned long nowtime); extern void pmac_read_rtc_time(void); @@ -77,24 +77,29 @@ extern void pmac_setup_pci_ptrs(void); extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char mackbd_unexpected_up(unsigned char keycode); +extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +extern int mackbd_unexpected_up(unsigned char keycode); extern void mackbd_leds(unsigned char leds); -extern void mackbd_init_hw(void); +extern void __init mackbd_init_hw(void); +extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mac_hid_kbd_unexpected_up(unsigned char keycode); +extern void mac_hid_init_hw(void); #ifdef CONFIG_MAGIC_SYSRQ -unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mac_hid_kbd_sysrq_xlate[128]; +extern unsigned char pckbd_sysrq_xlate[128]; +extern unsigned char mackbd_sysrq_xlate[128]; #endif /* CONFIG_MAGIC_SYSRQ */ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); +extern int keyboard_sends_linux_keycodes; extern void pmac_nvram_update(void); -extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn); +extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical); extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn); extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn); @@ -115,7 +120,6 @@ extern int pmac_newworld; extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); static void init_p2pbridge(void); -static void init_uninorth(void); #ifdef CONFIG_BOOTX_TEXT void pmac_progress(char *s, unsigned short hex); #endif @@ -276,7 +280,6 @@ pmac_setup_arch(void) pmac_find_bridges(); init_p2pbridge(); - init_uninorth(); /* Checks "l2cr-value" property in the registry */ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) { @@ -372,31 +375,6 @@ static void __init ohare_init(void) } } -static void __init -init_uninorth(void) -{ - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs - */ - struct device_node* gmac = find_devices("ethernet"); - - while(gmac) { - if (device_is_compatible(gmac, "gmac")) - break; - gmac = gmac->next; - } - if (gmac) - feature_set_gmac_power(gmac, 0); -} - extern char *bootpath; extern char *bootdevice; void *boot_host; @@ -404,14 +382,15 @@ int boot_target; int boot_part; kdev_t boot_dev; -extern void via_pmu_start(void); - void __init pmac_init2(void) { #ifdef CONFIG_ADB_PMU via_pmu_start(); #endif +#ifdef CONFIG_ADB_CUDA + via_cuda_start(); +#endif #ifdef CONFIG_PMAC_PBOOK media_bay_init(); #endif @@ -683,7 +662,26 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.pci_dev_mem_base = pmac_pci_dev_mem_base; ppc_md.pci_dev_root_bridge = pmac_pci_dev_root_bridge; -#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) +#ifdef CONFIG_VT +#ifdef CONFIG_INPUT_ADBHID + ppc_md.kbd_init_hw = mac_hid_init_hw; + ppc_md.kbd_translate = mac_hid_kbd_translate; + ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up; + ppc_md.kbd_setkeycode = 0; + ppc_md.kbd_getkeycode = 0; +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; + } else +#endif /* CONFIG_MAC_ADBKEYCODES */ + { + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; + } +#endif /* CONFIG_MAGIC_SYSRQ */ +#elif defined(CONFIG_ADB_KEYBOARD) ppc_md.kbd_setkeycode = mackbd_setkeycode; ppc_md.kbd_getkeycode = mackbd_getkeycode; ppc_md.kbd_translate = mackbd_translate; @@ -691,10 +689,11 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; + ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; SYSRQ_KEY = 0x69; -#endif -#endif +#endif /* CONFIG_MAGIC_SYSRQ */ +#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */ +#endif /* CONFIG_VT */ #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) ppc_ide_md.insw = pmac_ide_insw; diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index 9eb326bf94f8..00b6302a76e9 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -25,7 +25,7 @@ #include #include #include - +#include #include #include @@ -58,7 +58,7 @@ extern rwlock_t xtime_lock; extern struct timezone sys_tz; __init -void pmac_time_init(void) +long pmac_time_init(void) { #ifdef CONFIG_NVRAM s32 delta = 0; @@ -72,17 +72,18 @@ void pmac_time_init(void) dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, dst ? "on" : "off"); - sys_tz.tz_minuteswest = -delta/60; - /* I _suppose_ this is 0:off, 1:on */ - sys_tz.tz_dsttime = dst; + return delta; +#else + return 0; #endif } __pmac unsigned long pmac_get_rtc_time(void) { -#ifdef CONFIG_ADB +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; + unsigned long now; #endif /* Get the time from the RTC */ @@ -96,8 +97,9 @@ unsigned long pmac_get_rtc_time(void) if (req.reply_len != 7) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + return now - RTC_OFFSET; #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: @@ -108,21 +110,25 @@ unsigned long pmac_get_rtc_time(void) if (req.reply_len != 5) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET; + now = (req.reply[1] << 24) + (req.reply[2] << 16) + + (req.reply[3] << 8) + req.reply[4]; + return now - RTC_OFFSET; #endif /* CONFIG_ADB_PMU */ default: - return 0; } + return 0; } int pmac_set_rtc_time(unsigned long nowtime) { +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; +#endif - nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60; + nowtime += RTC_OFFSET; switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) @@ -133,16 +139,19 @@ int pmac_set_rtc_time(unsigned long nowtime) printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", req.reply_len); return 1; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) return 0; while (!req.complete) pmu_poll(); - if (req.reply_len != 5) + if (req.reply_len != 0) printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", req.reply_len); return 1; +#endif /* CONFIG_ADB_PMU */ default: return 0; } @@ -186,12 +195,11 @@ int __init via_calibrate_decr(void) ; dend = get_dec(); - decrementer_count = (dstart - dend) / 6; - count_period_num = 60; - count_period_den = decrementer_count * 6 * HZ / 100000; + tb_ticks_per_jiffy = (dstart - dend) / 6; + tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); - printk(KERN_INFO "via_calibrate_decr: decrementer_count = %u (%u ticks)\n", - decrementer_count, dstart - dend); + printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", + tb_ticks_per_jiffy, dstart - dend); return 1; } @@ -214,8 +222,11 @@ static int time_sleep_notify(struct pmu_sleep_notifier *self, int when) case PBOOK_WAKE: write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = pmac_get_rtc_time() + time_diff; + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + so use get_tbl, not native */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); xtime.tv_usec = 0; - set_dec(decrementer_count); last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); break; @@ -236,7 +247,7 @@ static struct pmu_sleep_notifier time_sleep_notifier = { void __init pmac_calibrate_decr(void) { struct device_node *cpu; - int freq, *fp, divisor; + unsigned int freq, *fp; #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&time_sleep_notifier); @@ -252,15 +263,13 @@ void __init pmac_calibrate_decr(void) cpu = find_type_devices("cpu"); if (cpu == 0) panic("can't find cpu node in time_init"); - fp = (int *) get_property(cpu, "timebase-frequency", NULL); + fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); if (fp == 0) panic("can't get cpu timebase frequency"); - freq = *fp * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", - freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + freq = *fp; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index e08ab97f8249..9240431e6321 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef CONFIG_SMP #include #endif /* CONFIG_SMP */ @@ -184,6 +185,10 @@ EXPORT_SYMBOL(giveup_fpu); EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +#ifdef CONFIG_ALTIVEC +EXPORT_SYMBOL(last_task_used_altivec); +EXPORT_SYMBOL(giveup_altivec); +#endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SMP EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); @@ -204,26 +209,34 @@ EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB -/* - * This could be more fine-grained, but for now assume if we have - * ADB we have it all -- Cort - */ EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_register); +EXPORT_SYMBOL(adb_unregister); +EXPORT_SYMBOL(adb_poll); +EXPORT_SYMBOL(adb_try_handler_change); +#endif /* CONFIG_ADB */ +#ifdef CONFIG_ADB_CUDA EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); +#endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); #endif /* CONFIG_ADB_PMU */ -#endif /* CONFIG_ADB */ #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); -#endif CONFIG_PMAC_PBOOK +#endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_PMAC_BACKLIGHT +EXPORT_SYMBOL(get_backlight_level); +EXPORT_SYMBOL(set_backlight_level); +#endif /* CONFIG_PMAC_BACKLIGHT */ #if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL_NOVERS(sys_ctrler); +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL_NOVERS(have_of); +#endif /* CONFIG_MACH_SPECIFIC */ EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -253,9 +266,7 @@ EXPORT_SYMBOL(nvram_write_byte); EXPORT_SYMBOL(pmac_xpram_read); EXPORT_SYMBOL(pmac_xpram_write); #endif /* CONFIG_NVRAM */ -#ifdef CONFIG_PPC_RTC EXPORT_SYMBOL(to_tm); -#endif EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(__ashldi3); @@ -279,7 +290,7 @@ EXPORT_SYMBOL(do_IRQ_intercept); EXPORT_SYMBOL(irq_desc); void ppc_irq_dispatch_handler(struct pt_regs *, int); EXPORT_SYMBOL(ppc_irq_dispatch_handler); -EXPORT_SYMBOL(decrementer_count); +EXPORT_SYMBOL(tb_ticks_per_jiffy); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); EXPORT_SYMBOL(console_lock); @@ -309,3 +320,17 @@ EXPORT_SYMBOL(do_softirq); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(mmu_context_overflow); + +#ifdef CONFIG_MOL +extern ulong mol_interface[]; +extern PTE *Hash; +extern unsigned long Hash_mask; +extern void (*ret_from_except)(void); +extern struct task_struct *last_task_used_altivec; +EXPORT_SYMBOL_NOVERS(mol_interface); +EXPORT_SYMBOL(Hash); +EXPORT_SYMBOL(Hash_mask); +EXPORT_SYMBOL(handle_mm_fault); +EXPORT_SYMBOL(last_task_used_math); +EXPORT_SYMBOL(ret_from_except); +#endif /* CONFIG_MOL */ diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index a09b4cf81240..d72e747350da 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -365,14 +365,13 @@ prep_setup_arch(void) */ void __init prep_res_calibrate_decr(void) { - int freq, divisor; + unsigned long freq, divisor=4; freq = res->VitalProductData.ProcessorBusHz; - divisor = 4; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + (freq/divisor)/1000000, (freq/divisor)%1000000); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); } /* @@ -381,32 +380,30 @@ void __init prep_res_calibrate_decr(void) * but on prep we have to figure it out. * -- Cort */ -int calibrate_done = 0; -volatile int *done_ptr = &calibrate_done; +/* Done with 3 interrupts: the first one primes the cache and the + * 2 following ones measure the interval. The precision of the method + * is still doubtful due to the short interval sampled. + */ +static __initdata volatile int calibrate_steps = 3; +static __initdata unsigned tbstamp; void __init prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs) { - unsigned long freq, divisor; - static unsigned long t1 = 0, t2 = 0; - - if ( !t1 ) - t1 = get_dec(); - else if (!t2) - { - t2 = get_dec(); - t2 = t1-t2; /* decr's in 1/HZ */ - t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; - *done_ptr = 1; + unsigned long t, freq; + int step=--calibrate_steps; + + t = get_tbl(); + if (step > 0) { + tbstamp = t; + } else { + freq = (t - tbstamp)*HZ; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } } @@ -428,17 +425,43 @@ void __init prep_calibrate_decr(void) if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) panic("Could not allocate timer IRQ!"); __sti(); - while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */ + while ( calibrate_steps ) /* nothing */; /* wait for calibrate */ restore_flags(flags); free_irq( 0, NULL); } -/* We use the NVRAM RTC to time a second to calibrate the decrementer. */ +static long __init mk48t59_init(void) { + unsigned char tmp; + + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); + if (tmp & MK48T59_RTC_CB_STOP) { + printk("Warning: RTC was stopped, date will be wrong.\n"); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, + tmp & ~MK48T59_RTC_CB_STOP); + /* Low frequency crystal oscillators may take a very long + * time to startup and stabilize. For now just ignore the + * the issue, but attempting to calibrate the decrementer + * from the RTC just after this wakeup is likely to be very + * inaccurate. Firmware should not allow to load + * the OS with the clock stopped anyway... + */ + } + /* Ensure that the clock registers are updated */ + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp); + return 0; +} + +/* We use the NVRAM RTC to time a second to calibrate the decrementer, + * the RTC registers have just been set up in the right state by the + * preceding routine. + */ void __init mk48t59_calibrate_decr(void) { - unsigned long freq, divisor; - unsigned long t1, t2; + unsigned long freq; + unsigned long t1; unsigned char save_control; long i; unsigned char sec; @@ -458,29 +481,31 @@ void __init mk48t59_calibrate_decr(void) /* Read the seconds value to see when it changes. */ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + /* Actually this is bad for precision, we should have a loop in + * which we only read the seconds counter. nvram_read_val writes + * the address bytes on every call and this takes a lot of time. + * Perhaps an nvram_wait_change method returning a time + * stamp with a loop count as parameter would be the solution. + */ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ + t1 = get_tbl(); if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t1 = get_dec(); sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */ + freq = get_tbl()-t1; if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t2 = t1 - get_dec(); - - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } void __prep @@ -788,6 +813,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, { ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; + ppc_md.time_init = mk48t59_init; } else { @@ -808,6 +834,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; ppc_md.calibrate_decr = mk48t59_calibrate_decr; + ppc_md.time_init = mk48t59_init; } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c index 6f773e79c9f4..78634c6e2591 100644 --- a/arch/ppc/kernel/prep_time.c +++ b/arch/ppc/kernel/prep_time.c @@ -100,28 +100,34 @@ __prep unsigned long mc146818_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; + int uip, i; /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = CMOS_READ(RTC_FREQ_SELECT); sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); day = CMOS_READ(RTC_DAY_OF_MONTH); mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); + uip |= CMOS_READ(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -178,29 +184,12 @@ unsigned long mk48t59_get_rtc_time(void) { unsigned char save_control; unsigned int year, mon, day, hour, min, sec; - int i; - /* Make sure the time is not stopped. */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); - - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, - (save_control & (~MK48T59_RTC_CB_STOP))); - - /* Now make sure the read bit is off so the value will change. */ + /* Simple: freeze the clock, read it and allow updates again */ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); save_control &= ~MK48T59_RTC_CA_READ; ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - /* Read the seconds value to see when it changes. */ - sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); - - /* Wait until the seconds value changes, then read the value. */ - for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ - if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { - break; - } - } - /* Set the register to read the value. */ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, (save_control | MK48T59_RTC_CA_READ)); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 7d228788c723..27adc9958430 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -234,7 +234,6 @@ _switch_to(struct task_struct *prev, struct task_struct *new, prev->thread.vrsave ) giveup_altivec(prev); #endif /* CONFIG_ALTIVEC */ - prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* CONFIG_SMP */ /* Avoid the trap. On smp this this never happens since @@ -266,7 +265,7 @@ void show_regs(struct pt_regs * regs) last_task_used_altivec); #ifdef CONFIG_SMP - printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); + printk(" CPU: %d", current->processor); #endif /* CONFIG_SMP */ printk("\n"); @@ -379,9 +378,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, childregs->msr &= ~MSR_VEC; #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_SMP - p->last_processor = NO_PROC_ID; -#endif /* CONFIG_SMP */ return 0; } @@ -441,8 +437,8 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) current->thread.fpscr = 0; } -asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { unsigned long clone_flags = p1; int res; @@ -460,8 +456,8 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, return res; } -asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { int res; @@ -478,15 +474,15 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, return res; } -asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); } -asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) +int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs *regs) { int error; char * filename; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 1d661fa712b8..5494f2f52dfd 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -140,8 +140,7 @@ static long g_loc_Y = 0; static long g_max_loc_X = 0; static long g_max_loc_Y = 0; -unsigned long disp_BATL = 0; -unsigned long disp_BATU = 0; +unsigned long disp_BAT[2] = {0, 0}; #define cmapsz (16*256) @@ -276,8 +275,7 @@ prom_print(const char *msg) prom_drawstring(msg); #endif return; - } - + } for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) @@ -362,7 +360,7 @@ prom_hold_cpus(unsigned long mem) /* copy the holding pattern code to someplace safe (0) */ /* the holding pattern is now within the first 0x100 bytes of the kernel image -- paulus */ - memcpy((void *)0, KERNELBASE + offset, 0x100); + memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100); flush_icache_range(0, 0x100); /* look for cpus */ @@ -556,6 +554,54 @@ prom_alloc_htab(void) } #endif /* CONFIG_PPC64BRIDGE */ +static __init void +prom_instantiate_rtas(void) +{ + ihandle prom_rtas; + unsigned int i; + struct prom_args prom_args; + unsigned long offset = reloc_offset(); + + prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); + if (prom_rtas == (void *) -1) + return; + + RELOC(rtas_size) = 0; + call_prom(RELOC("getprop"), 4, 1, prom_rtas, + RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); + prom_print(RELOC("instantiating rtas")); + if (RELOC(rtas_size) == 0) { + RELOC(rtas_data) = 0; + } else { + /* + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. + */ + RELOC(rtas_data) = 6 << 20; + prom_print(RELOC(" at ")); + prom_print_hex(RELOC(rtas_data)); + } + + prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); + prom_print(RELOC("...")); + prom_args.service = RELOC("call-method"); + prom_args.nargs = 3; + prom_args.nret = 2; + prom_args.args[0] = RELOC("instantiate-rtas"); + prom_args.args[1] = prom_rtas; + prom_args.args[2] = (void *) RELOC(rtas_data); + RELOC(prom)(&prom_args); + i = 0; + if (prom_args.args[3] == 0) + i = (unsigned int)prom_args.args[4]; + RELOC(rtas_entry) = i; + if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) + prom_print(RELOC(" failed\n")); + else + prom_print(RELOC(" done\n")); +} + /* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. @@ -566,7 +612,7 @@ prom_init(int r3, int r4, prom_entry pp) { int chrp = 0; unsigned long mem; - ihandle prom_rtas, prom_mmu, prom_op; + ihandle prom_mmu, prom_op; unsigned long offset = reloc_offset(); int l; char *p, *d; @@ -650,47 +696,7 @@ prom_init(int r3, int r4, prom_entry pp) mem = ALIGN(mem + strlen(d) + 1); } - prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); - if (prom_rtas != (void *) -1) { - int i, nargs; - struct prom_args prom_args; - - RELOC(rtas_size) = 0; - call_prom(RELOC("getprop"), 4, 1, prom_rtas, - RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); - prom_print(RELOC("instantiating rtas")); - if (RELOC(rtas_size) == 0) { - RELOC(rtas_data) = 0; - } else { - /* - * Ask OF for some space for RTAS. - * Actually OF has bugs so we just arbitrarily - * use memory at the 6MB point. - */ - RELOC(rtas_data) = 6 << 20; - prom_print(RELOC(" at ")); - prom_print_hex(RELOC(rtas_data)); - } - prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); - prom_print(RELOC("...")); - nargs = 3; - prom_args.service = RELOC("call-method"); - prom_args.nargs = nargs; - prom_args.nret = 2; - prom_args.args[0] = RELOC("instantiate-rtas"); - prom_args.args[1] = prom_rtas; - prom_args.args[2] = (void *) RELOC(rtas_data); - RELOC(prom)(&prom_args); - if (prom_args.args[nargs] != 0) - i = 0; - else - i = (int)prom_args.args[nargs+1]; - RELOC(rtas_entry) = i; - if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) - prom_print(RELOC(" failed\n")); - else - prom_print(RELOC(" done\n")); - } + prom_instantiate_rtas(); #ifdef CONFIG_PPC64BRIDGE /* @@ -737,7 +743,7 @@ prom_init(int r3, int r4, prom_entry pp) /* We assume the phys. address size is 3 cells */ if (prom_args.args[nargs] != 0) - prom_print(RELOC(" (translate failed) ")); + prom_print(RELOC(" (translate failed)\n")); else phys = (unsigned long)prom_args.args[nargs+3]; } @@ -752,8 +758,6 @@ prom_init(int r3, int r4, prom_entry pp) if (prom_version >= 3) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); - offset = reloc_offset(); - phys = offset + KERNELBASE; } #ifdef CONFIG_BOOTX_TEXT @@ -769,7 +773,9 @@ prom_init(int r3, int r4, prom_entry pp) } #endif - prom_print(RELOC("returning from prom_init\n")); + prom_print(RELOC("returning ")); + prom_print_hex(phys); + prom_print(RELOC(" from prom_init\n")); RELOC(prom_stdout) = 0; return phys; } @@ -836,9 +842,8 @@ prom_welcome(boot_infos_t* bi, unsigned long phys) } /* Calc BAT values for mapping the display and store them - * in disp_BATH and disp_BATL. Those values are then used - * from head.S to map the display during identify_machine() - * and MMU_Init() + * in disp_BAT. Those values are then used from head.S to map + * the display during identify_machine() and MMU_Init() * * For now, the display is mapped in place (1:1). This should * be changed if the display physical address overlaps @@ -862,13 +867,13 @@ prepare_disp_BAT(void) if ((_get_PVR() >> 16) != 1) { /* 603, 604, G3, G4, ... */ addr &= 0xFF000000UL; - RELOC(disp_BATU) = addr | (BL_16M<<2) | 2; - RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + RELOC(disp_BAT[0]) = addr | (BL_16M<<2) | 2; + RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ addr &= 0xFF800000UL; - RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; - RELOC(disp_BATL) = addr | BL_8M | 0x40; + RELOC(disp_BAT[0]) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + RELOC(disp_BAT[1]) = addr | BL_8M | 0x40; } bi->logicalDisplayBase = bi->dispDeviceBase; } @@ -1003,34 +1008,52 @@ setup_disp_fake_bi(ihandle dp) unsigned address; boot_infos_t* bi; unsigned long offset = reloc_offset(); - - prom_print(RELOC("Initializing fake screen\n")); - - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), - &width, sizeof(width)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), - &height, sizeof(height)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), - &depth, sizeof(depth)); + struct pci_reg_property addrs[8]; + int i, naddrs; + char name[32]; + char *getprop = RELOC("getprop"); + + prom_print(RELOC("Initializing fake screen: ")); + + memset(name, 0, sizeof(name)); + call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_print(name); + prom_print(RELOC("\n")); + call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width)); + call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height)); + call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), + call_prom(getprop, 4, 1, dp, RELOC("linebytes"), &pitch, sizeof(pitch)); - address = 0; - if (pitch == 1) { - address = 0xfa000000; + if (pitch == 1) pitch = 0x1000; /* for strange IBM display */ - } - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), + address = 0; + call_prom(getprop, 4, 1, dp, RELOC("address"), &address, sizeof(address)); if (address == 0) { - prom_print(RELOC("Failed to get address\n")); - return; + /* look for an assigned address with a size of >= 1MB */ + naddrs = (int) call_prom(getprop, 4, 1, dp, + RELOC("assigned-addresses"), + addrs, sizeof(addrs)); + naddrs /= sizeof(struct pci_reg_property); + for (i = 0; i < naddrs; ++i) { + if (addrs[i].size_lo >= (1 << 20)) { + address = addrs[i].addr.a_lo; + /* use the BE aperture if possible */ + if (addrs[i].size_lo >= (16 << 20)) + address += (8 << 20); + break; + } + } + if (address == 0) { + prom_print(RELOC("Failed to get address\n")); + return; + } } -#if 0 /* kludge for valkyrie */ - if (strcmp(dp->name, "valkyrie") == 0) - address += 0x1000; -#endif + if (strcmp(name, RELOC("valkyrie")) == 0) + address += 0x1000; RELOC(disp_bi) = &fake_bi; bi = PTRRELOC((&fake_bi)); @@ -1334,11 +1357,19 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start) */ if (get_property(node, "interrupt-controller", &l)) { int i,j; + int cvt_irq; + + /* XXX on chrp, offset interrupt numbers for the + 8259 by 0, those for the openpic by 16 */ + cvt_irq = _machine == _MACH_chrp + && get_property(node, "interrupt-parent", NULL) == 0; np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = ipsize / isize; mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *interrupts++; + if (cvt_irq) + np->intrs[i].line = openpic_to_irq(np->intrs[i].line); np->intrs[i].sense = 0; if (isize > 1) np->intrs[i].sense = *interrupts++; @@ -2072,7 +2103,6 @@ abort() * changes. */ -__init void map_bootx_text(void) { @@ -2083,7 +2113,10 @@ map_bootx_text(void) offset = ((unsigned long) disp_bi->dispDeviceBase) - base; size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset + disp_bi->dispDeviceRect[0]; - disp_bi->logicalDisplayBase = ioremap(base, size) + offset; + disp_bi->logicalDisplayBase = ioremap(base, size); + if (disp_bi->logicalDisplayBase == 0) + return; + disp_bi->logicalDisplayBase += offset; bootx_text_mapped = 1; } @@ -2102,6 +2135,35 @@ calc_base(boot_infos_t *bi, int x, int y) return base; } +/* Adjust the display to a new resolution */ +void +bootx_update_display(unsigned long phys, int width, int height, + int depth, int pitch) +{ + if (disp_bi == 0) + return; + /* check it's the same frame buffer (within 16MB) */ + if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xff000000) + return; + + disp_bi->dispDeviceBase = (__u8 *) phys; + disp_bi->dispDeviceRect[0] = 0; + disp_bi->dispDeviceRect[1] = 0; + disp_bi->dispDeviceRect[2] = width; + disp_bi->dispDeviceRect[3] = height; + disp_bi->dispDeviceDepth = depth; + disp_bi->dispDeviceRowBytes = pitch; + if (bootx_text_mapped) { + iounmap(disp_bi->logicalDisplayBase); + bootx_text_mapped = 0; + } + map_bootx_text(); + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; +} + __pmac static void clearscreen(void) @@ -2162,6 +2224,9 @@ scrollscreen(void) (bi->dispDeviceDepth >> 3)) >> 2; int i,j; +#ifdef CONFIG_ADB_PMU + pmu_suspend(); /* PMU will not shut us down ! */ +#endif for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; @@ -2178,6 +2243,9 @@ scrollscreen(void) *(dst_ptr++) = 0; dst += (bi->dispDeviceRowBytes >> 2); } +#ifdef CONFIG_ADB_PMU + pmu_resume(); /* PMU will not shut us down ! */ +#endif } #endif /* ndef NO_SCROLL */ diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 67387cca0248..6bafa57c128f 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -35,6 +35,8 @@ #include #include #include +#include + #ifdef CONFIG_OAK #include "oak_setup.h" #endif /* CONFIG_OAK */ @@ -655,16 +657,18 @@ int parse_bootinfo(void) } /* Checks "l2cr=xxxx" command-line option */ -void ppc_setup_l2cr(char *str, int *ints) +int ppc_setup_l2cr(char *str) { if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) ) { unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); - _set_L2CR(0); - _set_L2CR(val); + _set_L2CR(0); /* force invalidate by disable cache */ + _set_L2CR(val); /* and enable it */ } + return 1; } +__setup("l2cr=", ppc_setup_l2cr); void __init ppc_init(void) { @@ -683,6 +687,9 @@ void __init setup_arch(char **cmdline_p) extern char *klimit; extern void do_init_bootmem(void); + /* so udelay does something sensible, assume <= 1000 bogomips */ + loops_per_sec = 500000000; + #ifdef CONFIG_ALL_PPC feature_init(); #endif @@ -737,6 +744,7 @@ void __init setup_arch(char **cmdline_p) if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); + sort_exception_table(); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 31e381b1731f..dd3d1ae1b557 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -154,7 +154,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, } -asmlinkage int +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) { struct pt_regs *regs = (struct pt_regs *) &uss; @@ -232,7 +232,7 @@ struct rt_sigframe * Each of these things must be a multiple of 16 bytes in size. * */ -asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe *rt_sf; struct sigcontext_struct sigctx; @@ -301,7 +301,6 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) return ret; badframe: - lock_kernel(); do_exit(SIGSEGV); } @@ -351,7 +350,6 @@ badframe: printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -418,7 +416,6 @@ int sys_sigreturn(struct pt_regs *regs) return ret; badframe: - lock_kernel(); do_exit(SIGSEGV); } @@ -460,7 +457,6 @@ badframe: printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -541,7 +537,6 @@ badframe: regs, frame, *newspp); printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -645,7 +640,6 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* FALLTHRU */ default: - lock_kernel(); sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; @@ -663,6 +657,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); + break; } if (regs->trap == 0x0C00 /* System Call! */ && diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 4c46d380cd46..0a66d6c6b406 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -62,72 +62,62 @@ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; int start_secondary(void *); extern int cpu_idle(void *unused); u_int openpic_read(volatile u_int *addr); +void smp_call_function_interrupt(void); +void smp_message_pass(int target, int msg, unsigned long data, int wait); +/* register for interrupting the primary processor on the powersurge */ +/* N.B. this is actually the ethernet ROM! */ +#define PSURGE_PRI_INTR 0xf3019000 /* register for interrupting the secondary processor on the powersurge */ -#define PSURGE_INTR ((volatile unsigned *)0xf80000c0) +#define PSURGE_SEC_INTR 0xf80000c0 +/* register for storing the start address for the secondary processor */ +#define PSURGE_START 0xf2800000 +/* virtual addresses for the above */ +volatile u32 *psurge_pri_intr; +volatile u32 *psurge_sec_intr; +volatile u32 *psurge_start; + +/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. */ +#define PPC_MSG_CALL_FUNCTION 0 +#define PPC_MSG_RESCHEDULE 1 +#define PPC_MSG_INVALIDATE_TLB 2 +#define PPC_MSG_XMON_BREAK 3 + +static inline void set_tb(unsigned int upper, unsigned int lower) +{ + mtspr(SPRN_TBWU, upper); + mtspr(SPRN_TBWL, lower); +} void smp_local_timer_interrupt(struct pt_regs * regs) { int cpu = smp_processor_id(); - extern void update_one_process(struct task_struct *,unsigned long, - unsigned long,unsigned long,int); - if (!--prof_counter[cpu]) { - int user=0,system=0; - struct task_struct * p = current; - - /* - * After doing the above, we need to make like - * a normal interrupt - otherwise timer interrupts - * ignore the global interrupt lock, which is the - * WrongThing (tm) to do. - */ - - if (user_mode(regs)) - user=1; - else - system=1; - - if (p->pid) { - update_one_process(p, 1, user, system, cpu); - - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - current->need_resched = 1; - } - if (p->nice > 0) { - kstat.cpu_nice += user; - kstat.per_cpu_nice[cpu] += user; - } else { - kstat.cpu_user += user; - kstat.per_cpu_user[cpu] += user; - } - kstat.cpu_system += system; - kstat.per_cpu_system[cpu] += system; - - } + if (!--prof_counter[cpu]) { + update_process_times(user_mode(regs)); prof_counter[cpu]=prof_multiplier[cpu]; } } -void smp_message_recv(int msg) +void smp_message_recv(int msg, struct pt_regs *regs) { ipi_count++; - switch( msg ) - { - case MSG_STOP_CPU: - __cli(); - while (1) ; + switch( msg ) { + case PPC_MSG_CALL_FUNCTION: + smp_call_function_interrupt(); break; - case MSG_RESCHEDULE: + case PPC_MSG_RESCHEDULE: current->need_resched = 1; break; - case MSG_INVALIDATE_TLB: + case PPC_MSG_INVALIDATE_TLB: _tlbia(); - case 0xf0f0: /* pmac syncing time bases - just return */ break; +#ifdef CONFIG_XMON + case PPC_MSG_XMON_BREAK: + xmon(regs); + break; +#endif /* CONFIG_XMON */ default: printk("SMP %d: smp_message_recv(): unknown msg %d\n", smp_processor_id(), msg); @@ -142,25 +132,38 @@ void smp_message_recv(int msg) * smp_message[]. * * This is because don't have several IPI's on the PowerSurge even though - * we do on the chrp. It would be nice to use actual IPI's such as with openpic - * rather than this. + * we do on the chrp. It would be nice to use actual IPI's such as with + * openpic rather than this. * -- Cort */ int pmac_smp_message[NR_CPUS]; -void pmac_smp_message_recv(void) +void pmac_smp_message_recv(struct pt_regs *regs) { - int msg = pmac_smp_message[smp_processor_id()]; - + int cpu = smp_processor_id(); + int msg; + /* clear interrupt */ - out_be32(PSURGE_INTR, ~0); - - /* make sure msg is for us */ - if ( msg == -1 ) return; + if (cpu == 1) + out_be32(psurge_sec_intr, ~0); + + if (smp_num_cpus < 2) + return; + + /* make sure there is a message there */ + msg = pmac_smp_message[cpu]; + if (msg == 0) + return; - smp_message_recv(msg); - /* reset message */ - pmac_smp_message[smp_processor_id()] = -1; + pmac_smp_message[cpu] = 0; + + smp_message_recv(msg - 1, regs); +} + +void +pmac_primary_intr(int irq, void *d, struct pt_regs *regs) +{ + pmac_smp_message_recv(regs); } /* @@ -171,7 +174,7 @@ void pmac_smp_message_recv(void) void smp_send_tlb_invalidate(int cpu) { if ( (_get_PVR()>>16) == 8 ) - smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0); + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0); } void smp_send_reschedule(int cpu) @@ -187,18 +190,135 @@ void smp_send_reschedule(int cpu) */ /* This is only used if `cpu' is running an idle task, so it will reschedule itself anyway... */ - smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); + smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0); +} + +#ifdef CONFIG_XMON +void smp_send_xmon_break(int cpu) +{ + smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0); +} +#endif /* CONFIG_XMON */ + +static void stop_this_cpu(void *dummy) +{ + __cli(); + while (1) + ; } void smp_send_stop(void) { - smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0); + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; +} + +/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + * Stolen from the i386 version. + */ +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; + +static volatile struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} *call_data = NULL; + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) +/* + * [SUMMARY] Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * currently unused. + * 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. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +{ + struct call_data_struct data; + int ret = -1, cpus = smp_num_cpus-1; + int timeout; + + if (!cpus) + return 0; + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + /* Send a message to all other CPUs and wait for them to respond */ + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0); + + /* Wait for response */ + timeout = 1000000; + while (atomic_read(&data.started) != cpus) { + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", + smp_processor_id(), atomic_read(&data.started)); + goto out; + } + barrier(); + udelay(1); + } + + if (wait) { + timeout = 1000000; + while (atomic_read(&data.finished) != cpus) { + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", + smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); + goto out; + } + barrier(); + udelay(1); + } + } + ret = 0; + + out: + spin_unlock_bh(&call_lock); + return ret; +} + +void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function + */ + atomic_inc(&call_data->started); + /* + * At this point the info structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) + atomic_inc(&call_data->finished); } void smp_message_pass(int target, int msg, unsigned long data, int wait) { - int i; - if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) ) return; @@ -212,31 +332,29 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) * the recipient won't know the message was destined * for it. -- Cort */ - for ( i = 0; i <= smp_num_cpus ; i++ ) - pmac_smp_message[i] = -1; - switch( target ) - { - case MSG_ALL: - pmac_smp_message[smp_processor_id()] = msg; - /* fall through */ - case MSG_ALL_BUT_SELF: - for ( i = 0 ; i < smp_num_cpus ; i++ ) - if ( i != smp_processor_id () ) - pmac_smp_message[i] = msg; - break; - default: - pmac_smp_message[target] = msg; - break; + if (smp_processor_id() == 0) { + /* primary cpu */ + if (target == 1 || target == MSG_ALL_BUT_SELF + || target == MSG_ALL) { + pmac_smp_message[1] = msg + 1; + /* interrupt secondary processor */ + out_be32(psurge_sec_intr, ~0); + out_be32(psurge_sec_intr, 0); + } + } else { + /* secondary cpu */ + if (target == 0 || target == MSG_ALL_BUT_SELF + || target == MSG_ALL) { + pmac_smp_message[0] = msg + 1; + /* interrupt primary processor */ + in_be32(psurge_pri_intr); + } + } + if (target == smp_processor_id() || target == MSG_ALL) { + /* sending a message to ourself */ + /* XXX maybe we shouldn't do this if ints are off */ + smp_message_recv(msg, NULL); } - /* interrupt secondary processor */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); - /* - * Assume for now that the secondary doesn't send - * IPI's -- Cort - */ - /* interrupt primary */ - /**(volatile unsigned long *)(0xf3019000);*/ break; case _MACH_chrp: case _MACH_prep: @@ -261,7 +379,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) #else /* CONFIG_POWER4 */ /* for now, only do reschedule messages since we only have one IPI */ - if (msg != MSG_RESCHEDULE) + if (msg != PPC_MSG_RESCHEDULE) break; for (i = 0; i < smp_num_cpus; ++i) { if (target == MSG_ALL || target == i @@ -319,7 +437,10 @@ void __init smp_boot_cpus(void) { case _MACH_Pmac: /* assume powersurge board - 2 processors -- Cort */ - cpu_nr = 2; + cpu_nr = 2; + psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); + psurge_sec_intr = ioremap(PSURGE_SEC_INTR, 4); + psurge_start = ioremap(PSURGE_START, 4); break; case _MACH_chrp: if (OpenPIC) @@ -370,13 +491,11 @@ void __init smp_boot_cpus(void) { case _MACH_Pmac: /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) = - (unsigned long)__secondary_start_psurge-KERNELBASE; - eieio(); + out_be32(psurge_start, __pa(__secondary_start_psurge)); /* interrupt secondary to begin executing code */ - out_be32(PSURGE_INTR, ~0); + out_be32(psurge_sec_intr, ~0); udelay(1); - out_be32(PSURGE_INTR, 0); + out_be32(psurge_sec_intr, 0); break; case _MACH_chrp: *(unsigned long *)KERNELBASE = i; @@ -399,9 +518,6 @@ void __init smp_boot_cpus(void) if ( cpu_callin_map[i] ) { printk("Processor %d found.\n", i); - /* this sync's the decr's -- Cort */ - if ( _machine == _MACH_Pmac ) - set_dec(decrementer_count); smp_num_cpus++; } else { printk("Processor %d is stuck.\n", i); @@ -415,9 +531,25 @@ void __init smp_boot_cpus(void) { /* reset the entry point so if we get another intr we won't * try to startup again */ - *(volatile unsigned long *)(0xf2800000) = 0x100; - /* send interrupt to other processors to start decr's on all cpus */ - smp_message_pass(1,0xf0f0, 0, 0); + out_be32(psurge_start, 0x100); + if (request_irq(30, pmac_primary_intr, 0, "primary IPI", 0)) + printk(KERN_ERR "Couldn't get primary IPI interrupt"); + /* + * The decrementers of both cpus are frozen at this point + * until we give the secondary cpu another interrupt. + * We set them both to decrementer_count and then send + * the interrupt. This should get the decrementers + * synchronized. + * -- paulus. + */ + set_dec(tb_ticks_per_jiffy); + if ((_get_PVR() >> 16) != 1) { + set_tb(0, 0); /* set timebase if not 601 */ + last_jiffy_stamp(0) = 0; + } + out_be32(psurge_sec_intr, ~0); + udelay(1); + out_be32(psurge_sec_intr, 0); } } @@ -447,8 +579,11 @@ int __init start_secondary(void *unused) void __init smp_callin(void) { smp_store_cpu_info(current->processor); - set_dec(decrementer_count); - + set_dec(tb_ticks_per_jiffy); + if (_machine == _MACH_Pmac && (_get_PVR() >> 16) != 1) { + set_tb(0, 0); /* set timebase if not 601 */ + last_jiffy_stamp(current->processor) = 0; + } init_idle(); cpu_callin_map[current->processor] = 1; diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 314c1240c714..d0fee43442d4 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -45,7 +45,7 @@ check_bugs(void) { } -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) +int sys_ioperm(unsigned long from, unsigned long num, int on) { printk(KERN_ERR "sys_ioperm()\n"); return -EIO; @@ -74,7 +74,7 @@ int sys_modify_ldt(int a1, int a2, int a3, int a4) * * This is really horribly ugly. */ -asmlinkage int +int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { int version, ret; @@ -172,7 +172,7 @@ sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage int sys_pipe(int *fildes) +int sys_pipe(int *fildes) { int fd[2]; int error; @@ -185,19 +185,19 @@ asmlinkage int sys_pipe(int *fildes) return error; } -asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) +unsigned long sys_mmap(unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) { struct file * file = NULL; int ret = -EBADF; + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { if (!(file = fget(fd))) goto out; } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); down(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, offset); up(¤t->mm->mmap_sem); @@ -207,7 +207,7 @@ out: return ret; } -extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); /* * Due to some executables calling the wrong select we sometimes @@ -215,7 +215,7 @@ extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timev * (a single ptr to them all args passed) then calls * sys_select() with the appropriate args. -- Cort */ -asmlinkage int +int ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { if ( (unsigned long)n >= 4096 ) @@ -232,14 +232,14 @@ ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) return sys_select(n, inp, outp, exp, tvp); } -asmlinkage int sys_pause(void) +int sys_pause(void) { current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND; } -asmlinkage int sys_uname(struct old_utsname * name) +int sys_uname(struct old_utsname * name) { int err = -EFAULT; @@ -250,7 +250,7 @@ asmlinkage int sys_uname(struct old_utsname * name) return err; } -asmlinkage int sys_olduname(struct oldold_utsname * name) +int sys_olduname(struct oldold_utsname * name) { int error; diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index ff161d3574d9..f71c8cbbf811 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -6,6 +6,27 @@ * Paul Mackerras' version and mine for PReP and Pmac. * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net). * + * First round of bugfixes by Gabriel Paubert (paubert@iram.es) + * to make clock more stable (2.4.0-test5). The only thing + * that this code assumes is that the timebases have been synchronized + * by firmware on SMP and are never stopped (never do sleep + * on SMP then, nap and doze are OK). + * + * TODO (not necessarily in this file): + * - improve precision and reproducibility of timebase frequency + * measurement at boot time. + * - get rid of xtime_lock for gettimeofday (generic kernel problem + * to be implemented on all architectures for SMP scalability and + * eventually implementing gettimeofday without entering the kernel). + * - put all time/clock related variables in a single structure + * to minimize number of cache lines touched by gettimeofday() + * - for astronomical applications: add a new function to get + * non ambiguous timestamps even around leap seconds. This needs + * a new timestamp format and a good name. + * + * + * The following comment is partially obsolete (at least the long wait + * is no more a valid reason): * Since the MPC8xx has a programmable interrupt timer, I decided to * use that rather than the decrementer. Two reasons: 1.) the clock * frequency is low, causing 2.) a long wait in the timer interrupt @@ -49,18 +70,32 @@ void smp_local_timer_interrupt(struct pt_regs *); /* keep track of when we need to update the rtc */ -time_t last_rtc_update = 0; +time_t last_rtc_update; extern rwlock_t xtime_lock; /* The decrementer counts down by 128 every 128ns on a 601. */ #define DECREMENTER_COUNT_601 (1000000000 / HZ) -#define COUNT_PERIOD_NUM_601 1 -#define COUNT_PERIOD_DEN_601 1000 -unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ -unsigned count_period_num; /* 1 decrementer count equals */ -unsigned count_period_den; /* count_period_num / count_period_den us */ -unsigned long last_tb; +unsigned tb_ticks_per_jiffy; +unsigned tb_to_us; +unsigned tb_last_stamp; + +extern unsigned long wall_jiffies; + +static long time_offset; + +/* Timer interrupt helper function */ +static inline int tb_delta(unsigned *jiffy_stamp) { + int delta; + if (__USE_RTC()) { + delta = get_rtcl(); + if (delta < *jiffy_stamp) *jiffy_stamp -= 1000000000; + delta -= *jiffy_stamp; + } else { + delta = get_tbl() - *jiffy_stamp; + } + return delta; +} /* * timer_interrupt - gets called when the decrementer overflows, @@ -69,88 +104,56 @@ unsigned long last_tb; */ int timer_interrupt(struct pt_regs * regs) { - int dval, d; -#if 0 - unsigned long flags; -#endif + int next_dec; unsigned long cpu = smp_processor_id(); - + unsigned jiffy_stamp = last_jiffy_stamp(cpu); + hardirq_enter(cpu); -#ifdef CONFIG_SMP - { - unsigned int loops = 100000000; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* CONFIG_SMP */ - dval = get_dec(); - /* - * Wait for the decrementer to change, then jump - * in and add decrementer_count to its value - * (quickly, before it changes again!) - */ - while ((d = get_dec()) == dval) - ; - asm volatile("mftb %0" : "=r" (last_tb) ); - /* - * Don't play catchup between the call to time_init() - * and sti() in init/main.c. - * - * This also means if we're delayed for > HZ - * we lose those ticks. If we're delayed for > HZ - * then we have something wrong anyway, though. - * - * -- Cort - */ - if ( d < (-1*decrementer_count) ) - d = 0; - set_dec(d + decrementer_count); - if ( !smp_processor_id() ) - { + do { + jiffy_stamp += tb_ticks_per_jiffy; + if (smp_processor_id()) continue; + /* We are in an interrupt, no need to save/restore flags */ + write_lock(&xtime_lock); + tb_last_stamp = jiffy_stamp; do_timer(regs); -#if 0 - /* -- BenH -- I'm removing this for now since it can cause various - * troubles with local-time RTCs. Now that we have a - * /dev/rtc that uses ppc_md.set_rtc_time() on mac, it - * should be possible to program the RTC from userland - * in all cases. - */ + /* - * update the rtc when needed + * update the rtc when needed, this should be performed on the + * right fraction of a second. Half or full second ? + * Full second works on mk48t59 clocks, others need testing. + * Note that this update is basically only used through + * the adjtimex system calls. Setting the HW clock in + * any other way is a /dev/rtc and userland business. + * This is still wrong by -0.5/+1.5 jiffies because of the + * timer interrupt resolution and possible delay, but here we + * hit a quantization limit which can only be solved by higher + * resolution timers and decoupling time management from timer + * interrupts. This is also wrong on the clocks + * which require being written at the half second boundary. + * We should have an rtc call that only sets the minutes and + * seconds like on Intel to avoid problems with non UTC clocks. */ - read_lock_irqsave(&xtime_lock, flags); - if ( (time_status & STA_UNSYNC) && - ((xtime.tv_sec > last_rtc_update + 60) || - (xtime.tv_sec < last_rtc_update)) ) - { - if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; + if ( (time_status & STA_UNSYNC) == 0 && + xtime.tv_sec - last_rtc_update >= 659 && + abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ && + jiffies - wall_jiffies == 1) { + if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0) + last_rtc_update = xtime.tv_sec+1; else - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec; + /* Try again one minute later */ + last_rtc_update += 60; } - read_unlock_irqrestore(&xtime_lock, flags); -#endif - } + write_unlock(&xtime_lock); + } while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0); + set_dec(next_dec); + last_jiffy_stamp(cpu) = jiffy_stamp; + #ifdef CONFIG_SMP smp_local_timer_interrupt(regs); #endif - if ( ppc_md.heartbeat && !ppc_md.heartbeat_count--) + if (ppc_md.heartbeat && !ppc_md.heartbeat_count--) ppc_md.heartbeat(); hardirq_exit(cpu); @@ -162,74 +165,138 @@ int timer_interrupt(struct pt_regs * regs) */ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, diff; + unsigned long flags; + unsigned delta, lost_ticks, usec, sec; - save_flags(flags); - cli(); read_lock_irqsave(&xtime_lock, flags); - *tv = xtime; + sec = xtime.tv_sec; + usec = xtime.tv_usec; + delta = tb_ticks_since(tb_last_stamp); +#ifdef CONFIG_SMP + /* As long as timebases are not in sync, gettimeofday can only + * have jiffy resolution on SMP. + */ + if (_machine != _MACH_Pmac) + delta = 0; +#endif /* CONFIG_SMP */ + lost_ticks = jiffies - wall_jiffies; read_unlock_irqrestore(&xtime_lock, flags); - /* XXX we don't seem to have the decrementers synced properly yet */ -#ifndef CONFIG_SMP - asm volatile("mftb %0" : "=r" (diff) ); - diff -= last_tb; - tv->tv_usec += diff * count_period_num / count_period_den; - tv->tv_sec += tv->tv_usec / 1000000; - tv->tv_usec = tv->tv_usec % 1000000; -#endif - - restore_flags(flags); + + usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta); + while (usec > 1000000) { + sec++; + usec -= 1000000; + } + tv->tv_sec = sec; + tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) { unsigned long flags; - int frac_tick; - - last_rtc_update = 0; /* so the rtc gets updated soon */ - - frac_tick = tv->tv_usec % (1000000 / HZ); - save_flags(flags); - cli(); + int tb_delta, new_usec, new_sec; + write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = tv->tv_sec; - xtime.tv_usec = tv->tv_usec - frac_tick; - write_unlock_irqrestore(&xtime_lock, flags); - set_dec(frac_tick * count_period_den / count_period_num); + /* Updating the RTC is not the job of this code. If the time is + * stepped under NTP, the RTC will be update after STA_UNSYNC + * is cleared. Tool like clock/hwclock either copy the RTC + * to the system time, in which case there is no point in writing + * to the RTC again, or write to the RTC but then they don't call + * settimeofday to perform this operation. Note also that + * we don't touch the decrementer since: + * a) it would lose timer interrupt synchronization on SMP + * (if it is working one day) + * b) it could make one jiffy spuriously shorter or longer + * which would introduce another source of uncertainty potentially + * harmful to relatively short timers. + */ + + /* This works perfectly on SMP only if the tb are in sync but + * guarantees an error < 1 jiffy even if they are off by eons, + * still reasonable when gettimeofday resolution is 1 jiffy. + */ + tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id())); + tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; + new_sec = tv->tv_sec; + new_usec = tv->tv_usec - mulhwu(tb_to_us, tb_delta); + while (new_usec <0) { + new_sec--; + new_usec += 1000000; + } + xtime.tv_usec = new_usec; + xtime.tv_sec = new_sec; + + /* In case of a large backwards jump in time with NTP, we want the + * clock to be updated as soon as the PLL is again in lock. + */ + last_rtc_update = new_sec - 658; + time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - restore_flags(flags); + write_unlock_irqrestore(&xtime_lock, flags); } void __init time_init(void) { + time_t sec, old_sec; + unsigned old_stamp, stamp, elapsed; + /* This function is only called on the boot processor */ unsigned long flags; + if (ppc_md.time_init != NULL) - { - ppc_md.time_init(); - } + time_offset = ppc_md.time_init(); - if ((_get_PVR() >> 16) == 1) { + if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ - decrementer_count = DECREMENTER_COUNT_601; - count_period_num = COUNT_PERIOD_NUM_601; - count_period_den = COUNT_PERIOD_DEN_601; - } else if (!smp_processor_id()) { + tb_ticks_per_jiffy = DECREMENTER_COUNT_601; + /* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */ + tb_to_us = 0x418937; + } else { ppc_md.calibrate_decr(); } + /* Now that the decrementer is calibrated, it can be used in case the + * clock is stuck, but the fact that we have to handle the 601 + * makes things more complex. Repeatedly read the RTC until the + * next second boundary to try to achieve some precision... + */ + stamp = get_native_tbl(); + sec = ppc_md.get_rtc_time(); + elapsed = 0; + do { + old_stamp = stamp; + old_sec = sec; + stamp = get_native_tbl(); + if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000; + elapsed += stamp - old_stamp; + sec = ppc_md.get_rtc_time(); + } while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy); + if (sec==old_sec) { + printk("Warning: real time clock seems stuck!\n"); + } write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = ppc_md.get_rtc_time(); + xtime.tv_sec = sec; + last_jiffy_stamp(0) = tb_last_stamp = stamp; xtime.tv_usec = 0; + /* No update now, we just read the time from the RTC ! */ + last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); + /* Not exact, but the timer interrupt takes care of this */ + set_dec(tb_ticks_per_jiffy); - set_dec(decrementer_count); - /* allow setting the time right away */ - last_rtc_update = 0; + /* If platform provided a timezone (pmac), we correct the time + * using do_sys_settimeofday() which in turn calls warp_clock() + */ + if (time_offset) { + struct timezone tz; + tz.tz_minuteswest = -time_offset / 60; + tz.tz_dsttime = 0; + do_sys_settimeofday(NULL, &tz); + } } #define TICK_SIZE tick @@ -322,3 +389,31 @@ void to_tm(int tim, struct rtc_time * tm) */ GregorianDay(tm); } + +/* Auxiliary function to compute scaling factors */ +/* Actually the choice of a timebase running at 1/4 the of the bus + * frequency giving resolution of a few tens of nanoseconds is quite nice. + * It makes this computation very precise (27-28 bits typically) which + * is optimistic considering the stability of most processor clock + * oscillators and the precision with which the timebase frequency + * is measured but does not harm. + */ +unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { + unsigned mlt=0, tmp, err; + /* No concern for performance, it's done once: use a stupid + * but safe and compact method to find the multiplier. + */ + for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { + if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; + } + /* We might still be off by 1 for the best approximation. + * A side effect of this is that if outscale is too large + * the returned value will be zero. + * Many corner cases have been checked and seem to work, + * some might have been forgotten in the test however. + */ + err = inscale*(mlt+1); + if (err <= inscale/2) mlt++; + return mlt; +} + diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 0701f7118e34..3b7473dda3f5 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -87,45 +87,76 @@ _exception(int signr, struct pt_regs *regs) void MachineCheckException(struct pt_regs *regs) { - if ( !user_mode(regs) ) - { -#if defined(CONFIG_8xx) && defined(CONFIG_PCI) - /* the qspan pci read routines can cause machine checks -- Cort */ - bad_page_fault(regs, regs->dar); +#ifdef CONFIG_ALL_PPC + unsigned long fixup; +#endif /* CONFIG_ALL_PPC */ + + if (user_mode(regs)) { + _exception(SIGSEGV, regs); return; + } + +#if defined(CONFIG_8xx) && defined(CONFIG_PCI) + /* the qspan pci read routines can cause machine checks -- Cort */ + bad_page_fault(regs, regs->dar); + return; #endif #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - if (debugger_fault_handler) { - debugger_fault_handler(regs); - return; - } + if (debugger_fault_handler) { + debugger_fault_handler(regs); + return; + } #endif - printk("Machine check in kernel mode.\n"); - printk("Caused by (from SRR1=%lx): ", regs->msr); - switch (regs->msr & 0xF0000) { - case 0x80000: - printk("Machine check signal\n"); - break; - case 0x40000: - printk("Transfer error ack signal\n"); - break; - case 0x20000: - printk("Data parity error signal\n"); - break; - case 0x10000: - printk("Address parity error signal\n"); - break; - default: - printk("Unknown values in msr\n"); + +#ifdef CONFIG_ALL_PPC + /* + * I/O accesses can cause machine checks on powermacs. + * Check if the NIP corresponds to the address of a sync + * instruction for which there is an entry in the exception + * table. + */ + if (regs->msr & (0x80000 | 0x40000) + && (fixup = search_exception_table(regs->nip)) != 0) { + /* + * Check that it's a sync instruction. + * As the address is in the exception table + * we should be able to read the instr there. + */ + if (*(unsigned int *)regs->nip == 0x7c0004ac) { + unsigned int lsi = ((unsigned int *)regs->nip)[-1]; + int rb = (lsi >> 11) & 0x1f; + printk(KERN_DEBUG "%s bad port %lx at %lx\n", + (lsi & 0x100)? "OUT to": "IN from", + regs->gpr[rb] - _IO_BASE, regs->nip); + regs->nip = fixup; + return; } - show_regs(regs); + } +#endif /* CONFIG_ALL_PPC */ + printk("Machine check in kernel mode.\n"); + printk("Caused by (from SRR1=%lx): ", regs->msr); + switch (regs->msr & 0xF0000) { + case 0x80000: + printk("Machine check signal\n"); + break; + case 0x40000: + printk("Transfer error ack signal\n"); + break; + case 0x20000: + printk("Data parity error signal\n"); + break; + case 0x10000: + printk("Address parity error signal\n"); + break; + default: + printk("Unknown values in msr\n"); + } + show_regs(regs); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - debugger(regs); + debugger(regs); #endif - print_backtrace((unsigned long *)regs->gpr[1]); - panic("machine check"); - } - _exception(SIGSEGV, regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); } void @@ -166,6 +197,46 @@ RunModeException(struct pt_regs *regs) _exception(SIGTRAP, regs); } +/* Illegal instruction emulation support. Originally written to + * provide the PVR to user applications using the mfspr rd, PVR. + * Return non-zero if we can't emulate, or EFAULT if the associated + * memory access caused an access fault. Return zero on success. + * + * There are a couple of ways to do this, either "decode" the instruction + * or directly match lots of bits. In this case, matching lots of + * bits is faster and easier. + * + */ +#define INST_MFSPR_PVR 0x7c1f42a6 +#define INST_MFSPR_PVR_MASK 0xfc1fffff + +static int +emulate_instruction(struct pt_regs *regs) +{ + uint instword; + uint rd; + uint retval; + + retval = EFAULT; + + if (!user_mode(regs)) + return retval; + + if (get_user(instword, (uint *)(regs->nip))) + return retval; + + /* Emulate the mfspr rD, PVR. + */ + if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = _get_PVR(); + retval = 0; + } + if (retval == 0) + regs->nip += 4; + return(retval); +} + void ProgramCheckException(struct pt_regs *regs) { @@ -193,7 +264,14 @@ ProgramCheckException(struct pt_regs *regs) #endif _exception(SIGTRAP, regs); } else { - _exception(SIGILL, regs); + /* Try to emulate it if we should. */ + int errcode; + if ((errcode = emulate_instruction(regs))) { + if (errcode == EFAULT) + _exception(SIGBUS, regs); + else + _exception(SIGILL, regs); + } } #endif } diff --git a/arch/ppc/kernel/walnut_setup.c b/arch/ppc/kernel/walnut_setup.c index 768c36a94735..e48a3e61a9ed 100644 --- a/arch/ppc/kernel/walnut_setup.c +++ b/arch/ppc/kernel/walnut_setup.c @@ -226,10 +226,11 @@ walnut_halt(void) /* * Document me. */ -void __init +long __init walnut_time_init(void) { /* XXX - Implement me */ + return 0; } /* diff --git a/arch/ppc/kernel/xics.c b/arch/ppc/kernel/xics.c index a9772821bf96..2b277f952ee6 100644 --- a/arch/ppc/kernel/xics.c +++ b/arch/ppc/kernel/xics.c @@ -166,7 +166,7 @@ xics_get_irq(struct pt_regs *regs) void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) { qirr_info(smp_processor_id()) = 0xff; - smp_message_recv(MSG_RESCHEDULE); + smp_message_recv(MSG_RESCHEDULE, regs); } void xics_cause_IPI(int cpu) diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index 1c4f1f78edf7..df99728be2e4 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -12,10 +12,70 @@ #include #include -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 +#if defined(CONFIG_4xx) || defined(CONFIG_8xx) +#define CACHE_LINE_SIZE 16 +#define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 +#elif !defined(CONFIG_PPC64BRIDGE) +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 +#else +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 +#endif /* CONFIG_4xx || CONFIG_8xx */ + +#define COPY_16_BYTES \ + lwz r7,4(r4); \ + lwz r8,8(r4); \ + lwz r9,12(r4); \ + lwzu r10,16(r4); \ + stw r7,4(r6); \ + stw r8,8(r6); \ + stw r9,12(r6); \ + stwu r10,16(r6) + +#define COPY_16_BYTES_WITHEX(n) \ +8 ## n ## 0: \ + lwz r7,4(r4); \ +8 ## n ## 1: \ + lwz r8,8(r4); \ +8 ## n ## 2: \ + lwz r9,12(r4); \ +8 ## n ## 3: \ + lwzu r10,16(r4); \ +8 ## n ## 4: \ + stw r7,4(r6); \ +8 ## n ## 5: \ + stw r8,8(r6); \ +8 ## n ## 6: \ + stw r9,12(r6); \ +8 ## n ## 7: \ + stwu r10,16(r6) + +#define COPY_16_BYTES_EXCODE(n) \ +9 ## n ## 0: \ + addi r5,r5,-(16 * n); \ + b 104f; \ +9 ## n ## 1: \ + addi r5,r5,-(16 * n); \ + b 105f; \ +.section __ex_table,"a"; \ + .align 2; \ + .long 8 ## n ## 0b,9 ## n ## 0b; \ + .long 8 ## n ## 1b,9 ## n ## 0b; \ + .long 8 ## n ## 2b,9 ## n ## 0b; \ + .long 8 ## n ## 3b,9 ## n ## 0b; \ + .long 8 ## n ## 4b,9 ## n ## 1b; \ + .long 8 ## n ## 5b,9 ## n ## 1b; \ + .long 8 ## n ## 6b,9 ## n ## 1b; \ + .long 8 ## n ## 7b,9 ## n ## 1b; \ +.text + +CACHELINE_BYTES = CACHE_LINE_SIZE +LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE +CACHELINE_MASK = (CACHE_LINE_SIZE-1) .globl strcpy strcpy: @@ -105,7 +165,14 @@ cacheable_memzero: bdnz 4b 3: mtctr r9 li r7,4 +#if !defined(CONFIG_8xx) 10: dcbz r7,r6 +#else +10: stw r4, 4(r6) + stw r4, 8(r6) + stw r4, 12(r6) + stw r4, 16(r6) +#endif addi r6,r6,CACHELINE_BYTES bdnz 10b clrlwi r5,r8,32-LG_CACHELINE_BYTES @@ -202,23 +269,24 @@ cacheable_memcpy: li r11,4 mtctr r0 beq 63f -53: dcbz r11,r6 - lwz r7,4(r4) - lwz r8,8(r4) - lwz r9,12(r4) - lwzu r10,16(r4) - stw r7,4(r6) - stw r8,8(r6) - stw r9,12(r6) - stwu r10,16(r6) - lwz r7,4(r4) - lwz r8,8(r4) - lwz r9,12(r4) - lwzu r10,16(r4) - stw r7,4(r6) - stw r8,8(r6) - stw r9,12(r6) - stwu r10,16(r6) +53: +#if !defined(CONFIG_8xx) + dcbz r11,r6 +#endif + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif bdnz 53b 63: srwi. r0,r5,2 @@ -380,25 +448,59 @@ __copy_tofrom_user: 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ clrlwi r5,r5,32-LG_CACHELINE_BYTES li r11,4 - mtctr r0 beq 63f -53: dcbz r11,r6 -10: lwz r7,4(r4) -11: lwz r8,8(r4) -12: lwz r9,12(r4) -13: lwzu r10,16(r4) -14: stw r7,4(r6) -15: stw r8,8(r6) -16: stw r9,12(r6) -17: stwu r10,16(r6) -20: lwz r7,4(r4) -21: lwz r8,8(r4) -22: lwz r9,12(r4) -23: lwzu r10,16(r4) -24: stw r7,4(r6) -25: stw r8,8(r6) -26: stw r9,12(r6) -27: stwu r10,16(r6) + +#if !defined(CONFIG_8xx) + /* Here we decide how far ahead to prefetch the source */ +#if MAX_COPY_PREFETCH > 1 + /* Heuristically, for large transfers we prefetch + MAX_COPY_PREFETCH cachelines ahead. For small transfers + we prefetch 1 cacheline ahead. */ + cmpwi r0,MAX_COPY_PREFETCH + li r7,1 + li r3,4 + ble 111f + li r7,MAX_COPY_PREFETCH +111: mtctr r7 +112: dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES + bdnz 112b +#else /* MAX_COPY_PREFETCH == 1 */ + li r3,CACHELINE_BYTES + 4 + dcbt r11,r4 +#endif /* MAX_COPY_PREFETCH */ +#endif /* CONFIG_8xx */ + + mtctr r0 +53: +#if !defined(CONFIG_8xx) + dcbt r3,r4 + dcbz r11,r6 +#endif +/* had to move these to keep extable in order */ + .section __ex_table,"a" + .align 2 + .long 70b,100f + .long 71b,101f + .long 72b,102f + .long 73b,103f + .long 53b,105f + .text +/* the main body of the cacheline loop */ + COPY_16_BYTES_WITHEX(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_WITHEX(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_WITHEX(2) + COPY_16_BYTES_WITHEX(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_WITHEX(4) + COPY_16_BYTES_WITHEX(5) + COPY_16_BYTES_WITHEX(6) + COPY_16_BYTES_WITHEX(7) +#endif +#endif +#endif bdnz 53b 63: srwi. r0,r5,2 @@ -434,15 +536,31 @@ __copy_tofrom_user: 103: li r4,1 91: li r3,2 b 99f -/* read fault in 2nd half of cacheline loop */ -106: addi r5,r5,-16 -/* read fault in 1st half of cacheline loop */ + +/* + * this stuff handles faults in the cacheline loop and branches to either + * 104f (if in read part) or 105f (if in write part), after updating r5 + */ + COPY_16_BYTES_EXCODE(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_EXCODE(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_EXCODE(2) + COPY_16_BYTES_EXCODE(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_EXCODE(4) + COPY_16_BYTES_EXCODE(5) + COPY_16_BYTES_EXCODE(6) + COPY_16_BYTES_EXCODE(7) +#endif +#endif +#endif + +/* read fault in cacheline loop */ 104: li r4,0 b 92f -/* write fault in 2nd half of cacheline loop */ -107: addi r5,r5,-16 /* fault on dcbz (effectively a write fault) */ -/* or write fault in 1st half of cacheline loop */ +/* or write fault in cacheline loop */ 105: li r4,1 92: li r3,LG_CACHELINE_BYTES b 99f @@ -485,36 +603,15 @@ __copy_tofrom_user: bdnz 114b 120: blr -.section __ex_table,"a" + .section __ex_table,"a" .align 2 - .long 70b,100b - .long 71b,101b - .long 72b,102b - .long 73b,103b - .long 53b,105b - .long 10b,104b - .long 11b,104b - .long 12b,104b - .long 13b,104b - .long 14b,105b - .long 15b,105b - .long 16b,105b - .long 17b,105b - .long 20b,106b - .long 21b,106b - .long 22b,106b - .long 23b,106b - .long 24b,107b - .long 25b,107b - .long 26b,107b - .long 27b,107b .long 30b,108b .long 31b,109b .long 40b,110b .long 41b,111b .long 112b,120b .long 114b,120b -.text + .text .globl __clear_user __clear_user: @@ -546,12 +643,13 @@ __clear_user: blr 99: li r3,-EFAULT blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 11b,99b .long 1b,99b .long 8b,99b -.text + .text .globl __strncpy_from_user __strncpy_from_user: @@ -570,10 +668,11 @@ __strncpy_from_user: blr 99: li r3,-EFAULT blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 1b,99b -.text + .text /* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ .globl __strnlen_user @@ -596,6 +695,7 @@ __strnlen_user: blr 99: li r3,0 /* bad address, return 0 */ blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 1b,99b diff --git a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c index 60563122d36a..ac400b8c68f7 100644 --- a/arch/ppc/mbxboot/misc.c +++ b/arch/ppc/mbxboot/misc.c @@ -269,6 +269,11 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, b */ #ifdef CONFIG_MBX cmd_line = (char *)(load_addr - 0x10000); + + /* To be like everyone else, we need one too, although this + * board information is passed from the boot rom. + */ + bp->bi_baudrate = 9600; #else cmd_line = (char *)(0x200000); #endif diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c index dc57bf86845b..74f263f4857e 100644 --- a/arch/ppc/mm/extable.c +++ b/arch/ppc/mm/extable.c @@ -7,8 +7,43 @@ #include #include -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of segments + * such as the prep, pmac, chrp, etc. segments as well as the init + * segment and the main kernel text segment. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void +sort_exception_table(void) +{ + sort_ex_table(__start___ex_table, __stop___ex_table); +} static inline unsigned long search_one_table(const struct exception_table_entry *first, @@ -36,25 +71,21 @@ search_exception_table(unsigned long addr) { unsigned long ret; -#if 1 /*ndef CONFIG_MODULES*/ +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); if (ret) return ret; #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; - read_lock(&modlist_lock); for (mp = module_list; mp != NULL; mp = mp->next) { if (mp->ex_table_start == NULL) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); - if (ret) { - read_unlock(&modlist_lock); + if (ret) return ret; - } } - read_unlock(&modlist_lock); #endif return 0; diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 0b551c803285..b6da2cdfcabd 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -67,7 +67,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, #if defined(CONFIG_4xx) int is_write = error_code & ESR_DST; #else - int is_write = error_code & 0x02000000; + int is_write = 0; /* * Fortunately the bit assignments in SRR1 for an instruction @@ -77,6 +77,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, */ if (regs->trap == 0x400) error_code &= 0x48200000; + else + is_write = error_code & 0x02000000; #endif /* CONFIG_4xx */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 67257c50bf23..be7d1f06340a 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include /* for initrd_* */ #endif @@ -69,15 +70,20 @@ #include "4xx_tlb.h" #endif +#define MAX_LOW_MEM (640 << 20) + #define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) int prom_trashed; atomic_t next_mmu_context; unsigned long *end_of_DRAM; +unsigned long total_memory; +unsigned long total_lowmem; int mem_init_done; int init_bootmem_done; int boot_mapsize; unsigned long totalram_pages = 0; +unsigned long totalhigh_pages = 0; extern pgd_t swapper_pg_dir[]; extern char _start[], _end[]; extern char etext[], _stext[]; @@ -98,22 +104,26 @@ extern unsigned int rtas_data, rtas_size; #ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif +#ifdef CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; +#endif void MMU_init(void); static void *MMU_get_page(void); -unsigned long *prep_find_end_of_memory(void); -unsigned long *pmac_find_end_of_memory(void); -unsigned long *apus_find_end_of_memory(void); -unsigned long *gemini_find_end_of_memory(void); -extern unsigned long *find_end_of_memory(void); +unsigned long prep_find_end_of_memory(void); +unsigned long pmac_find_end_of_memory(void); +unsigned long apus_find_end_of_memory(void); +unsigned long gemini_find_end_of_memory(void); +extern unsigned long find_end_of_memory(void); #ifdef CONFIG_8xx -unsigned long *m8xx_find_end_of_memory(void); +unsigned long m8xx_find_end_of_memory(void); #endif /* CONFIG_8xx */ #ifdef CONFIG_4xx -unsigned long *oak_find_end_of_memory(void); +unsigned long oak_find_end_of_memory(void); #endif #ifdef CONFIG_8260 -unsigned long *m8260_find_end_of_memory(void); +unsigned long m8260_find_end_of_memory(void); #endif /* CONFIG_8260 */ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); @@ -269,6 +279,7 @@ void show_mem(void) int i,free = 0,total = 0,reserved = 0; int shared = 0, cached = 0; struct task_struct *p; + int highmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -276,6 +287,8 @@ void show_mem(void) i = max_mapnr; while (i-- > 0) { total++; + if (PageHighMem(mem_map+i)) + highmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -286,6 +299,7 @@ void show_mem(void) shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); + printk("%d pages of HIGHMEM\n", highmem); printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); @@ -354,6 +368,8 @@ void si_meminfo(struct sysinfo *val) continue; val->sharedram += atomic_read(&mem_map[i].count) - 1; } + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; } @@ -443,7 +459,8 @@ out: void iounmap(void *addr) { - /* XXX todo */ + if (addr > high_memory && (unsigned long) addr < ioremap_bot) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); } unsigned long iopa(unsigned long addr) @@ -476,7 +493,7 @@ map_page(unsigned long va, unsigned long pa, int flags) { pmd_t *pd, oldpd; pte_t *pg; - + /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); oldpd = *pd; @@ -516,6 +533,7 @@ local_flush_tlb_all(void) flush_hash_segments(0xd, 0xffffff); #else __clear_user(Hash, Hash_size); + _tlbia(); #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif /* CONFIG_SMP */ @@ -610,6 +628,13 @@ mmu_context_overflow(void) } #endif /* CONFIG_8xx */ +void flush_page_to_ram(struct page *page) +{ + unsigned long vaddr = kmap(page); + __flush_page_to_ram(vaddr); + kunmap(page); +} + #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); @@ -722,7 +747,7 @@ static void __init mapin_ram(void) if (align && align < max_size) max_size = align; - tot = (unsigned long)end_of_DRAM - KERNELBASE; + tot = total_lowmem; for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > tot) break; @@ -745,6 +770,8 @@ static void __init mapin_ram(void) for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); p = phys_mem.regions[i].address; + if (p >= total_lowmem) + break; for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { /* On the MPC8xx, we want the page shared so we * don't get ASID compares on kernel space. @@ -766,6 +793,8 @@ static void __init mapin_ram(void) map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; + if (p >= total_lowmem) + break; } } } @@ -788,77 +817,42 @@ static void __init *MMU_get_page(void) return p; } -void __init free_initmem(void) +static void free_sec(unsigned long start, unsigned long end, const char *name) { - unsigned long a; - unsigned long num_freed_pages = 0, num_prep_pages = 0, - num_pmac_pages = 0, num_openfirmware_pages = 0, - num_apus_pages = 0, num_chrp_pages = 0; -#define FREESEC(START,END,CNT) do { \ - a = (unsigned long)(&START); \ - for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ - clear_bit(PG_reserved, &virt_to_page(a)->flags); \ - set_page_count(virt_to_page(a), 1); \ - free_page(a); \ - CNT++; \ - } \ -} while (0) - - FREESEC(__init_begin,__init_end,num_freed_pages); - switch (_machine) - { - case _MACH_Pmac: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_chrp: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - break; - case _MACH_prep: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_mbx: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_apus: - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_gemini: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - } + unsigned long cnt = 0; - if ( !have_of ) - FREESEC( __openfirmware_begin, __openfirmware_end, - num_openfirmware_pages ); - - printk ("Freeing unused kernel memory: %ldk init", - PGTOKB(num_freed_pages)); - - if ( num_prep_pages ) - printk(" %ldk prep", PGTOKB(num_prep_pages)); - if ( num_chrp_pages ) - printk(" %ldk chrp", PGTOKB(num_chrp_pages)); - if ( num_pmac_pages ) - printk(" %ldk pmac", PGTOKB(num_pmac_pages)); - if ( num_openfirmware_pages ) - printk(" %ldk open firmware", PGTOKB(num_openfirmware_pages)); - if ( num_apus_pages ) - printk(" %ldk apus", PGTOKB(num_apus_pages)); - printk("\n"); + while (start < end) { + clear_bit(PG_reserved, &virt_to_page(start)->flags); + set_page_count(virt_to_page(start), 1); + free_page(start); + cnt++; + start += PAGE_SIZE; + } + if (cnt) + printk(" %ldk %s", PGTOKB(cnt), name); +} + +void free_initmem(void) +{ +#define FREESEC(TYPE) \ + free_sec((unsigned long)(&__ ## TYPE ## _begin), \ + (unsigned long)(&__ ## TYPE ## _end), \ + #TYPE); + + printk ("Freeing unused kernel memory:"); + FREESEC(init); + if (_machine != _MACH_Pmac) + FREESEC(pmac); + if (_machine != _MACH_chrp) + FREESEC(chrp); + if (_machine != _MACH_prep) + FREESEC(prep); + if (_machine != _MACH_apus) + FREESEC(apus); + if (!have_of) + FREESEC(openfirmware); + printk("\n"); +#undef FREESEC } #ifdef CONFIG_BLK_DEV_INITRD @@ -909,7 +903,8 @@ MMU_init(void) * at KERNELBASE. */ - end_of_DRAM = oak_find_end_of_memory(); + total_memory = total_lowmem = oak_find_end_of_memory(); + end_of_DRAM = __va(total_memory); mapin_ram(); /* @@ -939,23 +934,33 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); #ifndef CONFIG_8xx if (have_of) - end_of_DRAM = pmac_find_end_of_memory(); + total_memory = pmac_find_end_of_memory(); #ifdef CONFIG_APUS else if (_machine == _MACH_apus ) - end_of_DRAM = apus_find_end_of_memory(); + total_memory = apus_find_end_of_memory(); #endif #ifdef CONFIG_GEMINI else if ( _machine == _MACH_gemini ) - end_of_DRAM = gemini_find_end_of_memory(); + total_memory = gemini_find_end_of_memory(); #endif /* CONFIG_GEMINI */ #if defined(CONFIG_8260) else - end_of_DRAM = m8260_find_end_of_memory(); + total_memory = m8260_find_end_of_memory(); #else else /* prep */ - end_of_DRAM = prep_find_end_of_memory(); + total_memory = prep_find_end_of_memory(); #endif + total_lowmem = total_memory; +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); + if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifndef CONFIG_PPC64BRIDGE @@ -995,7 +1000,7 @@ void __init MMU_init(void) #endif break; case _MACH_Pmac: - ioremap_base = 0xf8000000; + ioremap_base = 0xfe000000; break; case _MACH_apus: /* Map PPC exception vectors. */ @@ -1022,7 +1027,15 @@ void __init MMU_init(void) #endif /* CONFIG_POWER4 */ #else /* CONFIG_8xx */ - end_of_DRAM = m8xx_find_end_of_memory(); + total_memory = total_lowmem = m8xx_find_end_of_memory(); +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); @@ -1055,7 +1068,7 @@ void __init MMU_init(void) if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT /* Must be done last, or ppc_md.progress will die */ - if (_machine == _MACH_Pmac) + if (_machine == _MACH_Pmac || _machine == _MACH_chrp) map_bootx_text(); #endif } @@ -1092,7 +1105,7 @@ void __init do_init_bootmem(void) start = PAGE_ALIGN(start); boot_mapsize = init_bootmem(start >> PAGE_SHIFT, - __pa(end_of_DRAM) >> PAGE_SHIFT); + total_lowmem >> PAGE_SHIFT); /* remove the bootmem bitmap from the available memory */ mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); @@ -1105,47 +1118,6 @@ void __init do_init_bootmem(void) init_bootmem_done = 1; } -#if 0 -/* - * Find some memory for setup_arch to return. - * We use the largest chunk of available memory as the area - * that setup_arch returns, making sure that there are at - * least 32 pages unused before this for MMU_get_page to use. - */ -unsigned long __init find_available_memory(void) -{ - int i, rn; - unsigned long a, free; - unsigned long start, end; - - if (_machine == _MACH_mbx) { - /* Return the first, not the last region, because we - * may not yet have properly initialized the additonal - * memory DIMM. - */ - a = PAGE_ALIGN(phys_avail.regions[0].address); - avail_start = (unsigned long) __va(a); - return avail_start; - } - - rn = 0; - for (i = 1; i < phys_avail.n_regions; ++i) - if (phys_avail.regions[i].size > phys_avail.regions[rn].size) - rn = i; - free = 0; - for (i = 0; i < rn; ++i) { - start = phys_avail.regions[i].address; - end = start + phys_avail.regions[i].size; - free += (end & PAGE_MASK) - PAGE_ALIGN(start); - } - a = PAGE_ALIGN(phys_avail.regions[rn].address); - if (free < 32 * PAGE_SIZE) - a += 32 * PAGE_SIZE - free; - avail_start = (unsigned long) __va(a); - return avail_start; -} -#endif /* 0 */ - /* * paging_init() sets up the page tables - in fact we've already done this. */ @@ -1153,6 +1125,14 @@ void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], i; +#ifdef CONFIG_HIGHMEM + map_page(PKMAP_BASE, 0, 0); /* XXX gross */ + pkmap_page_table = pte_offset(pmd_offset(pgd_offset_k(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ + kmap_pte = pte_offset(pmd_offset(pgd_offset_k(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_prot = PAGE_KERNEL; +#endif /* CONFIG_HIGHMEM */ + /* * Grab some memory for bad_page and bad_pagetable to use. */ @@ -1162,9 +1142,14 @@ void __init paging_init(void) /* * All pages are DMA-able so we put them all in the DMA zone. */ - zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT; + zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; for (i = 1; i < MAX_NR_ZONES; i++) zones_size[i] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + free_area_init(zones_size); } @@ -1176,7 +1161,17 @@ void __init mem_init(void) int codepages = 0; int datapages = 0; int initpages = 0; +#ifdef CONFIG_HIGHMEM + unsigned long highmem_mapnr; + + highmem_mapnr = total_lowmem >> PAGE_SHIFT; + highmem_start_page = mem_map + highmem_mapnr; + max_mapnr = total_memory >> PAGE_SHIFT; + totalram_pages += max_mapnr - highmem_mapnr; +#else max_mapnr = max_low_pfn; +#endif /* CONFIG_HIGHMEM */ + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1217,11 +1212,28 @@ void __init mem_init(void) datapages++; } - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", +#ifdef CONFIG_HIGHMEM + { + unsigned long pfn; + + for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { + struct page *page = mem_map + pfn; + + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; + } +#endif /* CONFIG_HIGHMEM */ + + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n", (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long) end_of_DRAM); + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); mem_init_done = 1; } @@ -1234,7 +1246,7 @@ void __init mem_init(void) * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ -unsigned long __init *pmac_find_end_of_memory(void) +unsigned long __init pmac_find_end_of_memory(void) { unsigned long a, total; unsigned long ram_limit = 0xe0000000 - KERNELBASE; @@ -1279,7 +1291,7 @@ unsigned long __init *pmac_find_end_of_memory(void) set_phys_avail(&phys_mem); - return __va(total); + return total; } #endif /* CONFIG_ALL_PPC */ @@ -1290,7 +1302,7 @@ unsigned long __init *pmac_find_end_of_memory(void) * this will likely stay separate from the pmac. * -- Cort */ -unsigned long __init *prep_find_end_of_memory(void) +unsigned long __init prep_find_end_of_memory(void) { unsigned long total; total = res->TotalMemory; @@ -1308,15 +1320,15 @@ unsigned long __init *prep_find_end_of_memory(void) mem_pieces_append(&phys_mem, 0, total); set_phys_avail(&phys_mem); - return (__va(total)); + return (total); } #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_GEMINI) -unsigned long __init *gemini_find_end_of_memory(void) +unsigned long __init gemini_find_end_of_memory(void) { - unsigned long total, *ret; + unsigned long total; unsigned char reg; reg = readb(GEMINI_MEMCFG); @@ -1327,9 +1339,8 @@ unsigned long __init *gemini_find_end_of_memory(void) phys_mem.regions[0].size = total; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* defined(CONFIG_GEMINI) */ @@ -1337,10 +1348,9 @@ unsigned long __init *gemini_find_end_of_memory(void) /* * Same hack as 8xx. */ -unsigned long __init *m8260_find_end_of_memory(void) +unsigned long __init m8260_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1349,15 +1359,14 @@ unsigned long __init *m8260_find_end_of_memory(void) phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* CONFIG_8260 */ #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init *apus_find_end_of_memory(void) +unsigned long __init apus_find_end_of_memory(void) { int shadow = 0; @@ -1421,7 +1430,7 @@ unsigned long __init *apus_find_end_of_memory(void) the PowerUP board. Other system memory is horrible slow in comparison. The user can use other memory for swapping using the z2ram device. */ - return __va(memory[0].addr + memory[0].size); + return memory[0].addr + memory[0].size; } #endif /* CONFIG_APUS */ @@ -1484,7 +1493,7 @@ static void __init hash_init(void) /* Find some memory for the hash table. */ if ( Hash_size ) { Hash = mem_pieces_find(Hash_size, Hash_size); - /*__clear_user(Hash, Hash_size);*/ + cacheable_memzero(Hash, Hash_size); } else Hash = 0; #endif /* CONFIG_PPC64BRIDGE */ @@ -1544,10 +1553,9 @@ static void __init hash_init(void) * functions in the image just to get prom_init, all we really need right * now is the initialization of the physical memory region. */ -unsigned long __init *m8xx_find_end_of_memory(void) +unsigned long __init m8xx_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1555,12 +1563,9 @@ unsigned long __init *m8xx_find_end_of_memory(void) phys_mem.regions[0].address = 0; phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address+ - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].address + phys_mem.regions[0].size; } #endif /* !CONFIG_4xx && !CONFIG_8xx */ @@ -1569,7 +1574,7 @@ unsigned long __init *m8xx_find_end_of_memory(void) * Return the virtual address representing the top of physical RAM * on the Oak board. */ -unsigned long __init * +unsigned long __init oak_find_end_of_memory(void) { extern unsigned char __res[]; @@ -1580,12 +1585,9 @@ oak_find_end_of_memory(void) phys_mem.regions[0].address = 0; phys_mem.regions[0].size = bip->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address + - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return (ret); + return (phys_mem.regions[0].address + phys_mem.regions[0].size); } #endif diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index a816f0b9d7b8..499c5b6c8303 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,12 @@ xmon_map_scc(void) use_screen = 1; } #endif +#ifdef CONFIG_ADB_CUDA + if (!via_modem && disp_bi ) { + prom_drawstring("xmon uses screen and keyboard\n"); + use_screen = 1; + } +#endif #endif #ifdef CHRP_ESCC @@ -100,6 +107,10 @@ xmon_map_scc(void) /* should already be mapped by the kernel boot */ sccc = (volatile unsigned char *) (isa_io_base + 0x3fd); sccd = (volatile unsigned char *) (isa_io_base + 0x3f8); + if (xmon_use_sccb) { + sccc -= 0x100; + sccd -= 0x100; + } TXRDY = 0x20; RXRDY = 1; } @@ -109,6 +120,19 @@ static int scc_initialized = 0; void xmon_init_scc(void); extern void pmu_poll(void); +extern void cuda_poll(void); + +static inline void do_poll_adb(void) +{ +#ifdef CONFIG_ADB_PMU + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll(); +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB_CUDA + if (sys_ctrler == SYS_CTRLER_CUDA) + cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ +} int xmon_write(void *handle, void *ptr, int nb) @@ -128,12 +152,8 @@ xmon_write(void *handle, void *ptr, int nb) xmon_init_scc(); ct = 0; for (i = 0; i < nb; ++i) { - while ((*sccc & TXRDY) == 0) { -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ - } + while ((*sccc & TXRDY) == 0) + do_poll_adb(); c = p[i]; if (c == '\n' && !ct) { c = '\r'; @@ -189,9 +209,7 @@ xmon_get_adb_key(void) prom_drawchar('\b'); t = 200000; } -#ifdef CONFIG_ADB_PMU - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); } while (xmon_adb_keycode == -1); k = xmon_adb_keycode; if (on) @@ -230,14 +248,9 @@ xmon_read(void *handle, void *ptr, int nb) xmon_init_scc(); for (i = 0; i < nb; ++i) { while ((*sccc & RXRDY) == 0) -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#else - ; -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); buf_access(); - *p++ = *sccd; + *p++ = *sccd; } return i; } @@ -246,10 +259,7 @@ int xmon_read_poll(void) { if ((*sccc & RXRDY) == 0) { -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); return -1; } buf_access(); @@ -491,3 +501,19 @@ xmon_fgets(char *str, int nb, void *f) *p = 0; return str; } + +void +xmon_enter(void) +{ +#ifdef CONFIG_ADB_PMU + pmu_suspend(); +#endif +} + +void +xmon_leave(void) +{ +#ifdef CONFIG_ADB_PMU + pmu_resume(); +#endif +} diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 75160d9b8aa9..49c3be834f95 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -6,15 +6,23 @@ #include #include #include +#include #include #include #include +#include #include "nonstdio.h" #include "privinst.h" #define scanhex xmon_scanhex #define skipbl xmon_skipbl +#ifdef CONFIG_SMP +static unsigned long cpus_in_xmon = 0; +static unsigned long got_xmon = 0; +static volatile int take_xmon = -1; +#endif /* CONFIG_SMP */ + static unsigned adrs; static int size = 1; static unsigned ndump = 64; @@ -84,6 +92,9 @@ static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); static void bpt_cmds(void); static void cacheflush(void); +#ifdef CONFIG_SMP +static void cpu_cmd(void); +#endif /* CONFIG_SMP */ #if 0 /* Makes compile with -Wall */ static char *pretty_print_addr(unsigned long addr); static char *lookup_name(unsigned long addr); @@ -96,8 +107,18 @@ extern int putchar(int ch); extern int setjmp(u_int *); extern void longjmp(u_int *, int); +extern void xmon_enter(void); +extern void xmon_leave(void); + #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) +#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'f') \ + || ('A' <= (c) && (c) <= 'F')) +#define isalnum(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'z') \ + || ('A' <= (c) && (c) <= 'Z')) + static char *help_string = "\ Commands:\n\ d dump bytes\n\ @@ -117,10 +138,12 @@ Commands:\n\ x exit monitor\n\ "; -static int xmon_trace; +static int xmon_trace[NR_CPUS]; #define SSTEP 1 /* stepping because of 's' command */ #define BRSTEP 2 /* stepping over breakpoint */ +static struct pt_regs *xmon_regs[NR_CPUS]; + void xmon(struct pt_regs *excp) { @@ -143,27 +166,52 @@ xmon(struct pt_regs *excp) msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ - remove_bpts(); + xmon_regs[smp_processor_id()] = excp; + xmon_enter(); excprint(excp); +#ifdef CONFIG_SMP + if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) + for (;;) + ; + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; + } + } + /* + * XXX: breakpoints are removed while any cpu is in xmon + */ +#endif /* CONFIG_SMP */ + remove_bpts(); cmd = cmds(excp); if (cmd == 's') { - xmon_trace = SSTEP; + xmon_trace[smp_processor_id()] = SSTEP; excp->msr |= 0x400; } else if (at_breakpoint(excp->nip)) { - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; excp->msr |= 0x400; } else { - xmon_trace = 0; + xmon_trace[smp_processor_id()] = 0; insert_bpts(); } + xmon_leave(); + xmon_regs[smp_processor_id()] = 0; +#ifdef CONFIG_SMP + clear_bit(0, &got_xmon); + clear_bit(smp_processor_id(), &cpus_in_xmon); +#endif /* CONFIG_SMP */ set_msr(msr); /* restore interrupt enable */ } void xmon_irq(int irq, void *d, struct pt_regs *regs) { + unsigned long flags; + save_flags(flags);cli(); printf("Keyboard interrupt\n"); xmon(regs); + restore_flags(flags); } int @@ -178,7 +226,7 @@ xmon_bpt(struct pt_regs *regs) --bp->count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); @@ -189,10 +237,10 @@ xmon_bpt(struct pt_regs *regs) int xmon_sstep(struct pt_regs *regs) { - if (!xmon_trace) + if (!xmon_trace[smp_processor_id()]) return 0; - if (xmon_trace == BRSTEP) { - xmon_trace = 0; + if (xmon_trace[smp_processor_id()] == BRSTEP) { + xmon_trace[smp_processor_id()] = 0; insert_bpts(); } else { xmon(regs); @@ -207,7 +255,7 @@ xmon_dabr_match(struct pt_regs *regs) --dabr.count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { dabr.instr = regs->nip; @@ -223,7 +271,7 @@ xmon_iabr_match(struct pt_regs *regs) --iabr.count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); @@ -264,6 +312,7 @@ insert_bpts() bp->address); bp->enabled = 0; } + store_inst((void *) bp->address); } #if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) if (dabr.enabled) @@ -293,6 +342,7 @@ remove_bpts() && mwrite(bp->address, &bp->instr, 4) != 4) printf("Couldn't remove breakpoint at %x\n", bp->address); + store_inst((void *) bp->address); } } @@ -306,6 +356,9 @@ cmds(struct pt_regs *excp) last_cmd = NULL; for(;;) { +#ifdef CONFIG_SMP + printf("%d:", smp_processor_id()); +#endif /* CONFIG_SMP */ printf("mon> "); fflush(stdout); flush_input(); @@ -383,12 +436,67 @@ cmds(struct pt_regs *excp) case 'b': bpt_cmds(); break; - case 'c': + case 'C': csum(); break; +#ifdef CONFIG_SMP + case 'c': + cpu_cmd(); + break; +#endif /* CONFIG_SMP */ + } + } +} + +#ifdef CONFIG_SMP +static void cpu_cmd(void) +{ + unsigned cpu; + int timeout; + int cmd; + + cmd = inchar(); + if (cmd == 'i') { + /* interrupt other cpu(s) */ + cpu = MSG_ALL_BUT_SELF; + scanhex(&cpu); + smp_send_xmon_break(cpu); + return; + } + termch = cmd; + if (!scanhex(&cpu)) { + /* print cpus waiting or in xmon */ + printf("cpus stopped:"); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (test_bit(cpu, &cpus_in_xmon)) { + printf(" %d", cpu); + if (cpu == smp_processor_id()) + printf("*", cpu); + } + } + printf("\n"); + return; + } + /* try to switch to cpu specified */ + take_xmon = cpu; + timeout = 10000000; + while (take_xmon >= 0) { + if (--timeout == 0) { + /* yes there's a race here */ + take_xmon = -1; + printf("cpu %u didn't take control\n", cpu); + return; + } + } + /* now have to wait to be given control back */ + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; } } } +#endif /* CONFIG_SMP */ static unsigned short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, @@ -551,6 +659,8 @@ backtrace(struct pt_regs *excp) extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; extern char ret_from_except; + printf("backtrace:\n"); + if (excp != NULL) sp = excp->gpr[1]; else @@ -592,6 +702,9 @@ getsp() void excprint(struct pt_regs *fp) { +#ifdef CONFIG_SMP + printf("cpu %d: ", smp_processor_id()); +#endif /* CONFIG_SMP */ printf("vector: %x at pc = %x", fp->trap, fp->nip); printf(", lr = %x, msr = %x, sp = %x [%x]\n", @@ -1163,9 +1276,6 @@ bsesc() return c; } -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) void dump() { @@ -1402,6 +1512,16 @@ skipbl() return c; } +#define N_PTREGS 44 +static char *regnames[N_PTREGS] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq", + "trap", "dar", "dsisr", "res" +}; + int scanhex(vp) unsigned *vp; @@ -1410,6 +1530,36 @@ unsigned *vp; unsigned v; c = skipbl(); + if (c == '%') { + /* parse register name */ + char regname[8]; + int i; + + for (i = 0; i < sizeof(regname) - 1; ++i) { + c = inchar(); + if (!isalnum(c)) { + termch = c; + break; + } + regname[i] = c; + } + regname[i] = 0; + for (i = 0; i < N_PTREGS; ++i) { + if (strcmp(regnames[i], regname) == 0) { + unsigned *rp = (unsigned *) + xmon_regs[smp_processor_id()]; + if (rp == NULL) { + printf("regs not available\n"); + return 0; + } + *vp = rp[i]; + return 1; + } + } + printf("invalid register name '%%%s'\n", regname); + return 0; + } + d = hexdigit(c); if( d == EOF ){ termch = c; diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 3d8dcb9544e8..9809815920ed 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.56 2000/06/13 22:51:28 anton Exp $ +/* $Id: time.c,v 1.57 2000/09/16 07:33:45 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 8683b87d761f..071510bbcb23 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.163 2000/08/22 10:09:10 jj Exp $ +/* $Id: sys_sparc32.c,v 1.164 2000/09/14 10:42:47 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1621,7 +1621,7 @@ struct ncp_mount_data32 { static void *do_ncp_super_data_conv(void *raw_data) { - struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; + struct ncp_mount_data news, *n = &news; struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; n->dir_mode = n32->dir_mode; @@ -1631,6 +1631,7 @@ static void *do_ncp_super_data_conv(void *raw_data) memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); n->wdog_pid = n32->wdog_pid; n->mounted_uid = low2highuid(n32->mounted_uid); + memcpy(raw_data, n, sizeof(struct ncp_mount_data)); return raw_data; } @@ -1645,7 +1646,7 @@ struct smb_mount_data32 { static void *do_smb_super_data_conv(void *raw_data) { - struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data news, *s = &news; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; s->version = s32->version; @@ -1654,6 +1655,7 @@ static void *do_smb_super_data_conv(void *raw_data) s->gid = low2highgid(s32->gid); s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; + memcpy(raw_data, s, sizeof(struct smb_mount_data)); return raw_data; } diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 911ac18afe0c..3c989847743a 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.28 2000/07/11 02:21:12 davem Exp $ +/* $Id: time.c,v 1.29 2000/09/16 07:33:45 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 9ebe1f49468c..12006b58a3d3 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.50 2000/08/11 03:00:13 davem Exp $ +/* $Id: fault.c,v 1.51 2000/09/14 06:22:32 anton Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -145,7 +145,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, if (!insn) { if (regs->tstate & TSTATE_PRIV) { - if (regs->tpc & 0x3) + if (!regs->tpc || (regs->tpc & 0x3)) goto cannot_handle; insn = *(unsigned int *)regs->tpc; } else { diff --git a/drivers/Makefile b/drivers/Makefile index 874799bbe868..cf9f91864d4c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -63,7 +63,7 @@ SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif -ifdef CONFIG_PPC +ifdef CONFIG_ALL_PPC SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif diff --git a/drivers/acpi/include/acenv.h b/drivers/acpi/include/acenv.h index 7d6f8659bda6..30c347b5fd7f 100644 --- a/drivers/acpi/include/acenv.h +++ b/drivers/acpi/include/acenv.h @@ -71,7 +71,6 @@ #ifdef _LINUX -#include #include #include #include diff --git a/drivers/block/lvm-snap.c b/drivers/block/lvm-snap.c index 938ffc26eb92..04007c1be586 100644 --- a/drivers/block/lvm-snap.c +++ b/drivers/block/lvm-snap.c @@ -118,7 +118,8 @@ static void lvm_drop_snapshot(lv_t * lv_snap, const char * reason) or error on this snapshot --> release it */ invalidate_buffers(lv_snap->lv_dev); - for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { + last_dev = 0; + for (i = 0; i < lv_snap->lv_remap_ptr; i++) { if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { last_dev = lv_snap->lv_block_exception[i].rdev_new; invalidate_buffers(last_dev); @@ -199,8 +200,9 @@ int lvm_snapshot_COW(kdev_t org_phys_dev, lv_t * lv_snap) { const char * reason; - unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; + unsigned long org_start, snap_start, virt_start, pe_off; int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; + kdev_t snap_phys_dev; struct kiobuf * iobuf; unsigned long blocks[KIO_MAX_SECTORS]; int blksize_snap, blksize_org, min_blksize, max_blksize; diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c index fc762c54ff49..239ed99aa13a 100644 --- a/drivers/block/lvm.c +++ b/drivers/block/lvm.c @@ -250,7 +250,7 @@ static int lvm_do_pv_change(vg_t*, void*); static int lvm_do_pv_status(vg_t *, void *); static void lvm_geninit(struct gendisk *); #ifdef LVM_GET_INODE -static struct inode *lvm_get_inode(int); +static struct inode *lvm_get_inode(kdev_t); void lvm_clear_inode(struct inode *); #endif /* END Internal function prototypes */ @@ -486,9 +486,8 @@ void __init lvm_init_vars(void) loadtime = CURRENT_TIME; pe_lock_req.lock = UNLOCK_PE; - pe_lock_req.data.lv_dev = \ - pe_lock_req.data.pv_dev = \ - pe_lock_req.data.pv_offset = 0; + pe_lock_req.data.lv_dev = pe_lock_req.data.pv_dev = 0; + pe_lock_req.data.pv_offset = 0; /* Initialize VG pointers */ for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL; @@ -1561,8 +1560,7 @@ static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) case UNLOCK_PE: pe_lock_req.lock = UNLOCK_PE; - pe_lock_req.data.lv_dev = \ - pe_lock_req.data.pv_dev = \ + pe_lock_req.data.lv_dev = pe_lock_req.data.pv_dev = 0; pe_lock_req.data.pv_offset = 0; wake_up(&lvm_map_wait); break; @@ -2542,7 +2540,7 @@ void __init * If you can convince Linus that it's worth changing - fine, then you'll need * to do blkdev_get()/blkdev_put(). Until then... */ -struct inode *lvm_get_inode(int dev) +struct inode *lvm_get_inode(kdev_t dev) { struct inode *inode_this = NULL; diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 802b04e89d72..7847cc9d84fb 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -246,6 +246,13 @@ static int floppy_revalidate(kdev_t dev); static int swim3_add_device(struct device_node *swims); int swim3_init(void); +#ifndef CONFIG_PMAC_PBOOK +static inline int check_media_bay(struct device_node *which_bay, int what) +{ + return 1; +} +#endif + static void swim3_select(struct floppy_state *fs, int sel) { volatile struct swim3 *sw = fs->swim3; diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c index c44546274726..b064b2e22f2c 100644 --- a/drivers/cdrom/mcd.c +++ b/drivers/cdrom/mcd.c @@ -275,7 +275,7 @@ static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr) static int statusCmd(void) { - int st, retry; + int st = -1, retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { @@ -297,7 +297,7 @@ statusCmd(void) static int mcdPlay(struct mcd_Play_msf *arg) { - int retry, st; + int retry, st = -1; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 7872a6f00ed3..11bd77b8cf70 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -90,8 +90,8 @@ if [ "$CONFIG_BUSMOUSE" != "n" ]; then dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - if [ "$CONFIG_ADB" = "y" ]; then - dep_tristate ' Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE + if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then + dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE fi fi diff --git a/drivers/char/drm/picker.c b/drivers/char/drm/picker.c index f8cfe4599f57..6053a947721a 100644 --- a/drivers/char/drm/picker.c +++ b/drivers/char/drm/picker.c @@ -1,4 +1,4 @@ -#include +#include #include #ifndef CONFIG_SMP diff --git a/drivers/char/mem.c b/drivers/char/mem.c index c39dcde03695..f63393a5f682 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -55,9 +55,6 @@ extern void mda_console_init(void); #if defined(CONFIG_ADB) extern void adbdev_init(void); #endif -#ifdef CONFIG_PHONE -extern void telephony_init(void); -#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -668,8 +665,5 @@ int __init chr_dev_init(void) #ifdef CONFIG_VIDEO_DEV videodev_init(); #endif -#ifdef CONFIG_PHONE - telephony_init(); -#endif return 0; } diff --git a/drivers/i2o/i2o_proc.c b/drivers/i2o/i2o_proc.c index 1032729e85ee..4c92ff09d1c0 100644 --- a/drivers/i2o/i2o_proc.c +++ b/drivers/i2o/i2o_proc.c @@ -3319,7 +3319,7 @@ static int create_i2o_procfs(void) return 0; } -static int destroy_i2o_procfs(void) +static int __exit destroy_i2o_procfs(void) { struct i2o_controller *pctrl = NULL; int i; @@ -3342,10 +3342,6 @@ static int destroy_i2o_procfs(void) return 0; } -#ifdef MODULE -#define i2o_proc_init init_module -#endif - int __init i2o_proc_init(void) { if (i2o_install_handler(&i2o_proc_handler) < 0) @@ -3360,14 +3356,17 @@ int __init i2o_proc_init(void) return 0; } -#ifdef MODULE - MODULE_AUTHOR("Deepak Saxena"); MODULE_DESCRIPTION("I2O procfs Handler"); -void cleanup_module(void) +static void __exit i2o_proc_exit(void) { destroy_i2o_procfs(); i2o_remove_handler(&i2o_proc_handler); } + +#ifdef MODULE +module_init(i2o_proc_init); #endif +module_exit(i2o_proc_exit); + diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 0b7cc80d2dda..ff91a89f84ab 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -212,6 +212,7 @@ #include #include #include +#include #include "capiutil.h" #include "capicmd.h" #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1930,7 +1931,7 @@ static struct procfsentries { { "capi/capi20ncci", 0 , proc_capincci_read_proc }, }; -static void proc_init(void) +static void __init proc_init(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -1942,7 +1943,7 @@ static void proc_init(void) } } -static void proc_exit(void) +static void __exit proc_exit(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -1981,7 +1982,7 @@ static void alloc_exit(void) #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } -static int alloc_init(void) +static int __init alloc_init(void) { capidev_cachep = kmem_cache_create("capi20_dev", sizeof(struct capidev), @@ -2052,10 +2053,6 @@ static void lower_callback(unsigned int cmd, __u32 contr, void *data) } } -#ifdef MODULE -#define capi_init init_module -#endif - static struct capi_interface_user cuser = { "capi20", lower_callback, @@ -2063,7 +2060,7 @@ static struct capi_interface_user cuser = { static char rev[10]; -int capi_init(void) +int __init capi_init(void) { char *p; @@ -2152,8 +2149,7 @@ int capi_init(void) return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit capi_exit(void) { #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE unsigned int j; @@ -2177,4 +2173,8 @@ void cleanup_module(void) printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev); } +#ifdef MODULE +module_init(capi_init); #endif +module_exit(capi_exit); + diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c index 58b2eb9c6631..a66057e1c0f2 100644 --- a/drivers/isdn/avmb1/capidrv.c +++ b/drivers/isdn/avmb1/capidrv.c @@ -200,6 +200,7 @@ #include #include #include +#include #include #include "capiutil.h" @@ -2436,7 +2437,7 @@ static struct procfsentries { { "capi/capidrv", 0 , proc_capidrv_read_proc }, }; -static void proc_init(void) +static void __init proc_init(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -2448,7 +2449,7 @@ static void proc_init(void) } } -static void proc_exit(void) +static void __exit proc_exit(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -2467,11 +2468,7 @@ static struct capi_interface_user cuser = { lower_callback }; -#ifdef MODULE -#define capidrv_init init_module -#endif - -int capidrv_init(void) +int __init capidrv_init(void) { struct capi_register_params rparam; capi_profile profile; @@ -2531,8 +2528,7 @@ int capidrv_init(void) return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit capidrv_exit(void) { char rev[10]; char *p; @@ -2554,4 +2550,8 @@ void cleanup_module(void) printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); } +#ifdef MODULE +module_init(capidrv_init); #endif +module_exit(capidrv_exit); + diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index ac096db95a5d..6edf9ff5e5f9 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -9,76 +9,67 @@ # parent makes.. # -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) +# Subdirs. -O_TARGET := macintosh.o -O_OBJS := -M_OBJS := +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) -ifeq ($(CONFIG_PMAC_PBOOK),y) - O_OBJS += mediabay.o -else - ifeq ($(CONFIG_MAC_FLOPPY),y) - O_OBJS += mediabay.o - endif -endif +# The target object and module list name. -ifeq ($(CONFIG_MAC_SERIAL),y) - O_OBJS += macserial.o -else - ifeq ($(CONFIG_MAC_SERIAL),m) - M_OBJS += macserial.o - endif -endif +O_TARGET := macintosh.o +M_OBJS := +O_OBJS := +MOD_LIST_NAME := MACINTOSH_MODULES -ifeq ($(CONFIG_NVRAM),y) - O_OBJS += nvram.o -else - ifeq ($(CONFIG_NVRAM),m) - M_OBJS += nvram.o - endif -endif +# Objects that export symbols. -ifdef CONFIG_ADB - OX_OBJS := adb.o -endif +export-objs := adb.o rtc.o mac_hid.o -ifdef CONFIG_ADB_KEYBOARD - O_OBJS += mac_keyb.o -endif +# Object file lists. -ifdef CONFIG_ADB_MACII - O_OBJS += via-macii.o -endif +obj-y := +obj-m := +obj-n := +obj- := -ifdef CONFIG_ADB_MACIISI - O_OBJS += via-maciisi.o -endif +# Each configuration option enables a list of files. -ifdef CONFIG_ADB_CUDA - O_OBJS += via-cuda.o +ifeq ($(CONFIG_PMAC_PBOOK),y) + obj-y += mediabay.o endif -ifdef CONFIG_ADB_IOP - O_OBJS += adb-iop.o -endif +obj-$(CONFIG_MAC_SERIAL) += macserial.o +obj-$(CONFIG_NVRAM) += nvram.o +obj-$(CONFIG_MAC_HID) += mac_hid.o +obj-$(CONFIG_INPUT_ADBHID) += adbhid.o +obj-$(CONFIG_PPC_RTC) += rtc.o -ifdef CONFIG_ADB_PMU - O_OBJS += via-pmu.o -endif +obj-$(CONFIG_ADB_PMU) += via-pmu.o +obj-$(CONFIG_ADB_CUDA) += via-cuda.o -ifdef CONFIG_ADB_PMU68K - O_OBJS += via-pmu68k.o -endif +obj-$(CONFIG_ADB) += adb.o +obj-$(CONFIG_ADB_KEYBOARD) += mac_keyb.o +obj-$(CONFIG_ADB_MACII) += via-macii.o +obj-$(CONFIG_ADB_MACIISI) += via-maciisi.o +obj-$(CONFIG_ADB_IOP) += adb-iop.o +obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o +obj-$(CONFIG_ADB_MACIO) += macio-adb.o -ifdef CONFIG_ADB_MACIO - O_OBJS += macio-adb.o -endif +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +# The global Rules.make. include $(TOPDIR)/Rules.make -# Integrated in mac_keyb.c -# mackeymap.map is retained for historical reasons -#mackeymap.c: mackeymap.map -# loadkeys --mktable mackeymap.map > mackeymap.c diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 10421b00d3aa..d17382f4fcc5 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -393,6 +393,15 @@ adb_register(int default_id, int handler_id, struct adb_ids *ids, return ids->nids; } +int +adb_unregister(int index) +{ + if (!adb_handler[index].handler) + return -ENODEV; + adb_handler[index].handler = 0; + return 0; +} + void adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll) { diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c new file mode 100644 index 000000000000..8ac4f37d4620 --- /dev/null +++ b/drivers/macintosh/adbhid.c @@ -0,0 +1,875 @@ +/* + * drivers/input/adbhid.c + * + * ADB HID driver for Power Macintosh computers. + * + * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl + * (see that file for its authors and contributors). + * + * Copyright (C) 2000 Franz Sirl. + * + * Adapted to ADB changes and support for more devices by + * Benjamin Herrenschmidt. Adapted from code in MkLinux + * and reworked. + * + * Supported devices: + * + * - Standard 1 button mouse + * - All standard Apple Extended protocol (handler ID 4) + * - mouseman and trackman mice & trackballs + * - PowerBook Trackpad (default setup: enable tapping) + * - MicroSpeed mouse & trackball (needs testing) + * - CH Products Trackball Pro (needs testing) + * - Contour Design (Contour Mouse) + * - Hunter digital (NoHandsMouse) + * - Kensignton TurboMouse 5 (needs testing) + * - Mouse Systems A3 mice and trackballs + * - MacAlly 2-buttons mouse (needs testing) + * + * To do: + * + * Improve Kensington support. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + +MODULE_AUTHOR("Franz Sirl "); + +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ + +static int adb_message_handler(struct notifier_block *, unsigned long, void *); +static struct notifier_block adbhid_adb_notifier = { + notifier_call: adb_message_handler, +}; + +unsigned char adb_to_linux_keycodes[128] = { + 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19, + 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, + 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, + 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0, + 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, + 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124, + 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88, + 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116 +}; + +struct adbhid { + struct input_dev input; + int id; + int default_id; + int original_handler_id; + int current_handler_id; + int mouse_kind; + unsigned char *keycode; + char name[64]; +}; + +static struct adbhid *adbhid[16] = { 0 }; + +static void adbhid_probe(void); + +static void adbhid_input_keycode(int, int, int); +static void leds_done(struct adb_request *); + +static void init_trackpad(int id); +static void init_trackball(int id); +static void init_turbomouse(int id); +static void init_microspeed(int id); +static void init_ms_a3(int id); + +static struct adb_ids keyboard_ids; +static struct adb_ids mouse_ids; +static struct adb_ids buttons_ids; + +/* Kind of keyboard, see Apple technote 1152 */ +#define ADB_KEYBOARD_UNKNOWN 0 +#define ADB_KEYBOARD_ANSI 0x0100 +#define ADB_KEYBOARD_ISO 0x0200 +#define ADB_KEYBOARD_JIS 0x0300 + +/* Kind of mouse */ +#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */ +#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */ +#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */ +#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */ +#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */ +#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */ +#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */ +#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */ +#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */ +#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ + +static void +adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n", + id, data[0], data[1], data[2], data[3]); + return; + } + + /* first check this is from register 0 */ + if (nb != 3 || (data[0] & 3) != KEYB_KEYREG) + return; /* ignore it */ + kbd_pt_regs = regs; + adbhid_input_keycode(id, data[1], 0); + if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f))) + adbhid_input_keycode(id, data[2], 0); +} + +static void +adbhid_input_keycode(int id, int keycode, int repeat) +{ + int up_flag; + + up_flag = (keycode & 0x80); + keycode &= 0x7f; + + switch (keycode) { + case 0x39: /* Generate down/up events for CapsLock everytime. */ + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1); + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0); + return; + case 0x3f: /* ignore Powerbook Fn key */ + return; + } + + if (adbhid[id]->keycode[keycode]) + input_report_key(&adbhid[id]->input, + adbhid[id]->keycode[keycode], !up_flag); + else + printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, + up_flag ? "released" : "pressed"); +} + +static void +adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx First button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + + Handler 4 -- Apple Extended mouse protocol. + + For Apple's 3-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + data[3] = byyy bxxx Third button and fourth button. Y is additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + + MacAlly 2-button mouse protocol. + + For MacAlly 2-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Right button and y-axis motion. + data[3] = ???? ???? unknown + data[4] = ???? ???? unknown + + */ + + /* If it's a trackpad, we alias the second button to the first. + NOTE: Apple sends an ADB flush command to the trackpad when + the first (the real) button is released. We could do + this here using async flush requests. + */ + switch (adbhid[id]->mouse_kind) + { + case ADBMOUSE_TRACKPAD: + data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); + data[2] = data[2] | 0x80; + break; + case ADBMOUSE_MICROSPEED: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5) + | (data[3] & 0x08); + break; + case ADBMOUSE_TRACKBALLPRO: + data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5) + & ((data[3] & 0x08) << 4)); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); + data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); + break; + case ADBMOUSE_MS_A3: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = ((data[3] & 0x04) << 5); + break; + case ADBMOUSE_MACALLY2: + data[3] = (data[2] & 0x80) ? 0x80 : 0x00; + data[2] |= 0x80; /* Right button is mapped as button 3 */ + nb=4; + break; + } + + input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); + input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); + + if (nb >= 4) + input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + + input_report_rel(&adbhid[id]->input, REL_X, + ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); + input_report_rel(&adbhid[id]->input, REL_Y, + ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); +} + +static void +adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + switch (adbhid[id]->original_handler_id) { + default: + case 0x02: /* Adjustable keyboard button device */ + printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); + break; + case 0x1f: /* Powerbook button device */ + { +#ifdef CONFIG_PMAC_BACKLIGHT + int backlight = get_backlight_level(); + + /* + * XXX: Where is the contrast control for the passive? + * -- Cort + */ + + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) + break; + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) + break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ + } + break; + } +} + +static struct adb_request led_request; +static int leds_pending[16]; +static int pending_devs[16]; +static int pending_led_start=0; +static int pending_led_end=0; + +static void real_leds(unsigned char leds, int device) +{ + if (led_request.complete) { + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, + ~leds); + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; + } +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ +static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct adbhid *adbhid = dev->private; + unsigned char leds; + + switch (type) { + case EV_LED: + leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) + | (test_bit(LED_NUML, dev->led) ? 1 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 2 : 0); + real_leds(leds, adbhid->id); + return 0; + } + + return -1; +} + +static void leds_done(struct adb_request *req) +{ + int leds,device; + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + real_leds(leds,device); + } + +} + +static int +adb_message_handler(struct notifier_block *this, unsigned long code, void *x) +{ + unsigned long flags; + + switch (code) { + case ADB_MSG_PRE_RESET: + case ADB_MSG_POWERDOWN: + /* Stop the repeat timer. Autopoll is already off at this point */ + save_flags(flags); + cli(); + { + int i; + for (i = 1; i < 16; i++) { + if (adbhid[i]) + del_timer(&adbhid[i]->input.timer); + } + } + restore_flags(flags); + + /* Stop pending led requests */ + while(!led_request.complete) + adb_poll(); + break; + + case ADB_MSG_POST_RESET: + adbhid_probe(); + break; + } + return NOTIFY_DONE; +} + +static void +adbhid_input_register(int id, int default_id, int original_handler_id, + int current_handler_id, int mouse_kind) +{ + int i; + + if (adbhid[id]) { + printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); + return; + } + + if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL))) + return; + + memset(adbhid[id], 0, sizeof(struct adbhid)); + + adbhid[id]->id = default_id; + adbhid[id]->original_handler_id = original_handler_id; + adbhid[id]->current_handler_id = current_handler_id; + adbhid[id]->mouse_kind = mouse_kind; + adbhid[id]->input.private = adbhid[id]; + adbhid[id]->input.name = adbhid[id]->name; + adbhid[id]->input.idbus = BUS_ADB; + adbhid[id]->input.idvendor = 0x0001; + adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; + adbhid[id]->input.idversion = 0x0100; + + switch (default_id) { + case ADB_KEYBOARD: + if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) { + kfree(adbhid[id]); + return; + } + + sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x", + id, default_id, original_handler_id); + + memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); + + printk(KERN_INFO "Detected ADB keyboard, type "); + switch (original_handler_id) { + default: + printk(".\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN; + break; + + case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: + case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: + case 0xC0: case 0xC3: case 0xC6: + printk("ANSI.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI; + break; + + case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: + case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: + case 0xC4: case 0xC7: + printk("ISO, swapping keys.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ISO; + i = adbhid[id]->keycode[10]; + adbhid[id]->keycode[10] = adbhid[id]->keycode[50]; + adbhid[id]->keycode[50] = i; + break; + + case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: + case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: + printk("JIS.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_JIS; + break; + } + + for (i = 0; i < 128; i++) + if (adbhid[id]->keycode[i]) + set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + adbhid[id]->input.event = adbhid_kbd_event; + adbhid[id]->input.keycodemax = 127; + adbhid[id]->input.keycodesize = 1; + break; + + case ADB_MOUSE: + sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x", + id, default_id, original_handler_id); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y); + break; + + case ADB_MISC: + switch (original_handler_id) { + case 0x02: /* Adjustable keyboard button device */ + sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + case 0x1f: /* Powerbook button device */ + sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + } + if (adbhid[id]->name[0]) + break; + /* else fall through */ + + default: + printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); + kfree(adbhid[id]); + return; + } + + adbhid[id]->input.keycode = adbhid[id]->keycode; + + input_register_device(&adbhid[id]->input); + + printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n", + adbhid[id]->input.number, id, default_id, original_handler_id); + + if (default_id == ADB_KEYBOARD) { + /* HACK WARNING!! This should go away as soon there is an utility + * to control that for event devices. + */ + adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */ + adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */ + } +} + +static void adbhid_input_unregister(int id) +{ + input_unregister_device(&adbhid[id]->input); + if (adbhid[id]->keycode) + kfree(adbhid[id]->keycode); + kfree(adbhid[id]); + adbhid[id] = 0; +} + + +static void +adbhid_probe(void) +{ + struct adb_request req; + int i, default_id, org_handler_id, cur_handler_id; + + for (i = 1; i < 16; i++) { + if (adbhid[i]) + adbhid_input_unregister(i); + } + + adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input); + adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input); + adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input); + + for (i = 0; i < keyboard_ids.nids; i++) { + int id = keyboard_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + + /* turn off all leds */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff); + + /* Enable full feature set of the keyboard + ->get it to send separate codes for left and right shift, + control, option keys */ +#if 0 /* handler 5 doesn't send separate codes for R modifiers */ + if (adb_try_handler_change(id, 5)) + printk("ADB keyboard at %d, handler set to 5\n", id); + else +#endif + if (adb_try_handler_change(id, 3)) + printk("ADB keyboard at %d, handler set to 3\n", id); + else + printk("ADB keyboard at %d, handler 1\n", id); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0); + } + + for (i = 0; i < buttons_ids.nids; i++) { + int id = buttons_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0); + } + + /* Try to switch all mice to handler 4, or 2 for three-button + mode and full resolution. */ + for (i = 0; i < mouse_ids.nids; i++) { + int id = mouse_ids.id[i]; + int mouse_kind; + + adb_get_infos(id, &default_id, &org_handler_id); + + if (adb_try_handler_change(id, 4)) { + printk("ADB mouse at %d, handler set to 4", id); + mouse_kind = ADBMOUSE_EXTENDED; + } + else if (adb_try_handler_change(id, 0x2F)) { + printk("ADB mouse at %d, handler set to 0x2F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x42)) { + printk("ADB mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_TRACKBALLPRO; + } + else if (adb_try_handler_change(id, 0x66)) { + printk("ADB mouse at %d, handler set to 0x66", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x5F)) { + printk("ADB mouse at %d, handler set to 0x5F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 3)) { + printk("ADB mouse at %d, handler set to 3", id); + mouse_kind = ADBMOUSE_MS_A3; + } + else if (adb_try_handler_change(id, 2)) { + printk("ADB mouse at %d, handler set to 2", id); + mouse_kind = ADBMOUSE_STANDARD_200; + } + else { + printk("ADB mouse at %d, handler 1", id); + mouse_kind = ADBMOUSE_STANDARD_100; + } + + if ((mouse_kind == ADBMOUSE_TRACKBALLPRO) + || (mouse_kind == ADBMOUSE_MICROSPEED)) { + init_microspeed(id); + } else if (mouse_kind == ADBMOUSE_MS_A3) { + init_ms_a3(id); + } else if (mouse_kind == ADBMOUSE_EXTENDED) { + /* + * Register 1 is usually used for device + * identification. Here, we try to identify + * a known device and call the appropriate + * init function. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id, 1)); + + if ((req.reply_len) && + (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) + || (req.reply[2] == 0x20))) { + mouse_kind = ADBMOUSE_TRACKBALL; + init_trackball(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && + (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) { + mouse_kind = ADBMOUSE_TRACKPAD; + init_trackpad(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && + (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) { + mouse_kind = ADBMOUSE_TURBOMOUSE5; + init_turbomouse(id); + } + else if ((req.reply_len == 9) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && + (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) { + if (adb_try_handler_change(id, 0x42)) { + printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_MACALLY2; + } + } + } + printk("\n"); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mouse_kind); + } +} + +static void +init_trackpad(int id) +{ + struct adb_request req; + unsigned char r1_buffer[8]; + + printk(" (trackpad)"); + + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id,1)); + if (req.reply_len < 8) + printk("bad length for reg. 1\n"); + else + { + memcpy(r1_buffer, &req.reply[1], 8); + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x0d, /*r1_buffer[6],*/ + r1_buffer[7]); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x03, /*r1_buffer[6],*/ + r1_buffer[7]); + } +} + +static void +init_trackball(int id) +{ + struct adb_request req; + + printk(" (trackman/mouseman)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); +} + +static void +init_turbomouse(int id) +{ + struct adb_request req; + + printk(" (TurboMouse 5)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xe7, + 0x8c, + 0, + 0, + 0, + 0xff, + 0xff, + 0x94); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xa5, + 0x14, + 0, + 0, + 0x69, + 0xff, + 0xff, + 0x27); +} + +static void +init_microspeed(int id) +{ + struct adb_request req; + + printk(" (Microspeed/MacPoint or compatible)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + /* This will initialize mice using the Microspeed, MacPoint and + other compatible firmware. Bit 12 enables extended protocol. + + Register 1 Listen (4 Bytes) + 0 - 3 Button is mouse (set also for double clicking!!!) + 4 - 7 Button is locking (affects change speed also) + 8 - 11 Button changes speed + 12 1 = Extended mouse mode, 0 = normal mouse mode + 13 - 15 unused 0 + 16 - 23 normal speed + 24 - 31 changed speed + + Register 1 talk holds version and product identification information. + Register 1 Talk (4 Bytes): + 0 - 7 Product code + 8 - 23 undefined, reserved + 24 - 31 Version number + + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 5, + ADB_WRITEREG(id,1), + 0x20, /* alt speed = 0x20 (rather slow) */ + 0x00, /* norm speed = 0x00 (fastest) */ + 0x10, /* extended protocol, no speed change */ + 0x07); /* all buttons enabled as mouse buttons, no locking */ + + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static void +init_ms_a3(int id) +{ + struct adb_request req; + + printk(" (Mouse Systems A3 Mouse, or compatible)"); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, 0x2), + 0x00, + 0x07); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static int __init adbhid_init(void) +{ + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return 0; + + led_request.complete = 1; + + adbhid_probe(); + + notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); + + return 0; +} + +static void __exit adbhid_exit(void) +{ +} + +module_init(adbhid_init); +module_exit(adbhid_exit); diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c new file mode 100644 index 000000000000..d97a1f6fb349 --- /dev/null +++ b/drivers/macintosh/mac_hid.c @@ -0,0 +1,492 @@ +/* + * drivers/macintosh/mac_hid.c + * + * HID support stuff for Macintosh computers. + * + * Copyright (C) 2000 Franz Sirl. + * + * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all + * major distributions are using the Linux keycodes. + * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MAC_ADBKEYCODES +#include +#include +#include +#endif + +#ifdef CONFIG_MAC_ADBKEYCODES +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char mac_hid_kbd_sysrq_xlate[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80o]" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000" + /* 0x30 - 0x3f */ + "\000\000\000*\000+\000\000\000\000\000/\r\000-\000" + /* 0x40 - 0x4f */ + "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */ + "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214"; + /* 0x60 - 0x6f */ +extern unsigned char pckbd_sysrq_xlate[128]; +#endif + +static u_short macplain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macaltgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c, +}; + +static u_short macalt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = { + macplain_map, macshift_map, macaltgr_map, 0, + macctrl_map, macshift_ctrl_map, 0, 0, + macalt_map, 0, 0, 0, + macctrl_alt_map, 0 +}; + +static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS]; + +int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); +char mac_hid_kbd_unexpected_up(unsigned char keycode); + +static int keyboard_lock_keycodes = 0; +int keyboard_sends_linux_keycodes = 0; +#else +int keyboard_sends_linux_keycodes = 1; +#endif + + +static unsigned char e0_keys[128] = { + 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ + KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ + KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ + KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +#ifdef CONFIG_MAC_EMUMOUSEBTN +static struct input_dev emumousebtn; +static void emumousebtn_input_register(void); +static int mouse_emulate_buttons = 0; +static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ +static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ +static int mouse_last_keycode = 0; +#endif + +extern void pckbd_init_hw(void); + +#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) +/* file(s) in /proc/sys/dev/mac_hid */ +ctl_table mac_hid_files[] = +{ +#ifdef CONFIG_MAC_ADBKEYCODES + { + DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES, + "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int), + 0644, NULL, &mac_hid_sysctl_keycodes + }, + { + DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES, + "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif +#ifdef CONFIG_MAC_EMUMOUSEBTN + { + DEV_MAC_HID_MOUSE_BUTTON_EMULATION, + "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE, + "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE, + "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif + { 0 } +}; + +/* dir in /proc/sys/dev */ +ctl_table mac_hid_dir[] = +{ + { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files }, + { 0 } +}; + +/* /proc/sys/dev itself, in case that is not there yet */ +ctl_table mac_hid_root_dir[] = +{ + { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir }, + { 0 } +}; + +static struct ctl_table_header *mac_hid_sysctl_header; + +#ifdef CONFIG_MAC_ADBKEYCODES +static +int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int val = keyboard_sends_linux_keycodes; + int ret = 0; + + if (!write + || (write && !keyboard_lock_keycodes)) + ret = proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write + && keyboard_sends_linux_keycodes != val) { + if (!keyboard_sends_linux_keycodes) { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); + } else { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; +#endif + memcpy(mac_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, pc_key_maps_save, sizeof(key_maps)); + } + } + + return ret; +} +#endif +#endif /* endif CONFIG_SYSCTL */ + +int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + if (!raw_mode) { + /* + * Convert R-shift/control/option to L version. + */ + switch (scancode) { + case 0x7b: scancode = 0x38; break; /* R-shift */ + case 0x7c: scancode = 0x3a; break; /* R-option */ + case 0x7d: scancode = 0x36; break; /* R-control */ + } + } + *keycode = scancode; + return 1; + } else +#endif + { + /* This code was copied from char/pc_keyb.c and will be + * superflous when the input layer is fully integrated. + * We don't need the high_keys handling, so this part + * has been removed. + */ + static int prev_scancode = 0; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = KEY_PAUSE; + prev_scancode = 0; + } else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + if (scancode == 0x2a || scancode == 0x36) + return 0; + } + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); + return 0; + } + } else { + switch (scancode) { + case 91: scancode = KEY_LINEFEED; break; + case 92: scancode = KEY_KPEQUAL; break; + case 125: scancode = KEY_INTL1; break; + } + *keycode = scancode; + } + return 1; + } +} + +char mac_hid_kbd_unexpected_up(unsigned char keycode) +{ + if (keyboard_sends_linux_keycodes && keycode == KEY_F13) + return 0; + else + return 0x80; +} + +#ifdef CONFIG_MAC_ADBKEYCODES +int mac_hid_keyboard_sends_linux_keycodes(void) +{ + return keyboard_sends_linux_keycodes; +} + +static int __init mac_hid_setup(char *str) +{ + int ints[2]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] == 1) { + keyboard_sends_linux_keycodes = ints[1] != 0; + keyboard_lock_keycodes = 1; + } + return 1; +} + +__setup("keyboard_sends_linux_keycodes=", mac_hid_setup); + +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN +int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) +{ + switch (caller) { + case 1: + /* Called from keybdev.c */ + if (mouse_emulate_buttons + && (keycode == mouse_button2_keycode + || keycode == mouse_button3_keycode)) { + if (mouse_emulate_buttons == 1) { + input_report_key(&emumousebtn, + keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, + down); + return 1; + } + mouse_last_keycode = down ? keycode : 0; + } + break; + case 2: + /* Called from mousedev.c */ + if (mouse_emulate_buttons == 2 && keycode == 0) { + if (mouse_last_keycode == mouse_button2_keycode) + return 1; /* map to middle button */ + if (mouse_last_keycode == mouse_button3_keycode) + return 2; /* map to right button */ + } + return keycode; /* keep button */ + } + return 0; +} + +static void emumousebtn_input_register(void) +{ + emumousebtn.name = "Macintosh mouse button emulation"; + + emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + emumousebtn.idbus = BUS_ADB; + emumousebtn.idvendor = 0x0001; + emumousebtn.idproduct = 0x0001; + emumousebtn.idversion = 0x0100; + + input_register_device(&emumousebtn); + + printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number); +} +#endif + +void __init mac_hid_init_hw(void) +{ + +#ifdef CONFIG_MAC_ADBKEYCODES + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + + if (!keyboard_sends_linux_keycodes) + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN + emumousebtn_input_register(); +#endif + +#if CONFIG_PPC + if (_machine != _MACH_Pmac) + pckbd_init_hw(); +#endif + +#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) + mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); +#endif /* CONFIG_SYSCTL */ +} diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index 7e9ec475182b..662f4a7f5e06 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -51,6 +51,10 @@ #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ @@ -585,68 +589,50 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) } #endif /* CONFIG_ADBMOUSE */ -/* XXX Needs to get rid of this, see comments in pmu.c */ -extern int backlight_level; - static void buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { -#ifdef CONFIG_ADB_PMU +#ifdef CONFIG_PMAC_BACKLIGHT + int backlight = get_backlight_level(); + /* * XXX: Where is the contrast control for the passive? * -- Cort */ /* 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 ) - { - /* mute */ - case 0x8: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast decrease */ - case 0x7: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast increase */ - case 0x6: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* brightness decrease */ - case 0xa: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level > 2) - pmu_set_brightness(backlight_level-2); - else - pmu_set_brightness(0); - } + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) break; - /* brightness increase */ - case 0x9: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level < 0x1e) - pmu_set_brightness(backlight_level+2); - else - pmu_set_brightness(0x1f); - } + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; } -#endif /* CONFIG_ADB_PMU */ +#endif /* CONFIG_PMAC_BACKLIGHT */ } /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index 52fc92198adc..abf570853dc4 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -122,6 +122,8 @@ int macio_init(void) out_8(&adb->autopoll.r, APE); out_8(&adb->intr_enb.r, DFB | TAG); + printk("adb: mac-io driver 1.0 for unified ADB\n"); + return 0; } diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 8e0528cba421..55cf255b9e5b 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -2291,7 +2291,7 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, zss->irq = ch->intrs[0].line; zss->has_dma = 0; #if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA) - if (ch->n_addrs == 3 && ch->n_intrs == 3) + if (ch->n_addrs >= 3 && ch->n_intrs == 3) zss->has_dma = 1; #endif zss->dma_initted = 0; @@ -2643,9 +2643,6 @@ void unregister_serial(int line) * ------------------------------------------------------------ */ #ifdef CONFIG_SERIAL_CONSOLE -#ifdef CONFIG_SERIAL -#error Cannot build serial console with macserial and serial drivers -#endif /* * Print a string to the serial port trying not to disturb @@ -2719,7 +2716,7 @@ static kdev_t serial_console_device(struct console *c) */ static int __init serial_console_setup(struct console *co, char *options) { - struct mac_serial *info = zs_soft + co->index; + struct mac_serial *info; int baud = 38400; int bits = 8; int parity = 'n'; @@ -2735,6 +2732,11 @@ static int __init serial_console_setup(struct console *co, char *options) if (zs_chain == 0) return -1; + /* Do we have the device asked for? */ + if (co->index >= zs_channels_found) + return -1; + info = zs_soft + co->index; + set_scc_power(info, 1); /* Reset the channel */ @@ -2904,7 +2906,7 @@ static struct console sercons = { /* * Register console. */ -void __init serial_console_init(void) +void __init mac_scc_console_init(void) { register_console(&sercons); } diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 6002870b4d0f..1bc1608d75f5 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -472,8 +472,11 @@ media_bay_step(int i) } else if (MB_IDE_READY(i)) { bay->timer = 0; bay->state = mb_up; - if (bay->cd_index < 0) + if (bay->cd_index < 0) { + pmu_suspend(); bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + pmu_resume(); + } if (bay->cd_index == -1) { /* We eventually do a retry */ bay->cd_retry++; @@ -605,7 +608,9 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when) only if it did not change. Note those bozo timings, they seem to help the 3400 get it right. */ - mdelay(MB_STABLE_DELAY); + /* Force MB power to 0 */ + set_mb_power(i, 0); + mdelay(MB_POWER_DELAY); if (!bay->pismo) out_8(&bay->addr->contents, 0x70); mdelay(MB_STABLE_DELAY); @@ -615,7 +620,9 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when) bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); +#ifdef CONFIG_BLK_DEV_IDE bay->cd_retry = 0; +#endif do { mdelay(1000/HZ); media_bay_step(i); diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c index 69d3f2d72ff5..3536c85cf35c 100644 --- a/drivers/macintosh/nvram.c +++ b/drivers/macintosh/nvram.c @@ -14,6 +14,7 @@ #include #include #include +#include #define NVRAM_SIZE 8192 @@ -70,11 +71,36 @@ static ssize_t write_nvram(struct file *file, const char *buf, return p - buf; } +static int nvram_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case PMAC_NVRAM_GET_OFFSET: + { + int part, offset; + if (copy_from_user(&part,(void*)arg,sizeof(part))!=0) + return -EFAULT; + if (part < pmac_nvram_OF || part > pmac_nvram_NR) + return -EINVAL; + offset = pmac_get_partition(part); + if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0) + return -EFAULT; + break; + } + + default: + return -EINVAL; + } + + return 0; +} + struct file_operations nvram_fops = { owner: THIS_MODULE, llseek: nvram_llseek, read: read_nvram, write: write_nvram, + ioctl: nvram_ioctl, }; static struct miscdevice nvram_dev = { diff --git a/drivers/macintosh/rtc.c b/drivers/macintosh/rtc.c new file mode 100644 index 000000000000..1d61793b7866 --- /dev/null +++ b/drivers/macintosh/rtc.c @@ -0,0 +1,158 @@ +/* + * Linux/PowerPC Real Time Clock Driver + * + * heavily based on: + * Linux/SPARC Real Time Clock Driver + * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * + * This is a little driver that lets a user-level program access + * the PPC clocks chip. It is no use unless you + * use the modified clock utility. + * + * Get the modified clock utility from: + * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int rtc_busy = 0; + +/* Retrieve the current date and time from the real time clock. */ +void get_rtc_time(struct rtc_time *t) +{ + unsigned long nowtime; + + nowtime = (ppc_md.get_rtc_time)(); + + to_tm(nowtime, t); + + t->tm_year -= 1900; + t->tm_mon -= 1; + t->tm_wday -= 1; +} + +/* Set the current date and time in the real time clock. */ +void set_rtc_time(struct rtc_time *t) +{ + unsigned long nowtime; + + printk(KERN_INFO "rtc.c:set_rtc_time: %04d-%02d-%02d %02d:%02d:%02d.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + + nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + + printk(KERN_INFO "rtc.c:set_rtc_time: set rtc time to %ld seconds.\n", nowtime); + + (ppc_md.set_rtc_time)(nowtime); +} + +static loff_t rtc_lseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time rtc_tm; + + switch (cmd) + { + case RTC_RD_TIME: + if (ppc_md.get_rtc_time) + { + get_rtc_time(&rtc_tm); + + if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + return -EFAULT; + + return 0; + } + else + return -EINVAL; + + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (ppc_md.set_rtc_time) + { + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; + + set_rtc_time(&rtc_tm); + + return 0; + } + else + return -EINVAL; + + default: + return -EINVAL; + } +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + if (rtc_busy) + return -EBUSY; + + rtc_busy = 1; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + rtc_busy = 0; + return 0; +} + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_lseek, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release +}; + +static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; + +EXPORT_NO_SYMBOLS; + +static int __init rtc_init(void) +{ + int error; + + error = misc_register(&rtc_dev); + if (error) { + printk(KERN_ERR "rtc: unable to get misc minor\n"); + return error; + } + + return 0; +} + +static void __exit rtc_exit(void) +{ + misc_deregister(&rtc_dev); +} + +module_init(rtc_init); +module_exit(rtc_exit); diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 1d1179b03be2..fe2ce318b64d 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -94,39 +94,48 @@ static struct device_node *vias; #endif static int cuda_fully_inited = 0; +#ifdef CONFIG_ADB static int cuda_probe(void); static int cuda_init(void); +static int cuda_send_request(struct adb_request *req, int sync); +static int cuda_adb_autopoll(int devs); +static int cuda_reset_adb_bus(void); +#endif /* CONFIG_ADB */ + static int cuda_init_via(void); static void cuda_start(void); 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_send_request(struct adb_request *req, int sync); -static int cuda_adb_autopoll(int devs); 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, ...); +#ifdef CONFIG_ADB struct adb_driver via_cuda_driver = { "CUDA", cuda_probe, cuda_init, cuda_send_request, - /*cuda_write,*/ cuda_adb_autopoll, cuda_poll, cuda_reset_adb_bus }; +#endif /* CONFIG_ADB */ #ifdef CONFIG_PPC -void -find_via_cuda() +int +find_via_cuda(void) { + int err; + struct adb_request req; + + if (vias != 0) + return 1; vias = find_devices("via-cuda"); if (vias == 0) - return; + return 0; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-cuda\n"); @@ -146,15 +155,54 @@ find_via_cuda() printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n", vias->n_addrs, vias->n_intrs); if (vias->n_addrs < 1 || vias->n_intrs < 1) - return; + return 0; } via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); cuda_state = idle; sys_ctrler = SYS_CTRLER_CUDA; + + err = cuda_init_via(); + if (err) { + printk(KERN_ERR "cuda_init_via() failed\n"); + via = NULL; + return 0; + } + + /* 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 + + /* enable autopoll */ + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); + while (!req.complete) + cuda_poll(); + + return 1; } #endif /* CONFIG_PPC */ +int via_cuda_start(void) +{ + if (via == NULL) + return -ENODEV; + + 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("Macintosh CUDA driver v0.5 for Unified ADB.\n"); + + cuda_fully_inited = 1; + return 0; +} + +#ifdef CONFIG_ADB static int cuda_probe() { @@ -172,46 +220,24 @@ cuda_probe() static int cuda_init(void) { - int err; - if (via == NULL) return -ENODEV; - - err = cuda_init_via(); - if (err) { - printk(KERN_ERR "cuda_probe: init_via() failed\n"); - via = NULL; - return err; - } - - /* 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 */ +#ifndef CONFIG_PPC + return via_cuda_start(); #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) \ - do { \ - for (x = 1000; !(cond); --x) { \ - if (x == 0) { \ - printk("Timeout waiting for " what); \ - return -ENXIO; \ - } \ +#endif /* CONFIG_ADB */ + +#define WAIT_FOR(cond, what) \ + do { \ + for (x = 1000; !(cond); --x) { \ + if (x == 0) { \ + printk("Timeout waiting for " what "\n"); \ + return -ENXIO; \ + } \ udelay(100); \ - } \ + } \ } while (0) static int @@ -255,6 +281,7 @@ cuda_init_via() return 0; } +#ifdef CONFIG_ADB /* Send an ADB command */ static int cuda_send_request(struct adb_request *req, int sync) @@ -309,7 +336,7 @@ cuda_reset_adb_bus(void) cuda_poll(); return 0; } - +#endif /* CONFIG_ADB */ /* Construct and send a cuda request */ int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), @@ -534,7 +561,18 @@ cuda_input(unsigned char *buf, int nb, struct pt_regs *regs) switch (buf[0]) { case ADB_PACKET: +#ifdef CONFIG_XMON + if (nb == 5 && buf[2] == 0x2c) { + extern int xmon_wants_key, xmon_adb_keycode; + if (xmon_wants_key) { + xmon_adb_keycode = buf[3]; + return; + } + } +#endif /* CONFIG_XMON */ +#ifdef CONFIG_ADB adb_input(buf+2, nb-2, regs, buf[1] & 0x40); +#endif /* CONFIG_ADB */ break; default: diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index efec54db0be6..9712ddbae821 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -39,10 +40,16 @@ #include #include #include +#include #include #include #include -#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + +/* Some compile options */ +#undef SUSPEND_USES_PMU /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -84,7 +91,7 @@ static volatile unsigned char *via; #define CB2_INT 0x08 #define CB1_INT 0x10 /* transition on CB1 input */ -static enum pmu_state { +static volatile enum pmu_state { idle, sending, intack, @@ -95,7 +102,7 @@ static enum pmu_state { static struct adb_request *current_req; static struct adb_request *last_req; static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[32]; +static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */ static unsigned char *reply_ptr; static int data_index; static int data_len; @@ -106,22 +113,27 @@ static struct adb_request bright_req_1, bright_req_2, bright_req_3; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; -static int pmu_has_adb, pmu_has_backlight; +static int pmu_has_adb; static unsigned char *gpio_reg = NULL; -static int gpio_irq; +static int gpio_irq = -1; +static volatile int pmu_suspended = 0; +static spinlock_t pmu_lock; int asleep; struct notifier_block *sleep_notifier_list; +#ifdef CONFIG_ADB static int pmu_probe(void); static int pmu_init(void); +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); +#endif /* CONFIG_ADB */ + 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_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); static void recv_byte(void); static void pmu_sr_intr(struct pt_regs *regs); @@ -130,20 +142,25 @@ static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +#ifdef CONFIG_PMAC_BACKLIGHT +static int pmu_set_backlight_level(int level, void* data); +static int pmu_set_backlight_enable(int on, int level, void* data); +#endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); #endif +#ifdef CONFIG_ADB struct adb_driver via_pmu_driver = { "PMU", pmu_probe, pmu_init, pmu_send_request, - /*pmu_queue_request,*/ pmu_adb_autopoll, pmu_poll, pmu_adb_reset_bus }; +#endif /* CONFIG_ADB */ extern void low_sleep_handler(void); extern void sleep_save_intrs(int); @@ -206,6 +223,13 @@ static char *pbook_type[] = { "Core99" }; +#ifdef CONFIG_PMAC_BACKLIGHT +static struct backlight_controller pmu_backlight_controller = { + pmu_set_backlight_enable, + pmu_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + int __openfirmware find_via_pmu() { @@ -216,17 +240,6 @@ find_via_pmu() return 0; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); -#if 0 - { int i; - - 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 ="); - for (i = 0; i < vias->n_intrs; ++i) - printk(" %x", vias->intrs[i].line); - printk("\n"); } -#endif if (vias->n_addrs < 1 || vias->n_intrs < 1) { printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n", @@ -235,8 +248,9 @@ find_via_pmu() return 0; } + spin_lock_init(&pmu_lock); + pmu_has_adb = 1; - pmu_has_backlight = 1; if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) @@ -246,9 +260,18 @@ find_via_pmu() else if (device_is_compatible(vias->parent, "heathrow")) pmu_kind = PMU_HEATHROW_BASED; else if (device_is_compatible(vias->parent, "Keylargo")) { + struct device_node *gpio, *gpiop; + pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); - pmu_has_backlight = (find_type_devices("backlight") != NULL); + + gpiop = find_devices("gpio"); + if (gpiop && gpiop->n_addrs) { + gpio_reg = ioremap(gpiop->addrs->address, 0x10); + gpio = find_devices("extint-gpio1"); + if (gpio && gpio->parent == gpiop && gpio->n_intrs) + gpio_irq = gpio->intrs[0].line; + } } else pmu_kind = PMU_UNKNOWN; @@ -266,10 +289,13 @@ find_via_pmu() printk(KERN_INFO "PMU driver initialized for %s\n", pbook_type[pmu_kind]); + sys_ctrler = SYS_CTRLER_PMU; + return 1; } +#ifdef CONFIG_ADB static int __openfirmware pmu_probe() { @@ -280,9 +306,10 @@ static int __openfirmware pmu_init(void) { if (vias == NULL) - return -ENXIO; + return -ENODEV; return 0; } +#endif /* CONFIG_ADB */ /* * We can't wait until pmu_init gets called, that happens too late. @@ -291,10 +318,10 @@ pmu_init(void) * turned us off. * This is called from arch/ppc/kernel/pmac_setup.c:pmac_init2(). */ -void via_pmu_start(void) +int via_pmu_start(void) { if (vias == NULL) - return; + return -ENODEV; bright_req_1.complete = 1; bright_req_2.complete = 1; @@ -304,24 +331,12 @@ void via_pmu_start(void) (void *)0)) { printk(KERN_ERR "VIA-PMU: can't get irq %d\n", vias->intrs[0].line); - return; + return -EAGAIN; } - if (pmu_kind == PMU_KEYLARGO_BASED) { - struct device_node *gpio, *gpiop; - - gpiop = find_devices("gpio"); - if (gpiop && gpiop->n_addrs) { - gpio_reg = ioremap(gpiop->addrs->address, 0x10); - gpio = find_devices("extint-gpio1"); - if (gpio && gpio->parent == gpiop && gpio->n_intrs) { - gpio_irq = gpio->intrs[0].line; - if (request_irq(gpio_irq, gpio1_interrupt, 0, - "GPIO1/ADB", (void *)0)) - printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", - gpio->intrs[0].line); - } - } + if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) { + if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0)) + printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq); } /* Enable interrupts */ @@ -329,8 +344,24 @@ void via_pmu_start(void) pmu_fully_inited = 1; +#ifdef CONFIG_PMAC_BACKLIGHT /* Enable backlight */ - pmu_enable_backlight(1); + register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + /* Make sure PMU settle down before continuing. This is _very_ important + * since the IDE probe may shut interrupts down for quite a bit of time. If + * a PMU communication is pending while this happens, the PMU may timeout + * Not that on Core99 machines, the PMU keeps sending us environement + * messages, we should find a way to either fix IDE or make it call + * pmu_suspend() before masking interrupts. This can also happens while + * scolling with some fbdevs. + */ + do { + pmu_poll(); + } while (pmu_state != idle); + + return 0; } static int __openfirmware @@ -342,7 +373,7 @@ init_pmu() out_8(&via[B], via[B] | TREQ); /* negate TREQ */ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); timeout = 100000; while (!req.complete) { if (--timeout < 0) { @@ -367,6 +398,13 @@ init_pmu() udelay(10); } + /* Tell PMU we are ready. Which PMU support this ? */ + if (pmu_kind == PMU_KEYLARGO_BASED) { + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + } + return 1; } @@ -376,6 +414,7 @@ pmu_get_model(void) return pmu_kind; } +#ifdef CONFIG_ADB /* Send an ADB command */ static int __openfirmware pmu_send_request(struct adb_request *req, int sync) @@ -513,6 +552,7 @@ pmu_adb_reset_bus(void) return 0; } +#endif /* CONFIG_ADB */ /* Construct and send a pmu request */ int __openfirmware @@ -568,8 +608,8 @@ pmu_queue_request(struct adb_request *req) req->next = 0; req->sent = 0; req->complete = 0; - save_flags(flags); cli(); + spin_lock_irqsave(&pmu_lock, flags); if (current_req != 0) { last_req->next = req; last_req = req; @@ -579,11 +619,27 @@ pmu_queue_request(struct adb_request *req) if (pmu_state == idle) pmu_start(); } + spin_unlock_irqrestore(&pmu_lock, flags); - restore_flags(flags); return 0; } +static void __openfirmware +wait_for_ack(void) +{ + /* Sightly increased the delay, I had one occurence of the message + * reported + */ + int timeout = 4000; + while ((in_8(&via[B]) & TACK) == 0) { + if (--timeout < 0) { + printk(KERN_ERR "PMU not responding (!ack)\n"); + return; + } + udelay(10); + } +} + /* New PMU seems to be very sensitive to those timings, so we make sure * PCI is flushed immediately */ static void __openfirmware @@ -613,57 +669,126 @@ static volatile int disable_poll; static void __openfirmware pmu_start() { - unsigned long flags; struct adb_request *req; /* assert pmu_state == idle */ /* get the packet to send */ - save_flags(flags); cli(); req = current_req; if (req == 0 || pmu_state != idle - || (req->reply_expected && req_awaiting_reply)) - goto out; + || (/*req->reply_expected && */req_awaiting_reply)) + return; pmu_state = sending; data_index = 1; data_len = pmu_data_len[req->data[0]][0]; + /* Sounds safer to make sure ACK is high before writing. This helped + * kill a problem with ADB and some iBooks + */ + wait_for_ack(); /* set the shift register to shift out and send a byte */ - ++disable_poll; send_byte(req->data[0]); - --disable_poll; - -out: - restore_flags(flags); } void __openfirmware pmu_poll() { - unsigned long flags; - + if (!via) + return; if (disable_poll) return; - save_flags(flags); - cli(); - if ((via[IFR] & (SR_INT | CB1_INT)) || - (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) + /* Kicks ADB read when PMU is suspended */ + if (pmu_suspended) + adb_int_pending = 1; + do { via_pmu_interrupt(0, 0, 0); - restore_flags(flags); + } while (pmu_suspended && (adb_int_pending || pmu_state != idle + || req_awaiting_reply)); +} + +/* This function loops until the PMU is idle and prevents it from + * anwsering to ADB interrupts. pmu_request can still be called. + * This is done to avoid spurrious shutdowns when we know we'll have + * interrupts switched off for a long time + */ +void __openfirmware +pmu_suspend(void) +{ + unsigned long flags; +#ifdef SUSPEND_USES_PMU + struct adb_request *req; +#endif + if (!via) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended++; + if (pmu_suspended > 1) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + + do { + spin_unlock(&pmu_lock); + via_pmu_interrupt(0, 0, 0); + spin_lock(&pmu_lock); + if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + disable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_CLR); + spin_unlock_irqrestore(&pmu_lock, flags); +#endif /* SUSPEND_USES_PMU */ + break; + } + } while (1); +} + +void __openfirmware +pmu_resume(void) +{ + unsigned long flags; + + if (!via || (pmu_suspended < 1)) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended--; + if (pmu_suspended > 0) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + adb_int_pending = 1; +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + enable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_SET); + spin_unlock_irqrestore(&pmu_lock, flags); + pmu_poll(); +#endif /* SUSPEND_USES_PMU */ } static void __openfirmware via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) { + unsigned long flags; int intr; int nloop = 0; - unsigned long flags; - /* Currently, we use brute-force cli() for syncing with GPIO - * interrupt. I'll make this smarter later, along with some - * spinlocks for SMP */ - save_flags(flags);cli(); + /* This is a bit brutal, we can probably do better */ + spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; + while ((intr = in_8(&via[IFR])) != 0) { if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " @@ -681,25 +806,38 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) out_8(&via[IFR], intr); } } - if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0) + /* This is not necessary except if synchronous ADB requests are done + * with interrupts off, which should not happen. Since I'm not sure + * this "wiring" will remain, I'm commenting it out for now. Please do + * not remove. -- BenH. + */ +#if 0 + if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0) adb_int_pending = 1; +#endif if (pmu_state == idle) { if (adb_int_pending) { pmu_state = intack; + /* Sounds safer to make sure ACK is high before writing. + * This helped kill a problem with ADB and some iBooks + */ + wait_for_ack(); send_byte(PMU_INT_ACK); adb_int_pending = 0; } else if (current_req) { pmu_start(); } } + --disable_poll; - restore_flags(flags); + spin_unlock_irqrestore(&pmu_lock, flags); } static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { + adb_int_pending = 1; via_pmu_interrupt(0, 0, 0); } @@ -707,7 +845,7 @@ static void __openfirmware pmu_sr_intr(struct pt_regs *regs) { struct adb_request *req; - int bite, timeout; + int bite; if (via[B] & TREQ) { printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); @@ -720,26 +858,16 @@ pmu_sr_intr(struct pt_regs *regs) if (via[B] & TACK) { while ((in_8(&via[B]) & TACK) != 0) ; -#if 0 - printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n", - via[B]); -#endif } /* reset TREQ and wait for TACK to go high */ out_8(&via[B], in_8(&via[B]) | TREQ); - timeout = 3200; - while ((in_8(&via[B]) & TACK) == 0) { - if (--timeout < 0) { - printk(KERN_ERR "PMU not responding (!ack)\n"); - return; - } - udelay(10); - } + wait_for_ack(); /* 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) { @@ -761,8 +889,11 @@ pmu_sr_intr(struct pt_regs *regs) current_req = req->next; if (req->reply_expected) req_awaiting_reply = req; - else + else { + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); + } } else { pmu_state = reading; data_index = 0; @@ -795,12 +926,16 @@ pmu_sr_intr(struct pt_regs *regs) } if (pmu_state == reading_intr) { + spin_unlock(&pmu_lock); pmu_handle_data(interrupt_data, data_index, regs); + spin_lock(&pmu_lock); } else { req = current_req; current_req = req->next; req->reply_len += data_index; + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); } pmu_state = idle; @@ -826,6 +961,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) { asleep = 0; if (len < 1) { +// xmon_printk("empty ADB\n"); adb_int_pending = 0; return; } @@ -854,6 +990,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) } } #endif /* CONFIG_XMON */ +#ifdef CONFIG_ADB /* * XXX On the [23]400 the PMU gives us an up * event for keycodes 0x74 or 0x75 when the PC @@ -864,10 +1001,13 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) && data[1] == 0x2c && data[3] == 0xff && (data[2] & ~1) == 0xf4)) adb_input(data+1, len-1, regs, 1); +#endif /* CONFIG_ADB */ } } else if (data[0] == 0x08 && len == 3) { /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_level(data[1] >> 4); +#endif set_volume(data[2]); } else { #ifdef CONFIG_PMAC_PBOOK @@ -876,53 +1016,23 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) } } -int backlight_level = -1; -int backlight_enabled = 0; - -#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) - -void __openfirmware -pmu_enable_backlight(int on) +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_to_bright[] = { + 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, + 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e +}; + +static int __openfirmware +pmu_set_backlight_enable(int on, int level, void* data) { struct adb_request req; + + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return; - - /* 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; - break; - 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(); - backlight_level = req.reply[1]; - printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level); - break; - case PMU_PADDINGTON_BASED: - case PMU_KEYLARGO_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: - backlight_enabled = 0; - return; - } - } if (on) { pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - LEVEL_TO_BRIGHT(backlight_level)); + backlight_to_bright[level]); while (!req.complete) pmu_poll(); } @@ -930,35 +1040,28 @@ pmu_enable_backlight(int on) PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); while (!req.complete) pmu_poll(); - backlight_enabled = on; + + return 0; } -void __openfirmware -pmu_set_brightness(int level) +static int __openfirmware +pmu_set_backlight_level(int level, void* data) { - int bright; + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return ; + if (!bright_req_1.complete) + return -EAGAIN; + pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + backlight_to_bright[level]); + if (!bright_req_2.complete) + return -EAGAIN; + pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT + | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); - backlight_level = level; - bright = LEVEL_TO_BRIGHT(level); - if (!backlight_enabled) - return; - if (bright_req_1.complete) - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, - bright); - if (bright_req_2.complete) - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); - - /* XXX nvram address is hard-coded and looks ok on wallstreet, please - test on your machine. Note that newer MacOS system software may break - the nvram layout. */ - if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete) - pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM, - 0x14, 0xe, level); + return 0; } +#endif /* CONFIG_PMAC_BACKLIGHT */ void __openfirmware pmu_enable_irled(int on) @@ -967,6 +1070,8 @@ pmu_enable_irled(int on) if (vias == NULL) return ; + if (pmu_kind == PMU_KEYLARGO_BASED) + return ; pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED | (on ? PMU_POW_ON : PMU_POW_OFF)); @@ -1201,17 +1306,9 @@ 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); + struct adb_request req; /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); @@ -1245,14 +1342,13 @@ int __openfirmware powerbook_sleep_G3(void) /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); + feature_prepare_for_sleep(); + /* 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)); - if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) giveup_fpu(current); @@ -1263,17 +1359,14 @@ int __openfirmware powerbook_sleep_G3(void) 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) + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) pmu_poll(); cli(); while (pmu_state != idle) pmu_poll(); - /* clear IOBUS enable */ - out_le32(FEATURE_CTRL(macio_base), save_fcr & ~HRW_IOBUS_ENABLE); - /* Call low-level ASM sleep handler */ low_sleep_handler(); @@ -1282,15 +1375,14 @@ int __openfirmware powerbook_sleep_G3(void) pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); - /* reenable IOBUS */ - out_le32(FEATURE_CTRL(macio_base), save_fcr | HRW_IOBUS_ENABLE); - /* Make sure the PMU is idle */ while (pmu_state != idle) pmu_poll(); sti(); + feature_wake_up(); + /* The PGD is only a placeholder until Dan finds a way to make * this work properly on the 8xx processors. It is only used on * 8xx processors, it is ignored here. @@ -1304,6 +1396,116 @@ int __openfirmware powerbook_sleep_G3(void) /* reenable interrupts */ sleep_restore_intrs(); + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + + /* Notify drivers */ + mdelay(10); + broadcast_wake(); + + return 0; +} + +/* Not finished yet */ +int __openfirmware powerbook_sleep_Core99(void) +{ + int ret; + unsigned long save_l2cr; + unsigned long wait; + struct adb_request req; + + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep rejected\n"); + 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. + * BenH: Moved to _after_ sleep request and changed video + * drivers to vmalloc() during sleep request. This way, all + * vmalloc's are done before actual sleep of block drivers */ + fsync_dev(0); + + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep failed\n"); + return -EBUSY; + } + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); + + /* Tell PMU what events will wake us up */ + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, + 0xff, 0xff); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, + 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + while (!req.complete) + pmu_poll(); + + /* 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)); + + /* Save the state of PCI config space for some slots */ + pbook_pci_save(); + + feature_prepare_for_sleep(); + + /* 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 (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) + mb(); + + cli(); + while (pmu_state != idle) + pmu_poll(); + + /* Call low-level ASM sleep handler */ + low_sleep_handler(); + + /* Make sure the PMU is idle */ + while (pmu_state != idle) + pmu_poll(); + + sti(); + + feature_wake_up(); + pbook_pci_restore(); + + set_context(current->mm->context, current->mm->pgd); + + /* Restore L2 cache */ + if (save_l2cr) + _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + + /* reenable interrupts */ + sleep_restore_intrs(); + + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + /* Notify drivers */ mdelay(10); broadcast_wake(); @@ -1557,7 +1759,6 @@ 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: @@ -1569,21 +1770,33 @@ static int pmu_ioctl(struct inode * inode, struct file *filp, case PMU_PADDINGTON_BASED: error = powerbook_sleep_G3(); break; +#if 0 /* Not ready yet */ + case PMU_KEYLARGO_BASED: + error = powerbook_sleep_Core99(); + break; +#endif default: error = -ENOSYS; } return error; +#ifdef CONFIG_PMAC_BACKLIGHT + /* Backlight should have its own device or go via + * the fbdev + */ case PMU_IOC_GET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; - return put_user(backlight_level, (__u32 *)arg); + error = get_backlight_level(); + if (error < 0) + return error; + return put_user(error, (__u32 *)arg); case PMU_IOC_SET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; + { + __u32 value; error = get_user(value, (__u32 *)arg); if (!error) - pmu_set_brightness(value); + error = set_backlight_level(value); return error; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); case PMU_IOC_HAS_ADB: diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 6c88a757e702..fe0d72e696c5 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3027,11 +3027,11 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) * Scan for a Bt848 card, request the irq and map the io memory */ -static void __devinit bttv_remove(struct pci_dev *pci_dev) +static void __devexit bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; - struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); + struct bttv *btv = pci_get_drvdata(pci_dev); /* unregister i2c_bus */ if (0 == btv->i2c_ok) @@ -3093,6 +3093,8 @@ static void __devinit bttv_remove(struct pci_dev *pci_dev) btv->shutdown=1; wake_up(&btv->gpioq); + pci_set_drvdata(pci_dev, NULL); + return; } @@ -3198,7 +3200,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id } } - PCI_SET_DRIVER_DATA(dev,btv); + pci_set_drvdata(dev,btv); if(init_bt848(btv) < 0) { bttv_remove(dev); diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index 6b35d23e5c20..5b9c178cb08b 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -23,11 +23,6 @@ #define BTTV_VERSION_CODE KERNEL_VERSION(0,7,38) -#ifndef PCI_GET_DRIVER_DATA -# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) -# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - #include #include #include diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index eab61b55e9c2..e549336fa146 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -332,6 +332,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) { static unsigned char init_ID_done = 0, version_printed = 0; int i, irq, irqval; + struct net_local *lp; if (init_ID_done == 0) { ushort lrs_state = 0xff; @@ -355,7 +356,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) /* Allocate a new 'dev' if needed. */ if (dev == NULL) - dev = init_etherdev(0, sizeof(struct net_local)); + dev = init_etherdev(0, 0); if (net_debug && version_printed++ == 0) printk(version); @@ -417,10 +418,11 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) printk(version); /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + lp = dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); + spin_lock_init(&lp->lock); dev->open = el16_open; dev->stop = el16_close; diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 819c49050bd5..0e91f92d0ae2 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -193,6 +193,7 @@ static int nopnp = 0; int el3_probe(struct net_device *dev) { + struct el3_private *lp; short lrs_state = 0xff, i; int ioaddr, irq, if_port; u16 phys_addr[3]; @@ -200,7 +201,7 @@ int el3_probe(struct net_device *dev) int mca_slot = -1; #ifdef __ISAPNP__ static int pnp_cards = 0; -#endif +#endif /* __ISAPNP__ */ /* First check all slots of the EISA bus. The next slot address to probe is kept in 'eisa_addr' to support multiple probe() calls. */ @@ -292,7 +293,7 @@ int el3_probe(struct net_device *dev) /* if we get here, we didn't find an MCA adapter */ return -ENODEV; } -#endif +#endif /* CONFIG_MCA */ #ifdef __ISAPNP__ if (nopnp == 1) @@ -330,7 +331,7 @@ int el3_probe(struct net_device *dev) } } no_pnp: -#endif +#endif /* __ISAPNP__ */ /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { @@ -396,7 +397,7 @@ no_pnp: } } } -#endif +#endif /* __ISAPNP__ */ { unsigned int iobase = id_read_eeprom(8); @@ -466,9 +467,10 @@ no_pnp: return -ENOMEM; memset(dev->priv, 0, sizeof(struct el3_private)); - ((struct el3_private *)dev->priv)->mca_slot = mca_slot; - ((struct el3_private *)dev->priv)->next_dev = el3_root_dev; - ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + lp = dev->priv; + lp->mca_slot = mca_slot; + lp->next_dev = el3_root_dev; + spin_lock_init(&lp->lock); el3_root_dev = dev; if (el3_debug > 0) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index b0d56c90c3b9..bbd2f0fac087 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2,9 +2,37 @@ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. - Copyright 2000 Jeff Garzik + Maintained by Jeff Garzik - Originally: Written 1997-1999 by Donald Becker. + Much code comes from Donald Becker's rtl8139.c driver, + versions 1.11 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + + ---------- + + Written 1997-2000 by Donald Becker. + This software may be used and distributed according to the + terms of the GNU General Public License (GPL), incorporated + herein by reference. Drivers based on or derived from this + code fall under the GPL and must retain the authorship, + copyright and license notice. This file is not a complete + program and may only be used when the entire operating + system is licensed under the GPL. + + This driver is for boards based on the RTL8129 and RTL8139 + PCI ethernet chips. + + The author may be reached as becker@scyld.com, or C/O Scyld + Computing Corporation 410 Severn Ave., Suite 210 Annapolis + MD 21403 + + Support and updates available at + http://www.scyld.com/network/rtl8139.html + + Twister-tuning table provided by Kinston + . + + ---------- This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -17,7 +45,7 @@ Tigran Aivazian - bug fixes, skbuff free cleanup Martin Mares - suggestions for PCI cleanup - + David S. Miller - PCI DMA and softnet updates Ernst Gill - fixes ported from BSD driver @@ -25,16 +53,23 @@ Daniel Kobras - identified specific locations of posted MMIO write bugginess - Gerard Sharp - bug fix - + Gerard Sharp - bug fix, testing and feedback + David Ford - Rx ring wrap fix - + Dan DeMaggio - swapped RTL8139 cards with me, and allowed me to find and fix a crucial bug on older chipsets. - + Donald Becker/Chris Butterworth/Marcus Westergren - Noticed various Rx packet size-related buglets. + Santiago Garcia Mantinan - testing and feedback + + Jens David - 2.2.x kernel backports + + Martin Dennett - incredibly helpful insight on undocumented + features of the 8139 chips + Submitting bug reports: "rtl8139-diag -mmmaaavvveefN" output @@ -82,7 +117,7 @@ that almost all frames will need to be copied to an alignment buffer. IVb. References http://www.realtek.com.tw/cn/cn.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.scyld.com/expert/NWay.html IVc. Errata @@ -105,27 +140,34 @@ an MMIO register read. #include #include -#undef USE_IO_OPS /* define to 1 to enable PIO instead of MMIO */ -#define RTL8139_VERSION "0.9.9" +#define RTL8139_VERSION "0.9.10" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " -#undef RTL8139_DEBUG /* define to 1 to enable copious debugging info */ + +/* define to 1 to enable PIO instead of MMIO */ +#undef USE_IO_OPS + +/* define to 1 to enable copious debugging info */ +#undef RTL8139_DEBUG + +/* define to 1 to disable lightweight runtime debugging checks */ +#undef RTL8139_NDEBUG + #ifdef RTL8139_DEBUG /* note: prints function name for you */ -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) #else -#define DPRINTK(fmt, args...) +# define DPRINTK(fmt, args...) #endif -#undef RTL8139_NDEBUG /* define to 1 to disable lightweight runtime checks */ #ifdef RTL8139_NDEBUG -#define assert(expr) +# define assert(expr) do {} while (0) #else -#define assert(expr) \ +# define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ #expr,__FILE__,__FUNCTION__,__LINE__); \ @@ -135,12 +177,6 @@ an MMIO register read. #define arraysize(x) (sizeof(x)/sizeof(*(x))) -#ifndef PCI_GET_DRIVER_DATA - #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) - #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - - /* A few user-configurable values. */ /* media options */ static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; @@ -156,7 +192,8 @@ static int multicast_filter_limit = 32; #define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) #define RX_BUF_PAD 16 -#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD) +#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ +#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -170,9 +207,9 @@ static int multicast_filter_limit = 32; #define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '7' is unlimited */ -#define TX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 */ +#define RX_FIFO_THRESH 6 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ /* Operational parameters that usually are not changed. */ @@ -331,6 +368,7 @@ enum tx_config_bits { TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ }; @@ -351,7 +389,7 @@ enum RxConfigBits { /* Early Rx threshold, none or X/16 */ RxCfgEarlyRxNone = 0, RxCfgEarlyRxShift = 24, - + /* rx fifo threshold */ RxCfgFIFOShift = 13, RxCfgFIFONone = (7 << RxCfgFIFOShift), @@ -365,6 +403,9 @@ enum RxConfigBits { RxCfgRcv16K = (1 << 11), RxCfgRcv32K = (1 << 12), RxCfgRcv64K = (1 << 11) | (1 << 12), + + /* Disable packet wrap at end of Rx buffer */ + RxNoWrap = (1 << 7), }; @@ -421,17 +462,17 @@ const static struct { 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ }, - + { "RTL-8139 rev K", 0x60, - 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + 0xf0fe0040, }, - + { "RTL-8139A", 0x70, 0xf0fe0040, }, - + { "RTL-8139B", 0x78, 0xf0fc0040 @@ -564,12 +605,14 @@ static void rtl8139_hw_start (struct net_device *dev); #endif /* USE_IO_OPS */ -static const u16 rtl8139_intr_mask = +static const u16 rtl8139_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - RxCfgEarlyRxNone | RxCfgFIFONone | RxCfgRcv32K | RxCfgDMAUnlimited; + RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); static int __devinit rtl8139_init_board (struct pci_dev *pdev, @@ -615,7 +658,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, /* set this immediately, we need to know before * we talk to the chip directly */ DPRINTK("PIO region size == 0x%02X\n", pio_len); - DPRINTK("MMIO region size == 0x%02X\n", mmio_len); + DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); if (pio_len == RTL8139B_IO_SIZE) tp->chipset = CH_8139B; @@ -625,14 +668,14 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, rc = -ENODEV; goto err_out; } - + /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; goto err_out; } - + /* check for weird/broken PCI region reporting */ if ((pio_len != mmio_len) || (pio_len < RTL_MIN_IO_SIZE) || @@ -648,14 +691,14 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, rc = -EBUSY; goto err_out; } - + /* make sure our MMIO region in PCI space is available */ if (!request_mem_region (mmio_start, mmio_len, dev->name)) { printk (KERN_ERR PFX "no mem resource available, aborting\n"); rc = -EBUSY; goto err_out_free_pio; } - + /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device (pdev); if (rc) @@ -702,7 +745,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); #endif /* !USE_IO_OPS */ - + /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { @@ -715,7 +758,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, rc = -EIO; goto err_out_iounmap; } - + /* identify chip attached to board */ tmp = RTL_R8 (ChipVersion); for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--) @@ -735,11 +778,11 @@ match: tmp, tp->chipset, rtl_chip_info[tp->chipset].name); - + DPRINTK ("EXIT, returning 0\n"); *ioaddr_out = ioaddr; *dev_out = dev; - return 0; + return 0; err_out_iounmap: assert (ioaddr > 0); @@ -766,14 +809,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - u8 tmp; - -#ifndef RTL8139_NDEBUG static int printed_version = 0; -#endif /* RTL8139_NDEBUG */ + u8 tmp; DPRINTK ("ENTER\n"); - + assert (pdev != NULL); assert (ent != NULL); @@ -789,9 +829,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, DPRINTK ("EXIT, returning %d\n", i); return i; } - + tp = dev->priv; - + assert (ioaddr != NULL); assert (dev != NULL); assert (tp != NULL); @@ -825,24 +865,23 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, tp->mmio_addr = ioaddr; tp->lock = SPIN_LOCK_UNLOCKED; - PCI_SET_DRIVER_DATA (pdev, dev); + pdev->driver_data = dev; tp->phys[0] = 32; - printk (KERN_INFO "%s: %s board found at 0x%lx, IRQ %d\n", - dev->name, board_info[ent->driver_data].name, - dev->base_addr, dev->irq); - - printk (KERN_INFO "%s: Chip is '%s'\n", - dev->name, - rtl_chip_info[tp->chipset].name); - - printk (KERN_INFO "%s: MAC address " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + printk (KERN_INFO "%s: %s at 0x%lx, " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "IRQ %d\n", dev->name, + board_info[ent->driver_data].name, + dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + dev->dev_addr[4], dev->dev_addr[5], + dev->irq); + + printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", + dev->name, rtl_chip_info[tp->chipset].name); /* Put the chip into low-power mode. */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -877,7 +916,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, static void __devexit rtl8139_remove_one (struct pci_dev *pdev) { - struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct net_device *dev = pdev->driver_data; struct rtl8139_private *np; DPRINTK ("ENTER\n"); @@ -906,7 +945,9 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) #endif /* RTL8139_NDEBUG */ kfree (dev); - + + pdev->driver_data = NULL; + DPRINTK ("EXIT\n"); } @@ -1143,9 +1184,9 @@ static int rtl8139_open (struct net_device *dev) DPRINTK ("EXIT, returning -ENOMEM\n"); MOD_DEC_USE_COUNT; return -ENOMEM; - + } - + tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; @@ -1180,7 +1221,7 @@ static void rtl8139_hw_start (struct net_device *dev) u8 tmp; DPRINTK ("ENTER\n"); - + /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); udelay (100); @@ -1203,7 +1244,7 @@ static void rtl8139_hw_start (struct net_device *dev) RTL_W32_F (RxConfig, i); /* Check this value: the documentation for IFG contradicts ifself. */ - RTL_W32 (TxConfig, (TX_DMA_BURST << 8)); + RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); /* unlock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -1224,9 +1265,9 @@ static void rtl8139_hw_start (struct net_device *dev) if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ - tmp |= (1<<7); + tmp |= (1<<7); RTL_W8 (Config4, tmp); - + /* disable magic packet scanning, which is enabled * when PM is enabled above (Config1) */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); @@ -1383,15 +1424,13 @@ static void rtl8139_timer (unsigned long data) { struct net_device *dev = (struct net_device *) data; struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; int mii_reg5; - spin_lock_irq (&tp->lock); - mii_reg5 = mdio_read (dev, tp->phys[0], 5); if (!tp->duplex_lock && mii_reg5 != 0xffff) { - void *ioaddr = tp->mmio_addr; int duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { @@ -1420,8 +1459,6 @@ static void rtl8139_timer (unsigned long data) dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); - spin_unlock_irq (&tp->lock); - tp->timer.expires = jiffies + next_tick; add_timer (&tp->timer); } @@ -1432,6 +1469,7 @@ static void rtl8139_tx_timeout (struct net_device *dev) struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1439,25 +1477,20 @@ static void rtl8139_tx_timeout (struct net_device *dev) RTL_R16 (IntrStatus), RTL_R8 (MediaStatus)); - spin_lock_irq (&tp->lock); - /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); - spin_unlock_irq (&tp->lock); - /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG - "%s: Tx queue start entry %d dirty entry %d.\n", + printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", dev->name, atomic_read (&tp->cur_tx), atomic_read (&tp->dirty_tx)); for (i = 0; i < NUM_TX_DESC; i++) printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n", dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), - i == - atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? " (queue head)" : ""); + i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? + " (queue head)" : ""); - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); /* Stop a shared interrupt from scavenging while we are. */ atomic_set (&tp->cur_tx, 0); @@ -1467,7 +1500,8 @@ static void rtl8139_tx_timeout (struct net_device *dev) for (i = 0; i < NUM_TX_DESC; i++) { struct ring_info *rp = &tp->tx_info[i]; if (rp->mapping != 0) { - pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); + pci_unmap_single (tp->pci_dev, rp->mapping, + rp->skb->len, PCI_DMA_TODEVICE); rp->mapping = 0; } if (rp->skb) { @@ -1476,9 +1510,10 @@ static void rtl8139_tx_timeout (struct net_device *dev) tp->stats.tx_dropped++; } } - - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); + + /* ...and finally, reset everything */ rtl8139_hw_start (dev); } @@ -1493,18 +1528,17 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) /* Calculate the next Tx descriptor entry. */ entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC; + assert (tp->tx_info[entry].skb == NULL); + assert (tp->tx_info[entry].mapping == 0); + tp->tx_info[entry].skb = skb; - tp->tx_info[entry].mapping = 0; + /* tp->tx_info[entry].mapping = 0; */ memcpy (tp->tx_buf[entry], skb->data, skb->len); - spin_lock_irq (&tp->lock); - /* Note: the chip doesn't have auto-pad! */ RTL_W32 (TxStatus0 + (entry * sizeof(u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); - spin_unlock_irq (&tp->lock); - dev->trans_start = jiffies; atomic_inc (&tp->cur_tx); if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC) @@ -1526,20 +1560,15 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - - /* drop lock held in rtl8139_interrupt */ - spin_unlock (&tp->lock); - + dirty_tx = atomic_read (&tp->dirty_tx); while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus; - spin_lock (&tp->lock); - txstatus = RTL_R32 (TxStatus0 + (entry * 4)); - spin_unlock (&tp->lock); - + txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32))); + if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) break; /* It still hasn't been Txed */ @@ -1551,9 +1580,7 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; - spin_lock (&tp->lock); - RTL_W32 (TxConfig, (TX_DMA_BURST << 8)); - spin_unlock (&tp->lock); + RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; @@ -1600,9 +1627,6 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, #endif /* RTL8139_NDEBUG */ atomic_set (&tp->dirty_tx, dirty_tx); - - /* obtain lock need for rtl8139_interrupt */ - spin_lock (&tp->lock); } @@ -1738,32 +1762,9 @@ static void rtl8139_rx_interrupt (struct net_device *dev, skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset + rx_size > RX_BUF_LEN) { - int semi_count = RX_BUF_LEN - ring_offset - 4; - - /* This could presumably use two calls to copy_and_sum()? */ - memcpy (skb_put (skb, semi_count), - &rx_ring[ring_offset + 4], semi_count); - memcpy (skb_put (skb, pkt_size - semi_count), - rx_ring, pkt_size - semi_count); -#if RTL8139_DEBUG > 4 - { - int i; - printk (KERN_DEBUG "%s: Frame wrap @%d", - dev->name, semi_count); - for (i = 0; i < 16; i++) - printk (" %2.2x", rx_ring[i]); - printk ("\n"); - memset (rx_ring, 0xcc, 16); - } -#endif /* RTL8139_DEBUG */ + eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); + skb_put (skb, pkt_size); - } else { - eth_copy_and_sum (skb, - &rx_ring[ring_offset + 4], - pkt_size, 0); - skb_put (skb, pkt_size); - } skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); tp->stats.rx_bytes += pkt_size; @@ -1782,18 +1783,18 @@ static void rtl8139_rx_interrupt (struct net_device *dev, } -static int rtl8139_weird_interrupt (struct net_device *dev, - struct rtl8139_private *tp, - void *ioaddr, - int status, int link_changed) +static void rtl8139_weird_interrupt (struct net_device *dev, + struct rtl8139_private *tp, + void *ioaddr, + int status, int link_changed) { - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); - + printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); + assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - + /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); @@ -1831,8 +1832,6 @@ static int rtl8139_weird_interrupt (struct net_device *dev, printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); } - - return 0; } @@ -1848,14 +1847,14 @@ static void rtl8139_interrupt (int irq, void *dev_instance, int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ spin_lock (&tp->lock); - + do { status = RTL_R16 (IntrStatus); /* h/w no longer present (hotplug?) or major error, bail */ if (status == 0xFFFF) break; - + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -1917,7 +1916,7 @@ static void rtl8139_interrupt (int irq, void *dev_instance, } spin_unlock (&tp->lock); - + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -1938,7 +1937,7 @@ static int rtl8139_close (struct net_device *dev) dev->name, RTL_R16 (IntrStatus)); del_timer_sync (&tp->timer); - + spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts by clearing the interrupt mask. */ @@ -1952,7 +1951,7 @@ static int rtl8139_close (struct net_device *dev) RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); - + /* snooze for a small bit */ if (current->need_resched) schedule (); @@ -2116,7 +2115,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev) set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); } - + /* if called from irq handler, lock already acquired */ if (!in_irq ()) spin_lock_irq (&tp->lock); @@ -2137,13 +2136,13 @@ static void rtl8139_set_rx_mode (struct net_device *dev) static void rtl8139_suspend (struct pci_dev *pdev) { - struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct net_device *dev = pdev->driver_data; struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; netif_device_detach (dev); - + spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts, stop Tx and Rx. */ @@ -2160,7 +2159,7 @@ static void rtl8139_suspend (struct pci_dev *pdev) static void rtl8139_resume (struct pci_dev *pdev) { - struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct net_device *dev = pdev->driver_data; netif_device_attach (dev); rtl8139_hw_start (dev); diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5aa7f585802c..80d4dceda215 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -304,7 +304,7 @@ M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) ifneq ($(ARCH),s390) -O_OBJS += auto_irq.o +OX_OBJS += auto_irq.o endif include $(TOPDIR)/Rules.make diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index dd65e6c4eeea..afb43d67a8be 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -155,9 +155,6 @@ void __init arcnet_init(void) #ifdef CONFIG_ARCNET_COM90xx com90xx_probe(NULL); #endif -#ifdef CONFIG_ARCNET_COM20020_PCI - com20020pci_probe_all(); -#endif #endif } diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 9363422188c8..c66c98495816 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -205,7 +205,7 @@ static int __init com20020isa_setup(char *s) case 6: /* Timeout */ lp->timeout = ints[6]; case 5: /* CKP value */ - lp->clock = ints[5]; + lp->clockp = ints[5]; case 4: /* Backplane flag */ lp->backplane = ints[4]; case 3: /* Node ID */ diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 0c92cc4d2471..b4adf1043677 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -148,7 +148,7 @@ static struct pci_driver com20020pci_driver = { remove: com20020pci_remove }; -int com20020pci_init(void) +static int __init com20020pci_init(void) { BUGLVL(D_NORMAL) printk(VERSION); #ifndef MODULE @@ -157,7 +157,7 @@ int com20020pci_init(void) return pci_module_init(&com20020pci_driver); } -void com20020pci_cleanup(void) +static void __exit com20020pci_cleanup(void) { pci_unregister_driver(&com20020pci_driver); } diff --git a/drivers/net/auto_irq.c b/drivers/net/auto_irq.c index efeaeb52c792..2d562b5268ce 100644 --- a/drivers/net/auto_irq.c +++ b/drivers/net/auto_irq.c @@ -32,6 +32,7 @@ static const char *version= "auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)"; #endif +#include #include #include #include @@ -53,6 +54,10 @@ int autoirq_report(int waittime) BUSY_LOOP_UNTIL(delay) return probe_irq_off(irqs); } + +EXPORT_SYMBOL(autoirq_setup); +EXPORT_SYMBOL(autoirq_report); + /* * Local variables: diff --git a/drivers/net/declance.c b/drivers/net/declance.c index d7aa8927d0e7..6d8addf13085 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -1030,6 +1030,7 @@ static int __init dec_lance_init(struct net_device *dev, const int type) /* Make certain the data structures used by the LANCE are aligned. */ dev->priv = (void *) (((unsigned long) dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; + spin_lock_init(&lp->lock); switch (type) { #ifdef CONFIG_TC @@ -1193,9 +1194,9 @@ static int __init dec_lance_init(struct net_device *dev, const int type) lp->multicast_timer.function = &lance_set_multicast_retry; #ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_lance_dev; - root_lance_dev = lp; + dev->ifindex = dev_new_index(); + lp->next_module = root_lance_dev; + root_lance_dev = lp; #endif return 0; } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index f8cf5004aa7c..5f1f697bc549 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -1084,6 +1084,7 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); + spin_lock_init(&lp->lock); printk("(IRQ %d, %s connector, %d-bit bus", dev->irq, eexp_ifmap[dev->if_port], buswidth?8:16); diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c index 0457d374f27b..81a9408df88c 100644 --- a/drivers/net/gmac.c +++ b/drivers/net/gmac.c @@ -9,10 +9,15 @@ * Changes: * Arnaldo Carvalho de Melo - 08/06/2000 * - check init_etherdev return in gmac_probe1 + * BenH - 03/09/2000 + * - Add support for new PHYs + * - Add some PowerBook sleep code * */ #include + +#include #include #include #include @@ -29,13 +34,19 @@ #include #include #include +#include +#ifdef CONFIG_PMAC_PBOOK +#include +#include +#include +#endif #include "gmac.h" #define DEBUG_PHY -/* Driver version 1.1, kernel 2.4.x */ -#define GMAC_VERSION "v1.1k4" +/* Driver version 1.2, kernel 2.4.x */ +#define GMAC_VERSION "v1.2k4" static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; static struct net_device *gmacs = NULL; @@ -48,9 +59,12 @@ static void mii_poll_stop(struct gmac *gm); static void mii_interrupt(struct gmac *gm); static int mii_lookup_and_reset(struct gmac *gm); static void mii_setup_phy(struct gmac *gm); +static int mii_do_reset_phy(struct gmac *gm, int phy_addr); +static void mii_init_BCM5400(struct gmac *gm); static void gmac_set_power(struct gmac *gm, int power_up); static int gmac_powerup_and_reset(struct net_device *dev); +static void gmac_set_gigabit_mode(struct gmac *gm, int gigabit); static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex); static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr); static void gmac_init_rings(struct gmac *gm, int from_irq); @@ -71,6 +85,13 @@ static void gmac_probe1(struct device_node *gmac); extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr); +#ifdef CONFIG_PMAC_PBOOK +int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier gmac_sleep_notifier = { + gmac_sleep_notify, SLEEP_LEVEL_NET, +}; +#endif + /* * Read via the mii interface from a PHY register */ @@ -161,6 +182,19 @@ mii_poll_stop(struct gmac *gm) * a timer and control the autoneg. process more closely. Also, we may * want to stop rx and tx side when the link is down. */ + +/* Link modes of the BCM5400 PHY */ +static int phy_BCM5400_link_table[8][3] = { + { 0, 0, 0 }, /* No link */ + { 0, 0, 0 }, /* 10BT Half Duplex */ + { 1, 0, 0 }, /* 10BT Full Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 1, 1, 0 }, /* 100BT Full Duplex*/ + { 1, 0, 1 }, /* 1000BT */ + { 1, 0, 1 }, /* 1000BT */ +}; + static void mii_interrupt(struct gmac *gm) { @@ -175,8 +209,9 @@ mii_interrupt(struct gmac *gm) /* We read the Auxilliary Status Summary register */ phy_status = mii_read(gm, gm->phy_addr, MII_SR); if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) { - int full_duplex; - int link_100; + int full_duplex = 0; + int link_100 = 0; + int gigabit = 0; #ifdef DEBUG_PHY printk("Link state change, phy_status: 0x%04x\n", phy_status); #endif @@ -188,8 +223,9 @@ mii_interrupt(struct gmac *gm) else GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); - /* Link ? For now we handle only the 5201 PHY */ + /* Link ? Check for speed and duplex */ if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) { + int restart = 0; if (gm->phy_type == PHY_B5201) { int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS); #ifdef DEBUG_PHY @@ -197,19 +233,41 @@ mii_interrupt(struct gmac *gm) #endif full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0); link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0); - } else { - full_duplex = 1; - link_100 = 1; + } else if (gm->phy_type == PHY_B5400) { + int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS); + int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> + MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT; +#ifdef DEBUG_PHY + printk(" Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n", + aux_stat, link); +#endif + full_duplex = phy_BCM5400_link_table[link][0]; + link_100 = phy_BCM5400_link_table[link][1]; + gigabit = phy_BCM5400_link_table[link][2]; + } else if (gm->phy_type == PHY_LXT971) { + int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2); +#ifdef DEBUG_PHY + printk(" Link up ! LXT971 stat2: 0x%04x\n", stat2); +#endif + full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); + link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, - link_100 ? "100" : "10"); + gigabit ? "1000" : (link_100 ? "100" : "10")); #endif + if (gigabit != gm->gigabit) { + gm->gigabit = gigabit; + gmac_set_gigabit_mode(gm, gm->gigabit); + restart = 1; + } if (full_duplex != gm->full_duplex) { gm->full_duplex = full_duplex; gmac_set_duplex_mode(gm, gm->full_duplex); - gmac_start_dma(gm); + restart = 1; } + if (restart) + gmac_start_dma(gm); } else if (!(phy_status & MII_SR_LKS)) { #ifdef DEBUG_PHY printk(" Link down !\n"); @@ -218,19 +276,73 @@ mii_interrupt(struct gmac *gm) } } -/* - * Lookup for a PHY on the mii interface and reset it - */ +static int +mii_do_reset_phy(struct gmac *gm, int phy_addr) +{ + int mii_control, timeout; + + mii_control = mii_read(gm, phy_addr, MII_CR); + mii_write(gm, phy_addr, MII_CR, mii_control | MII_CR_RST); + mdelay(10); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mii_read(gm, phy_addr, MII_CR); + if (mii_control == -1) { + printk(KERN_ERR "%s PHY died after reset !\n", + gm->dev->name); + return 1; + } + if ((mii_control & MII_CR_RST) == 0) + break; + mdelay(10); + } + if (mii_control & MII_CR_RST) { + printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + return 1; + } + mii_write(gm, phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); + return 0; +} + +static void +mii_init_BCM5400(struct gmac *gm) +{ + int data; + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data |= MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + mii_do_reset_phy(gm, 0x1f); + + data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); +} + static int mii_lookup_and_reset(struct gmac *gm) { - int i, timeout; - int mii_status, mii_control; + int i, mii_status, mii_control; - /* Find the PHY */ gm->phy_addr = -1; gm->phy_type = PHY_UNKNOWN; + + /* Hard reset the PHY */ + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT); + mdelay(10); + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE); + mdelay(10); + /* Find the PHY */ for(i=31; i>0; --i) { mii_control = mii_read(gm, i, MII_CR); mii_status = mii_read(gm, i, MII_SR); @@ -243,25 +355,9 @@ mii_lookup_and_reset(struct gmac *gm) return 0; /* Reset it */ - mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST); - mdelay(10); - for (timeout = 100; timeout > 0; --timeout) { - mii_control = mii_read(gm, gm->phy_addr, MII_CR); - if (mii_control == -1) { - printk(KERN_ERR "%s PHY died after reset !\n", - gm->dev->name); - goto fail; - } - if ((mii_control & MII_CR_RST) == 0) - break; - mdelay(10); - } - if (mii_control & MII_CR_RST) { - printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + if (mii_do_reset_phy(gm, gm->phy_addr)) goto fail; - } - mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); - + /* Read the PHY ID */ gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) | mii_read(gm, gm->phy_addr, MII_ID1); @@ -270,10 +366,15 @@ mii_lookup_and_reset(struct gmac *gm) #endif if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) { gm->phy_type = PHY_B5400; - printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n", + printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n", gm->dev->name); + mii_init_BCM5400(gm); } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) { gm->phy_type = PHY_B5201; + printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name); + } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) { + gm->phy_type = PHY_LXT971; + printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name); } else { printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n", gm->dev->name, gm->phy_id); @@ -405,6 +506,22 @@ gmac_set_duplex_mode(struct gmac *gm, int full_duplex) } } +/* Set the MAC gigabit mode. Side effect: stops Tx MAC */ +static void +gmac_set_gigabit_mode(struct gmac *gm, int gigabit) +{ + /* Stop Tx MAC */ + GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE) + ; + + if (gigabit) { + GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } else { + GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } +} + /* * Initialize a bunch of registers to put the chip into a known * and hopefully happy state @@ -788,6 +905,65 @@ gmac_close(struct net_device *dev) return 0; } +#ifdef CONFIG_PMAC_PBOOK +int +gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct gmac *gm; + int i; + + /* XXX should handle more than one */ + if (gmacs == NULL) + return PBOOK_SLEEP_OK; + + gm = (struct gmac *) gmacs->priv; + if (!gm->opened) + return PBOOK_SLEEP_OK; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + break; + case PBOOK_SLEEP_REJECT: + break; + case PBOOK_SLEEP_NOW: + disable_irq(gm->dev->irq); + netif_stop_queue(gm->dev); + gmac_stop_dma(gm); + mii_poll_stop(gm); + gmac_set_power(gm, 0); + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + for (i = 0; i < NTX; ++i) { + if (gm->tx_buff[i] != 0) { + dev_kfree_skb(gm->tx_buff[i]); + gm->tx_buff[i] = 0; + } + } + break; + case PBOOK_WAKE: + /* see if this is enough */ + gmac_powerup_and_reset(gm->dev); + gm->full_duplex = 0; + gm->phy_status = 0; + mii_lookup_and_reset(gm); + mii_setup_phy(gm); + gmac_init_rings(gm, 0); + gmac_mac_init(gm, gm->dev->dev_addr); + gmac_set_multicast(gm->dev); + mii_interrupt(gm); + gmac_start_dma(gm); + netif_start_queue(gm->dev); + enable_irq(gm->dev->irq); + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ + /* * Handle a transmit timeout */ @@ -1196,7 +1372,8 @@ gmac_probe1(struct device_node *gmac) ioremap(gmac->addrs[0].address, 0x10000); dev->irq = gmac->intrs[0].line; gm->dev = dev; - + gm->of_node = gmac; + if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) { gm->pci_bus = gm->pci_devfn = 0xff; printk(KERN_ERR "Can't locate GMAC PCI entry\n"); @@ -1229,6 +1406,10 @@ gmac_probe1(struct device_node *gmac) gm->next_gmac = gmacs; gmacs = dev; + +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&gmac_sleep_notifier); +#endif } MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); diff --git a/drivers/net/gmac.h b/drivers/net/gmac.h index 40bc95bfa936..4148c7db862e 100644 --- a/drivers/net/gmac.h +++ b/drivers/net/gmac.h @@ -730,8 +730,9 @@ */ /* Supported PHYs (phy_type field ) */ -#define PHY_B5400 5400 -#define PHY_B5201 5201 +#define PHY_B5400 0x5400 +#define PHY_B5201 0x5201 +#define PHY_LXT971 0x0971 #define PHY_UNKNOWN 0 /* Identification (for multi-PHY) */ @@ -745,6 +746,11 @@ #define MII_BCM5400_REV 0x01 #define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4)) #define MII_BCM5400_MASK 0xfffffff0 +#define MII_LXT971_OUI 0x0004de +#define MII_LXT971_MODEL 0x0e +#define MII_LXT971_REV 0x00 +#define MII_LXT971_ID ((MII_LXT971_OUI << 10) | (MII_LXT971_MODEL << 4)) +#define MII_LXT971_MASK 0xfffffff0 /* BCM5201 AUX STATUS register */ #define MII_BCM5201_AUXCTLSTATUS 0x18 @@ -764,6 +770,26 @@ #define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 #define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 +/* MII BCM5400 1000-BASET Control register */ +#define MII_BCM5400_GB_CONTROL 0x09 +#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 + +/* MII BCM5400 AUXCONTROL register */ +#define MII_BCM5400_AUXCONTROL 0x18 +#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 + +/* MII BCM5400 AUXSTATUS register */ +#define MII_BCM5400_AUXSTATUS 0x19 +#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 + +/* MII LXT971 STATUS2 register */ +#define MII_LXT971_STATUS2 0x11 +#define MII_LXT971_STATUS2_SPEED 0x4000 +#define MII_LXT971_STATUS2_LINK 0x0400 +#define MII_LXT971_STATUS2_FULLDUPLEX 0x0200 +#define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 + /* @@ -845,6 +871,7 @@ struct gmac { int phy_type; int phy_status; /* Cached PHY status */ int full_duplex; /* Current set to full duplex */ + int gigabit; /* Current set to 1000BT */ struct net_device_stats stats; u8 pci_bus; u8 pci_devfn; diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c index 387208e2f243..65ccfee2b0c9 100644 --- a/drivers/net/irda/toshoboe.c +++ b/drivers/net/irda/toshoboe.c @@ -900,7 +900,6 @@ toshoboe_gotosleep (struct toshoboe_cb *self) static void toshoboe_wakeup (struct toshoboe_cb *self) { - struct net_device *dev = self->netdev; unsigned long flags; if (!self->stopped) diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 33952e0ad628..6cfd71f15044 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -26,10 +26,13 @@ You can try if you want more info, as I've never even seen one of these cards. :) + Arnaldo Carvalho de Melo - 2000/09/01 + - get rid of check_region + - no need to check if dev == NULL in lne390_probe1 */ static const char *version = - "lne390.c: Driver revision v0.99, 12/05/98\n"; + "lne390.c: Driver revision v0.99.1, 01/09/2000\n"; #include #include @@ -103,9 +106,16 @@ static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0 int __init lne390_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; - - if (ioaddr > 0x1ff) /* Check a single specified location. */ - return lne390_probe1(dev, ioaddr); + int ret; + + if (ioaddr > 0x1ff) { /* Check a single specified location. */ + if (!request_region(ioaddr, LNE390_IO_EXTENT, "lne390")) + return -EBUSY; + ret = lne390_probe1(dev, ioaddr); + if (ret) + release_region(ioaddr, LNE390_IO_EXTENT); + return ret; + } else if (ioaddr > 0) /* Don't probe at all. */ return -ENXIO; @@ -118,10 +128,11 @@ int __init lne390_probe(struct net_device *dev) /* EISA spec allows for up to 16 slots, but 8 is typical. */ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - if (check_region(ioaddr , LNE390_IO_EXTENT)) + if (!request_region(ioaddr, LNE390_IO_EXTENT, "lne390")) continue; if (lne390_probe1(dev, ioaddr) == 0) return 0; + release_region(ioaddr, LNE390_IO_EXTENT); } return -ENODEV; @@ -129,7 +140,7 @@ int __init lne390_probe(struct net_device *dev) int __init lne390_probe1(struct net_device *dev, int ioaddr) { - int i, revision; + int i, revision, ret; unsigned long eisa_id; if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; @@ -161,13 +172,6 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr) return -ENODEV; } #endif - - /* We should have a "dev" from Space.c or the static module table. */ - if (dev == NULL) { - printk("lne390.c: Passed a NULL device.\n"); - dev = init_etherdev(0, 0); - } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { printk ("lne390.c: unable to allocate memory for dev->priv!\n"); @@ -225,20 +229,16 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr) printk(KERN_CRIT "lne390.c: Use EISA SCU to set card memory below 1MB,\n"); printk(KERN_CRIT "lne390.c: or to an address above 0x%lx.\n", virt_to_bus(high_memory)); printk(KERN_CRIT "lne390.c: Driver NOT installed.\n"); - free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; - return -EINVAL; + ret = -EINVAL; + goto cleanup; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, LNE390_STOP_PG*0x100); if (dev->mem_start == 0) { printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n"); printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n"); printk(KERN_ERR "lne390.c: Driver NOT installed.\n"); - free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; - return -EAGAIN; + ret = -EAGAIN; + goto cleanup; } ei_status.reg0 = 1; /* Use as remap flag */ printk("lne390.c: remapped %dkB card memory to virtual address %#lx\n", @@ -251,7 +251,6 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr) /* The 8390 offset is zero for the LNE390 */ dev->base_addr = ioaddr; - request_region(dev->base_addr, LNE390_IO_EXTENT, "lne390"); ei_status.name = "LNE390"; ei_status.tx_start_page = LNE390_START_PG; @@ -271,6 +270,11 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr) dev->stop = &lne390_close; NS8390_init(dev, 0); return 0; +cleanup: + free_irq(dev->irq, dev); + kfree(dev->priv); + dev->priv = NULL; + return ret; } /* diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index 61f6dbd68bcd..6fa6bb18963d 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -198,7 +198,7 @@ static int fddi_change_mtu(struct net_device *dev, int new_mtu) return(0); } -#endif +#endif /* CONFIG_FDDI */ #ifdef CONFIG_HIPPI @@ -256,7 +256,7 @@ static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) return 0; } -#endif +#endif /* CONFIG_HIPPI */ void ether_setup(struct net_device *dev) { @@ -314,7 +314,7 @@ void fddi_setup(struct net_device *dev) return; } -#endif +#endif /* CONFIG_FDDI */ #ifdef CONFIG_HIPPI void hippi_setup(struct net_device *dev) @@ -350,7 +350,7 @@ void hippi_setup(struct net_device *dev) dev_init_buffers(dev); } -#endif +#endif /* CONFIG_HIPPI */ #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) @@ -389,7 +389,7 @@ void ltalk_setup(struct net_device *dev) dev_init_buffers(dev); } -#endif +#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */ int ether_config(struct net_device *dev, struct ifmap *map) { @@ -506,7 +506,7 @@ void unregister_trdev(struct net_device *dev) unregister_netdevice(dev); rtnl_unlock(); } -#endif +#endif /* CONFIG_TR */ #ifdef CONFIG_NET_FC @@ -555,10 +555,3 @@ void unregister_fcdev(struct net_device *dev) #endif /* CONFIG_NET_FC */ -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c" - * version-control: t - * kept-new-versions: 5 - * End: - */ diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index 0355f9e5d692..aff697033fc1 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -3034,10 +3034,7 @@ static void set_rx_mode(struct net_device *dev) if (entry == TX_RING_SIZE-1) tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ tp->tx_ring[entry].length = tx_flags; - if(tp->chip_id == X3201_3) - tp->tx_ring[entry].buffer1 = (virt_to_bus(tp->setup_frame) + 4); - else - tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); tp->tx_ring[entry].status = DescOwned; if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { tp->tx_full = 1; diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c index 941bf369e7f1..207b029f3508 100644 --- a/drivers/net/pppox.c +++ b/drivers/net/pppox.c @@ -141,6 +141,8 @@ struct net_proto_family pppox_proto_family = { pppox_create }; +extern int pppoe_init (void); + #ifdef MODULE int init_module(void) #else @@ -154,9 +156,7 @@ void __init pppox_proto_init(struct net_proto *pro) if (err == 0) printk(KERN_INFO "Registered PPPoX v0.5\n"); -#ifdef CONFIG_PPPOE pppoe_init(); -#endif return err; } diff --git a/drivers/net/rtl8129.c b/drivers/net/rtl8129.c index e3fedb0c96a8..028044b8a8a7 100644 --- a/drivers/net/rtl8129.c +++ b/drivers/net/rtl8129.c @@ -406,6 +406,8 @@ static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, printk(KERN_INFO "%s", version); dev = init_etherdev(NULL, 0); + if (dev == NULL) + goto out; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_tbl[chip_idx].name, ioaddr, irq); @@ -427,13 +429,17 @@ static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, printk("%2.2x.\n", dev->dev_addr[i]); /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); + if (!request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name)) + goto out_free_dev; dev->base_addr = ioaddr; dev->irq = irq; /* Some data structures must be quadword aligned. */ tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + if (tp == NULL) + goto out_release_region; + memset(tp, 0, sizeof(*tp)); dev->priv = tp; @@ -499,8 +505,15 @@ static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, dev->get_stats = &rtl8129_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; - return dev; + +out_release_region: + release_region(ioaddr, pci_tbl[chip_idx].io_size); +out_free_dev: + unregister_netdev(dev); + kfree(dev); +out: + return NULL; } /* Serial EEPROM section. */ @@ -660,17 +673,18 @@ rtl8129_open(struct net_device *dev) { struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; - int i; + int i, retval; + + MOD_INC_USE_COUNT; /* Soft reset the chip. */ outb(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) { - return -EAGAIN; + if ((retval = request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev))) { + MOD_DEC_USE_COUNT; + return retval; } - MOD_INC_USE_COUNT; - tp->tx_bufs = pci_alloc_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, &tp->tx_bufs_dma); @@ -690,6 +704,7 @@ rtl8129_open(struct net_device *dev) if (rtl8129_debug > 0) printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", dev->name, RX_BUF_LEN); + MOD_DEC_USE_COUNT; return -ENOMEM; } rtl8129_init_ring(dev); @@ -1226,8 +1241,9 @@ static int rtl8129_rx(struct net_device *dev) /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ struct sk_buff *skb; + int pkt_size = rx_size - 4; - skb = dev_alloc_skb(rx_size + 2); + skb = dev_alloc_skb(pkt_size + 2); if (skb == NULL) { printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", dev->name); @@ -1238,12 +1254,12 @@ static int rtl8129_rx(struct net_device *dev) } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size+4 > RX_BUF_LEN) { + if (ring_offset+rx_size > RX_BUF_LEN) { int semi_count = RX_BUF_LEN - ring_offset - 4; memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], semi_count); - memcpy(skb_put(skb, rx_size-semi_count), rx_ring, - rx_size-semi_count); + memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, + pkt_size-semi_count); if (rtl8129_debug > 4) { int i; printk(KERN_DEBUG"%s: Frame wrap @%d", @@ -1256,17 +1272,17 @@ static int rtl8129_rx(struct net_device *dev) } else { #if 1 /* USE_IP_COPYSUM */ eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - rx_size, 0); - skb_put(skb, rx_size); + pkt_size, 0); + skb_put(skb, pkt_size); #else - memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4], - rx_size); + memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4], + pkt_size); #endif } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); #if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += rx_size; + tp->stats.rx_bytes += pkt_size; #endif tp->stats.rx_packets++; } @@ -1292,6 +1308,8 @@ rtl8129_close(struct net_device *dev) netif_stop_queue(dev); + del_timer_sync(&tp->timer); + if (rtl8129_debug > 1) printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, inw(ioaddr + IntrStatus)); @@ -1306,8 +1324,6 @@ rtl8129_close(struct net_device *dev) tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); - del_timer(&tp->timer); - free_irq(dev->irq, dev); for (i = 0; i < NUM_TX_DESC; i++) { diff --git a/drivers/net/setup.c b/drivers/net/setup.c index b4e5da200129..5d4f13375e00 100644 --- a/drivers/net/setup.c +++ b/drivers/net/setup.c @@ -22,6 +22,7 @@ extern int awc4500_pnp_probe(void); extern int awc4500_365_probe(void); extern int arcnet_init(void); extern int scc_enet_init(void); +extern int fec_enet_init(void); extern int dlci_setup(void); extern int lapbeth_init(void); extern int sdla_setup(void); @@ -75,6 +76,9 @@ struct net_probe pci_probes[] __initdata = { #if defined(CONFIG_SCC_ENET) {scc_enet_init, 0}, #endif +#if defined(CONFIG_FEC_ENET) + {fec_enet_init, 0}, +#endif #if defined(CONFIG_COMX) {comx_init, 0}, #endif diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index ad98ac40583f..34c0ae78af63 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1332,6 +1332,7 @@ static int __init sparc_lance_init(struct net_device *dev, /* Make certain the data structures used by the LANCE are aligned. */ dev->priv = (void *)(((unsigned long)dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; + spin_lock_init(&lp->lock); /* Copy the IDPROM ethernet address to the device structure, later we * will copy the address in the device structure to the lance diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 5b13578e7ff4..34dabc206599 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o obj-$(CONFIG_COSA) += syncppp.o cosa.o obj-$(CONFIG_LANMEDIA) += syncppp.o +obj-$(CONFIG_X25_ASY) += x25_asy.o ifeq ($(CONFIG_LANMEDIA),y) SUB_DIRS += lmc diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog index 4c4fb9f9b8dc..1314e9f9d0d8 100644 --- a/drivers/parport/ChangeLog +++ b/drivers/parport/ChangeLog @@ -1,3 +1,8 @@ +2000-09-16 Cesar Eduardo Barros + + * parport_pc.c (sio_via_686a_probe): Handle case + where hardware returns 255 for IRQ or DMA. + 2000-07-20 Eddie C. Dost * share.c (attach_driver_chain): attach[i](port) needs to be diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index f37e8f283772..952eaec41f99 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2239,11 +2239,13 @@ static int __devinit sio_via_686a_probe (struct pci_dev *pdev) irq = ((irq >> 4) & 0x0F); /* filter bogus IRQs */ + /* 255 means NONE, and is bogus as well */ switch (irq) { case 0: case 2: case 8: case 13: + case 255: irq = PARPORT_IRQ_NONE; break; @@ -2252,7 +2254,9 @@ static int __devinit sio_via_686a_probe (struct pci_dev *pdev) } /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ - if (!have_eppecp) + /* 255 means NONE. Looks like some BIOS don't set the DMA correctly + * even on ECP mode */ + if (!have_eppecp || dma == 255) dma = PARPORT_DMA_NONE; /* finally, do the probe with values obtained */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0b59ec0b61b2..446d3e239ce3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -657,134 +657,82 @@ static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pc return child; } -/* - * A CardBus bridge is basically the same as a regular PCI bridge, - * except we don't scan behind it because it will be changing. - */ -static int __init pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr) -{ - int i; - unsigned short cr; - unsigned int buses; - struct pci_bus *child; - - /* - * Insert it into the tree of buses. - */ - DBG("Scanning CardBus bridge %s\n", dev->slot_name); - child = pci_add_new_bus(bus, dev, ++busnr); - - for (i = 0; i < 4; i++) - child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; - - /* - * Maybe we'll have another bus behind this one? - */ - child->subordinate = ++busnr; - sprintf(child->name, "PCI CardBus #%02x", child->number); - - /* - * Clear all status bits and turn off memory, - * I/O and master enables. - */ - pci_read_config_word(dev, PCI_COMMAND, &cr); - pci_write_config_word(dev, PCI_COMMAND, 0x0000); - pci_write_config_word(dev, PCI_STATUS, 0xffff); - - /* - * Read the existing primary/secondary/subordinate bus - * number configuration to determine if the bridge - * has already been configured by the system. If so, - * do not modify the configuration, merely note it. - */ - pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); - if ((buses & 0xFFFFFF) != 0 && ! pcibios_assign_all_busses()) { - child->primary = buses & 0xFF; - child->secondary = (buses >> 8) & 0xFF; - child->subordinate = (buses >> 16) & 0xFF; - child->number = child->secondary; - if (child->subordinate > busnr) - busnr = child->subordinate; - } else { - /* - * Configure the bus numbers for this bridge: - */ - buses &= 0xff000000; - buses |= - (((unsigned int)(child->primary) << 0) | - ((unsigned int)(child->secondary) << 8) | - ((unsigned int)(child->subordinate) << 16)); - pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); - } - pci_write_config_word(dev, PCI_COMMAND, cr); - return busnr; -} - static unsigned int __init pci_do_scan_bus(struct pci_bus *bus); /* - * If it's a bridge, scan the bus behind it. + * If it's a bridge, configure it and scan the bus behind it. + * For CardBus bridges, we don't scan behind as the devices will + * be handled by the bridge driver itself. + * + * We need to process bridges in two passes -- first we scan those + * already configured by the BIOS and after we are done with all of + * them, we proceed to assigning numbers to the remaining buses in + * order to avoid overlaps between old and new bus numbers. */ -static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max) +static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) { unsigned int buses; unsigned short cr; struct pci_bus *child; + int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); - /* - * Insert it into the tree of buses. - */ - DBG("Scanning behind PCI bridge %s\n", dev->slot_name); - child = pci_add_new_bus(bus, dev, ++max); - sprintf(child->name, "PCI Bus #%02x", child->number); - - /* - * Clear all status bits and turn off memory, - * I/O and master enables. - */ - pci_read_config_word(dev, PCI_COMMAND, &cr); - pci_write_config_word(dev, PCI_COMMAND, 0x0000); - pci_write_config_word(dev, PCI_STATUS, 0xffff); - - /* - * Read the existing primary/secondary/subordinate bus - * number configuration to determine if the PCI bridge - * has already been configured by the system. If so, - * do not modify the configuration, merely note it. - */ pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); - if ((buses & 0xFFFFFF) != 0 && ! pcibios_assign_all_busses()) { - unsigned int cmax; + DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass); + if ((buses & 0xffffff) && !pcibios_assign_all_busses()) { + /* + * Bus already configured by firmware, process it in the first + * pass and just note the configuration. + */ + if (pass) + return max; + child = pci_add_new_bus(bus, dev, 0); child->primary = buses & 0xFF; child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; child->number = child->secondary; - cmax = pci_do_scan_bus(child); - if (cmax > max) max = cmax; + if (!is_cardbus) { + unsigned int cmax = pci_do_scan_bus(child); + if (cmax > max) max = cmax; + } } else { /* - * Configure the bus numbers for this bridge: + * We need to assign a number to this bus which we always + * do in the second pass. We also keep all address decoders + * on the bridge disabled during scanning. FIXME: Why? */ - buses &= 0xff000000; - buses |= - (((unsigned int)(child->primary) << 0) | - ((unsigned int)(child->secondary) << 8) | - ((unsigned int)(child->subordinate) << 16)); - pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + if (!pass) + return max; + pci_read_config_word(dev, PCI_COMMAND, &cr); + pci_write_config_word(dev, PCI_COMMAND, 0x0000); + pci_write_config_word(dev, PCI_STATUS, 0xffff); + child = pci_add_new_bus(bus, dev, ++max); + buses = (buses & 0xff000000) + | ((unsigned int)(child->primary) << 0) + | ((unsigned int)(child->secondary) << 8) + | ((unsigned int)(child->subordinate) << 16); /* - * Now we can scan all subordinate buses: + * We need to blast all three values with a single write. */ - max = pci_do_scan_bus(child); + pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + if (!is_cardbus) { + /* Now we can scan all subordinate buses... */ + max = pci_do_scan_bus(child); + } else { + /* + * For CardBus bridges, we leave 4 bus numbers + * as cards with a PCI-to-PCI bridge can be + * inserted later. + */ + max += 3; + } /* - * Set the subordinate bus number to its real - * value: + * Set the subordinate bus number to its real value. */ child->subordinate = max; - buses = (buses & 0xff00ffff) - | ((unsigned int)(child->subordinate) << 16); - pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); + pci_write_config_word(dev, PCI_COMMAND, cr); } - pci_write_config_word(dev, PCI_COMMAND, cr); + sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number); return max; } @@ -933,7 +881,7 @@ struct pci_dev * __init pci_scan_slot(struct pci_dev *temp) static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) { - unsigned int devfn, max; + unsigned int devfn, max, pass; struct list_head *ln; struct pci_dev *dev, dev0; @@ -957,17 +905,12 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) */ DBG("Fixups for bus %02x\n", bus->number); pcibios_fixup_bus(bus); - for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { - dev = pci_dev_b(ln); - switch (dev->class >> 8) { - case PCI_CLASS_BRIDGE_PCI: - max = pci_scan_bridge(bus, dev, max); - break; - case PCI_CLASS_BRIDGE_CARDBUS: - max = pci_scan_cardbus(bus, dev, max); - break; + for (pass=0; pass < 2; pass++) + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + dev = pci_dev_b(ln); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + max = pci_scan_bridge(bus, dev, max, pass); } - } /* * We've scanned the bus and so we know all about what's on diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index de225879f0d7..3acc62f2756d 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -30,7 +30,7 @@ CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM obj-$(CONFIG_SCSI) += scsi_mod.o obj-$(CONFIG_CHR_DEV_ST) += st.o -obj-$(CONFIG_BLK_DEV_SD) += sd.o +obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o @@ -152,6 +152,9 @@ include $(TOPDIR)/Rules.make scsi_mod.o: $(scsi_mod-objs) $(LD) -r -o $@ $(scsi_mod-objs) +sd_mod.o: sd.o + $(LD) -r -o $@ sd.o + sr_mod.o: $(sr_mod-objs) $(LD) -r -o $@ $(sr_mod-objs) diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index 8a59351aac54..f5edf09dd67f 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -2509,7 +2509,7 @@ VOID SetupFinish (PADAPTER2220I padapter, char *str, int irq) init_timer (&padapter->reconTimer); padapter->reconTimer.function = ReconTimerExpiry; padapter->reconTimer.data = (unsigned long)padapter; - printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX IRQ = %ld\n", str, padapter->basePort, padapter->regBase, irq); + printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq); printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); } /**************************************************************** diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 9bc66953da23..ef9e8f76dc05 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -643,8 +643,10 @@ int qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[]) ip[0] = 0xff; ip[1] = 0x3f; ip[2] = disk->capacity / (ip[0] * ip[1]); +#if 0 if (ip[2] > 1023) ip[2] = 1023; +#endif } return 0; } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 10b65fa2d449..91289caf8ae9 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -384,7 +384,7 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, * return NULL. */ SCpnt = NULL; - break; + goto busy; } } /* @@ -402,6 +402,7 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, if (SCpnt) { break; } + busy: /* * If we have been asked to wait for a free block, then * wait here. @@ -495,30 +496,7 @@ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, return SCpnt; } -/* - * Function: scsi_release_command - * - * Purpose: Release a command block. - * - * Arguments: SCpnt - command block we are releasing. - * - * Notes: The command block can no longer be used by the caller once - * this funciton is called. This is in effect the inverse - * of scsi_allocate_device. Note that we also must perform - * a couple of additional tasks. We must first wake up any - * processes that might have blocked waiting for a command - * block, and secondly we must hit the queue handler function - * to make sure that the device is busy. - * - * The idea is that a lot of the mid-level internals gunk - * gets hidden in this function. Upper level drivers don't - * have any chickens to wave in the air to get things to - * work reliably. - * - * This function is deprecated, and drivers should be - * rewritten to use Scsi_Request instead of Scsi_Cmnd. - */ -void scsi_release_command(Scsi_Cmnd * SCpnt) +inline void __scsi_release_command(Scsi_Cmnd * SCpnt) { unsigned long flags; Scsi_Device * SDpnt; @@ -562,6 +540,43 @@ void scsi_release_command(Scsi_Cmnd * SCpnt) * they wake up. */ wake_up(&SDpnt->scpnt_wait); +} + +/* + * Function: scsi_release_command + * + * Purpose: Release a command block. + * + * Arguments: SCpnt - command block we are releasing. + * + * Notes: The command block can no longer be used by the caller once + * this funciton is called. This is in effect the inverse + * of scsi_allocate_device. Note that we also must perform + * a couple of additional tasks. We must first wake up any + * processes that might have blocked waiting for a command + * block, and secondly we must hit the queue handler function + * to make sure that the device is busy. Note - there is an + * option to not do this - there were instances where we could + * recurse too deeply and blow the stack if this happened + * when we were indirectly called from the request function + * itself. + * + * The idea is that a lot of the mid-level internals gunk + * gets hidden in this function. Upper level drivers don't + * have any chickens to wave in the air to get things to + * work reliably. + * + * This function is deprecated, and drivers should be + * rewritten to use Scsi_Request instead of Scsi_Cmnd. + */ +void scsi_release_command(Scsi_Cmnd * SCpnt) +{ + request_queue_t *q; + Scsi_Device * SDpnt; + + SDpnt = SCpnt->device; + + __scsi_release_command(SCpnt); /* * Finally, hit the queue request function to make sure that @@ -569,12 +584,8 @@ void scsi_release_command(Scsi_Cmnd * SCpnt) * This won't block - if the device cannot take any more, life * will go on. */ - { - request_queue_t *q; - - q = &SDpnt->request_queue; - scsi_queue_next_request(q, NULL); - } + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); } /* diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index e40d64ccb4ce..8dafee2bddaa 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -492,6 +492,7 @@ extern void scsi_done(Scsi_Cmnd * SCpnt); extern void scsi_finish_command(Scsi_Cmnd *); extern int scsi_retry_command(Scsi_Cmnd *); extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int, int); +extern void __scsi_release_command(Scsi_Cmnd *); extern void scsi_release_command(Scsi_Cmnd *); extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd, void *buffer, unsigned bufflen, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 362173b56fcb..ace7c7e2c518 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -381,6 +381,8 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt) * uptodate - 1 if I/O indicates success, 0 for I/O error. * sectors - number of sectors we want to mark. * requeue - indicates whether we should requeue leftovers. + * frequeue - indicates that if we release the command block + * that the queue request function should be called. * * Lock status: Assumed that lock is not held upon entry. * @@ -395,10 +397,12 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt) static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors, - int requeue) + int requeue, + int frequeue) { struct request *req; struct buffer_head *bh; + Scsi_Device * SDpnt; ASSERT_LOCK(&io_request_lock, 0); @@ -458,11 +462,20 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, } add_blkdev_randomness(MAJOR(req->rq_dev)); + SDpnt = SCpnt->device; + /* * This will goose the queue request function at the end, so we don't * need to worry about launching another command. */ - scsi_release_command(SCpnt); + __scsi_release_command(SCpnt); + + if( frequeue ) { + request_queue_t *q; + + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); + } return NULL; } @@ -488,7 +501,7 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, */ Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) { - return __scsi_end_request(SCpnt, uptodate, sectors, 1); + return __scsi_end_request(SCpnt, uptodate, sectors, 1, 1); } /* @@ -648,7 +661,8 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, SCpnt = __scsi_end_request(SCpnt, 1, good_sectors, - result == 0); + result == 0, + 1); /* * If the command completed without error, then either finish off the @@ -718,8 +732,8 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, } break; case NOT_READY: - printk(KERN_INFO "Device %x not ready.\n", - SCpnt->request.rq_dev); + printk(KERN_INFO "Device %s not ready.\n", + kdevname(SCpnt->request.rq_dev)); SCpnt = scsi_end_request(SCpnt, 0, this_count); return; break; @@ -962,6 +976,7 @@ void scsi_request_fn(request_queue_t * q) } } else { + SRpnt = NULL; STpnt = scsi_get_request_dev(req); if (!STpnt) { panic("Unable to find device associated with request"); @@ -1010,7 +1025,7 @@ void scsi_request_fn(request_queue_t * q) */ blkdev_dequeue_request(req); - if (req != &SCpnt->request) { + if (req != &SCpnt->request && req != &SRpnt->sr_request ) { memcpy(&SCpnt->request, req, sizeof(struct request)); /* @@ -1048,8 +1063,12 @@ void scsi_request_fn(request_queue_t * q) * get those allocated here. */ if (!SDpnt->scsi_init_io_fn(SCpnt)) { - scsi_end_request(SCpnt, 0, - SCpnt->request.nr_sectors); + SCpnt = __scsi_end_request(SCpnt, 0, + SCpnt->request.nr_sectors, 0, 0); + if( SCpnt != NULL ) + { + panic("Should not have leftover blocks\n"); + } spin_lock_irq(&io_request_lock); SHpnt->host_busy--; SDpnt->device_busy--; @@ -1060,8 +1079,12 @@ void scsi_request_fn(request_queue_t * q) */ if (!STpnt->init_command(SCpnt)) { scsi_release_buffers(SCpnt); - scsi_end_request(SCpnt, 0, - SCpnt->request.nr_sectors); + SCpnt = __scsi_end_request(SCpnt, 0, + SCpnt->request.nr_sectors, 0, 0); + if( SCpnt != NULL ) + { + panic("Should not have leftover blocks\n"); + } spin_lock_irq(&io_request_lock); SHpnt->host_busy--; SDpnt->device_busy--; diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c index 162088204524..4793f1e8bf94 100644 --- a/drivers/scsi/scsi_queue.c +++ b/drivers/scsi/scsi_queue.c @@ -118,7 +118,7 @@ int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason) * If a host is inactive and cannot queue any commands, I don't see * how things could possibly work anyways. */ - if (cmd->device->device_blocked == 0) { + if (cmd->device->device_busy == 0) { if (scsi_retry_command(cmd) == 0) { return 0; } diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 53f194e432da..dc9512407e2d 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -5,7 +5,8 @@ * * Note : TMC-880 boards don't work because they have two bits in * the status register flipped, I'll fix this "RSN" - * [why do I have strong feeling that above message is from 1993? :-) pavel@ucw.cz] + * [why do I have strong feeling that above message is from 1993? :-) + * pavel@ucw.cz] * * This card does all the I/O via memory mapped I/O, so there is no need * to check or allocate a region of the I/O address space. @@ -18,6 +19,13 @@ * * 1998-jul-29 - created DPRINTK macros and made it work under * linux 2.1.112, simplified some #defines etc. + * + * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to + * read the physical disk geometry, a bad mistake. Of course it doesnt + * matter much what geometry one invents, but on large disks it + * returned 256 (or more) heads, causing all kind of failures. + * Of course this means that people might see a different geometry now, + * so boot parameters may be necessary in some cases. */ /* @@ -1702,124 +1710,6 @@ int seagate_st0x_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) } -int seagate_st0x_biosparam (Disk * disk, kdev_t dev, int *ip) -{ - unsigned char buf[256 + sizeof (Scsi_Ioctl_Command)], - cmd[6], *data, *page; - Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf; - int result, formatted_sectors, total_sectors; - int cylinders, heads, sectors; - int capacity; - -/* - * Only SCSI-I CCS drives and later implement the necessary mode sense - * pages. - */ - - if (disk->device->scsi_level < 2) - return -1; - - data = sic->data; - - cmd[0] = MODE_SENSE; - cmd[1] = (disk->device->lun << 5) & 0xe5; - cmd[2] = 0x04; /* Read page 4, rigid disk geometry - page current values */ - cmd[3] = 0; - cmd[4] = 255; - cmd[5] = 0; - -/* - * We are transferring 0 bytes in the out direction, and expect to get back - * 24 bytes for each mode page. - */ - sic->inlen = 0; - sic->outlen = 256; - - memcpy (data, cmd, 6); - - if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, - sic))) - { -/* - * The mode page lies beyond the MODE SENSE header, with length 4, and - * the BLOCK DESCRIPTOR, with length header[3]. - */ - page = data + 4 + data[3]; - heads = (int) page[5]; - cylinders = (page[2] << 16) | (page[3] << 8) | page[4]; - - cmd[2] = 0x03; /* Read page 3, format page current - values */ - memcpy (data, cmd, 6); - - if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, - sic))) - { - page = data + 4 + data[3]; - sectors = (page[10] << 8) | page[11]; -/* - * Get the total number of formatted sectors from the block descriptor, - * so we can tell how many are being used for alternates. - */ - formatted_sectors = (data[4 + 1] << 16) | (data[4 + 2] << 8) - | data[4 + 3]; - - total_sectors = (heads * cylinders * sectors); - -/* - * Adjust the real geometry by subtracting - * (spare sectors / (heads * tracks)) cylinders from the number of cylinders. - * - * It appears that the CE cylinder CAN be a partial cylinder. - */ - - printk ("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %d\n", - hostno, heads, cylinders, sectors, total_sectors, - formatted_sectors); - - if (!heads || !sectors || !cylinders) - result = -1; - else - cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors)); - -/* - * Now, we need to do a sanity check on the geometry to see if it is - * BIOS compatible. The maximum BIOS geometry is 1024 cylinders * - * 256 heads * 64 sectors. - */ - - if ((cylinders > 1024) || (sectors > 64)) - { - /* The Seagate's seem to have some mapping. Multiply - heads*sectors*cyl to get capacity. Then start rounding down. - */ - capacity = heads * sectors * cylinders; - - /* Old MFM Drives use this, so does the Seagate */ - sectors = 17; - heads = 2; - capacity = capacity / sectors; - while (cylinders > 1024) - { - heads *= 2; /* For some reason, they go in - multiples */ - cylinders = capacity / heads; - } - } - ip[0] = heads; - ip[1] = sectors; - ip[2] = cylinders; -/* - * There should be an alternate mapping for things the seagate doesn't - * understand, but I couldn't say what it is with reasonable certainty. - */ - } - } - - return result; -} - #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ Scsi_Host_Template driver_template = SEAGATE_ST0X; diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h index c8ead00c4df6..3aedafd573fd 100644 --- a/drivers/scsi/seagate.h +++ b/drivers/scsi/seagate.h @@ -20,16 +20,12 @@ int seagate_st0x_abort(Scsi_Cmnd *); const char *seagate_st0x_info(struct Scsi_Host *); int seagate_st0x_reset(Scsi_Cmnd *, unsigned int); -#include -int seagate_st0x_biosparam(Disk *, kdev_t, int*); - #define SEAGATE_ST0X { detect: seagate_st0x_detect, \ info: seagate_st0x_info, \ command: seagate_st0x_command, \ queuecommand: seagate_st0x_queue_command, \ abort: seagate_st0x_abort, \ reset: seagate_st0x_reset, \ - bios_param: seagate_st0x_biosparam, \ can_queue: 1, \ this_id: 7, \ sg_tablesize: SG_ALL, \ diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 75493008ed6d..5ea2799611d1 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -112,7 +112,7 @@ static void sg_finish(void); static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); -static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ +static Scsi_Request * dummy_cmdp = 0; /* only used for sizeof */ static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock file descriptor list for device */ @@ -148,12 +148,12 @@ struct sg_fd; typedef struct sg_request /* SG_MAX_QUEUE requests outstanding per file */ { - Scsi_Cmnd * my_cmdp; /* != 0 when request with lower levels */ + Scsi_Request * my_cmdp; /* != 0 when request with lower levels */ struct sg_request * nextrp; /* NULL -> tail request (slist) */ struct sg_fd * parentfp; /* NULL -> not in use */ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ sg_io_hdr_t header; /* scsi command+info, see */ - unsigned char sense_b[sizeof(dummy_cmdp->sense_buffer)]; + unsigned char sense_b[sizeof(dummy_cmdp->sr_sense_buffer)]; char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ @@ -230,8 +230,8 @@ static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); static int sg_dio_in_use(Sg_fd * sfp); -static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); -static void sg_shorten_timeout(Scsi_Cmnd * scpnt); +static void sg_clr_srpnt(Scsi_Request * SRpnt); +static void sg_shorten_timeout(Scsi_Request * srpnt); static int sg_ms_to_jif(unsigned int msecs); static unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); @@ -460,7 +460,7 @@ static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, if ((hp->mx_sb_len > 0) && hp->sbp) { if ((CHECK_CONDITION & hp->masked_status) || (DRIVER_SENSE & hp->driver_status)) { - int sb_len = sizeof(dummy_cmdp->sense_buffer); + int sb_len = sizeof(dummy_cmdp->sr_sense_buffer); sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len; len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */ len = (len > sb_len) ? sb_len : len; @@ -492,7 +492,7 @@ static ssize_t sg_write(struct file * filp, const char * buf, Sg_request * srp; struct sg_header old_hdr; sg_io_hdr_t * hp; - unsigned char cmnd[sizeof(dummy_cmdp->cmnd)]; + unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; @@ -581,7 +581,7 @@ static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, int k; Sg_request * srp; sg_io_hdr_t * hp; - unsigned char cmnd[sizeof(dummy_cmdp->cmnd)]; + unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; int timeout; if (count < size_sg_io_hdr) @@ -625,7 +625,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char * cmnd, int timeout, int blocking) { int k; - Scsi_Cmnd * SCpnt; + Scsi_Request * SRpnt; Sg_device * sdp = sfp->parentdp; sg_io_hdr_t * hp = &srp->header; @@ -652,38 +652,34 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, return k; } /* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ - SCpnt = scsi_allocate_device(sdp->device, blocking, TRUE); - if (! SCpnt) { - sg_finish_rem_req(srp); - return (signal_pending(current)) ? -EINTR : -EAGAIN; - /* No available command blocks, or, interrupted while waiting */ - } + SRpnt = scsi_allocate_request(sdp->device); + /* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ - srp->my_cmdp = SCpnt; - SCpnt->request.rq_dev = sdp->i_rdev; - SCpnt->request.rq_status = RQ_ACTIVE; - SCpnt->sense_buffer[0] = 0; - SCpnt->cmd_len = hp->cmd_len; + srp->my_cmdp = SRpnt; + SRpnt->sr_request.rq_dev = sdp->i_rdev; + SRpnt->sr_request.rq_status = RQ_ACTIVE; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_cmd_len = hp->cmd_len; /* Set the LUN field in the command structure, overriding user input */ if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); /* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ - SCpnt->use_sg = srp->data.k_use_sg; - SCpnt->sglist_len = srp->data.sglist_len; - SCpnt->bufflen = srp->data.bufflen; - SCpnt->underflow = 0; - SCpnt->buffer = srp->data.buffer; + SRpnt->sr_use_sg = srp->data.k_use_sg; + SRpnt->sr_sglist_len = srp->data.sglist_len; + SRpnt->sr_bufflen = srp->data.bufflen; + SRpnt->sr_underflow = 0; + SRpnt->sr_buffer = srp->data.buffer; switch (hp->dxfer_direction) { case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: - SCpnt->sc_data_direction = SCSI_DATA_READ; break; + SRpnt->sr_data_direction = SCSI_DATA_READ; break; case SG_DXFER_TO_DEV: - SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; + SRpnt->sr_data_direction = SCSI_DATA_WRITE; break; case SG_DXFER_UNKNOWN: - SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; break; + SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; break; default: - SCpnt->sc_data_direction = SCSI_DATA_NONE; break; + SRpnt->sr_data_direction = SCSI_DATA_NONE; break; } srp->data.k_use_sg = 0; srp->data.sglist_len = 0; @@ -692,10 +688,10 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, hp->duration = jiffies; /* unit jiffies now, millisecs after done */ /* Now send everything of to mid-level. The next time we hear about this packet is when sg_cmd_done_bh() is called (i.e. a callback). */ - scsi_do_cmd(SCpnt, (void *)cmnd, - (void *)SCpnt->buffer, hp->dxfer_len, + scsi_do_req(SRpnt, (void *)cmnd, + (void *)SRpnt->sr_buffer, hp->dxfer_len, sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES); - /* dxfer_len overwrites SCpnt->bufflen, hence need for b_malloc_len */ + /* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */ return 0; } @@ -989,7 +985,8 @@ static int sg_fasync(int fd, struct file * filp, int mode) * mid level when a command is completed (or has failed). */ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) { - int dev = MINOR(SCpnt->request.rq_dev); + Scsi_Request * SRpnt = SCpnt->sc_request; + int dev = MINOR(SRpnt->sr_request.rq_dev); Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; @@ -1002,15 +999,15 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) if (NULL == sdp) { read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return; } sfp = sdp->headfp; while (sfp) { read_lock(&sfp->rq_list_lock); for (srp = sfp->headrp; srp; srp = srp->nextrp) { - if (SCpnt == srp->my_cmdp) + if (SRpnt == srp->my_cmdp) break; } read_unlock(&sfp->rq_list_lock); @@ -1021,41 +1018,41 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) read_unlock(&sg_dev_arr_lock); if (! srp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return; } /* First transfer ownership of data buffers to sg_device object. */ - srp->data.k_use_sg = SCpnt->use_sg; - srp->data.sglist_len = SCpnt->sglist_len; - srp->data.bufflen = SCpnt->bufflen; - srp->data.buffer = SCpnt->buffer; - sg_clr_scpnt(SCpnt); + srp->data.k_use_sg = SRpnt->sr_use_sg; + srp->data.sglist_len = SRpnt->sr_sglist_len; + srp->data.bufflen = SRpnt->sr_bufflen; + srp->data.buffer = SRpnt->sr_buffer; + sg_clr_srpnt(SRpnt); srp->my_cmdp = NULL; srp->done = 1; SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", - dev, srp->header.pack_id, (int)SCpnt->result)); + dev, srp->header.pack_id, (int)SRpnt->sr_result)); srp->header.resid = SCpnt->resid; /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration); - if (0 != SCpnt->result) { - memcpy(srp->sense_b, SCpnt->sense_buffer, sizeof(srp->sense_b)); - srp->header.status = 0xff & SCpnt->result; - srp->header.masked_status = status_byte(SCpnt->result); - srp->header.msg_status = msg_byte(SCpnt->result); - srp->header.host_status = host_byte(SCpnt->result); - srp->header.driver_status = driver_byte(SCpnt->result); + if (0 != SRpnt->sr_result) { + memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof(srp->sense_b)); + srp->header.status = 0xff & SRpnt->sr_result; + srp->header.masked_status = status_byte(SRpnt->sr_result); + srp->header.msg_status = msg_byte(SRpnt->sr_result); + srp->header.host_status = host_byte(SRpnt->sr_result); + srp->header.driver_status = driver_byte(SRpnt->sr_result); if ((sdp->sgdebug > 0) && ((CHECK_CONDITION == srp->header.masked_status) || (COMMAND_TERMINATED == srp->header.masked_status))) - print_sense("sg_cmd_done_bh", SCpnt); + print_req_sense("sg_cmd_done_bh", SRpnt); /* Following if statement is a patch supplied by Eric Youngdale */ - if (driver_byte(SCpnt->result) != 0 - && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 - && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION + if (driver_byte(SRpnt->sr_result) != 0 + && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70 + && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION && sdp->device->removable) { /* Detected disc change. Set the bit - this may be used if */ /* there are filesystems using this device. */ @@ -1064,8 +1061,8 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) } /* Rely on write phase to clean out srp status values, so no "else" */ - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; if (sfp->closed) { /* whoops this fd already released, cleanup */ SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, freeing ...\n")); @@ -1336,7 +1333,7 @@ extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); #endif /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ -static void sg_shorten_timeout(Scsi_Cmnd * scpnt) +static void sg_shorten_timeout(Scsi_Request * srpnt) { #if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); @@ -2366,14 +2363,14 @@ static void sg_free(char * buff, int size, int mem_src) sg_low_free(buff, size, mem_src); } -static void sg_clr_scpnt(Scsi_Cmnd * SCpnt) +static void sg_clr_srpnt(Scsi_Request * SRpnt) { - SCpnt->use_sg = 0; - SCpnt->sglist_len = 0; - SCpnt->bufflen = 0; - SCpnt->buffer = NULL; - SCpnt->underflow = 0; - SCpnt->request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ + SRpnt->sr_use_sg = 0; + SRpnt->sr_sglist_len = 0; + SRpnt->sr_bufflen = 0; + SRpnt->sr_buffer = NULL; + SRpnt->sr_underflow = 0; + SRpnt->sr_request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ } static int sg_ms_to_jif(unsigned int msecs) @@ -2642,8 +2639,8 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, /* stop indenting so far ... */ PRINT_PROC(srp->res_used ? " rb>> " : ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); - blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen; - usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg; + blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen; + usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg; PRINT_PROC(srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") : (srp->my_cmdp ? "act:" : "prior:")); PRINT_PROC(" id=%d blen=%d", srp->header.pack_id, blen); diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index bec37e4a71f5..2a51299e8c16 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -698,6 +698,9 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; #elif defined(__alpha__) # define pcivtobus(p) ((p) & 0xfffffffful) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#elif defined(CONFIG_PPC) +# define pcivtobus(p) phys_to_bus(p) +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #else /* others */ # define pcivtobus(p) (p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) diff --git a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h index 703b36c3193a..5ea158b286be 100644 --- a/drivers/scsi/sym53c8xx_comm.h +++ b/drivers/scsi/sym53c8xx_comm.h @@ -498,7 +498,7 @@ spinlock_t DRIVER_SMP_LOCK = SPIN_LOCK_UNLOCKED; # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #endif -#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED +#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) static u_long __init remap_pci_mem(u_long base, u_long size) { u_long page_base = ((u_long) base) & PAGE_MASK; diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index 5ed418e304a6..43f67cd41d92 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -48,6 +48,7 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned static int ac97_init_mixer(struct ac97_codec *codec); static int sigmatel_init(struct ac97_codec *codec); +static int enable_eapd(struct ac97_codec *codec); #define arraysize(x) (sizeof(x)/sizeof((x)[0])) @@ -58,11 +59,14 @@ static struct { } ac97_codec_ids[] = { {0x414B4D00, "Asahi Kasei AK4540" , NULL}, {0x41445340, "Analog Devices AD1881" , NULL}, + {0x41445360, "Analog Devices AD1885" , enable_eapd}, {0x43525900, "Cirrus Logic CS4297" , NULL}, {0x43525903, "Cirrus Logic CS4297" , NULL}, {0x43525913, "Cirrus Logic CS4297A" , NULL}, {0x43525923, "Cirrus Logic CS4298" , NULL}, + {0x4352592B, "Cirrus Logic CS4294" , NULL}, {0x43525931, "Cirrus Logic CS4299" , NULL}, + {0x43525934, "Cirrus Logic CS4299" , NULL}, {0x4e534331, "National Semiconductor LM4549" , NULL}, {0x53494c22, "Silicon Laboratory Si3036" , NULL}, {0x53494c23, "Silicon Laboratory Si3038" , NULL}, @@ -562,8 +566,10 @@ int ac97_probe_codec(struct ac97_codec *codec) /* also according to spec, we wait for codec-ready state */ if (codec->codec_wait) codec->codec_wait(codec); - else + else { + current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(5); + } if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", @@ -582,6 +588,7 @@ int ac97_probe_codec(struct ac97_codec *codec) id2 = codec->codec_read(codec, AC97_VENDOR_ID2); for (i = 0; i < arraysize(ac97_codec_ids); i++) { if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { + codec->id = ac97_codec_ids[i].id; codec->name = ac97_codec_ids[i].name; codec->codec_init = ac97_codec_ids[i].init; break; @@ -660,5 +667,17 @@ static int sigmatel_init(struct ac97_codec * codec) return 1; } +/* + * Bring up an AD1885 + */ + +static int enable_eapd(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_POWER_CONTROL, + codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); + return 0; +} + + EXPORT_SYMBOL(ac97_read_proc); EXPORT_SYMBOL(ac97_probe_codec); diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c index 1bc2f66535db..6b370c2fc7d4 100644 --- a/drivers/sound/adlib_card.c +++ b/drivers/sound/adlib_card.c @@ -20,15 +20,10 @@ static void __init attach_adlib_card(struct address_info *hw_config) { hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp, THIS_MODULE); - request_region(hw_config->io_base, 4, "OPL3/OPL2"); } static int __init probe_adlib(struct address_info *hw_config) { - if (check_region(hw_config->io_base, 4)) { - DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); - return 0; - } return opl3_detect(hw_config->io_base, hw_config->osp); } @@ -55,7 +50,6 @@ static int __init init_adlib(void) static void __exit cleanup_adlib(void) { - release_region(cfg.io_base, 4); sound_unload_synthdev(cfg.slots[0]); } diff --git a/drivers/sound/cs46xx.c b/drivers/sound/cs46xx.c index 2817abc83eef..765c1a643bad 100644 --- a/drivers/sound/cs46xx.c +++ b/drivers/sound/cs46xx.c @@ -100,12 +100,6 @@ struct cs_channel /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ #define NR_AC97 2 -/* minor number of /dev/dspW */ -#define SND_DEV_DSP8 1 - -/* minor number of /dev/dspW */ -#define SND_DEV_DSP16 1 - static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; diff --git a/drivers/sound/dmasound/awacs_defs.h b/drivers/sound/dmasound/awacs_defs.h index 2757347ad1f9..ba6669aa679c 100644 --- a/drivers/sound/dmasound/awacs_defs.h +++ b/drivers/sound/dmasound/awacs_defs.h @@ -62,6 +62,11 @@ struct awacs_regs { #define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */ #define MASK_ADDR_VOLSPK MASK_ADDR4 +/* additional registers of screamer */ +#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */ +#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */ +#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */ + /* Address 0 Bit Masks & Macros */ /* ------- - --- ----- - ------ */ #define MASK_GAINRIGHT (0xf) /* Gain Right Mask */ diff --git a/drivers/sound/dmasound/dmasound_awacs.c b/drivers/sound/dmasound/dmasound_awacs.c index f80ada7fd4a3..0415191ec926 100644 --- a/drivers/sound/dmasound/dmasound_awacs.c +++ b/drivers/sound/dmasound/dmasound_awacs.c @@ -17,8 +17,12 @@ #include #include #include +#ifdef CONFIG_ADB_CUDA #include +#endif +#ifdef CONFIG_ADB_PMU #include +#endif #include #include @@ -45,6 +49,9 @@ static struct device_node* awacs_node; static char awacs_name[64]; static int awacs_revision; +int awacs_is_screamer = 0; +int awacs_device_id = 0; +int awacs_has_iic = 0; #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ /* @@ -60,7 +67,7 @@ static volatile struct dbdma_cmd *awacs_rx_cmds; * Cached values of AWACS registers (we can't read them). * Except on the burgundy. XXX */ -int awacs_reg[5]; +int awacs_reg[8]; #define HAS_16BIT_TABLES #undef HAS_8BIT_TABLES @@ -1303,6 +1310,11 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) awacs_write(awacs_reg[1] | MASK_ADDR1); awacs_write(awacs_reg[2] | MASK_ADDR2); awacs_write(awacs_reg[4] | MASK_ADDR4); + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); enable_irq(awacs_irq); enable_irq(awacs_tx_irq); @@ -1551,6 +1563,7 @@ awacs_enable_amp(int spkr_vol) if (sys_ctrler != SYS_CTRLER_CUDA) return; +#ifdef CONFIG_ADB_CUDA /* turn on headphones */ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 4, 0); @@ -1570,6 +1583,7 @@ awacs_enable_amp(int spkr_vol) cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 1, 0x29); while (!req.complete) cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ } @@ -1974,6 +1988,13 @@ int __init dmasound_awacs_init(void) awacs_subframe = *prop; if (device_is_compatible(sound, "burgundy")) awacs_revision = AWACS_BURGUNDY; + /* This should be verified on older screamers */ + if (device_is_compatible(sound, "screamer")) + awacs_is_screamer = 1; + prop = (unsigned int *)get_property(sound, "device-id", 0); + if (prop != 0) + awacs_device_id = *prop; + awacs_has_iic = (find_devices("perch") != NULL); /* look for a property saying what sample rates are available */ @@ -2029,10 +2050,12 @@ int __init dmasound_awacs_init(void) #ifdef CONFIG_PMAC_PBOOK if (machine_is_compatible("PowerBook1,1") || machine_is_compatible("AAPL,PowerBook1998")) { + pmu_suspend(); feature_set(np, FEATURE_Sound_CLK_enable); feature_set(np, FEATURE_Sound_power); /* Shorter delay will not work */ mdelay(1000); + pmu_resume(); } #endif awacs_tx_cmds = (volatile struct dbdma_cmd *) @@ -2050,16 +2073,28 @@ int __init dmasound_awacs_init(void) awacs_reg[0] = MASK_MUX_CD; - awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT; + /* FIXME: Only machines with external SRS module need MASK_PAROUT */ + awacs_reg[1] = MASK_LOOPTHRU; + if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8 + || */awacs_device_id == 0xb) + awacs_reg[1] |= MASK_PAROUT; /* get default volume from nvram */ vol = (~nvram_read_byte(0x1308) & 7) << 1; awacs_reg[2] = vol + (vol << 6); awacs_reg[4] = vol + (vol << 6); + awacs_reg[5] = 0; + awacs_reg[6] = 0; + awacs_reg[7] = 0; out_le32(&awacs->control, 0x11); awacs_write(awacs_reg[0] + MASK_ADDR0); awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_write(awacs_reg[2] + MASK_ADDR2); awacs_write(awacs_reg[4] + MASK_ADDR4); + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } /* Initialize recent versions of the awacs */ if (awacs_revision == 0) { @@ -2118,7 +2153,15 @@ int __init dmasound_awacs_init(void) break; } } - /* enable CD sound input */ + /* + * Enable CD sound input. + * The relevant bits for writing to this byte are 0x8f. + * I haven't found out what the 0x80 bit does. + * For the 0xf bits, writing 3 or 7 enables the CD + * input, any other value disables it. Values + * 1, 3, 5, 7 enable the microphone. Values 0, 2, + * 4, 6, 8 - f enable the input from the modem. + */ if (macio_base) out_8(macio_base + 0x37, 3); } diff --git a/drivers/sound/emu10k1/emu_wrapper.h b/drivers/sound/emu10k1/emu_wrapper.h index 20cb56464cc0..3a9862832bbe 100644 --- a/drivers/sound/emu10k1/emu_wrapper.h +++ b/drivers/sound/emu10k1/emu_wrapper.h @@ -5,9 +5,4 @@ #define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask)) -#ifndef PCI_GET_DRIVER_DATA - #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) - #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - #endif diff --git a/drivers/sound/emu10k1/main.c b/drivers/sound/emu10k1/main.c index c8ddfb2b4067..b7ad5b717f6f 100644 --- a/drivers/sound/emu10k1/main.c +++ b/drivers/sound/emu10k1/main.c @@ -641,7 +641,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev return -ENODEV; } - PCI_SET_DRIVER_DATA(pci_dev, card); + pci_set_drvdata(pci_dev, card); PCI_SET_DMA_MASK(pci_dev, EMU10K1_DMA_MASK); card->irq = pci_dev->irq; @@ -736,7 +736,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev static void __devexit emu10k1_remove(struct pci_dev *pci_dev) { - struct emu10k1_card *card = PCI_GET_DRIVER_DATA(pci_dev); + struct emu10k1_card *card = pci_get_drvdata(pci_dev); midi_exit(card); emu10k1_exit(card); @@ -755,7 +755,7 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev) kfree(card); - return; + pci_set_drvdata(pci_dev, NULL); } MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"); diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index 30d02d226e53..9b937a253e5c 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -198,7 +198,9 @@ static void __exit unload_gus_db16(struct address_info *hw_config) } #endif +#ifdef CONFIG_SOUND_GUS16 static int gus16 = 0; +#endif #ifdef CONFIG_SOUND_GUSMAX static int no_wave_dma = 0;/* Set if no dma is to be used for the wave table (GF1 chip) */ @@ -223,12 +225,12 @@ MODULE_PARM(irq, "i"); MODULE_PARM(dma, "i"); MODULE_PARM(dma16, "i"); MODULE_PARM(type, "i"); -MODULE_PARM(gus16, "i"); #ifdef CONFIG_SOUND_GUSMAX MODULE_PARM(no_wave_dma, "i"); #endif #ifdef CONFIG_SOUND_GUS16 MODULE_PARM(db16, "i"); +MODULE_PARM(gus16, "i"); #endif static int __init init_gus(void) diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 74d7149458b6..c86eb61d5aa0 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -15,6 +15,8 @@ * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) * Alan Cox modularisation, fixed sound_mem allocs. * Christoph Hellwig Adapted to module_init/module_exit + * Arnaldo C. de Melo get rid of check_region, use request_region for + * OPL4, release it on exit, some cleanups. * * Status * Believed to work. Badly needs rewriting a bit to support multiple @@ -172,6 +174,15 @@ int opl3_detect(int ioaddr, int *osp) "structure \n "); return 0; } + + memset(devc, 0, sizeof(*devc)); + strcpy(devc->fm_info.name, "OPL2"); + + if (!request_region(ioaddr, 4, devc->fm_info.name)) { + printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr); + goto cleanup_devc; + } + devc->osp = osp; devc->base = ioaddr; @@ -187,7 +198,7 @@ int opl3_detect(int ioaddr, int *osp) signature != 0x0f) { MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature)); - return 0; + goto cleanup_region; } if (signature == 0x06) /* OPL2 */ @@ -214,7 +225,7 @@ int opl3_detect(int ioaddr, int *osp) detected_model = 4; } - if (!check_region(ioaddr - 8, 2)) /* OPL4 port is free */ + if (request_region(ioaddr - 8, 2, "OPL4")) /* OPL4 port was free */ { int tmp; @@ -232,7 +243,10 @@ int opl3_detect(int ioaddr, int *osp) udelay(10); } else + { /* release OPL4 port */ + release_region(ioaddr - 8, 2); detected_model = 3; + } } opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); } @@ -246,6 +260,12 @@ int opl3_detect(int ioaddr, int *osp) * Melodic mode. */ return 1; +cleanup_region: + release_region(ioaddr, 4); +cleanup_devc: + kfree(devc); + devc = NULL; + return 0; } static int opl3_kill_note (int devno, int voice, int note, int velocity) @@ -1099,12 +1119,7 @@ int opl3_init(int ioaddr, int *osp, struct module *owner) return -1; } - memset((char *) devc, 0x00, sizeof(*devc)); - devc->osp = osp; - devc->base = ioaddr; - devc->nr_voice = 9; - strcpy(devc->fm_info.name, "OPL2"); devc->fm_info.device = 0; devc->fm_info.synth_type = SYNTH_TYPE_FM; @@ -1191,18 +1206,12 @@ static int __init init_opl3 (void) if (io != -1) /* User loading pure OPL3 module */ { - if (check_region(io, 4)) - { - printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", io); - return 0; - } if (!opl3_detect(io, NULL)) { return -ENODEV; } - me = opl3_init(io, NULL, THIS_MODULE); - request_region(io, 4, devc->fm_info.name); + me = opl3_init(io, NULL, THIS_MODULE); } return 0; @@ -1212,8 +1221,11 @@ static void __exit cleanup_opl3(void) { if (devc && io != -1) { - if(devc->base) + if (devc->base) { release_region(devc->base,4); + if (devc->is_opl4) + release_region(devc->base - 8, 2); + } kfree(devc); devc = NULL; sound_unload_synthdev(me); diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index e42e7d16ca2a..437f28102d91 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -13,8 +13,11 @@ * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now * uses native linux resources * Christoph Hellwig: Adapted to module_init/module_exit + * Jeff Garzik: Made it work again, in theory + * FIXME: If the request_irq() succeeds, the probe succeeds. Ug. + * + * Status: Testing required (no shit -jgarzik) * - * Status: Testing required * */ @@ -64,12 +67,11 @@ static void uart6850_write(unsigned char byte) #define UART_RESET 0x95 #define UART_MODE_ON 0x03 -static int uart6850_opened = 0; +static int uart6850_opened; static int uart6850_irq; -static int uart6850_detected = 0; +static int uart6850_detected; static int my_dev; -static int reset_uart6850(void); static void (*midi_input_intr) (int dev, unsigned char data); static void poll_uart6850(unsigned long dummy); @@ -251,6 +253,9 @@ static void __init attach_uart6850(struct address_info *hw_config) int ok, timeout; unsigned long flags; + if (!uart6850_detected) + return; + if ((my_dev = sound_alloc_mididev()) == -1) { printk(KERN_INFO "uart6850: Too many midi devices detected\n"); @@ -260,11 +265,6 @@ static void __init attach_uart6850(struct address_info *hw_config) uart6850_osp = hw_config->osp; uart6850_irq = hw_config->irq; - if (!uart6850_detected) - { - sound_unload_mididev(my_dev); - return; - } save_flags(flags); cli(); @@ -283,7 +283,7 @@ static void __init attach_uart6850(struct address_info *hw_config) sequencer_init(); } -static int reset_uart6850(void) +static inline int reset_uart6850(void) { uart6850_read(); return 1; /* @@ -291,10 +291,9 @@ static int reset_uart6850(void) */ } - static int __init probe_uart6850(struct address_info *hw_config) { - int ok = 0; + int ok; uart6850_osp = hw_config->osp; uart6850_base = hw_config->io_base; @@ -334,6 +333,7 @@ static int __init init_uart6850(void) if (probe_uart6850(&cfg_mpu)) return -ENODEV; + attach_uart6850(&cfg_mpu); return 0; } diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c index 59e5a04da53f..23a2a8e166f8 100644 --- a/drivers/sound/wf_midi.c +++ b/drivers/sound/wf_midi.c @@ -781,8 +781,7 @@ virtual_midi_disable (void) return 0; } -static int __init detect_wf_mpu (int irq, int io_base) - +int __init detect_wf_mpu (int irq, int io_base) { if (check_region (io_base, 2)) { printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n", diff --git a/drivers/telephony/Makefile b/drivers/telephony/Makefile index 517200ade033..9cbdedcc8aab 100644 --- a/drivers/telephony/Makefile +++ b/drivers/telephony/Makefile @@ -1,35 +1,29 @@ # -# Makefile for the kernel miscellaneous drivers. +# Makefile for drivers/telephony # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes.. -SUB_DIRS := +SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := telephony.a -MX_OBJS := -M_OBJS := +obj-y := +obj-n := +obj-m := +obj- := +export-objs := phonedev.o -ifeq ($(CONFIG_PHONE),y) - LX_OBJS += phonedev.o -else - ifeq ($(CONFIG_PHONE),m) - MX_OBJS += phonedev.o - endif -endif +obj-$(CONFIG_PHONE) += phonedev.o +obj-$(CONFIG_PHONE_IXJ) += ixj.o -ifeq ($(CONFIG_PHONE_IXJ),y) - L_OBJS += ixj.o -else - ifeq ($(CONFIG_PHONE_IXJ),m) - M_OBJS += ixj.o - endif -endif +O_TARGET := telephony.o +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make + diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 47485dbde8ba..e6cc146dec9a 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -4493,8 +4493,8 @@ static DWORD PCIEE_GetSerialNumber(WORD wAddress) return (((DWORD) wHi << 16) | wLo); } -static int dspio[IXJMAX + 1] = {0,}; -static int xio[IXJMAX + 1] = {0,}; +static int dspio[IXJMAX + 1]; +static int xio[IXJMAX + 1]; MODULE_DESCRIPTION("Internet PhoneJACK/Internet LineJACK module - www.quicknet.net"); MODULE_AUTHOR("Ed Okerson "); @@ -4502,27 +4502,24 @@ MODULE_AUTHOR("Ed Okerson "); MODULE_PARM(dspio, "1-" __MODULE_STRING(IXJMAX) "i"); MODULE_PARM(xio, "1-" __MODULE_STRING(IXJMAX) "i"); -#ifdef MODULE - -void cleanup_module(void) +static void __exit ixj_exit(void) { cleanup(); } -int init_module(void) -#else -int __init ixj_init(void) -#endif +static int __init ixj_init(void) { int result; - int func = 0x110, i = 0; + int i = 0; int cnt = 0; int probe = 0; - struct pci_dev *dev = NULL, *old_dev = NULL; struct pci_dev *pci = NULL; #ifdef CONFIG_ISAPNP + struct pci_dev *dev = NULL, *old_dev = NULL; + int func = 0x110; + while (1) { do { old_dev = dev; @@ -4637,6 +4634,10 @@ int __init ixj_init(void) return probe; } +module_init(ixj_init); +module_exit(ixj_exit); + + static void DAA_Coeff_US(int board) { IXJ *j = &ixj[board]; diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c index 74abe1bf99fa..63586caf4cd4 100644 --- a/drivers/telephony/phonedev.c +++ b/drivers/telephony/phonedev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -143,40 +144,29 @@ static struct file_operations phone_fops = * Board init functions */ -extern int ixj_init(void); /* * Initialise Telephony for linux */ -int telephony_init(void) +static int __init telephony_init(void) { printk(KERN_INFO "Linux telephony interface: v1.00\n"); if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) { printk("phonedev: unable to get major %d\n", PHONE_MAJOR); return -EIO; } - /* - * Init kernel installed drivers - */ -#ifdef CONFIG_PHONE_IXJ - ixj_init(); -#endif - return 0; -} -#ifdef MODULE -int init_module(void) -{ - return telephony_init(); + return 0; } -void cleanup_module(void) +static void __exit telephony_exit(void) { unregister_chrdev(PHONE_MAJOR, "telephony"); } -#endif +module_init(telephony_init); +module_exit(telephony_exit); EXPORT_SYMBOL(phone_register_device); EXPORT_SYMBOL(phone_unregister_device); diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index be853dee8168..71948e53ae79 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -28,7 +28,6 @@ * (http://www.freecom.de/) */ -#include #include "transport.h" #include "protocol.h" #include "usb.h" diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index d06808d65f2a..60cdc821e138 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -48,6 +48,7 @@ #include "usb.h" #include "debug.h" +#include #include #include #include diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 740709883a57..4c36c532e97a 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -43,6 +43,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -62,7 +63,6 @@ #include "freecom.h" #endif -#include #include #include #include diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index a1875608b3f2..774e6bd0e8ad 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -12,7 +12,6 @@ #include #include -#include #include #include diff --git a/drivers/video/Makefile b/drivers/video/Makefile index d3b8959d4adb..688f576cfecc 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -46,7 +46,10 @@ obj-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o # Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o +# Only include macmodes.o if we have FB support and are PPC +ifeq ($(CONFIG_FB),y) obj-$(CONFIG_PPC) += macmodes.o +endif obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_AMIGA) += amifb.o diff --git a/drivers/video/aty.h b/drivers/video/aty.h index 4441f0929f37..938ba185716c 100644 --- a/drivers/video/aty.h +++ b/drivers/video/aty.h @@ -461,6 +461,7 @@ #define VERTEX_2_SECONDARY_T 0x0738 /* Dword offset 1_CE */ #define VERTEX_2_SECONDARY_W 0x073C /* Dword offset 1_CF */ +#define GTC_3D_RESET_DELAY 3 /* 3D engine reset delay in ms */ /* CRTC control values (mostly CRTC_GEN_CNTL) */ @@ -747,7 +748,8 @@ #define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ #define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */ #define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */ -#define LN_CHIP_ID 0x4c4d /* RAGE Mobility AGP */ +#define LM_CHIP_ID 0x4c4d /* RAGE Mobility PCI */ +#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */ /* Mach64 major ASIC revisions */ @@ -998,5 +1000,12 @@ #define LCD_LT_GIO 0x07 #define LCD_POWER_MANAGEMENT 0x08 #define LCD_ZVGPIO 0x09 +#define LCD_MISC_CNTL 0x14 + +/* Values in LCD_MISC_CNTL */ +#define BIAS_MOD_LEVEL_MASK 0x0000ff00 +#define BIAS_MOD_LEVEL_SHIFT 8 +#define BLMOD_EN 0x00010000 +#define BIASMOD_EN 0x00020000 #endif /* REGMACH64_H */ diff --git a/drivers/video/aty128.h b/drivers/video/aty128.h index f650425e5ddc..e2b54f8f490d 100644 --- a/drivers/video/aty128.h +++ b/drivers/video/aty128.h @@ -43,6 +43,7 @@ #define OVR_CLR 0x0230 #define OVR_WID_LEFT_RIGHT 0x0234 #define OVR_WID_TOP_BOTTOM 0x0238 +#define LVDS_GEN_CNTL 0x02d0 #define DDA_CONFIG 0x02e0 #define DDA_ON_OFF 0x02e4 #define VGA_DDA_CONFIG 0x02e8 @@ -267,7 +268,8 @@ #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 #define DAC_RANGE_CNTL 0x00000003 -#define PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PDWN 0x00008000 /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 @@ -340,4 +342,11 @@ #define DP_SRC_HOST 0x00000300 #define DP_SRC_HOST_BYTEALIGN 0x00000400 +/* LVDS_GEN_CNTL constants */ +#define LVDS_BL_MOD_LEVEL_MASK 0x0000ff00 +#define LVDS_BL_MOD_LEVEL_SHIFT 8 +#define LVDS_BL_MOD_EN 0x00010000 +#define LVDS_DIGION 0x00040000 +#define LVDS_BLON 0x00080000 + #endif /* REG_RAGE128_H */ diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index ef0871369c81..05fcfcbe152d 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -55,6 +55,15 @@ #endif #endif +#ifdef CONFIG_ADB_PMU +#include +#include +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif @@ -211,13 +220,8 @@ static const char *mode_option __initdata = NULL; #endif #ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED -static int default_vmode __initdata = VMODE_640_480_60; +static int default_vmode __initdata = VMODE_1024_768_60; static int default_cmode __initdata = CMODE_8; -#else -static int default_vmode __initdata = VMODE_NVRAM; -static int default_cmode __initdata = CMODE_NVRAM; -#endif #endif #ifdef CONFIG_MTRR @@ -419,6 +423,15 @@ static struct fb_ops aty128fb_ops = { fb_rasterimg: aty128fb_rasterimg, }; +#ifdef CONFIG_PMAC_BACKLIGHT +static int aty128_set_backlight_enable(int on, int level, void* data); +static int aty128_set_backlight_level(int level, void* data); + +static struct backlight_controller aty128_backlight_controller = { + aty128_set_backlight_enable, + aty128_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Functions to read from/write to the mmio registers @@ -1712,15 +1725,8 @@ aty128_init(struct fb_info_aty128 *info, const char *name) if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) var = default_var; } else { -#ifdef CONFIG_NVRAM - if (default_vmode == VMODE_NVRAM) - default_vmode = nvram_read_byte(NV_VMODE); - - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); -#endif if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_640_480_60; + default_vmode = VMODE_1024_768_60; if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; @@ -1772,6 +1778,12 @@ aty128_init(struct fb_info_aty128 *info, const char *name) if (register_framebuffer(&info->fb_info) < 0) return 0; +#ifdef CONFIG_PMAC_BACKLIGHT + /* Could be extended to Rage128Pro LVDS output too */ + if (info->chip_gen == rage_M3) + register_backlight_controller(&aty128_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", GET_FB_IDX(info->fb_info.node), aty128fb_name, name); @@ -1916,6 +1928,11 @@ aty128_pci_register(struct pci_dev *pdev, } #endif /* CONFIG_MTRR */ +#ifdef CONFIG_FB_COMPAT_XPMAC + if (!console_fb_info) + console_fb_info = &info->fb_info; +#endif + return 0; err_out: @@ -2136,6 +2153,11 @@ aty128fbcon_blank(int blank, struct fb_info *fb) struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; u8 state = 0; +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && blank) + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ + if (blank & VESA_VSYNC_SUSPEND) state |= 2; if (blank & VESA_HSYNC_SUSPEND) @@ -2144,6 +2166,11 @@ aty128fbcon_blank(int blank, struct fb_info *fb) state |= 4; aty_st_8(CRTC_EXT_CNTL+1, state); + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && !blank) + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ } @@ -2199,7 +2226,7 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, int i; if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); @@ -2208,7 +2235,7 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, } if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); @@ -2221,7 +2248,7 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, /* initialize palette */ if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); @@ -2230,7 +2257,7 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, col = (red << 16) | (green << 8) | blue; aty_st_le32(PALETTE_DATA, col); if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); else @@ -2283,6 +2310,38 @@ do_install_cmap(int con, struct fb_info *info) } +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_conv[] = { + 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, + 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 +}; + +static int +aty128_set_backlight_enable(int on, int level, void* data) +{ + struct fb_info_aty128 *info = (struct fb_info_aty128 *)data; + unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); + + reg |= LVDS_BL_MOD_EN | LVDS_BLON; + if (on && level > BACKLIGHT_OFF) { + reg &= ~LVDS_BL_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); + } else { + reg &= ~LVDS_BL_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); + } + aty_st_le32(LVDS_GEN_CNTL, reg); + + return 0; +} + +static int +aty128_set_backlight_level(int level, void* data) +{ + return aty128_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ + /* * Accelerated functions */ diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index fb91aae15e6d..48b3b4ca28ff 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -20,6 +20,8 @@ * 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 for * more details. + * + * Many thanks to Nitya from ATI devrel for support and patience ! */ /****************************************************************************** @@ -73,6 +75,10 @@ #ifdef CONFIG_NVRAM #include #endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #ifdef __sparc__ #include #include @@ -286,6 +292,15 @@ struct fb_info_aty { static struct fb_info_aty* first_display = NULL; #endif +#ifdef CONFIG_PMAC_BACKLIGHT +static int aty_set_backlight_enable(int on, int level, void* data); +static int aty_set_backlight_level(int level, void* data); + +static struct backlight_controller aty_backlight_controller = { + aty_set_backlight_enable, + aty_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Frame buffer device API @@ -556,6 +571,8 @@ static struct aty_features { { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" }, { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" }, { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" }, + { 0x4c4d, 0x4c4d, "3D RAGE Mobility (PCI)" }, + { 0x4c4e, 0x4c4e, "3D RAGE Mobility (AGP)" }, }; static const char *aty_gx_ram[8] __initdata = { @@ -567,48 +584,51 @@ static const char *aty_ct_ram[8] __initdata = { }; -static inline u32 aty_ld_le32(unsigned int regindex, +static inline u32 aty_ld_le32(int regindex, const struct fb_info_aty *info) { -#if defined(__powerpc__) - unsigned long temp; - u32 val; + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; - temp = info->ati_regbase; - asm volatile("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b" (regindex), "r" (temp)); - return val; -#elif defined(__mc68000__) +#if defined(__mc68000__) return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex))); #else return readl (info->ati_regbase + regindex); #endif } -static inline void aty_st_le32(unsigned int regindex, u32 val, +static inline void aty_st_le32(int regindex, u32 val, const struct fb_info_aty *info) { -#if defined(__powerpc__) - unsigned long temp; + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; - temp = info->ati_regbase; - asm volatile("stwbrx %0,%1,%2;eieio" : : "r" (val), "b" (regindex), "r" (temp) : - "memory"); -#elif defined(__mc68000__) +#if defined(__mc68000__) *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val); #else writel (val, info->ati_regbase + regindex); #endif } -static inline u8 aty_ld_8(unsigned int regindex, +static inline u8 aty_ld_8(int regindex, const struct fb_info_aty *info) { + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + return readb (info->ati_regbase + regindex); } -static inline void aty_st_8(unsigned int regindex, u8 val, +static inline void aty_st_8(int regindex, u8 val, const struct fb_info_aty *info) { + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + writeb (val, info->ati_regbase + regindex); } @@ -675,6 +695,16 @@ static void reset_engine(const struct fb_info_aty *info) BUS_FIFO_ERR_ACK, info); } +static void reset_GTC_3D_engine(const struct fb_info_aty *info) +{ + aty_st_le32(SCALE_3D_CNTL, 0xc0, info); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SETUP_CNTL, 0x00, info); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SCALE_3D_CNTL, 0x00, info); + mdelay(GTC_3D_RESET_DELAY); +} + static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) { u32 pitch_value; @@ -688,6 +718,13 @@ static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) pitch_value = pitch_value * 3; } + /* On GTC (RagePro), we need to reset the 3D engine before */ + if (Gx == LB_CHIP_ID || Gx == LD_CHIP_ID || Gx == LI_CHIP_ID || + Gx == LP_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || + Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || + Gx == LM_CHIP_ID || Gx == LN_CHIP_ID) + reset_GTC_3D_engine(info); + /* Reset engine, enable, and clear any engine errors */ reset_engine(info); /* Ensure that vga page pointers are set to zero - the upper */ @@ -2494,6 +2531,9 @@ static void atyfb_set_par(const struct atyfb_par *par, } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) { aty_st_le32(DAC_CNTL, 0x87010184, info); aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) { + aty_st_le32(DAC_CNTL, 0x80010102, info); + aty_st_le32(BUS_CNTL, 0x7b33a040, info); } else { /* GT */ aty_st_le32(DAC_CNTL, 0x86010102, info); @@ -3375,6 +3415,10 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) /* Rage LT */ pll = 230; mclk = 63; + } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) { + /* Rage mobility M1 */ + pll = 230; + mclk = 50; } else { /* other RAGE */ pll = 135; @@ -3545,13 +3589,15 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) info->fb_info.blank = &atyfbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; -#ifdef CONFIG_PPC +#ifdef CONFIG_PMAC_BACKLIGHT if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) { /* these bits let the 101 powerbook wake up from sleep -- paulus */ aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info) | (USE_F32KHZ | TRISTATE_MEM_EN), info); } -#endif /* CONFIG_PPC */ + if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) + register_backlight_controller(&aty_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef MODULE var = default_var; @@ -3580,6 +3626,9 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) default_vmode = VMODE_1024_768_60; else if (machine_is_compatible("iMac")) default_vmode = VMODE_1024_768_75; + else if (machine_is_compatible("PowerBook2,1")) + /* iBook with 800x600 LCD */ + default_vmode = VMODE_800_600_60; else default_vmode = VMODE_640_480_67; sense = read_aty_sense(info); @@ -4216,10 +4265,10 @@ static void atyfbcon_blank(int blank, struct fb_info *fb) struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; -#ifdef CONFIG_ADB_PMU +#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) - pmu_enable_backlight(0); -#endif + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); if (blank > 0) @@ -4241,10 +4290,10 @@ static void atyfbcon_blank(int blank, struct fb_info *fb) gen_cntl &= ~(0x4c); aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); -#ifdef CONFIG_ADB_PMU +#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) - pmu_enable_backlight(1); -#endif + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ } @@ -4955,6 +5004,40 @@ aty_sleep_notify(struct pmu_sleep_notifier *self, int when) } #endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_conv[] = { + 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, + 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff +}; + +static int +aty_set_backlight_enable(int on, int level, void* data) +{ + struct fb_info_aty *info = (struct fb_info_aty *)data; + unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); + + reg |= (BLMOD_EN | BIASMOD_EN); + if (on && level > BACKLIGHT_OFF) { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); + } else { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); + } + aty_st_lcd(LCD_MISC_CNTL, reg, info); + + return 0; +} + +static int +aty_set_backlight_level(int level, void* data) +{ + return aty_set_backlight_enable(1, level, data); +} + +#endif /* CONFIG_PMAC_BACKLIGHT */ + + #ifdef MODULE int __init init_module(void) { diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 22f6031b2495..9a3908c4b078 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -35,6 +35,9 @@ #include #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif #include #include @@ -245,7 +248,9 @@ static void chipsfb_blank(int blank, struct fb_info *info) // used to disable backlight only for blank > 1, but it seems // useful at blank = 1 too (saves battery, extends backlight life) if (blank) { - pmu_enable_backlight(0); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ /* get the palette from the chip */ for (i = 0; i < 256; ++i) { out_8(p->io_base + 0x3c7, i); @@ -262,7 +267,9 @@ static void chipsfb_blank(int blank, struct fb_info *info) out_8(p->io_base + 0x3c9, 0); } } else { - pmu_enable_backlight(1); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ for (i = 0; i < 256; ++i) { out_8(p->io_base + 0x3c8, i); udelay(1); @@ -673,8 +680,10 @@ static void __init chips_of_init(struct device_node *dp) /* Clear the entire framebuffer */ memset(p->frame_buffer, 0, 0x100000); +#ifdef CONFIG_PMAC_BACKLIGHT /* turn on the backlight */ - pmu_enable_backlight(1); + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ init_chips(p); } diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index b609f43f2796..1e06548b3cf0 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -122,6 +122,8 @@ static int control_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int control_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -171,6 +173,7 @@ static struct fb_ops controlfb_ops = { fb_get_cmap: control_get_cmap, fb_set_cmap: control_set_cmap, fb_pan_display: control_pan_display, + fb_mmap: control_mmap, }; @@ -327,6 +330,48 @@ static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, return 0; } +/* Private mmap since we want to have a different caching on the framebuffer + * for controlfb. + * Note there's no locking in here; it's done in fb_mmap() in fbmem.c. + */ +static int control_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct fb_ops *fb = info->fbops; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + unsigned long off, start; + u32 len; + + fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); + off = vma->vm_pgoff << PAGE_SHIFT; + + /* frame buffer memory */ + start = fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len); + if (off >= len) { + /* memory mapped io */ + off -= len; + fb->fb_get_var(&var, PROC_CONSOLE(info), info); + if (var.accel_flags) + return -EINVAL; + start = fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; + } else { + /* framebuffer */ + pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; + } + start &= PAGE_MASK; + vma->vm_pgoff = off >> PAGE_SHIFT; + if (io_remap_page_range(vma->vm_start, off, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + + /******************** End of controlfb_ops implementation ********************/ /* (new one that is) */ @@ -466,11 +511,6 @@ static void do_install_cmap(int con, struct fb_info *info) } } -#ifdef CONFIG_FB_COMPAT_XPMAC -extern struct vc_mode display_info; -extern struct fb_info *console_fb_info; -#endif /* CONFIG_FB_COMPAT_XPMAC */ - static inline int control_vram_reqd(int video_mode, int color_mode) { return (control_reg_init[video_mode-1]->vres @@ -483,12 +523,14 @@ static void set_control_clock(unsigned char *params) struct adb_request req; int i; +#ifdef CONFIG_ADB_CUDA for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); while (!req.complete) cuda_poll(); } +#endif } diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 1399d68827ab..81b08345e472 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -43,6 +43,15 @@ static int currcon = 0; +/* Supported palette hacks */ +enum { + cmap_unknown, + cmap_m64, /* ATI Mach64 */ + cmap_r128, /* ATI Rage128 */ + cmap_M3A, /* ATI Rage Mobility M3 Head A */ + cmap_M3B /* ATI Rage Mobility M3 Head B */ +}; + struct fb_info_offb { struct fb_info info; struct fb_fix_screeninfo fix; @@ -51,7 +60,7 @@ struct fb_info_offb { struct { u_char red, green, blue, pad; } palette[256]; volatile unsigned char *cmap_adr; volatile unsigned char *cmap_data; - int is_rage_128; + int cmap_type; union { #ifdef FBCON_HAS_CFB16 u16 cfb16[16]; @@ -408,21 +417,27 @@ static void offb_init_fb(const char *name, const char *full_name, fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - info->is_rage_128 = 0; + info->cmap_type = cmap_unknown; if (depth == 8) { /* XXX kludge for ati */ - if (strncmp(name, "ATY,Rage128", 11) == 0) { - if (dp) { + if (dp && !strncmp(name, "ATY,Rage128", 11)) { unsigned long regbase = dp->addrs[2].address; - info->cmap_adr = ioremap(regbase, 0x1FFF) + 0x00b0; - info->cmap_data = info->cmap_adr + 4; - info->is_rage_128 = 1; - } - } else if (strncmp(name, "ATY,", 4) == 0) { + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_r128; + } else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) { + unsigned long regbase = dp->parent->addrs[2].address; + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_M3A; + } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { + unsigned long regbase = dp->parent->addrs[2].address; + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_M3B; + } else if (!strncmp(name, "ATY,", 4)) { unsigned long base = address & 0xff000000UL; info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0; info->cmap_data = info->cmap_adr + 1; + info->cmap_type = cmap_m64; } fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; @@ -580,7 +595,7 @@ static void offb_init_fb(const char *name, const char *full_name, display_info.cmap_data_address = 0; display_info.disp_reg_address = 0; /* XXX kludge for ati */ - if (strncmp(name, "ATY,", 4) == 0) { + if (info->cmap_type == cmap_m64) { unsigned long base = address & 0xff000000UL; display_info.disp_reg_address = base + 0x7ffc00; display_info.cmap_adr_address = base + 0x7ffcc0; @@ -628,11 +643,32 @@ static void offbcon_blank(int blank, struct fb_info *info) if (blank) for (i = 0; i < 256; i++) { - *info2->cmap_adr = i; - mach_eieio(); - for (j = 0; j < 3; j++) { - *info2->cmap_data = 0; - mach_eieio(); + switch(info2->cmap_type) { + case cmap_m64: + *info2->cmap_adr = i; + mach_eieio(); + for (j = 0; j < 3; j++) { + *info2->cmap_data = 0; + mach_eieio(); + } + break; + case cmap_M3A: + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20); + case cmap_r128: + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; + case cmap_M3B: + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20); + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; } } else @@ -682,18 +718,36 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, info2->palette[regno].green = green; info2->palette[regno].blue = blue; - *info2->cmap_adr = regno;/* On some chipsets, add << 3 in 15 bits */ - mach_eieio(); - if (info2->is_rage_128) { - out_le32((unsigned int *)info2->cmap_data, - (red << 16 | green << 8 | blue)); - } else { + switch(info2->cmap_type) { + case cmap_m64: + *info2->cmap_adr = regno; + mach_eieio(); *info2->cmap_data = red; - mach_eieio(); - *info2->cmap_data = green; - mach_eieio(); - *info2->cmap_data = blue; - mach_eieio(); + mach_eieio(); + *info2->cmap_data = green; + mach_eieio(); + *info2->cmap_data = blue; + mach_eieio(); + break; + case cmap_M3A: + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20); + case cmap_r128: + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, regno); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), + (red << 16 | green << 8 | blue)); + break; + case cmap_M3B: + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20); + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, regno); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), + (red << 16 | green << 8 | blue)); + break; } if (regno < 16) diff --git a/drivers/video/sisfb.c b/drivers/video/sisfb.c index 0307995af153..44f92d872f95 100644 --- a/drivers/video/sisfb.c +++ b/drivers/video/sisfb.c @@ -356,8 +356,6 @@ u16 VGA_DAC[] = { 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -#ifdef CONFIG_FB_SIS_LINUXBIOS - #define Monitor1Sense 0x20 unsigned char SRegsInit[] = { @@ -371,6 +369,8 @@ unsigned char SRegsInit[] = { 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff }; +#ifdef CONFIG_FB_SIS_LINUXBIOS + unsigned char SRegs[] = { 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13, 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, @@ -1440,7 +1440,6 @@ static u32 get_reg3(u16 port) static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo) { - unsigned char ModeID; u16 modeidlength; u16 usModeIDOffset; unsigned short PreviousWord,CurrentWord; diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 9e7132f864f6..24a8b04a11bc 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -425,12 +425,14 @@ static void set_valkyrie_clock(unsigned char *params) struct adb_request req; int i; +#ifdef CONFIG_ADB_CUDA for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); while (!req.complete) cuda_poll(); } +#endif } static void __init init_valkyrie(struct fb_info_valkyrie *p) diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index f96acf581a3b..fe1396497122 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -197,7 +197,7 @@ static int bfs_statfs(struct super_block *s, struct statfs *buf) buf->f_bfree = buf->f_bavail = s->su_freeb; buf->f_files = s->su_lasti + 1 - BFS_ROOT_INO; buf->f_ffree = s->su_freei; - buf->f_fsid.val[0] = s->s_dev; + buf->f_fsid.val[0] = kdev_t_to_nr(s->s_dev); buf->f_namelen = BFS_NAMELEN; return 0; } diff --git a/fs/block_dev.c b/fs/block_dev.c index 038c7c697b26..fc4a86e77ae4 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -310,6 +310,39 @@ ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos) return read; } +/* + * private llseek: + * for a block special file file->f_dentry->d_inode->i_size is zero + * so we compute the size by hand (just as in block_read/write above) + */ +static loff_t block_llseek(struct file *file, loff_t offset, int origin) +{ + long long retval; + kdev_t dev; + + switch (origin) { + case 2: + dev = file->f_dentry->d_inode->i_rdev; + if (blk_size[MAJOR(dev)]) + offset += (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS; + /* else? return -EINVAL? */ + break; + case 1: + offset += file->f_pos; + } + retval = -EINVAL; + if (offset >= 0) { + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + retval = offset; + } + return retval; +} + + /* * Filp may be NULL when we are called by an msync of a vma * since the vma has no handle. @@ -612,7 +645,7 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) int blkdev_open(struct inode * inode, struct file * filp) { - int ret = -ENODEV; + int ret = -ENXIO; struct block_device *bdev = inode->i_bdev; down(&bdev->bd_sem); lock_kernel(); @@ -678,6 +711,7 @@ static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, struct file_operations def_blk_fops = { open: blkdev_open, release: blkdev_close, + llseek: block_llseek, read: block_read, write: block_write, fsync: block_fsync, diff --git a/fs/buffer.c b/fs/buffer.c index 43e04eea49b2..47076f058a5d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -410,8 +410,9 @@ out: */ #define _hashfn(dev,block) \ ((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \ - (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12)))) -#define hash(dev,block) hash_table[(_hashfn(dev,block) & bh_hash_mask)] + (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \ + ((block) << (bh_hash_shift - 12)))) +#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)] static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **head) { @@ -705,9 +706,9 @@ void set_blocksize(kdev_t dev, int size) static void refill_freelist(int size) { if (!grow_buffers(size)) { - //wakeup_bdflush(1); balance_dirty(NODEV); - wakeup_kswapd(1); + wakeup_kswapd(0); /* We can't wait because of __GFP_IO */ + schedule(); } } @@ -863,15 +864,14 @@ int balance_dirty_state(kdev_t dev) dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; tot = nr_free_buffer_pages(); -// tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT; dirty *= 200; soft_dirty_limit = tot * bdf_prm.b_un.nfract; hard_dirty_limit = soft_dirty_limit * 2; /* First, check for the "real" dirty limit. */ - if (dirty > soft_dirty_limit || inactive_shortage()) { - if (dirty > hard_dirty_limit) + if (dirty > soft_dirty_limit) { + if (dirty > hard_dirty_limit || inactive_shortage()) return 1; return 0; } @@ -2279,7 +2279,9 @@ int try_to_free_buffers(struct page * page, int wait) { struct buffer_head * tmp, * bh = page->buffers; int index = BUFSIZE_INDEX(bh->b_size); + int loop = 0; +cleaned_buffers_try_again: spin_lock(&lru_list_lock); write_lock(&hash_table_lock); spin_lock(&free_list[index].lock); @@ -2325,8 +2327,14 @@ busy_buffer_page: spin_unlock(&free_list[index].lock); write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); - if (wait) + if (wait) { sync_page_buffers(bh, wait); + /* We waited synchronously, so we can free the buffers. */ + if (wait > 1 && !loop) { + loop = 1; + goto cleaned_buffers_try_again; + } + } return 0; } diff --git a/fs/dcache.c b/fs/dcache.c index 214f0da2ec47..b7505aea6f6c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1248,7 +1248,7 @@ void __init vfs_caches_init(unsigned long mempages) panic("Cannot create buffer head SLAB cache"); names_cachep = kmem_cache_create("names_cache", - PAGE_SIZE, 0, + PATH_MAX + 1, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!names_cachep) panic("Cannot create names SLAB cache"); diff --git a/fs/namei.c b/fs/namei.c index 75ffc6ef0434..a78918206815 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -107,7 +107,7 @@ static inline int do_getname(const char *filename, char *page) { int retval; - unsigned long len = PAGE_SIZE; + unsigned long len = PATH_MAX + 1; if ((unsigned long) filename >= TASK_SIZE) { if (!segment_eq(get_fs(), KERNEL_DS)) @@ -683,7 +683,7 @@ walk_init_root(const char *name, struct nameidata *nd) } /* SMP-safe */ -int path_init(const char *name,unsigned int flags,struct nameidata *nd) +int path_init(const char *name, unsigned int flags, struct nameidata *nd) { nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index fc13e8698b77..4f7f23667923 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index 119de17bac50..5c46935c7288 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c @@ -21,7 +21,7 @@ #include "mac.h" #ifdef CONFIG_PPC -extern void note_bootable_part(kdev_t dev, int part); +extern void note_bootable_part(kdev_t dev, int part, int goodness); #endif /* @@ -67,7 +67,7 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_ brelse(bh); dev_pos = secsize; if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", + printk("%s: error reading Mac partition table\n", kdevname(dev)); return -1; } @@ -77,6 +77,7 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_ brelse(bh); return 0; /* not a MacOS disk */ } + printk(" [mac]"); blocks_in_map = be32_to_cpu(part->map_count); for (blk = 1; blk <= blocks_in_map; ++blk) { pos = blk * secsize; @@ -114,7 +115,8 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_ goodness++; if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0 - || strcasecmp(part->type, "Linux_PPC") == 0) { + || (strnicmp(part->type, "Linux", 5) == 0 + && strcasecmp(part->type, "Linux_swap") != 0)) { int i, l; goodness++; @@ -143,7 +145,7 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_ } #ifdef CONFIG_PPC if (found_root_goodness) - note_bootable_part(dev, found_root); + note_bootable_part(dev, found_root, found_root_goodness); #endif brelse(bh); printk("\n"); diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 116f0134596a..43c401a97558 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -336,14 +336,14 @@ static int kstat_read_proc(char *page, char **start, off_t off, for (major = 0; major < DK_MAX_MAJOR; major++) { for (disk = 0; disk < DK_MAX_DISK; disk++) { - int active = kstat.dk_drive_rio[major][disk] + + int active = kstat.dk_drive[major][disk] + kstat.dk_drive_rblk[major][disk] + - kstat.dk_drive_wio[major][disk] + kstat.dk_drive_wblk[major][disk]; if (active) len += sprintf(page + len, - "(%u,%u):(%u,%u,%u,%u) ", + "(%u,%u):(%u,%u,%u,%u,%u) ", major, disk, + kstat.dk_drive[major][disk], kstat.dk_drive_rio[major][disk], kstat.dk_drive_rblk[major][disk], kstat.dk_drive_wio[major][disk], diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index dc424b72e422..f13ba4f3d4f4 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -121,7 +121,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev) inode->i_size = 0; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; - inode->i_rdev = dev; + inode->i_rdev = to_kdev_t(dev); inode->i_nlink = 1; inode->i_op = NULL; inode->i_fop = NULL; diff --git a/fs/super.c b/fs/super.c index 81a3fafc2b19..f789dd6209be 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1303,20 +1303,21 @@ static int copy_mount_options (const void *data, unsigned long *where) * information (or be NULL). * * NOTE! As pre-0.97 versions of mount() didn't use this setup, the - * flags have to have a special 16-bit magic number in the high word: - * 0xC0ED. If this magic word isn't present, the flags and data info - * aren't used, as the syscall assumes we are talking to an older - * version that didn't understand them. + * flags used to have a special 16-bit magic number in the high word: + * 0xC0ED. If this magic number is present, the high word is discarded. */ long do_mount(char * dev_name, char * dir_name, char *type_page, - unsigned long new_flags, void *data_page) + unsigned long flags, void *data_page) { struct file_system_type * fstype; struct nameidata nd; struct vfsmount *mnt = NULL; struct super_block *sb; int retval = 0; - unsigned long flags = 0; + + /* Discard magic */ + if ((flags & MS_MGC_MSK) == MS_MGC_VAL) + flags &= ~MS_MGC_MSK; /* Basic sanity checks */ @@ -1328,21 +1329,25 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, /* OK, looks good, now let's see what do they want */ /* just change the flags? - capabilities are checked in do_remount() */ - if ((new_flags & (MS_MGC_MSK|MS_REMOUNT)) == (MS_MGC_VAL|MS_REMOUNT)) - return do_remount(dir_name, new_flags&~(MS_MGC_MSK|MS_REMOUNT), - (char *) data_page); + if (flags & MS_REMOUNT) + return do_remount(dir_name, flags & ~MS_REMOUNT, + (char *) data_page); - if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) - flags = new_flags & ~MS_MGC_MSK; + /* "mount --bind"? Equivalent to older "mount -t bind" */ + /* No capabilities? What if users do thousands of these? */ + if (flags & MS_BIND) + return do_loopback(dev_name, dir_name); /* For the rest we need the type */ if (!type_page || !memchr(type_page, 0, PAGE_SIZE)) return -EINVAL; +#if 0 /* Can be deleted again. Introduced in patch-2.3.99-pre6 */ /* loopback mount? This is special - requires fewer capabilities */ if (strcmp(type_page, "bind")==0) return do_loopback(dev_name, dir_name); +#endif /* for the rest we _really_ need capabilities... */ if (!capable(CAP_SYS_ADMIN)) @@ -1354,7 +1359,8 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, return -ENODEV; /* ... and mountpoint. Do the lookup first to force automounting. */ - if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) + if (path_init(dir_name, + LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) retval = path_walk(dir_name, &nd); if (retval) goto fs_out; @@ -1363,7 +1369,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if (fstype->fs_flags & FS_NOMOUNT) sb = ERR_PTR(-EINVAL); else if (fstype->fs_flags & FS_REQUIRES_DEV) - sb = get_sb_bdev(fstype, dev_name,flags, data_page); + sb = get_sb_bdev(fstype, dev_name, flags, data_page); else if (fstype->fs_flags & FS_SINGLE) sb = get_sb_single(fstype, flags, data_page); else @@ -1376,6 +1382,13 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, /* Something was mounted here while we slept */ while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry)) ; + + /* Refuse the same filesystem on the same mount point */ + retval = -EBUSY; + if (nd.mnt && nd.mnt->mnt_sb == sb + && nd.mnt->mnt_root == nd.dentry) + goto fail; + retval = -ENOENT; if (!nd.dentry->d_inode) goto fail; @@ -1403,7 +1416,7 @@ fail: } asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void * data) + unsigned long flags, void * data) { int retval; unsigned long data_page; @@ -1423,14 +1436,18 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, retval = copy_mount_options (dev_name, &dev_page); if (retval < 0) goto out2; + retval = copy_mount_options (data, &data_page); - if (retval >= 0) { - lock_kernel(); - retval = do_mount((char*)dev_page,dir_page,(char*)type_page, - new_flags, (void*)data_page); - unlock_kernel(); - free_page(data_page); - } + if (retval < 0) + goto out3; + + lock_kernel(); + retval = do_mount((char*)dev_page, dir_page, (char*)type_page, + flags, (void*)data_page); + unlock_kernel(); + free_page(data_page); + +out3: free_page(dev_page); out2: putname(dir_page); diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index 972b450cfc44..ecceb0c7b156 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -64,7 +64,7 @@ struct semaphore { #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) -extern inline void sema_init (struct semaphore *sem, int val) +static inline void sema_init (struct semaphore *sem, int val) { /* * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); @@ -105,7 +105,7 @@ asmlinkage void __up(struct semaphore * sem); * "__down_failed" is a special asm handler that calls the C * routine that actually waits. See arch/i386/kernel/semaphore.c */ -extern inline void down(struct semaphore * sem) +static inline void down(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -125,7 +125,7 @@ extern inline void down(struct semaphore * sem) :"memory"); } -extern inline int down_interruptible(struct semaphore * sem) +static inline int down_interruptible(struct semaphore * sem) { int result; @@ -149,7 +149,7 @@ extern inline int down_interruptible(struct semaphore * sem) return result; } -extern inline int down_trylock(struct semaphore * sem) +static inline int down_trylock(struct semaphore * sem) { int result; @@ -179,7 +179,7 @@ extern inline int down_trylock(struct semaphore * sem) * The default case (no contention) will result in NO * jumps for both down() and up(). */ -extern inline void up(struct semaphore * sem) +static inline void up(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -252,7 +252,7 @@ struct rw_semaphore { #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) -extern inline void init_rwsem(struct rw_semaphore *sem) +static inline void init_rwsem(struct rw_semaphore *sem) { atomic_set(&sem->count, RW_LOCK_BIAS); sem->read_bias_granted = 0; @@ -271,7 +271,7 @@ extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem)); extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); -extern inline void down_read(struct rw_semaphore *sem) +static inline void down_read(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->__magic != (long)&sem->__magic) @@ -287,7 +287,7 @@ extern inline void down_read(struct rw_semaphore *sem) #endif } -extern inline void down_write(struct rw_semaphore *sem) +static inline void down_write(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->__magic != (long)&sem->__magic) @@ -311,7 +311,7 @@ extern inline void down_write(struct rw_semaphore *sem) * case is when there was a writer waiting, and we've * bumped the count to 0: we must wake the writer up. */ -extern inline void __up_read(struct rw_semaphore *sem) +static inline void __up_read(struct rw_semaphore *sem) { __asm__ __volatile__( "# up_read\n\t" @@ -330,7 +330,7 @@ extern inline void __up_read(struct rw_semaphore *sem) /* releasing the writer is easy -- just release it and * wake up any sleepers. */ -extern inline void __up_write(struct rw_semaphore *sem) +static inline void __up_write(struct rw_semaphore *sem) { __asm__ __volatile__( "# up_write\n\t" @@ -346,7 +346,7 @@ extern inline void __up_write(struct rw_semaphore *sem) ); } -extern inline void up_read(struct rw_semaphore *sem) +static inline void up_read(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->write_bias_granted) @@ -358,7 +358,7 @@ extern inline void up_read(struct rw_semaphore *sem) __up_read(sem); } -extern inline void up_write(struct rw_semaphore *sem) +static inline void up_write(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->read_bias_granted) diff --git a/include/asm-ppc/atomic.h b/include/asm-ppc/atomic.h index c3c5133d67ab..bafb66ada903 100644 --- a/include/asm-ppc/atomic.h +++ b/include/asm-ppc/atomic.h @@ -21,7 +21,7 @@ typedef struct { int counter; } atomic_t; extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); extern void atomic_set_mask(unsigned long mask, unsigned long *addr); -extern __inline__ int atomic_add_return(int a, atomic_t *v) +extern __inline__ int atomic_add_return(int a, volatile atomic_t *v) { int t; @@ -37,7 +37,7 @@ extern __inline__ int atomic_add_return(int a, atomic_t *v) return t; } -extern __inline__ int atomic_sub_return(int a, atomic_t *v) +extern __inline__ int atomic_sub_return(int a, volatile atomic_t *v) { int t; @@ -53,7 +53,7 @@ extern __inline__ int atomic_sub_return(int a, atomic_t *v) return t; } -extern __inline__ int atomic_inc_return(atomic_t *v) +extern __inline__ int atomic_inc_return(volatile atomic_t *v) { int t; @@ -69,7 +69,7 @@ extern __inline__ int atomic_inc_return(atomic_t *v) return t; } -extern __inline__ int atomic_dec_return(atomic_t *v) +extern __inline__ int atomic_dec_return(volatile atomic_t *v) { int t; diff --git a/include/asm-ppc/backlight.h b/include/asm-ppc/backlight.h index db315e67791f..79756eca3c58 100644 --- a/include/asm-ppc/backlight.h +++ b/include/asm-ppc/backlight.h @@ -25,4 +25,4 @@ extern int get_backlight_enable(void); extern int set_backlight_level(int level); extern int get_backlight_level(void); -#endif \ No newline at end of file +#endif diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h index ccb0f199f34a..9c55e00ee216 100644 --- a/include/asm-ppc/bitops.h +++ b/include/asm-ppc/bitops.h @@ -230,6 +230,8 @@ extern __inline__ unsigned long find_next_zero_bit(void * addr, tmp = *p; found_first: tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } @@ -320,6 +322,8 @@ extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, tmp = cpu_to_le32p(p); found_first: tmp |= ~0U << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } diff --git a/include/asm-ppc/bootx.h b/include/asm-ppc/bootx.h index 5674bd0f9e51..90c79cdb795e 100644 --- a/include/asm-ppc/bootx.h +++ b/include/asm-ppc/bootx.h @@ -133,4 +133,3 @@ typedef struct boot_infos #endif #endif - \ No newline at end of file diff --git a/include/asm-ppc/cpm_8260.h b/include/asm-ppc/cpm_8260.h index 5f500d5c3338..427ec188428c 100644 --- a/include/asm-ppc/cpm_8260.h +++ b/include/asm-ppc/cpm_8260.h @@ -85,6 +85,7 @@ #define CPM_DATAONLY_BASE ((uint)128) #define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) #define CPM_DP_NOSPACE ((uint)0x7fffffff) +#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) /* The number of pages of host memory we allocate for CPM. This is * done early in kernel initialization to get physically contiguous @@ -97,8 +98,8 @@ * and dual port ram. */ extern cpm8260_t *cpmp; /* Pointer to comm processor */ -uint m8260_cpm_dpalloc(uint size); -uint m8260_cpm_hostalloc(uint size); +uint m8260_cpm_dpalloc(uint size, uint align); +uint m8260_cpm_hostalloc(uint size, uint align); void m8260_cpm_setbrg(uint brg, uint rate); void m8260_cpm_fastbrg(uint brg, uint rate, int div16); @@ -153,7 +154,7 @@ typedef struct cpm_buf_desc { #define PROFF_REVNUM ((uint)0x8af0) #define PROFF_RAND ((uint)0x8af8) #define PROFF_I2C_BASE ((uint)0x8afc) -#define PROFF_IDMA4_BASE ((uint)0x89fe) +#define PROFF_IDMA4_BASE ((uint)0x8afe) /* The SMCs are relocated to any of the first eight DPRAM pages. * We will fix these at the first locations of DPRAM, until we @@ -403,40 +404,44 @@ typedef struct scc_enet { #define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ #define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ -/* SCC Mode Register (PMSR) as used by Ethernet. +/* SCC Mode Register (PSMR) as used by Ethernet. */ -#define SCC_PMSR_HBC ((ushort)0x8000) /* Enable heartbeat */ -#define SCC_PMSR_FC ((ushort)0x4000) /* Force collision */ -#define SCC_PMSR_RSH ((ushort)0x2000) /* Receive short frames */ -#define SCC_PMSR_IAM ((ushort)0x1000) /* Check individual hash */ -#define SCC_PMSR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ -#define SCC_PMSR_PRO ((ushort)0x0200) /* Promiscuous mode */ -#define SCC_PMSR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ -#define SCC_PMSR_SBT ((ushort)0x0080) /* Special backoff timer */ -#define SCC_PMSR_LPB ((ushort)0x0040) /* Set Loopback mode */ -#define SCC_PMSR_SIP ((ushort)0x0020) /* Sample Input Pins */ -#define SCC_PMSR_LCW ((ushort)0x0010) /* Late collision window */ -#define SCC_PMSR_NIB22 ((ushort)0x000a) /* Start frame search */ -#define SCC_PMSR_FDE ((ushort)0x0001) /* Full duplex enable */ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ /* Buffer descriptor control/status used by Ethernet receive. -*/ + * Common to SCC and FCC. + */ #define BD_ENET_RX_EMPTY ((ushort)0x8000) #define BD_ENET_RX_WRAP ((ushort)0x2000) #define BD_ENET_RX_INTR ((ushort)0x1000) #define BD_ENET_RX_LAST ((ushort)0x0800) #define BD_ENET_RX_FIRST ((ushort)0x0400) #define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_BC ((ushort)0x0080) /* FCC Only */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* FCC Only */ #define BD_ENET_RX_LG ((ushort)0x0020) #define BD_ENET_RX_NO ((ushort)0x0010) #define BD_ENET_RX_SH ((ushort)0x0008) #define BD_ENET_RX_CR ((ushort)0x0004) #define BD_ENET_RX_OV ((ushort)0x0002) #define BD_ENET_RX_CL ((ushort)0x0001) -#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ +#define BD_ENET_RX_STATS ((ushort)0x01ff) /* All status bits */ /* Buffer descriptor control/status used by Ethernet transmit. -*/ + * Common to SCC and FCC. + */ #define BD_ENET_TX_READY ((ushort)0x8000) #define BD_ENET_TX_PAD ((ushort)0x4000) #define BD_ENET_TX_WRAP ((ushort)0x2000) @@ -523,6 +528,152 @@ typedef struct scc_trans { #define BD_SCC_TX_LAST ((ushort)0x0800) +/* How about some FCCs..... +*/ +#define FCC_GFMR_DIAG_NORM ((uint)0x00000000) +#define FCC_GFMR_DIAG_LE ((uint)0x40000000) +#define FCC_GFMR_DIAG_AE ((uint)0x80000000) +#define FCC_GFMR_DIAG_ALE ((uint)0xc0000000) +#define FCC_GFMR_TCI ((uint)0x20000000) +#define FCC_GFMR_TRX ((uint)0x10000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_CDP ((uint)0x04000000) +#define FCC_GFMR_CTSP ((uint)0x02000000) +#define FCC_GFMR_CDS ((uint)0x01000000) +#define FCC_GFMR_CTSS ((uint)0x00800000) +#define FCC_GFMR_SYNL_NONE ((uint)0x00000000) +#define FCC_GFMR_SYNL_AUTO ((uint)0x00004000) +#define FCC_GFMR_SYNL_8 ((uint)0x00008000) +#define FCC_GFMR_SYNL_16 ((uint)0x0000c000) +#define FCC_GFMR_RTSM ((uint)0x00002000) +#define FCC_GFMR_RENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_RENC_NRZI ((uint)0x00000800) +#define FCC_GFMR_REVD ((uint)0x00000400) +#define FCC_GFMR_TENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_TENC_NRZI ((uint)0x00000100) +#define FCC_GFMR_TCRC_16 ((uint)0x00000000) +#define FCC_GFMR_TCRC_32 ((uint)0x00000080) +#define FCC_GFMR_ENR ((uint)0x00000020) +#define FCC_GFMR_ENT ((uint)0x00000010) +#define FCC_GFMR_MODE_ENET ((uint)0x0000000c) +#define FCC_GFMR_MODE_ATM ((uint)0x0000000a) +#define FCC_GFMR_MODE_HDLC ((uint)0x00000000) + +/* Generic FCC parameter ram. +*/ +typedef struct fcc_param { + ushort fcc_riptr; /* Rx Internal temp pointer */ + ushort fcc_tiptr; /* Tx Internal temp pointer */ + ushort fcc_res1; + ushort fcc_mrblr; /* Max receive buffer length, mod 32 bytes */ + uint fcc_rstate; /* Upper byte is Func code, must be set */ + uint fcc_rbase; /* Receive BD base */ + ushort fcc_rbdstat; /* RxBD status */ + ushort fcc_rbdlen; /* RxBD down counter */ + uint fcc_rdptr; /* RxBD internal data pointer */ + uint fcc_tstate; /* Upper byte is Func code, must be set */ + uint fcc_tbase; /* Transmit BD base */ + ushort fcc_tbdstat; /* TxBD status */ + ushort fcc_tbdlen; /* TxBD down counter */ + uint fcc_tdptr; /* TxBD internal data pointer */ + uint fcc_rbptr; /* Rx BD Internal buf pointer */ + uint fcc_tbptr; /* Tx BD Internal buf pointer */ + uint fcc_rcrc; /* Rx temp CRC */ + uint fcc_res2; + uint fcc_tcrc; /* Tx temp CRC */ +} fccp_t; + + +/* Ethernet controller through FCC. +*/ +typedef struct fcc_enet { + fccp_t fen_genfcc; + uint fen_statbuf; /* Internal status buffer */ + uint fen_camptr; /* CAM address */ + uint fen_cmask; /* Constant mask for CRC */ + uint fen_cpres; /* Preset CRC */ + uint fen_crcec; /* CRC Error counter */ + uint fen_alec; /* alignment error counter */ + uint fen_disfc; /* discard frame counter */ + ushort fen_retlim; /* Retry limit */ + ushort fen_retcnt; /* Retry counter */ + ushort fen_pper; /* Persistence */ + ushort fen_boffcnt; /* backoff counter */ + uint fen_gaddrh; /* Group address filter, high 32-bits */ + uint fen_gaddrl; /* Group address filter, low 32-bits */ + ushort fen_tfcstat; /* out of sequence TxBD */ + ushort fen_tfclen; + uint fen_tfcptr; + ushort fen_mflr; /* Maximum frame length (1518) */ + ushort fen_paddrh; /* MAC address */ + ushort fen_paddrm; + ushort fen_paddrl; + ushort fen_ibdcount; /* Internal BD counter */ + ushort fen_idbstart; /* Internal BD start pointer */ + ushort fen_ibdend; /* Internal BD end pointer */ + ushort fen_txlen; /* Internal Tx frame length counter */ + uint fen_ibdbase[8]; /* Internal use */ + uint fen_iaddrh; /* Individual address filter */ + uint fen_iaddrl; + ushort fen_minflr; /* Minimum frame length (64) */ + ushort fen_taddrh; /* Filter transfer MAC address */ + ushort fen_taddrm; + ushort fen_taddrl; + ushort fen_padptr; /* Pointer to pad byte buffer */ + ushort fen_cftype; /* control frame type */ + ushort fen_cfrange; /* control frame range */ + ushort fen_maxb; /* maximum BD count */ + ushort fen_maxd1; /* Max DMA1 length (1520) */ + ushort fen_maxd2; /* Max DMA2 length (1520) */ + ushort fen_maxd; /* internal max DMA count */ + ushort fen_dmacnt; /* internal DMA counter */ + uint fen_octc; /* Total octect counter */ + uint fen_colc; /* Total collision counter */ + uint fen_broc; /* Total broadcast packet counter */ + uint fen_mulc; /* Total multicast packet count */ + uint fen_uspc; /* Total packets < 64 bytes */ + uint fen_frgc; /* Total packets < 64 bytes with errors */ + uint fen_ospc; /* Total packets > 1518 */ + uint fen_jbrc; /* Total packets > 1518 with errors */ + uint fen_p64c; /* Total packets == 64 bytes */ + uint fen_p65c; /* Total packets 64 < bytes <= 127 */ + uint fen_p128c; /* Total packets 127 < bytes <= 255 */ + uint fen_p256c; /* Total packets 256 < bytes <= 511 */ + uint fen_p512c; /* Total packets 512 < bytes <= 1023 */ + uint fen_p1024c; /* Total packets 1024 < bytes <= 1518 */ + uint fen_cambuf; /* Internal CAM buffer poiner */ + ushort fen_rfthr; /* Received frames threshold */ + ushort fen_rfcnt; /* Received frames count */ +} fcc_enet_t; + +/* FCC Event/Mask register as used by Ethernet. +*/ +#define FCC_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define FCC_ENET_RXC ((ushort)0x0040) /* Control Frame Received */ +#define FCC_ENET_TXC ((ushort)0x0020) /* Out of seq. Tx sent */ +#define FCC_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define FCC_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define FCC_ENET_BSY ((ushort)0x0004) /* Busy. Rx Frame dropped */ +#define FCC_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define FCC_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* FCC Mode Register (FPSMR) as used by Ethernet. +*/ +#define FCC_PSMR_HBC ((uint)0x80000000) /* Enable heartbeat */ +#define FCC_PSMR_FC ((uint)0x40000000) /* Force Collision */ +#define FCC_PSMR_SBT ((uint)0x20000000) /* Stop backoff timer */ +#define FCC_PSMR_LPB ((uint)0x10000000) /* Local protect. 1 = FDX */ +#define FCC_PSMR_LCW ((uint)0x08000000) /* Late collision select */ +#define FCC_PSMR_FDE ((uint)0x04000000) /* Full Duplex Enable */ +#define FCC_PSMR_MON ((uint)0x02000000) /* RMON Enable */ +#define FCC_PSMR_PRO ((uint)0x00400000) /* Promiscuous Enable */ +#define FCC_PSMR_FCE ((uint)0x00200000) /* Flow Control Enable */ +#define FCC_PSMR_RSH ((uint)0x00100000) /* Receive Short Frames */ +#define FCC_PSMR_CAM ((uint)0x00000400) /* CAM enable */ +#define FCC_PSMR_BRO ((uint)0x00000200) /* Broadcast pkt discard */ +#define FCC_PSMR_ENCRC ((uint)0x00000080) /* Use 32-bit CRC */ + /* IIC parameter RAM. */ typedef struct iic { diff --git a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h index 6250eba7cf0f..81e57da5d312 100644 --- a/include/asm-ppc/fcntl.h +++ b/include/asm-ppc/fcntl.h @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -68,4 +72,12 @@ struct flock { pid_t l_pid; }; +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + #endif diff --git a/include/asm-ppc/feature.h b/include/asm-ppc/feature.h index c9f2d2eac3fe..ca4ca469276d 100644 --- a/include/asm-ppc/feature.h +++ b/include/asm-ppc/feature.h @@ -7,7 +7,9 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1998 Paul Mackerras. + * Copyright (C) 1998 Paul Mackerras & + * Ben. Herrenschmidt. + * * */ #ifndef __ASM_PPC_FEATURE_H @@ -76,6 +78,9 @@ extern void feature_init(void); */ extern void feature_set_gmac_power(struct device_node* device, int power); + /* use constants in KeyLargo.h for the reset parameter */ +extern void feature_set_gmac_phy_reset(struct device_node* device, int reset); + extern void feature_set_usb_power(struct device_node* device, int power); extern void feature_set_firewire_power(struct device_node* device, int power); diff --git a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h index 07398997aa90..f7c12df773c1 100644 --- a/include/asm-ppc/hardirq.h +++ b/include/asm-ppc/hardirq.h @@ -5,16 +5,23 @@ #include /* entry.S is sensitive to the offsets of these fields */ +/* The __last_jiffy_stamp field is needed to ensure that no decrementer + * interrupt is lost on SMP machines. Since on most CPUs it is in the same + * cache line as local_irq_count, it is cheap to access and is also used on UP + * for uniformity. + */ typedef struct { unsigned int __softirq_active; unsigned int __softirq_mask; unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; + unsigned int __last_jiffy_stamp; } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ +#define last_jiffy_stamp(cpu) __IRQ_STAT((cpu), __last_jiffy_stamp) /* * Are we in an interrupt context? Either doing bottom half * or hardware interrupt processing? diff --git a/include/asm-ppc/heathrow.h b/include/asm-ppc/heathrow.h index 647c63261592..039f221581f0 100644 --- a/include/asm-ppc/heathrow.h +++ b/include/asm-ppc/heathrow.h @@ -44,4 +44,9 @@ #define HRW_BMAC_IO_ENABLE 0x60000000 /* two bits, not documented in OF */ #define HRW_BMAC_RESET 0x80000000 /* not documented in OF */ +/* We OR those features at boot on desktop G3s */ +#define HRW_DEFAULTS (HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE) + +/* Those seem to be different on paddington */ #define PADD_MODEM_POWER_N 0x00000001 /* modem power on paddington */ +#define PADD_RESET_SCC 0x02000000 /* check this please */ diff --git a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h new file mode 100644 index 000000000000..428a59d1c6c9 --- /dev/null +++ b/include/asm-ppc/highmem.h @@ -0,0 +1,121 @@ +/* + * highmem.h: virtual kernel memory mappings for high memory + * + * PowerPC version, stolen from the i386 version. + * + * Used in CONFIG_HIGHMEM systems for memory pages which + * are not addressable by direct kernel virtual adresses. + * + * Copyright (C) 1999 Gerhard Wichert, Siemens AG + * Gerhard.Wichert@pdb.siemens.de + * + * + * Redesigned the x86 32-bit VM architecture to deal with + * up to 16 Terrabyte physical memory. With current x86 CPUs + * we now support up to 64 Gigabytes physical RAM. + * + * Copyright (C) 1999 Ingo Molnar + */ + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* undef for production */ +#define HIGHMEM_DEBUG 1 + +extern pte_t *kmap_pte; +extern pgprot_t kmap_prot; +extern pte_t *pkmap_page_table; + +extern void kmap_init(void) __init; + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +#define PKMAP_BASE (0xfe000000UL) +#define LAST_PKMAP 1024 +#define LAST_PKMAP_MASK (LAST_PKMAP-1) +#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define KMAP_FIX_BEGIN (0xfe400000UL) + +extern unsigned long kmap_high(struct page *page); +extern void kunmap_high(struct page *page); + +extern inline unsigned long kmap(struct page *page) +{ + if (in_interrupt()) + BUG(); + if (page < highmem_start_page) + return (unsigned long) page_address(page); + return kmap_high(page); +} + +extern inline void kunmap(struct page *page) +{ + if (in_interrupt()) + BUG(); + if (page < highmem_start_page) + return; + kunmap_high(page); +} + +/* + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap + * gives a more generic (and caching) interface. But kmap_atomic can + * be used in IRQ contexts, so in some (very limited) cases we need + * it. + */ +extern inline unsigned long kmap_atomic(struct page *page, enum km_type type) +{ + unsigned int idx; + unsigned long vaddr; + + if (page < highmem_start_page) + return (unsigned long) page_address(page); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE; +#if HIGHMEM_DEBUG + if (!pte_none(*(kmap_pte+idx))) + BUG(); +#endif + set_pte(kmap_pte+idx, mk_pte(page, kmap_prot)); + flush_hash_page(0, vaddr); + + return vaddr; +} + +extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type) +{ +#if HIGHMEM_DEBUG + unsigned int idx = type + KM_TYPE_NR*smp_processor_id(); + + if (vaddr < KMAP_FIX_BEGIN) // FIXME + return; + + if (vaddr != KMAP_FIX_BEGIN + idx * PAGE_SIZE) + BUG(); + + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(kmap_pte+idx); + flush_hash_page(0, vaddr); +#endif +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_HIGHMEM_H */ diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h index 198132fa43a7..8b50f862b243 100644 --- a/include/asm-ppc/ide.h +++ b/include/asm-ppc/ide.h @@ -63,7 +63,6 @@ void ide_insw(ide_ioreg_t port, void *buf, int ns); void ide_outsw(ide_ioreg_t port, void *buf, int ns); void ppc_generic_ide_fix_driveid(struct hd_driveid *id); -#if 0 #undef insw #define insw(port, buf, ns) do { \ ppc_ide_md.insw((port), (buf), (ns)); \ @@ -73,7 +72,6 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id); #define outsw(port, buf, ns) do { \ ppc_ide_md.outsw((port), (buf), (ns)); \ } while (0) -#endif #undef SUPPORT_SLOW_DATA_PORTS #define SUPPORT_SLOW_DATA_PORTS 0 diff --git a/include/asm-ppc/immap_8260.h b/include/asm-ppc/immap_8260.h index 407cbf04cf7b..298276363eae 100644 --- a/include/asm-ppc/immap_8260.h +++ b/include/asm-ppc/immap_8260.h @@ -241,10 +241,12 @@ typedef struct fcc { char res1[2]; ushort fcc_fdsr; char res2[2]; - uint fcc_fcce; - uint fcc_fccm; + ushort fcc_fcce; + char res3[2]; + ushort fcc_fccm; + char res4[2]; u_char fcc_fccs; - char res3[3]; + char res5[3]; u_char fcc_ftirr_phy[4]; } fcc_t; diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 6e5a57ad61ef..45b2531a3865 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -25,12 +25,12 @@ #include #elif defined(CONFIG_8260) #include -#else +#else /* 4xx/8xx/8260 */ #ifdef CONFIG_APUS #define _IO_BASE 0 #define _ISA_MEM_BASE 0 #define PCI_DRAM_OFFSET 0 -#else +#else /* CONFIG_APUS */ extern unsigned long isa_io_base; extern unsigned long isa_mem_base; extern unsigned long pci_dram_offset; @@ -54,6 +54,14 @@ extern unsigned long pci_dram_offset; #define writel(b,addr) out_le32((volatile u32 *)(addr),(b)) #endif + +#define __raw_readb(addr) (*(volatile unsigned char *)(addr)) +#define __raw_readw(addr) (*(volatile unsigned short *)(addr)) +#define __raw_readl(addr) (*(volatile unsigned int *)(addr)) +#define __raw_writeb(v, addr) (*(volatile unsigned char *)(addr) = (v)) +#define __raw_writew(v, addr) (*(volatile unsigned short *)(addr) = (v)) +#define __raw_writel(v, addr) (*(volatile unsigned int *)(addr) = (v)) + /* * The insw/outsw/insl/outsl macros don't do byte-swapping. * They are only used in practice for transferring buffers which @@ -67,26 +75,76 @@ extern unsigned long pci_dram_offset; #define insl(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) #define outsl(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) +#ifdef CONFIG_ALL_PPC +/* + * We have to handle possible machine checks here on powermacs + * and potentially some CHRPs -- paulus. + */ +#define __do_in_asm(name, op) \ +extern __inline__ unsigned int name(unsigned int port) \ +{ \ + unsigned int x; \ + __asm__ __volatile__( \ + op " %0,0,%1\n" \ + "1: sync\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"ax\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=&r" (x) \ + : "r" (port + _IO_BASE)); \ + return x; \ +} + +#define __do_out_asm(name, op) \ +extern __inline__ void name(unsigned int val, unsigned int port) \ +{ \ + __asm__ __volatile__( \ + op " %0,0,%1\n" \ + "1: sync\n" \ + "2:\n" \ + ".section __ex_table,\"ax\"\n" \ + " .align 2\n" \ + " .long 1b,2b\n" \ + ".previous" \ + : : "r" (val), "r" (port + _IO_BASE)); \ +} + +__do_in_asm(inb, "lbzx") +__do_in_asm(inw, "lhbrx") +__do_in_asm(inl, "lwbrx") +__do_out_asm(outb, "stbx") +__do_out_asm(outw, "sthbrx") +__do_out_asm(outl, "stwbrx") + +#elif defined(CONFIG_APUS) #define inb(port) in_8((u8 *)((port)+_IO_BASE)) #define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) -#if defined(CONFIG_APUS) #define inw(port) in_be16((u16 *)((port)+_IO_BASE)) #define outw(val, port) out_be16((u16 *)((port)+_IO_BASE), (val)) #define inl(port) in_be32((u32 *)((port)+_IO_BASE)) #define outl(val, port) out_be32((u32 *)((port)+_IO_BASE), (val)) -#else + +#else /* not APUS or ALL_PPC */ +#define inb(port) in_8((u8 *)((port)+_IO_BASE)) +#define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) #define inw(port) in_le16((u16 *)((port)+_IO_BASE)) #define outw(val, port) out_le16((u16 *)((port)+_IO_BASE), (val)) #define inl(port) in_le32((u32 *)((port)+_IO_BASE)) #define outl(val, port) out_le32((u32 *)((port)+_IO_BASE), (val)) #endif -#define inb_p(port) in_8((u8 *)((port)+_IO_BASE)) -#define outb_p(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) -#define inw_p(port) in_le16((u16 *)((port)+_IO_BASE)) -#define outw_p(val, port) out_le16((u16 *)((port)+_IO_BASE), (val)) -#define inl_p(port) in_le32((u32 *)((port)+_IO_BASE)) -#define outl_p(val, port) out_le32((u32 *)((port)+_IO_BASE), (val)) +#define inb_p(port) inb((port)) +#define outb_p(val, port) outb((val), (port)) +#define inw_p(port) inw((port)) +#define outw_p(val, port) outw((val), (port)) +#define inl_p(port) inl((port)) +#define outl_p(val, port) outl((val), (port)) extern void _insb(volatile u8 *port, void *buf, int ns); extern void _outsb(volatile u8 *port, const void *buf, int ns); @@ -123,6 +181,8 @@ extern void _outsl_ns(volatile u32 *port, const void *buf, int nl); */ extern void *__ioremap(unsigned long address, unsigned long size, unsigned long flags); +extern void *__ioremap_at(unsigned long phys, unsigned long size, + unsigned long flags); extern void *ioremap(unsigned long address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) extern void iounmap(void *addr); diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index 0f1972ddf9bc..86647a0e6fb1 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -184,6 +184,9 @@ extern irq_node_t *new_irq_node(void); */ #define SIU_INT_SMC1 ((uint)0x04) #define SIU_INT_SMC2 ((uint)0x05) +#define SIU_INT_FCC1 ((uint)0x20) +#define SIU_INT_FCC2 ((uint)0x21) +#define SIU_INT_FCC3 ((uint)0x22) #define SIU_INT_SCC1 ((uint)0x28) #define SIU_INT_SCC2 ((uint)0x29) #define SIU_INT_SCC3 ((uint)0x2a) diff --git a/include/asm-ppc/keylargo.h b/include/asm-ppc/keylargo.h new file mode 100644 index 000000000000..5408262a1790 --- /dev/null +++ b/include/asm-ppc/keylargo.h @@ -0,0 +1,103 @@ +/* + * keylargo.h: definitions for using the "KeyLargo" I/O controller chip. + * + */ + +/* offset from base for feature control registers */ +#define KEYLARGO_MBCR 0x34 /* Media bay control/status */ +#define KEYLARGO_FCR0 0x38 +#define KEYLARGO_FCR1 0x3c +#define KEYLARGO_FCR2 0x40 +#define KEYLARGO_FCR3 0x44 +#define KEYLARGO_FCR4 0x48 + +/* GPIO registers */ +#define KEYLARGO_GPIO_LEVELS0 0x50 +#define KEYLARGO_GPIO_LEVELS1 0x54 +#define KEYLARGO_GPIO_EXTINT_0 0x58 +#define KEYLARGO_GPIO_EXTINT_CNT 18 +#define KEYLARGO_GPIO_0 0x6A +#define KEYLARGO_GPIO_CNT 17 + +/* Specific GPIO regs */ +#define KL_GPIO_ETH_PHY_RESET (KEYLARGO_GPIO_0+0x10) +#define KL_GPIO_ETH_PHY_RESET_ASSERT 0x04 +#define KL_GPIO_ETH_PHY_RESET_RELEASE 0x05 +#define KL_GPIO_ETH_PHY_RESET_TRISTATE 0x00 +/* + * Bits in feature control register + */ +#define KL_MBCR_MBDEV_ENABLE 0x00001000 + +#define KL0_SCC_B_INTF_ENABLE 0x00000001 /* ??? */ +#define KL0_SCC_A_INTF_ENABLE 0x00000002 /* ??? */ +#define KL0_SCC_SLOWPCLK 0x00000004 +#define KL0_SCC_RESET 0x00000008 +#define KL0_SCCA_ENABLE 0x00000010 +#define KL0_SCCB_ENABLE 0x00000020 +#define KL0_SCC_CELL_ENABLE 0x00000040 +#define KL0_IRDA_ENABLE 0x00008000 +#define KL0_IRDA_CLK32_ENABLE 0x00010000 +#define KL0_IRDA_CLK19_ENABLE 0x00020000 +#define KL0_USB0_PAD_SUSPEND0 0x00040000 +#define KL0_USB0_PAD_SUSPEND1 0x00080000 +#define KL0_USB0_CELL_ENABLE 0x00100000 +#define KL0_USB1_PAD_SUSPEND0 0x00400000 +#define KL0_USB1_PAD_SUSPEND1 0x00800000 +#define KL0_USB1_CELL_ENABLE 0x01000000 +#define KL0_USB_REF_SUSPEND 0x10000000 + +#define KL0_SERIAL_ENABLE (KL0_SCC_B_INTF_ENABLE | \ + KL0_SCC_SLOWPCLK | \ + KL0_SCC_CELL_ENABLE | KL0_SCCA_ENABLE) + +#define KL1_AUDIO_SEL_22MCLK 0x00000002 +#define KL1_AUDIO_CLK_ENABLE_BIT 0x00000008 +#define KL1_AUDIO_CLK_OUT_ENABLE 0x00000020 /* Burgundy only ? */ +#define KL1_AUDIO_CELL_ENABLE 0x00000040 +#define KL1_AUDIO_CHOOSE 0x00000080 /* Burgundy only ? */ +#define KL1_I2S0_CELL_ENABLE 0x00000400 +#define KL1_I2S0_CLK_ENABLE_BIT 0x00001000 +#define KL1_I2S0_ENABLE 0x00002000 +#define KL1_I2S1_CELL_ENABLE 0x00020000 +#define KL1_I2S1_CLK_ENABLE_BIT 0x00080000 +#define KL1_I2S1_ENABLE 0x00100000 +#define KL1_EIDE0_ENABLE 0x00800000 +#define KL1_EIDE0_RESET_N 0x01000000 +#define KL1_EIDE1_ENABLE 0x04000000 +#define KL1_EIDE1_RESET_N 0x08000000 +#define KL1_UIDE_ENABLE 0x20000000 +#define KL1_UIDE_RESET_N 0x40000000 + +#define KL2_IOBUS_ENABLE 0x00000002 +#define KL2_SLEEP_STATE_BIT 0x00000100 +#define KL2_MPIC_ENABLE 0x00020000 +#define KL2_MODEM_POWER_N 0x02000000 +#define KL2_AIRPORT_RESET_N 0x08000000 /* Or power ? */ + +#define KL3_SHUTDOWN_PLL_TOTAL 0x00000001 +#define KL3_SHUTDOWN_PLLKW6 0x00000002 +#define KL3_SHUTDOWN_PLLKW4 0x00000004 +#define KL3_SHUTDOWN_PLLKW35 0x00000008 +#define KL3_SHUTDOWN_PLLKW12 0x00000010 +#define KL3_PLL_RESET 0x00000020 +#define KL3_SHUTDOWN_PLL2X 0x00000080 +#define KL3_CLK66_ENABLE 0x00000100 +#define KL3_CLK49_ENABLE 0x00000200 +#define KL3_CLK45_ENABLE 0x00000400 +#define KL3_CLK31_ENABLE 0x00000800 +#define KL3_TIMER_CLK18_ENABLE 0x00001000 +#define KL3_I2S1_CLK18_ENABLE 0x00002000 +#define KL3_I2S0_CLK18_ENABLE 0x00004000 +#define KL3_VIA_CLK16_ENABLE 0x00008000 +#define KL3_STOPPING33_ENABLED 0x00080000 + +/* Port 0,1 : bus 0, port 2,3 : bus 1 */ +#define KL4_SET_PORT_ENABLE(p) (0x00000008 << (p<<3)) +#define KL4_SET_PORT_RESUME(p) (0x00000004 << (p<<3)) +#define KL4_SET_PORT_CONNECT(p) (0x00000002 << (p<<3)) +#define KL4_SET_PORT_DISCONNECT(p) (0x00000001 << (p<<3)) +#define KL4_GET_PORT_RESUME(p) (0x00000040 << (p<<3)) +#define KL4_GET_PORT_CONNECT(p) (0x00000020 << (p<<3)) +#define KL4_GET_PORT_DISCONNECT(p) (0x00000010 << (p<<3)) + diff --git a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h new file mode 100644 index 000000000000..d92d81b203f4 --- /dev/null +++ b/include/asm-ppc/kmap_types.h @@ -0,0 +1,10 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_BOUNCE_WRITE, + KM_TYPE_NR +}; + +#endif diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index 306fc2b210b8..709827f29a4b 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -31,7 +31,7 @@ struct machdep_calls { void (*power_off)(void); void (*halt)(void); - void (*time_init)(void); /* Optional, may be NULL */ + long (*time_init)(void); /* Optional, may be NULL */ int (*set_rtc_time)(unsigned long nowtime); unsigned long (*get_rtc_time)(void); void (*calibrate_decr)(void); @@ -75,7 +75,7 @@ struct machdep_calls { void (*pcibios_fixup)(void); void (*pcibios_fixup_bus)(struct pci_bus *); - void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn); + void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical); void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn); int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn); diff --git a/include/asm-ppc/mbx.h b/include/asm-ppc/mbx.h index e67e0344f7a0..6c84b89556c2 100644 --- a/include/asm-ppc/mbx.h +++ b/include/asm-ppc/mbx.h @@ -25,6 +25,7 @@ typedef struct bd_info { unsigned int bi_busfreq; /* Bus Freq, in Hz */ unsigned int bi_clun; /* Boot device controller */ unsigned int bi_dlun; /* Boot device logical dev */ + unsigned int bi_baudrate; /* ...to be like everyone else */ } bd_t; /* Memory map for the MBX as configured by EPPC-Bug. We could reprogram diff --git a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h index 99a5c83861c6..64abf0c58ced 100644 --- a/include/asm-ppc/mman.h +++ b/include/asm-ppc/mman.h @@ -22,8 +22,8 @@ #define MS_INVALIDATE 2 /* invalidate the caches */ #define MS_SYNC 4 /* synchronous memory sync */ -#define MCL_CURRENT 1 /* lock all current mappings */ -#define MCL_FUTURE 2 /* lock all future mappings */ +#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */ +#define MCL_FUTURE 0x4000 /* lock all additions to address space */ #define MADV_NORMAL 0x0 /* default page-in behavior */ #define MADV_RANDOM 0x1 /* page-in minimum required */ diff --git a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h index 985d2a321c50..144d518b9668 100644 --- a/include/asm-ppc/nvram.h +++ b/include/asm-ppc/nvram.h @@ -38,6 +38,8 @@ enum { pmac_nvram_NR /* MacOS Name Registry partition */ }; +#ifdef __KERNEL__ + /* Return partition offset in nvram */ extern int pmac_get_partition(int partition); @@ -45,15 +47,20 @@ extern int pmac_get_partition(int partition); extern u8 pmac_xpram_read(int xpaddr); extern void pmac_xpram_write(int xpaddr, u8 data); +#endif /* __KERNEL__ */ + /* Some offsets in XPRAM */ #define PMAC_XPRAM_MACHINE_LOC 0xe4 #define PMAC_XPRAM_SOUND_VOLUME 0x08 /* Machine location structure in XPRAM */ struct pmac_machine_location { - u32 latitude; /* 2+30 bit Fractional number */ - u32 longitude; /* 2+30 bit Fractional number */ - u32 delta; /* mix of GMT delta and DLS */ + unsigned int latitude; /* 2+30 bit Fractional number */ + unsigned int longitude; /* 2+30 bit Fractional number */ + unsigned int delta; /* mix of GMT delta and DLS */ }; +/* /dev/nvram ioctls */ +#define PMAC_NVRAM_GET_OFFSET _IOWR('p', 0x40, int) /* Get NVRAM partition offset */ + #endif diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h index ca893118a799..5aa72d3a243a 100644 --- a/include/asm-ppc/pci-bridge.h +++ b/include/asm-ppc/pci-bridge.h @@ -15,8 +15,12 @@ void *pci_io_base(unsigned int bus); /* This version handles the new Uni-N host bridge, the iobase is now * a per-device thing. I also added the memory base so PReP can * be fixed to return 0xc0000000 (I didn't actually implement it) + * + * pci_dev_io_base() returns either a virtual (ioremap'ed) address or + * a physical address. In-kernel clients will use logical while the + * sys_pciconfig_iobase syscall returns a physical one to userland. */ -void *pci_dev_io_base(unsigned char bus, unsigned char devfn); +void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical); void *pci_dev_mem_base(unsigned char bus, unsigned char devfn); /* Returns the root-bridge number (Uni-N number) of a device */ @@ -33,7 +37,8 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, struct bridge_data { volatile unsigned int *cfg_addr; volatile unsigned char *cfg_data; - void *io_base; + void *io_base; /* virtual */ + unsigned long io_base_phys; int bus_number; int max_bus; struct bridge_data *next; diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 3484048282ad..c5a90fba0ddb 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -69,7 +69,7 @@ extern inline void flush_tlb_pgtables(struct mm_struct *mm, extern void flush_icache_range(unsigned long, unsigned long); extern void __flush_page_to_ram(unsigned long page_va); -#define flush_page_to_ram(page) __flush_page_to_ram((unsigned long) page_address(page)) +extern void flush_page_to_ram(struct page *page); #define flush_dcache_page(page) do { } while (0) diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h index 4fd684705f37..f99eb4abed0b 100644 --- a/include/asm-ppc/processor.h +++ b/include/asm-ppc/processor.h @@ -287,6 +287,7 @@ #define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ #define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ #define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ +#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ #define SPRN_XER 0x001 /* Fixed Point Exception Register */ #define SPRN_ZPR 0x3B0 /* Zone Protection Register */ diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index a3d6e5d2298e..a3d037e815b1 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -12,6 +12,9 @@ typedef void *ihandle; extern char *prom_display_paths[]; extern unsigned int prom_num_displays; +#ifndef CONFIG_MACH_SPECIFIC +extern int have_of; +#endif struct address_range { unsigned int space; diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h index 61d3412b9b21..b6b89dc79055 100644 --- a/include/asm-ppc/serial.h +++ b/include/asm-ppc/serial.h @@ -23,16 +23,6 @@ #define RS_TABLE_SIZE 4 #endif -#ifdef CONFIG_PMAC -/* - * Auto-probing will cause machine checks on powermacs. - */ -#define SERIAL_PORT_DFNS -#else -/* - * PReP, CHRP, etc. - */ - /* Standard COM flags (except for COM4, because of the 8514 problem) */ #ifdef CONFIG_SERIAL_DETECT_IRQ #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) @@ -136,5 +126,4 @@ HUB6_SERIAL_PORT_DFNS \ MCA_SERIAL_PORT_DFNS -#endif /* CONFIG_PMAC */ #endif /* CONFIG_GEMINI */ diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index aec727670a6d..abbd0ca0c348 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -24,10 +24,11 @@ extern struct cpuinfo_PPC cpu_data[NR_CPUS]; extern unsigned long smp_proc_in_lock[NR_CPUS]; -extern void smp_message_pass(int target, int msg, unsigned long data, int wait); extern void smp_store_cpu_info(int id); -extern void smp_message_recv(int); -void smp_send_tlb_invalidate(int); +extern void smp_send_tlb_invalidate(int); +extern void smp_send_xmon_break(int cpu); +struct pt_regs; +extern void smp_message_recv(int, struct pt_regs *); #define NO_PROC_ID 0xFF /* No processor magic marker */ #define PROC_CHANGE_PENALTY 20 diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h index 5e7e2a19eba4..292406736981 100644 --- a/include/asm-ppc/spinlock.h +++ b/include/asm-ppc/spinlock.h @@ -41,6 +41,7 @@ typedef struct { } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) extern void _read_lock(rwlock_t *rw); extern void _read_unlock(rwlock_t *rw); diff --git a/include/asm-ppc/time.h b/include/asm-ppc/time.h index 2fd7cc5a05c1..1eb0ae9f02fa 100644 --- a/include/asm-ppc/time.h +++ b/include/asm-ppc/time.h @@ -12,9 +12,10 @@ #include /* time.c */ -extern unsigned decrementer_count; -extern unsigned count_period_num; -extern unsigned count_period_den; +extern unsigned tb_ticks_per_jiffy; +extern unsigned tb_to_us; +extern unsigned tb_last_stamp; + extern void to_tm(int tim, struct rtc_time * tm); extern time_t last_rtc_update; @@ -34,7 +35,81 @@ static __inline__ void set_dec(unsigned int val) { #if defined(CONFIG_4xx) mtspr(SPRN_PIT, val); +#else +#ifdef CONFIG_8xx_CPU6 + set_dec_cpu6(val); #else mtspr(SPRN_DEC, val); #endif +#endif +} + +/* Accessor functions for the timebase (RTC on 601) registers. */ +/* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ +#ifdef CONFIG_6xx +extern __inline__ int const __USE_RTC(void) { + return (mfspr(SPRN_PVR)>>16) == 1; +} +#else +#define __USE_RTC() 0 +#endif + +extern __inline__ unsigned long get_tbl(void) { + unsigned long tbl; + asm volatile("mftb %0" : "=r" (tbl)); + return tbl; } + +extern __inline__ unsigned long get_rtcl(void) { + unsigned long rtcl; + asm volatile("mfrtcl %0" : "=r" (rtcl)); + return rtcl; +} + +extern __inline__ unsigned get_native_tbl(void) { + if (__USE_RTC()) + return get_rtcl(); + else + return get_tbl(); +} + +/* On machines with RTC, this function can only be used safely + * after the timestamp and for 1 second. It is only used by gettimeofday + * however so it should not matter. + */ +extern __inline__ unsigned tb_ticks_since(unsigned tstamp) { + if (__USE_RTC()) { + int delta = get_rtcl() - tstamp; + return delta<0 ? delta + 1000000000 : delta; + } else { + return get_tbl() - tstamp; + } +} + +#if 0 +extern __inline__ unsigned long get_bin_rtcl(void) { + unsigned long rtcl, rtcu1, rtcu2; + asm volatile("\ +1: mfrtcu %0\n\ + mfrtcl %1\n\ + mfrtcu %2\n\ + cmpw %0,%2\n\ + bne- 1b\n" + : "=r" (rtcu1), "=r" (rtcl), "=r" (rtcu2) + : : "cr0"); + return rtcu2*1000000000+rtcl; +} + +extern __inline__ unsigned binary_tbl(void) { + if (__USE_RTC()) + return get_bin_rtcl(); + else + return get_tbl(); +} +#endif + +/* Use mulhwu to scale processor timebase to timeval */ +#define mulhwu(x,y) \ +({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) + +unsigned mulhwu_scale_factor(unsigned, unsigned); diff --git a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h index fcb22706b1e3..628373b1537a 100644 --- a/include/asm-ppc/uaccess.h +++ b/include/asm-ppc/uaccess.h @@ -57,7 +57,7 @@ struct exception_table_entry /* Returns 0 if exception not found and fixup otherwise. */ extern unsigned long search_exception_table(unsigned long); - +extern void sort_exception_table(void); /* * These are the main single-value transfer routines. They automatically @@ -131,10 +131,11 @@ struct __large_struct { unsigned long buf[100]; }; ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ " b 2b\n" \ + ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 2\n" \ " .long 1b,3b\n" \ - ".text" \ + ".previous" \ : "=r"(err) \ : "r"(x), "b"(addr), "i"(-EFAULT), "0"(err)) @@ -178,10 +179,11 @@ do { \ "3: li %0,%3\n" \ " li %1,0\n" \ " b 2b\n" \ + ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 2\n" \ " .long 1b,3b\n" \ - ".text" \ + ".previous" \ : "=r"(err), "=r"(x) \ : "b"(addr), "i"(-EFAULT), "0"(err)) diff --git a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h new file mode 100644 index 000000000000..eefe4389cdd9 --- /dev/null +++ b/include/asm-ppc/uninorth.h @@ -0,0 +1,83 @@ +/* + * uninorth.h: definitions for using the "UniNorth" host bridge chip + * from Apple. This chip is used on "Core99" machines + * + */ + + +/* + * Uni-N config space reg. definitions + * + * (Little endian) + */ + +/* Address ranges selection. This one should work with Bandit too */ +#define UNI_N_ADDR_SELECT 0x48 +#define UNI_N_ADDR_COARSE_MASK 0xffff0000 /* 256Mb regions at *0000000 */ +#define UNI_N_ADDR_FINE_MASK 0x0000ffff /* 16Mb regions at f*000000 */ + +/* AGP registers */ +#define UNI_N_CFG_GART_BASE 0x8c +#define UNI_N_CFG_AGP_BASE 0x90 +#define UNI_N_CFG_GART_CTRL 0x94 +#define UNI_N_CFG_INTERNAL_STATUS 0x98 + +/* UNI_N_CFG_GART_CTRL bits definitions */ +#define UNI_N_CFG_GART_INVAL 0x00000001 +#define UNI_N_CFG_GART_ENABLE 0x00000100 +#define UNI_N_CFG_GART_2xRESET 0x00010000 + + +/* + * Uni-N memory mapped reg. definitions + * + * Those registers are Big-Endian !! + * + * Their meaning come from either Darwin and/or from experiments I made with + * the bootrom, I'm not sure about their exact meaning yet + * + */ + +/* Version of the UniNorth chip */ +#define UNI_N_VERSION 0x0000 /* Known versions: 3,7 and 8 */ + +/* This register is used to enable/disable various parts */ +#define UNI_N_CLOCK_CNTL 0x0020 +#define UNI_N_CLOCK_CNTL_PCI 0x00000001 /* guess ? */ +#define UNI_N_CLOCK_CNTL_GMAC 0x00000002 +#define UNI_N_CLOCK_CNTL_FW 0x00000004 /* guess ? */ + +/* Power Management control ? (from Darwin) */ +#define UNI_N_POWER_MGT 0x0030 +#define UNI_N_POWER_MGT_NORMAL 0x00 +#define UNI_N_POWER_MGT_IDLE2 0x01 +#define UNI_N_POWER_MGT_SLEEP 0x02 + +/* This register is configured by Darwin depending on the UniN + * revision + */ +#define UNI_N_ARB_CTRL 0x0040 +#define UNI_N_ARB_CTRL_QACK_DELAY_SHIFT 15 +#define UNI_N_ARB_CTRL_QACK_DELAY_MASK 0x0e1f8000 +#define UNI_N_ARB_CTRL_QACK_DELAY 0x30 +#define UNI_N_ARB_CTRL_QACK_DELAY105 0x00 + +/* This one _might_ return the CPU number of the CPU reading it; + * the bootROM decides wether to boot or to sleep/spinloop depending + * on this register beeing 0 or not + */ +#define UNI_N_CPU_NUMBER 0x0050 + +/* This register appear to be read by the bootROM to decide what + * to do on a non-recoverable reset (powerup or wakeup) + */ +#define UNI_N_HWINIT_STATE 0x0070 +#define UNI_N_HWINIT_STATE_SLEEPING 0x01 +#define UNI_N_HWINIT_STATE_RUNNING 0x02 +/* This last bit appear to be used by the bootROM to know the second + * CPU has started and will enter it's sleep loop with IP=0 + */ +#define UNI_N_HWINIT_STATE_CPU1_FLAG 0x10000000 + + + diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h index 3b884cbb483f..5c432792b381 100644 --- a/include/asm-ppc/unistd.h +++ b/include/asm-ppc/unistd.h @@ -201,10 +201,10 @@ #define __NR_stat64 195 #define __NR_lstat64 196 #define __NR_fstat64 197 -#define __NR_sys_pciconfig_read 198 -#define __NR_sys_pciconfig_write 199 -#define __NR_sys_pciconfig_iobase 200 -#define __NR_multiplexer 201 +#define __NR_pciconfig_read 198 +#define __NR_pciconfig_write 199 +#define __NR_pciconfig_iobase 200 +#define __NR_multiplexer 201 #define __NR_getdents64 202 #define __NR(n) #n diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h index a32ce08feb64..7c9bfa8e9952 100644 --- a/include/asm-sparc/io.h +++ b/include/asm-sparc/io.h @@ -1,5 +1,5 @@ /* - * $Id: io.h,v 1.27 2000/04/13 04:45:59 davem Exp $ + * $Id: io.h,v 1.28 2000/09/17 05:12:00 davem Exp $ */ #ifndef __SPARC_IO_H #define __SPARC_IO_H @@ -164,6 +164,8 @@ static inline void *sbus_memset_io(void *__dst, int c, __kernel_size_t n) return (void *) dst; } +#ifdef __KERNEL__ + /* * Bus number may be embedded in the higher bits of the physical address. * This is why we have no bus number argument to ioremap(). @@ -200,4 +202,6 @@ extern void sbus_iounmap(unsigned long vaddr, unsigned long size); #define dma_cache_wback(_start,_size) do { } while (0) #define dma_cache_wback_inv(_start,_size) do { } while (0) +#endif + #endif /* !(__SPARC_IO_H) */ diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index d829b7c5345b..9e80435f8f99 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.35 2000/04/13 04:45:59 davem Exp $ */ +/* $Id: io.h,v 1.36 2000/09/17 05:12:00 davem Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H @@ -363,6 +363,8 @@ out: return retval; } +#ifdef __KERNEL__ + /* On sparc64 we have the whole physical IO address space accessible * using physically addressed loads and stores, so this does nothing. */ @@ -389,4 +391,6 @@ out: #define dma_cache_wback(_start,_size) do { } while (0) #define dma_cache_wback_inv(_start,_size) do { } while (0) +#endif + #endif /* !(__SPARC64_IO_H) */ diff --git a/include/linux/adb.h b/include/linux/adb.h index 639a6535d327..e2af8f33c122 100644 --- a/include/linux/adb.h +++ b/include/linux/adb.h @@ -58,7 +58,6 @@ struct adb_driver { int (*probe)(void); int (*init)(void); int (*send_request)(struct adb_request *req, int sync); - /*int (*write)(struct adb_request *req);*/ int (*autopoll)(int devs); void (*poll)(void); int (*reset_bus)(void); @@ -83,6 +82,7 @@ int adb_request(struct adb_request *req, void (*done)(struct adb_request *), int flags, int nbytes, ...); int adb_register(int default_id,int handler_id,struct adb_ids *ids, void (*handler)(unsigned char *, int, struct pt_regs *, int)); +int adb_unregister(int index); void adb_poll(void); void adb_input(unsigned char *, int, struct pt_regs *, int); int adb_reset_bus(void); diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index dd88e8a80178..3c37d0538cc2 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -340,7 +340,6 @@ void arcnet_rfc1051_init(void); void arcnet_raw_init(void); int com90xx_probe(struct net_device *dev); -void com20020pci_probe_all(void); #endif /* __KERNEL__ */ diff --git a/include/linux/blk.h b/include/linux/blk.h index 778617529036..66bbdcf606e7 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -308,7 +308,7 @@ static void floppy_off(unsigned int nr); #elif (MAJOR_NR == I2O_MAJOR) #define DEVICE_NAME "I2O block" -#define DEVICE_REQUEST do_i2ob_request +#define DEVICE_REQUEST i2ob_request #define DEVICE_NR(device) (MINOR(device)>>4) #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR) diff --git a/include/linux/cuda.h b/include/linux/cuda.h index 049448cc9654..75549da3fc6a 100644 --- a/include/linux/cuda.h +++ b/include/linux/cuda.h @@ -28,7 +28,8 @@ #ifdef __KERNEL__ -void find_via_cuda(void); +extern int find_via_cuda(void); +extern int via_cuda_start(void); extern int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); extern void cuda_poll(void); diff --git a/include/linux/fs.h b/include/linux/fs.h index a759d8a6ab0b..368bafc85a58 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -93,7 +93,7 @@ extern int max_super_blocks, nr_super_blocks; * as nfs_rename() will be cleaned up */ /* - * These are the fs-independent mount-flags: up to 16 flags are supported + * These are the fs-independent mount-flags: up to 32 flags are supported */ #define MS_RDONLY 1 /* Mount read-only */ #define MS_NOSUID 2 /* Ignore suid and sgid bits */ @@ -104,6 +104,7 @@ extern int max_super_blocks, nr_super_blocks; #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ #define MS_NOATIME 1024 /* Do not update access times. */ #define MS_NODIRATIME 2048 /* Do not update directory access times */ +#define MS_BIND 4096 /* * Flags that can be altered by MS_REMOUNT diff --git a/include/linux/mount.h b/include/linux/mount.h index 8eff1ecc9d2d..a4fc9a05c484 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -27,8 +27,7 @@ struct vfsmount struct list_head mnt_child; /* and going through their mnt_child */ atomic_t mnt_count; int mnt_flags; - - char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ + char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; uid_t mnt_owner; }; diff --git a/include/linux/pci.h b/include/linux/pci.h index 1efa437bb08f..5406f07d66c3 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -553,14 +553,14 @@ const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, co */ #ifndef CONFIG_PCI -extern inline int pcibios_present(void) { return 0; } -extern inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn) +static inline int pcibios_present(void) { return 0; } +static inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn) { return PCIBIOS_DEVICE_NOT_FOUND; } #define _PCI_NOP(o,s,t) \ - extern inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \ + static inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } \ - extern inline int pci_##o##_config_##s## (struct pci_dev *dev, int where, t val) \ + static inline int pci_##o##_config_##s## (struct pci_dev *dev, int where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } #define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \ _PCI_NOP(o,word,u16 x) \ @@ -568,27 +568,27 @@ extern inline int pcibios_find_class (unsigned int class_code, unsigned short in _PCI_NOP_ALL(read, *) _PCI_NOP_ALL(write,) -extern inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) +static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) { return NULL; } -extern inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from) +static inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from) { return NULL; } -extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) +static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) { return NULL; } -extern inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device, +static inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) { return NULL; } -extern inline void pci_set_master(struct pci_dev *dev) { } -extern inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } -extern inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } -extern inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} -extern inline int pci_register_driver(struct pci_driver *drv) { return 0;} -extern inline void pci_unregister_driver(struct pci_driver *drv) { } -extern inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } -extern inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } +static inline void pci_set_master(struct pci_dev *dev) { } +static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } +static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } +static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} +static inline int pci_register_driver(struct pci_driver *drv) { return 0;} +static inline void pci_unregister_driver(struct pci_driver *drv) { } +static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } +static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } #else @@ -598,7 +598,7 @@ extern inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; * * This MUST stay in a header, as it checks for -DMODULE */ -extern inline int pci_module_init(struct pci_driver *drv) +static inline int pci_module_init(struct pci_driver *drv) { int rc = pci_register_driver (drv); @@ -636,6 +636,20 @@ extern inline int pci_module_init(struct pci_driver *drv) (pci_resource_end((dev),(bar)) - \ pci_resource_start((dev),(bar)) + 1)) +/* Similar to the helpers above, these manipulate per-pci_dev + * driver-specific data. Currently stored as pci_dev::driver_data, + * a void pointer, but it is not present on older kernels. + */ +static inline void *pci_get_drvdata (struct pci_dev *pdev) +{ + return pdev->driver_data; +} + +static inline void pci_set_drvdata (struct pci_dev *pdev, void *data) +{ + pdev->driver_data = data; +} + /* * The world is not perfect and supplies us with broken PCI devices. * For at least a part of these bugs we need a work-around, so both diff --git a/include/linux/pmu.h b/include/linux/pmu.h index ad4d12b67731..cd1ac601af84 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -10,6 +10,7 @@ /* * PMU commands */ +#define PMU_POWER_CTRL0 0x10 /* control power of some devices */ #define PMU_POWER_CTRL 0x11 /* control power of some devices */ #define PMU_ADB_CMD 0x20 /* send ADB packet */ #define PMU_ADB_POLL_OFF 0x21 /* disable ADB auto-poll */ @@ -26,15 +27,25 @@ #define PMU_INT_ACK 0x78 /* read interrupt bits */ #define PMU_SHUTDOWN 0x7e /* turn power off */ #define PMU_SLEEP 0x7f /* put CPU to sleep */ +#define PMU_POWER_EVENTS 0x8f /* Send power-event commands to PMU */ #define PMU_RESET 0xd0 /* reset CPU */ #define PMU_GET_BRIGHTBUTTON 0xd9 /* report brightness up/down pos */ #define PMU_GET_COVER 0xdc /* report cover open/closed */ +#define PMU_SYSTEM_READY 0xdf /* tell PMU we are awake */ + +/* Bits to use with the PMU_POWER_CTRL0 command */ +#define PMU_POW0_ON 0x80 /* OR this to power ON the device */ +#define PMU_POW0_OFF 0x00 /* leave bit 7 to 0 to power it OFF */ +#define PMU_POW0_HARD_DRIVE 0x04 /* Hard drive power (on wallstreet/lombard ?) */ /* Bits to use with the PMU_POWER_CTRL command */ #define PMU_POW_ON 0x80 /* OR this to power ON the device */ #define PMU_POW_OFF 0x00 /* leave bit 7 to 0 to power it OFF */ #define PMU_POW_BACKLIGHT 0x01 /* backlight power */ +#define PMU_POW_CHARGER 0x02 /* battery charger power */ #define PMU_POW_IRLED 0x04 /* IR led power (on wallstreet) */ +#define PMU_POW_MEDIABAY 0x08 /* media bay power (wallstreet/lombard ?) */ + /* Bits in PMU interrupt and interrupt mask bytes */ #define PMU_INT_ADB_AUTO 0x04 /* ADB autopoll, when PMU_INT_ADB */ @@ -54,6 +65,25 @@ enum { PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */ }; +/* PMU PMU_POWER_EVENTS commands */ +enum { + PMU_PWR_GET_POWERUP_EVENTS = 0x00, + PMU_PWR_SET_POWERUP_EVENTS = 0x01, + PMU_PWR_CLR_POWERUP_EVENTS = 0x02, + PMU_PWR_GET_WAKEUP_EVENTS = 0x03, + PMU_PWR_SET_WAKEUP_EVENTS = 0x04, + PMU_PWR_CLR_WAKEUP_EVENTS = 0x05, +}; + +/* Power events wakeup bits */ +enum { + PMU_PWR_WAKEUP_KEY = 0x01, /* Wake on key press */ + PMU_PWR_WAKEUP_AC_INSERT = 0x02, /* Wake on AC adapter plug */ + PMU_PWR_WAKEUP_AC_CHANGE = 0x04, + PMU_PWR_WAKEUP_LID_OPEN = 0x08, + PMU_PWR_WAKEUP_RING = 0x10, +}; + /* * Ioctl commands for the /dev/pmu device */ @@ -61,34 +91,38 @@ enum { /* no param */ #define PMU_IOC_SLEEP _IO('B', 0) -/* out param: u32* backlight value: 0 to 31 */ +/* out param: u32* backlight value: 0 to 15 */ #define PMU_IOC_GET_BACKLIGHT _IOR('B', 1, sizeof(__u32*)) -/* in param: u32 backlight value: 0 to 31 */ +/* in param: u32 backlight value: 0 to 15 */ #define PMU_IOC_SET_BACKLIGHT _IOW('B', 2, sizeof(__u32)) -/* out param: u32* backlight value: 0 to 31 */ +/* out param: u32* PMU model */ #define PMU_IOC_GET_MODEL _IOR('B', 3, sizeof(__u32*)) /* out param: u32* has_adb: 0 or 1 */ #define PMU_IOC_HAS_ADB _IOR('B', 4, sizeof(__u32*)) #ifdef __KERNEL__ -int find_via_pmu(void); -int via_pmu_init(void); +extern int find_via_pmu(void); +extern int via_pmu_start(void); -int pmu_request(struct adb_request *req, +extern int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); -void pmu_poll(void); -void pmu_enable_backlight(int on); -void pmu_set_brightness(int level); +extern void pmu_poll(void); + +/* For use before switching interrupts off for a long time; + * warning: not stackable + */ +extern void pmu_suspend(void); +extern void pmu_resume(void); -void pmu_enable_irled(int on); +extern void pmu_enable_irled(int on); -void pmu_restart(void); -void pmu_shutdown(void); +extern void pmu_restart(void); +extern void pmu_shutdown(void); -int pmu_present(void); -int pmu_get_model(void); +extern int pmu_present(void); +extern int pmu_get_model(void); #ifdef CONFIG_PMAC_PBOOK /* @@ -135,4 +169,4 @@ int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* notifier); #endif /* CONFIG_PMAC_PBOOK */ -#endif /* __KERNEL */ +#endif /* __KERNEL__ */ diff --git a/include/linux/raid/md_compatible.h b/include/linux/raid/md_compatible.h index fbeac31a1ad9..1dd42218584f 100644 --- a/include/linux/raid/md_compatible.h +++ b/include/linux/raid/md_compatible.h @@ -77,11 +77,7 @@ extern inline void md_init_signals (void) /* 011 */ #define md_signal_pending signal_pending -/* 012 */ -extern inline void md_set_global_readahead(int * table) -{ - max_readahead[MD_MAJOR] = table; -} +/* 012 - md_set_global_readahead - nowhere used */ /* 013 */ #define md_mdelay(x) mdelay(x) diff --git a/include/linux/signal.h b/include/linux/signal.h index 2da2daa79e13..f2d0766ef7c8 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -28,7 +28,7 @@ struct sigpending { /* We don't use for these because there is no need to be atomic. */ -extern inline void sigaddset(sigset_t *set, int _sig) +static inline void sigaddset(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -37,7 +37,7 @@ extern inline void sigaddset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW); } -extern inline void sigdelset(sigset_t *set, int _sig) +static inline void sigdelset(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -46,7 +46,7 @@ extern inline void sigdelset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW)); } -extern inline int sigismember(sigset_t *set, int _sig) +static inline int sigismember(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -55,7 +55,7 @@ extern inline int sigismember(sigset_t *set, int _sig) return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); } -extern inline int sigfindinword(unsigned long word) +static inline int sigfindinword(unsigned long word) { return ffz(~word); } @@ -68,7 +68,7 @@ extern inline int sigfindinword(unsigned long word) #include #define _SIG_SET_BINOP(name, op) \ -extern inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ +static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ { \ unsigned long a0, a1, a2, a3, b0, b1, b2, b3; \ unsigned long i; \ @@ -119,7 +119,7 @@ _SIG_SET_BINOP(signandsets, _sig_nand) #undef _sig_nand #define _SIG_SET_OP(name, op) \ -extern inline void name(sigset_t *set) \ +static inline void name(sigset_t *set) \ { \ unsigned long i; \ \ @@ -142,7 +142,7 @@ _SIG_SET_OP(signotset, _sig_not) #undef _SIG_SET_OP #undef _sig_not -extern inline void sigemptyset(sigset_t *set) +static inline void sigemptyset(sigset_t *set) { switch (_NSIG_WORDS) { default: @@ -154,7 +154,7 @@ extern inline void sigemptyset(sigset_t *set) } } -extern inline void sigfillset(sigset_t *set) +static inline void sigfillset(sigset_t *set) { switch (_NSIG_WORDS) { default: @@ -170,22 +170,22 @@ extern char * render_sigset_t(sigset_t *set, char *buffer); /* Some extensions for manipulating the low 32 signals in particular. */ -extern inline void sigaddsetmask(sigset_t *set, unsigned long mask) +static inline void sigaddsetmask(sigset_t *set, unsigned long mask) { set->sig[0] |= mask; } -extern inline void sigdelsetmask(sigset_t *set, unsigned long mask) +static inline void sigdelsetmask(sigset_t *set, unsigned long mask) { set->sig[0] &= ~mask; } -extern inline int sigtestsetmask(sigset_t *set, unsigned long mask) +static inline int sigtestsetmask(sigset_t *set, unsigned long mask) { return (set->sig[0] & mask) != 0; } -extern inline void siginitset(sigset_t *set, unsigned long mask) +static inline void siginitset(sigset_t *set, unsigned long mask) { set->sig[0] = mask; switch (_NSIG_WORDS) { @@ -197,7 +197,7 @@ extern inline void siginitset(sigset_t *set, unsigned long mask) } } -extern inline void siginitsetinv(sigset_t *set, unsigned long mask) +static inline void siginitsetinv(sigset_t *set, unsigned long mask) { set->sig[0] = ~mask; switch (_NSIG_WORDS) { diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 91913e545ad2..7c60862c390a 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -522,7 +522,8 @@ enum { DEV_CDROM=1, DEV_HWMON=2, DEV_PARPORT=3, - DEV_RAID=4 + DEV_RAID=4, + DEV_MAC_HID=5 }; /* /proc/sys/dev/cdrom */ @@ -573,6 +574,16 @@ enum { DEV_PARPORT_DEVICE_TIMESLICE=1, }; +/* /proc/sys/dev/mac_hid */ +enum { + DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES=1, + DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES=2, + DEV_MAC_HID_MOUSE_BUTTON_EMULATION=3, + DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE=4, + DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE=5, + DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6 +}; + #ifdef __KERNEL__ extern asmlinkage long sys_sysctl(struct __sysctl_args *); diff --git a/include/linux/usb.h b/include/linux/usb.h index c01871586191..70d0335417fa 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -775,13 +775,13 @@ extern void usbdevfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -extern inline void usbdevfs_add_bus(struct usb_bus *bus) {} -extern inline void usbdevfs_remove_bus(struct usb_bus *bus) {} -extern inline void usbdevfs_add_device(struct usb_device *dev) {} -extern inline void usbdevfs_remove_device(struct usb_device *dev) {} +static inline void usbdevfs_add_bus(struct usb_bus *bus) {} +static inline void usbdevfs_remove_bus(struct usb_bus *bus) {} +static inline void usbdevfs_add_device(struct usb_device *dev) {} +static inline void usbdevfs_remove_device(struct usb_device *dev) {} -extern inline int usbdevfs_init(void) { return 0; } -extern inline void usbdevfs_cleanup(void) { } +static inline int usbdevfs_init(void) { return 0; } +static inline void usbdevfs_cleanup(void) { } #endif /* CONFIG_USB_DEVICEFS */ diff --git a/include/linux/vt_buffer.h b/include/linux/vt_buffer.h index 626b2524d7c2..87561dd4eeba 100644 --- a/include/linux/vt_buffer.h +++ b/include/linux/vt_buffer.h @@ -32,7 +32,7 @@ #endif #ifndef VT_BUF_HAVE_MEMSETW -extern inline void scr_memsetw(u16 *s, u16 c, unsigned int count) +static inline void scr_memsetw(u16 *s, u16 c, unsigned int count) { count /= 2; while (count--) @@ -41,7 +41,7 @@ extern inline void scr_memsetw(u16 *s, u16 c, unsigned int count) #endif #ifndef VT_BUF_HAVE_MEMCPYW -extern inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) { count /= 2; while (count--) @@ -50,7 +50,7 @@ extern inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) #endif #ifndef VT_BUF_HAVE_MEMMOVEW -extern inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) { if (d < s) scr_memcpyw(d, s, count); @@ -65,14 +65,14 @@ extern inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) #endif #ifndef VT_BUF_HAVE_MEMCPYF -extern inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count) { count /= 2; while (count--) *d++ = scr_readw(s++); } -extern inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count) { count /= 2; while (count--) diff --git a/include/linux/wait.h b/include/linux/wait.h index a3687bf53b2a..8629f32412ef 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -158,7 +158,7 @@ static inline int waitqueue_active(wait_queue_head_t *q) return !list_empty(&q->task_list); } -extern inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) +static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { #if WAITQUEUE_DEBUG if (!head || !new) @@ -174,7 +174,7 @@ extern inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) /* * Used for wake-one threads: */ -extern inline void __add_wait_queue_tail(wait_queue_head_t *head, +static inline void __add_wait_queue_tail(wait_queue_head_t *head, wait_queue_t *new) { #if WAITQUEUE_DEBUG @@ -188,7 +188,7 @@ extern inline void __add_wait_queue_tail(wait_queue_head_t *head, list_add_tail(&new->task_list, &head->task_list); } -extern inline void __remove_wait_queue(wait_queue_head_t *head, +static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) { #if WAITQUEUE_DEBUG diff --git a/include/linux/zftape.h b/include/linux/zftape.h index ec5d2ffe0d67..b057c65366c6 100644 --- a/include/linux/zftape.h +++ b/include/linux/zftape.h @@ -56,7 +56,7 @@ struct mtblksz { extern int zft_init(void); -extern inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) +static inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) { if (blk_sz == 1) { return value; @@ -66,7 +66,7 @@ extern inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) } } -extern inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz) +static inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz) { if (blk_sz == 1) { return value; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 6a5b87ee6f44..465b452aefe0 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -87,7 +87,7 @@ extern int ipv6_chk_mcast_addr(struct net_device *dev, extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); -extern __inline__ struct inet6_dev * +static inline struct inet6_dev * __in6_dev_get(struct net_device *dev) { return (struct inet6_dev *)dev->ip6_ptr; @@ -95,7 +95,7 @@ __in6_dev_get(struct net_device *dev) extern rwlock_t addrconf_lock; -extern __inline__ struct inet6_dev * +static inline struct inet6_dev * in6_dev_get(struct net_device *dev) { struct inet6_dev *idev = NULL; @@ -109,7 +109,7 @@ in6_dev_get(struct net_device *dev) extern void in6_dev_finish_destroy(struct inet6_dev *idev); -extern __inline__ void +static inline void in6_dev_put(struct inet6_dev *idev) { if (atomic_dec_and_test(&idev->refcnt)) @@ -122,7 +122,7 @@ in6_dev_put(struct inet6_dev *idev) extern void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); -extern __inline__ void in6_ifa_put(struct inet6_ifaddr *ifp) +static inline void in6_ifa_put(struct inet6_ifaddr *ifp) { if (atomic_dec_and_test(&ifp->refcnt)) inet6_ifa_finish_destroy(ifp); @@ -157,7 +157,7 @@ static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr) * compute link-local solicited-node multicast address */ -extern __inline__ void addrconf_addr_solict_mult_old(struct in6_addr *addr, +static inline void addrconf_addr_solict_mult_old(struct in6_addr *addr, struct in6_addr *solicited) { ipv6_addr_set(solicited, @@ -165,7 +165,7 @@ extern __inline__ void addrconf_addr_solict_mult_old(struct in6_addr *addr, __constant_htonl(0x1), addr->s6_addr32[3]); } -extern __inline__ void addrconf_addr_solict_mult_new(struct in6_addr *addr, +static inline void addrconf_addr_solict_mult_new(struct in6_addr *addr, struct in6_addr *solicited) { ipv6_addr_set(solicited, @@ -175,21 +175,21 @@ extern __inline__ void addrconf_addr_solict_mult_new(struct in6_addr *addr, } -extern __inline__ void ipv6_addr_all_nodes(struct in6_addr *addr) +static inline void ipv6_addr_all_nodes(struct in6_addr *addr) { ipv6_addr_set(addr, __constant_htonl(0xFF020000), 0, 0, __constant_htonl(0x1)); } -extern __inline__ void ipv6_addr_all_routers(struct in6_addr *addr) +static inline void ipv6_addr_all_routers(struct in6_addr *addr) { ipv6_addr_set(addr, __constant_htonl(0xFF020000), 0, 0, __constant_htonl(0x2)); } -extern __inline__ int ipv6_addr_is_multicast(struct in6_addr *addr) +static inline int ipv6_addr_is_multicast(struct in6_addr *addr) { return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000); } diff --git a/include/net/checksum.h b/include/net/checksum.h index 6793f196fb0f..76cf27e77f34 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -93,7 +93,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, #endif #ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER -extern __inline__ +static inline unsigned int csum_and_copy_from_user (const char *src, char *dst, int len, int sum, int *err_ptr) { diff --git a/include/net/dn_route.h b/include/net/dn_route.h index 7c7d3dd0e06a..30ec0d245bc9 100644 --- a/include/net/dn_route.h +++ b/include/net/dn_route.h @@ -91,12 +91,12 @@ extern void dn_route_cleanup(void); #include #include -extern __inline__ void dn_rt_send(struct sk_buff *skb) +static inline void dn_rt_send(struct sk_buff *skb) { dev_queue_xmit(skb); } -extern __inline__ void dn_rt_finish_output(struct sk_buff *skb, char *dst) +static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst) { struct net_device *dev = skb->dev; @@ -110,7 +110,7 @@ extern __inline__ void dn_rt_finish_output(struct sk_buff *skb, char *dst) kfree_skb(skb); } -extern __inline__ void dn_nsp_send(struct sk_buff *skb) +static inline void dn_nsp_send(struct sk_buff *skb) { struct sock *sk = skb->sk; struct dn_scp *scp = &sk->protinfo.dn; diff --git a/include/net/x25.h b/include/net/x25.h index 66575c464a27..fb8346f81981 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -188,7 +188,7 @@ extern struct x25_neigh *x25_get_neigh(struct net_device *); extern void x25_link_free(void); /* x25_out.c */ -extern void x25_output(struct sock *, struct sk_buff *); +extern int x25_output(struct sock *, struct sk_buff *); extern void x25_kick(struct sock *); extern void x25_enquiry_response(struct sock *); diff --git a/kernel/exit.c b/kernel/exit.c index 255446884efa..35114e2a6e27 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -229,6 +229,7 @@ void exit_files(struct task_struct *tsk) { __exit_files(tsk); } + static inline void __put_fs_struct(struct fs_struct *fs) { /* No need to hold fs->lock if we are killing it */ diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 78527a70172f..b8a8e13df58c 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -361,8 +361,6 @@ EXPORT_SYMBOL(remove_wait_queue); #if !defined(CONFIG_ARCH_S390) EXPORT_SYMBOL(probe_irq_on); EXPORT_SYMBOL(probe_irq_off); -EXPORT_SYMBOL(autoirq_setup); -EXPORT_SYMBOL(autoirq_report); #endif #ifdef CONFIG_SMP diff --git a/mm/slab.c b/mm/slab.c index ed5d018f1729..ea1df0f202cb 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1772,14 +1772,6 @@ void kmem_cache_reap (int gfp_mask) /* It's safe to test this without holding the cache-lock. */ if (searchp->flags & SLAB_NO_REAP) goto next; - /* FIXME: is this really a good idea? */ - if (gfp_mask & GFP_DMA) { - if (!(searchp->gfpflags & GFP_DMA)) - goto next; - } else { - if (searchp->gfpflags & GFP_DMA) - goto next; - } spin_lock_irq(&searchp->spinlock); if (searchp->growing) goto next_unlock; diff --git a/mm/swap.c b/mm/swap.c index 8ba1ea995cb6..86ca1843f267 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -161,14 +161,19 @@ void deactivate_page_nolock(struct page * page) * Don't touch it if it's not on the active list. * (some pages aren't on any list at all) */ - if (PageActive(page) && (page_count(page) == 1 || page->buffers) && + if (PageActive(page) && (page_count(page) <= 2 || page->buffers) && !page_ramdisk(page)) { /* * We can move the page to the inactive_dirty list * if we know there is backing store available. + * + * We also move pages here that we cannot free yet, + * but may be able to free later - because most likely + * we're holding an extra reference on the page which + * will be dropped right after deactivate_page(). */ - if (page->buffers) { + if (page->buffers || page_count(page) == 2) { del_page_from_active_list(page); add_page_to_inactive_dirty_list(page); /* @@ -181,8 +186,7 @@ void deactivate_page_nolock(struct page * page) add_page_to_inactive_clean_list(page); } /* - * ELSE: no backing store available, leave it on - * the active list. + * OK, we cannot free the page. Leave it alone. */ } } diff --git a/mm/vmscan.c b/mm/vmscan.c index cf198d415c2c..d562af48531e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -103,8 +103,8 @@ drop_pte: UnlockPage(page); vma->vm_mm->rss--; flush_tlb_page(vma, address); - page_cache_release(page); deactivate_page(page); + page_cache_release(page); goto out_failed; } @@ -572,6 +572,9 @@ int page_launder(int gfp_mask, int sync) maxlaunder = 0; cleaned_pages = 0; + if (!(gfp_mask & __GFP_IO)) + return 0; + dirty_page_rescan: spin_lock(&pagemap_lru_lock); maxscan = nr_inactive_dirty_pages; @@ -681,19 +684,26 @@ dirty_page_rescan: if (freed_page && !free_shortage()) break; continue; + } else if (page->mapping && !PageDirty(page)) { + /* + * If a page had an extra reference in + * deactivate_page(), we will find it here. + * Now the page is really freeable, so we + * move it to the inactive_clean list. + */ + UnlockPage(page); + del_page_from_inactive_dirty_list(page); + add_page_to_inactive_clean_list(page); + cleaned_pages++; } else { /* - * Somebody else freed the bufferheads for us? - * This really shouldn't happen, but we check - * for it anyway. + * OK, we don't know what to do with the page. + * It's no use keeping it here, so we move it to + * the active list. */ - printk("VM: page_launder, found pre-cleaned page ?!\n"); UnlockPage(page); - if (page->mapping && !PageDirty(page)) { - del_page_from_inactive_dirty_list(page); - add_page_to_inactive_clean_list(page); - cleaned_pages++; - } + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); } } spin_unlock(&pagemap_lru_lock); @@ -717,8 +727,6 @@ dirty_page_rescan: maxlaunder = MAX_LAUNDER; /* Kflushd takes care of the rest. */ wakeup_bdflush(0); - current->policy |= SCHED_YIELD; - schedule(); goto dirty_page_rescan; } @@ -738,7 +746,7 @@ int refill_inactive_scan(unsigned int priority, int oneshot) { struct list_head * page_lru; struct page * page; - int maxscan; + int maxscan, page_active = 0; int ret = 0; /* Take the lock while messing with the list... */ @@ -758,17 +766,17 @@ int refill_inactive_scan(unsigned int priority, int oneshot) /* Do aging on the pages. */ if (PageTestandClearReferenced(page)) { age_page_up_nolock(page); - goto must_be_active; + page_active = 1; } else { age_page_down_nolock(page); + page_active = 0; } /* * If the page is still on the active list, move it * to the other end of the list. Otherwise it was * deactivated by age_page_down and we exit successfully. */ - if (PageActive(page)) { -must_be_active: + if (page_active || PageActive(page)) { list_del(page_lru); list_add(page_lru, &active_list); } else { @@ -865,10 +873,8 @@ static int refill_inactive(unsigned int gfp_mask, int user) do { made_progress = 0; - if (!inactive_shortage() && !free_shortage()) - goto done; - if (current->need_resched) { + __set_current_state(TASK_RUNNING); schedule(); } @@ -913,6 +919,14 @@ static int refill_inactive(unsigned int gfp_mask, int user) goto done; } + /* + * If we either have enough free memory, or if + * page_launder() will be able to make enough + * free memory, then stop. + */ + if (!inactive_shortage() || !free_shortage()) + goto done; + /* * Only switch to a lower "priority" if we * didn't make any useful progress in the @@ -958,10 +972,14 @@ static int do_try_to_free_pages(unsigned int gfp_mask, int user) * the inode and dentry cache whenever we do this. */ if (free_shortage() || inactive_shortage()) { - ret += shrink_dcache_memory(6, gfp_mask); - ret += shrink_icache_memory(6, gfp_mask); + if (gfp_mask & __GFP_IO) { + ret += shrink_dcache_memory(6, gfp_mask); + ret += shrink_icache_memory(6, gfp_mask); + } ret += refill_inactive(gfp_mask, user); + } else { + ret = 1; } return ret; @@ -1059,8 +1077,7 @@ int kswapd(void *unused) * We go to sleep for one second, but if it's needed * we'll be woken up earlier... */ - if (!free_shortage() || - inactive_shortage() <= inactive_target / 3) + if (!free_shortage() || !inactive_shortage()) interruptible_sleep_on_timeout(&kswapd_wait, HZ); } } @@ -1073,7 +1090,8 @@ void wakeup_kswapd(int block) return; if (!block) { - wake_up(&kswapd_wait); + if (waitqueue_active(&kswapd_wait)) + wake_up(&kswapd_wait); return; } @@ -1110,12 +1128,13 @@ void wakeup_kswapd(int block) */ int try_to_free_pages(unsigned int gfp_mask) { + int ret = 1; + if (gfp_mask & __GFP_WAIT) { - balance_dirty(NODEV); - wakeup_kswapd(1); + ret = do_try_to_free_pages(gfp_mask, 1); } - return 1; + return ret; } DECLARE_WAIT_QUEUE_HEAD(kreclaimd_wait); diff --git a/net/core/sock.c b/net/core/sock.c index 32c757e30d98..5df425ae1c05 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.98 2000/08/16 16:09:15 davem Exp $ + * Version: $Id: sock.c,v 1.99 2000/09/16 07:33:53 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 6e80ed9120e7..337f40890eec 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.112 2000/08/16 16:20:56 davem Exp $ + * Version: $Id: af_inet.c,v 1.113 2000/09/11 23:35:29 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -390,7 +390,6 @@ static int inet_create(struct socket *sock, int protocol) if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - sk->dead = 1; inet_sock_release(sk); return(err); } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4287c7525410..a82e4be1fbc1 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.51 2000/08/09 11:59:04 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.52 2000/09/09 08:26:04 davem Exp $ * * Authors: see ip.c * @@ -380,31 +380,39 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt { int val=0,err; - if(optlen>=sizeof(int)) { - if(get_user(val, (int *) optval)) - return -EFAULT; - } else if(optlen>=sizeof(char)) { - unsigned char ucval; - if(get_user(ucval, (unsigned char *) optval)) - return -EFAULT; - val = (int)ucval; + if (optname == IP_PKTINFO || optname == IP_RECVTTL || + optname == IP_RECVTOS || optname == IP_RECVOPTS || + optname == IP_RETOPTS || optname == IP_TOS || + optname == IP_TTL || optname == IP_HDRINCL || + optname == IP_MTU_DISCOVER || optname == IP_RECVERR || + optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP || + optname == IP_ROUTER_ALERT) { + if (optlen >= sizeof(int)) { + if (get_user(val, (int *) optval)) + return -EFAULT; + } else if (optlen >= sizeof(char)) { + unsigned char ucval; + + if (get_user(ucval, (unsigned char *) optval)) + return -EFAULT; + val = (int) ucval; + } } + /* If optlen==0, it is equivalent to val == 0 */ - if(level!=SOL_IP) + if (level != SOL_IP) return -ENOPROTOOPT; + #ifdef CONFIG_IP_MROUTE - if(optname>=MRT_BASE && optname <=MRT_BASE+10) - { + if (optname >= MRT_BASE && optname <= (MRT_BASE + 10)) return ip_mroute_setsockopt(sk,optname,optval,optlen); - } #endif err = 0; lock_sock(sk); - switch(optname) - { + switch (optname) { case IP_OPTIONS: { struct ip_options * opt = NULL; diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c index c3d8ccab0848..54f89f7651f1 100644 --- a/net/ipv4/netfilter/ip_nat_ftp.c +++ b/net/ipv4/netfilter/ip_nat_ftp.c @@ -372,8 +372,9 @@ static unsigned int help(struct ip_conntrack *ct, newseq = ntohl(tcph->seq) + ftp[dir].syn_offset_before; newseq = htonl(newseq); - /* Ack adjust */ - if (after(ntohl(tcph->ack_seq), ftp[!dir].syn_correction_pos)) + /* Ack adjust: other dir sees offset seq numbers */ + if (after(ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_before, + ftp[!dir].syn_correction_pos)) newack = ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_after; else newack = ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_before; diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index c6de039e638f..10d09a6bd8e7 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -7,6 +7,7 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General Public Licence. */ +#include #include #include #include diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index f58cd8b331e5..c52ada64e606 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -3,6 +3,7 @@ * * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling */ +#include #include #include #include diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 187fbbc3b0f1..d9f05c671f91 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.45 2000/09/06 23:30:29 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.46 2000/09/16 09:38:30 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -15,19 +15,6 @@ #include #include -/* - * TCP configuration parameters - */ - -#define TCP_PMTU_DISC 0x00000001 /* perform PMTU discovery */ -#define TCP_CONG_AVOID 0x00000002 /* congestion avoidance algorithm */ -#define TCP_DELAY_ACKS 0x00000003 /* delayed ack stategy */ - -#if 0 -static int boolean_min = 0; -static int boolean_max = 1; -#endif - /* From icmp.c */ extern int sysctl_icmp_echo_ignore_all; extern int sysctl_icmp_echo_ignore_broadcasts; @@ -57,7 +44,10 @@ extern int inet_peer_maxttl; extern int inet_peer_gc_mintime; extern int inet_peer_gc_maxtime; -int tcp_retr1_max = 255; +static int tcp_retr1_max = 255; + +static int ip_local_port_range_min[] = { 1, 1 }; +static int ip_local_port_range_max[] = { 65535, 65535 }; struct ipv4_config ipv4_config; @@ -170,7 +160,8 @@ ctl_table ipv4_table[] = { sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_LOCAL_PORT_RANGE, "ip_local_port_range", &sysctl_local_port_range, sizeof(sysctl_local_port_range), 0644, - NULL, &proc_dointvec}, + NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, + ip_local_port_range_min, ip_local_port_range_max }, {NET_IPV4_ICMP_ECHO_IGNORE_ALL, "icmp_echo_ignore_all", &sysctl_icmp_echo_ignore_all, sizeof(int), 0644, NULL, &proc_dointvec}, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ff40ffbf852f..3a01e4fac691 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.199 2000/09/06 23:30:29 davem Exp $ + * Version: $Id: tcp_input.c,v 1.200 2000/09/16 16:39:16 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -58,6 +58,7 @@ * J Hadi Salim: ECN support */ +#include #include #include #include @@ -1952,7 +1953,7 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_opt *tp) if (opsize < 2) /* "silly options" */ return; if (opsize > length) - break; /* don't parse partial options */ + return; /* don't parse partial options */ switch(opcode) { case TCPOPT_MSS: if(opsize==TCPOLEN_MSS && th->syn) { diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 8b039a658dc7..c5c1103776e2 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -7,10 +7,11 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.56 2000/04/25 04:13:34 davem Exp $ + * $Id: af_inet6.c,v 1.57 2000/09/11 23:35:29 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support + * Arnaldo Melo : check proc_net_create return, cleanups * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -189,7 +190,7 @@ static int inet6_create(struct socket *sock, int protocol) if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - sk->dead = 1; + MOD_DEC_USE_COUNT; inet_sock_release(sk); return(err); } @@ -395,10 +396,8 @@ static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { case FIOSETOWN: case SIOCSPGRP: - err = get_user(pid, (int *) arg); - if(err) - return err; - + if (get_user(pid, (int *) arg)) + return -EFAULT; /* see sock_no_fcntl */ if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN)) @@ -407,10 +406,7 @@ static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return(0); case FIOGETOWN: case SIOCGPGRP: - err = put_user(sk->proc,(int *)arg); - if(err) - return err; - return(0); + return put_user(sk->proc,(int *)arg); case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; @@ -550,6 +546,20 @@ void __init inet6_proto_init(struct net_proto *pro) err = igmp6_init(&inet6_family_ops); if (err) goto igmp_fail; + /* Create /proc/foo6 entries. */ +#ifdef CONFIG_PROC_FS + err = -ENOMEM; + if (!proc_net_create("raw6", 0, raw6_get_info)) + goto proc_raw6_fail; + if (!proc_net_create("tcp6", 0, tcp6_get_info)) + goto proc_tcp6_fail; + if (!proc_net_create("udp6", 0, udp6_get_info)) + goto proc_udp6_fail; + if (!proc_net_create("sockstat6", 0, afinet6_get_info)) + goto proc_sockstat6_fail; + if (!proc_net_create("snmp6", 0, afinet6_get_snmp)) + goto proc_snmp6_fail; +#endif ipv6_netdev_notif_init(); ipv6_packet_init(); ip6_route_init(); @@ -561,15 +571,6 @@ void __init inet6_proto_init(struct net_proto *pro) udpv6_init(); tcpv6_init(); - /* Create /proc/foo6 entries. */ -#ifdef CONFIG_PROC_FS - proc_net_create("raw6", 0, raw6_get_info); - proc_net_create("tcp6", 0, tcp6_get_info); - proc_net_create("udp6", 0, udp6_get_info); - proc_net_create("sockstat6", 0, afinet6_get_info); - proc_net_create("snmp6", 0, afinet6_get_snmp); -#endif - /* Now the userspace is allowed to create INET6 sockets. */ (void) sock_register(&inet6_family_ops); @@ -579,6 +580,18 @@ void __init inet6_proto_init(struct net_proto *pro) return; #endif +#ifdef CONFIG_PROC_FS +proc_snmp6_fail: + proc_net_remove("sockstat6"); +proc_sockstat6_fail: + proc_net_remove("udp6"); +proc_udp6_fail: + proc_net_remove("tcp6"); +proc_tcp6_fail: + proc_net_remove("raw6"); +proc_raw6_fail: + igmp6_cleanup(); +#endif igmp_fail: ndisc_cleanup(); ndisc_fail: diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 3edc09a64521..49fc32f59961 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fib.c,v 1.21 2000/05/03 06:37:07 davem Exp $ + * $Id: ip6_fib.c,v 1.22 2000/09/12 00:38:34 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -638,10 +638,8 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, if (narg->addr) { st = fib6_lookup_1(fn->subtree, narg); - if (!(st->fn_flags & RTN_ROOT)) - { + if (st && !(st->fn_flags & RTN_ROOT)) return st; - } } } #endif diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 79880595d7e9..9af3a0e3d595 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -21,6 +21,8 @@ * facilities negotiation and increased * the throughput upper limit. * 2000-27-08 Arnaldo C. Melo s/suser/capable/ + micro cleanups + * 2000-04-09 Henner Eisen Set sock->state in x25_accept(). + * Fixed x25_output() related skb leakage. */ #include @@ -721,6 +723,7 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; + newsock->state = SS_CONNECTED; return 0; } @@ -971,7 +974,11 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct if (msg->msg_flags & MSG_OOB) { skb_queue_tail(&sk->protinfo.x25->interrupt_out_queue, skb); } else { - x25_output(sk, skb); + err = x25_output(sk, skb); + if(err){ + len = err; + kfree_skb(skb); + } } x25_kick(sk); diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index 1808361a66c5..d986022fbd9c 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -14,6 +14,7 @@ * * History * X.25 001 Jonathan Naylor Started coding. + * 2000-09-04 Henner Eisen Prevent freeing a dangling skb. */ #include @@ -78,12 +79,13 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh) return x25_rx_call_request(skb, neigh, lci); /* - * Its not a Call Request, nor is it a control frame, throw it awa + * Its not a Call Request, nor is it a control frame. + * Let caller throw it away. */ /* x25_transmit_clear_request(neigh, lci, 0x0D); */ - kfree_skb(skb); + printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype); return 0; } diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c index 34d065b833b3..d6b878371127 100644 --- a/net/x25/x25_link.c +++ b/net/x25/x25_link.c @@ -17,6 +17,7 @@ * X.25 002 Jonathan Naylor New timer architecture. * mar/20/00 Daniela Squassoni Disabling/enabling of facilities * negotiation. + * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh. */ #include @@ -292,6 +293,7 @@ void x25_link_device_up(struct net_device *dev) init_timer(&x25_neigh->t20timer); + dev_hold(dev); x25_neigh->dev = dev; x25_neigh->state = X25_LINK_STATE_0; x25_neigh->extended = 0; @@ -349,8 +351,10 @@ void x25_link_device_down(struct net_device *dev) neigh = x25_neigh; x25_neigh = x25_neigh->next; - if (neigh->dev == dev) + if (neigh->dev == dev){ x25_remove_neigh(neigh); + dev_put(dev); + } } } diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c index 24fdf4d47917..077f2c0b4212 100644 --- a/net/x25/x25_out.c +++ b/net/x25/x25_out.c @@ -15,6 +15,7 @@ * History * X.25 001 Jonathan Naylor Started coding. * X.25 002 Jonathan Naylor New timer architecture. + * 2000-09-04 Henner Eisen Prevented x25_output() skb leakage. */ #include @@ -56,7 +57,7 @@ static int x25_pacsize_to_bytes(unsigned int pacsize) /* * This is where all X.25 information frames pass; */ -void x25_output(struct sock *sk, struct sk_buff *skb) +int x25_output(struct sock *sk, struct sk_buff *skb) { struct sk_buff *skbn; unsigned char header[X25_EXT_MIN_LEN]; @@ -73,9 +74,12 @@ void x25_output(struct sock *sk, struct sk_buff *skb) frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL) - return; - + if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL){ + int unsent = skb->len - header_len; + SOCK_DEBUG(sk, "x25_output: framgent allocation failed, err=%d, %d bytes unsent\n", err, unsent); + return err; + } + skb_reserve(skbn, frontlen); len = (max_len > skb->len) ? skb->len : max_len; @@ -102,6 +106,7 @@ void x25_output(struct sock *sk, struct sk_buff *skb) } else { skb_queue_tail(&sk->write_queue, skb); } + return 0; } /* diff --git a/scripts/ver_linux b/scripts/ver_linux index 20ebfd3902b8..4682d0c7eb50 100644 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -10,6 +10,8 @@ echo '-- unusual then possibly you have very old versions)' uname -a insmod -V 2>&1 | awk 'NR==1 {print "Kernel modules ",$NF}' echo "Gnu C " `gcc --version` +make --version 2>&1 | awk -F, '{print $1}' | awk \ + '/GNU Make/{print "Gnu Make ",$NF}' ld -v 2>&1 | awk -F\) '{print $1}' | awk \ '/BFD/{print "Binutils ",$NF}' ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed -e 's/\.so$//' \ -- 2.39.5