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
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).
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.
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
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 <http://www.maconlinux.org> 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
- 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
--- /dev/null
+Linux Kernel Makefiles
+16 August 2000
+Michael Elizabeth Chastain, <chastain@redhat.com>
+
+
+
+=== 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.
And thanks to every supporter free software.
+(see top of 8139too.c for further credits and kudos)
+
Submitting Bug Reports
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)
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
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
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)
/*
* See http://www.geocities.com/SiliconValley/Hardware/3165/
* for the user-level ACPI stuff
+ *
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/08/31
+ * - check copy*user return
+ * - get rid of check_region
+ * - get rid of verify_area
*/
#include <linux/config.h>
*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)
*/
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;
}
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
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)
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;
}
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);
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);
}
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
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)
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;
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
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
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;
* 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;
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);
}
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);
}
/* 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
* 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];
/* 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.
--- /dev/null
+/*
+ * Fast Ethernet Controller (FCC) driver for Motorola MPC8260.
+ * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
+ *
+ * This version of the driver is a combination of the 8xx fec and
+ * 8260 SCC Ethernet drivers. People seem to be choosing common I/O
+ * configurations, so this driver will work on the EST8260 boards and
+ * others yet to be announced.
+ *
+ * Right now, I am very watseful with the buffers. I allocate memory
+ * pages and then divide them into 2K frame buffers. This way I know I
+ * have buffers large enough to hold one frame within one buffer descriptor.
+ * Once I get this working, I will use 64 or 128 byte CPM buffers, which
+ * will be much more memory efficient and will easily handle lots of
+ * small packets.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+#include <asm/immap_8260.h>
+#include <asm/pgtable.h>
+#include <asm/mpc8260.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/cpm_8260.h>
+
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT (2*HZ)
+
+/* The number of Tx and Rx buffers. These are allocated from the page
+ * pool. The code may assume these are power of two, so it it best
+ * to keep them that size.
+ * We don't need to allocate pages for the transmitter. We just use
+ * the skbuffer directly.
+ */
+#define FCC_ENET_RX_PAGES 16
+#define FCC_ENET_RX_FRSIZE 2048
+#define FCC_ENET_RX_FRPPG (PAGE_SIZE / FCC_ENET_RX_FRSIZE)
+#define RX_RING_SIZE (FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES)
+#define TX_RING_SIZE 16 /* Must be power of two */
+#define TX_RING_MOD_MASK 15 /* for this to work */
+
+/* The FCC stores dest/src/type, data, and checksum for receive packets.
+ */
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+
+/* Maximum input DMA size. Must be a should(?) be a multiple of 4.
+*/
+#define PKT_MAXDMA_SIZE 1520
+
+/* Maximum input buffer size. Must be a multiple of 32.
+*/
+#define PKT_MAXBLR_SIZE 1536
+
+static int fcc_enet_open(struct net_device *dev);
+static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int fcc_enet_rx(struct net_device *dev);
+static void fcc_enet_mii(struct net_device *dev);
+static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static int fcc_enet_close(struct net_device *dev);
+static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void restart_fcc(struct net_device *dev);
+
+/* These will be configurable for the FCC choice.
+ * Multiple ports can be configured. There is little choice among the
+ * I/O pins to the PHY, except the clocks. We will need some board
+ * dependent clock selection.
+ * Why in the hell did I put these inside #ifdef's? I dunno, maybe to
+ * help show what pins are used for each device.
+ */
+
+/* I/O Pin assignment for FCC1. I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PA1_COL ((uint)0x00000001)
+#define PA1_CRS ((uint)0x00000002)
+#define PA1_TXER ((uint)0x00000004)
+#define PA1_TXEN ((uint)0x00000008)
+#define PA1_RXDV ((uint)0x00000010)
+#define PA1_RXER ((uint)0x00000020)
+#define PA1_TXDAT ((uint)0x00003c00)
+#define PA1_RXDAT ((uint)0x0003c000)
+#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT)
+#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \
+ PA1_RXDV | PA1_RXER)
+#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
+#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER)
+
+/* CLK12 is receive, CLK11 is transmit. These are board specific.
+*/
+#define PC_F1RXCLK ((uint)0x00000800)
+#define PC_F1TXCLK ((uint)0x00000400)
+#define CMX1_CLK_ROUTE ((uint)0x3e000000)
+#define CMX1_CLK_MASK ((uint)0xff000000)
+
+/* I/O Pin assignment for FCC2. I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB2_TXER ((uint)0x00000001)
+#define PB2_RXDV ((uint)0x00000002)
+#define PB2_TXEN ((uint)0x00000004)
+#define PB2_RXER ((uint)0x00000008)
+#define PB2_COL ((uint)0x00000010)
+#define PB2_CRS ((uint)0x00000020)
+#define PB2_TXDAT ((uint)0x000003c0)
+#define PB2_RXDAT ((uint)0x00003c00)
+#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \
+ PB2_RXER | PB2_RXDV | PB2_TXER)
+#define PB2_PSORB1 (PB2_TXEN)
+#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV)
+#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER)
+
+/* CLK13 is receive, CLK14 is transmit. These are board dependent.
+*/
+#define PC_F2RXCLK ((uint)0x00001000)
+#define PC_F2TXCLK ((uint)0x00002000)
+#define CMX2_CLK_ROUTE ((uint)0x00250000)
+#define CMX2_CLK_MASK ((uint)0x00ff0000)
+
+/* I/O Pin assignment for FCC3. I don't yet know the best way to do this,
+ * but there is little variation among the choices.
+ */
+#define PB3_RXDV ((uint)0x00004000)
+#define PB3_RXER ((uint)0x00008000)
+#define PB3_TXER ((uint)0x00010000)
+#define PB3_TXEN ((uint)0x00020000)
+#define PB3_COL ((uint)0x00040000)
+#define PB3_CRS ((uint)0x00080000)
+#define PB3_TXDAT ((uint)0x0f000000)
+#define PB3_RXDAT ((uint)0x00f00000)
+#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \
+ PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN)
+#define PB3_PSORB1 (0)
+#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV)
+#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER)
+
+/* CLK15 is receive, CLK16 is transmit. These are board dependent.
+*/
+#define PC_F3RXCLK ((uint)0x00004000)
+#define PC_F3TXCLK ((uint)0x00008000)
+#define CMX3_CLK_ROUTE ((uint)0x00003700)
+#define CMX3_CLK_MASK ((uint)0x0000ff00)
+
+/* MII status/control serial interface.
+*/
+#define PC_MDIO ((uint)0x00400000)
+#define PC_MDCK ((uint)0x00200000)
+
+/* A table of information for supporting FCCs. This does two things.
+ * First, we know how many FCCs we have and they are always externally
+ * numbered from zero. Second, it holds control register and I/O
+ * information that could be different among board designs.
+ */
+typedef struct fcc_info {
+ uint fc_fccnum;
+ uint fc_cpmblock;
+ uint fc_cpmpage;
+ uint fc_proff;
+ uint fc_interrupt;
+ uint fc_trxclocks;
+ uint fc_clockroute;
+ uint fc_clockmask;
+ uint fc_mdio;
+ uint fc_mdck;
+} fcc_info_t;
+
+static fcc_info_t fcc_ports[] = {
+#ifdef CONFIG_FCC1_ENET
+ { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1,
+ (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK,
+ PC_MDIO, PC_MDCK },
+#endif
+#ifdef CONFIG_FCC2_ENET
+ { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2,
+ (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK,
+ PC_MDIO, PC_MDCK },
+#endif
+#ifdef CONFIG_FCC3_ENET
+ { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3,
+ (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK,
+ PC_MDIO, PC_MDCK },
+#endif
+};
+
+/* The FCC buffer descriptors track the ring buffers. The rx_bd_base and
+ * tx_bd_base always point to the base of the buffer descriptors. The
+ * cur_rx and cur_tx point to the currently available buffer.
+ * The dirty_tx tracks the current buffer that is being sent by the
+ * controller. The cur_tx and dirty_tx are equal under both completely
+ * empty and completely full conditions. The empty/ready indicator in
+ * the buffer descriptor determines the actual condition.
+ */
+struct fcc_enet_private {
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ ushort skb_cur;
+ ushort skb_dirty;
+
+ /* CPM dual port RAM relative addresses.
+ */
+ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */
+ cbd_t *tx_bd_base;
+ cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
+ cbd_t *dirty_tx; /* The ring entries to be free()ed. */
+ volatile fcc_t *fccp;
+ volatile fcc_enet_t *ep;
+ struct net_device_stats stats;
+ uint tx_full;
+ spinlock_t lock;
+ uint phy_address;
+ uint phy_type;
+ uint phy_duplex;
+ fcc_info_t *fip;
+};
+
+static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
+ volatile immap_t *immap);
+static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev);
+static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
+ volatile immap_t *immap);
+static void init_fcc_param(fcc_info_t *fip, struct net_device *dev,
+ volatile immap_t *immap);
+
+/* MII processing. We keep this as simple as possible. Requests are
+ * placed on the list (if there is room). When the request is finished
+ * by the MII, an optional function may be called.
+ */
+typedef struct mii_list {
+ uint mii_regval;
+ void (*mii_func)(uint val, struct net_device *dev);
+ struct mii_list *mii_next;
+} mii_list_t;
+
+#define NMII 20
+mii_list_t mii_cmds[NMII];
+mii_list_t *mii_free;
+mii_list_t *mii_head;
+mii_list_t *mii_tail;
+
+static int phyaddr;
+static uint phytype;
+
+static int mii_queue(int request, void (*func)(uint, struct net_device *));
+static void mii_startup_cmds(void);
+static uint mii_send_receive(fcc_info_t *fip, uint cmd);
+
+/* Make MII read/write commands for the FCC.
+*/
+
+#define mk_mii_phyaddr(ADDR) (0x60020000 | ((ADDR) << 23) | (2 << 18))
+
+#define mk_mii_read(REG) (0x60020000 | ((phyaddr << 23) | \
+ (REG & 0x1f) << 18))
+
+#define mk_mii_write(REG, VAL) (0x50020000 | ((phyaddr << 23) | \
+ (REG & 0x1f) << 18) | \
+ (VAL & 0xffff))
+
+
+static int
+fcc_enet_open(struct net_device *dev)
+{
+ netif_start_queue(dev);
+ return 0; /* Always succeed */
+}
+
+static int
+fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;
+ volatile cbd_t *bdp;
+
+
+ /* Fill in a Tx ring entry */
+ bdp = cep->cur_tx;
+
+#ifndef final_version
+ if (bdp->cbd_sc & BD_ENET_TX_READY) {
+ /* Ooops. All transmit buffers are full. Bail out.
+ * This should not happen, since cep->tx_full should be set.
+ */
+ printk("%s: tx queue full!.\n", dev->name);
+ return 1;
+ }
+#endif
+
+ /* Clear all of the status flags.
+ */
+ bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+
+ /* If the frame is short, tell CPM to pad it.
+ */
+ if (skb->len <= ETH_ZLEN)
+ bdp->cbd_sc |= BD_ENET_TX_PAD;
+ else
+ bdp->cbd_sc &= ~BD_ENET_TX_PAD;
+
+ /* Set buffer length and buffer pointer.
+ */
+ bdp->cbd_datlen = skb->len;
+ bdp->cbd_bufaddr = __pa(skb->data);
+
+ /* Save skb pointer.
+ */
+ cep->tx_skbuff[cep->skb_cur] = skb;
+
+ cep->stats.tx_bytes += skb->len;
+ cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
+
+ spin_lock_irq(&cep->lock);
+
+ /* Send it on its way. Tell CPM its ready, interrupt when done,
+ * its the last BD of the frame, and to put the CRC on the end.
+ */
+ bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+
+#if 0
+ /* Errata says don't do this.
+ */
+ cep->fccp->fcc_ftodr = 0x8000;
+#endif
+ dev->trans_start = jiffies;
+
+ /* If this was the last BD in the ring, start at the beginning again.
+ */
+ if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+ bdp = cep->tx_bd_base;
+ else
+ bdp++;
+
+ if (bdp->cbd_sc & BD_ENET_TX_READY) {
+ netif_stop_queue(dev);
+ cep->tx_full = 1;
+ }
+
+ cep->cur_tx = (cbd_t *)bdp;
+
+ spin_unlock_irq(&cep->lock);
+
+ return 0;
+}
+
+
+static void
+fcc_enet_timeout(struct net_device *dev)
+{
+ struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;
+
+ printk("%s: transmit timed out.\n", dev->name);
+ cep->stats.tx_errors++;
+#ifndef final_version
+ {
+ int i;
+ cbd_t *bdp;
+ printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
+ cep->cur_tx, cep->tx_full ? " (full)" : "",
+ cep->cur_rx);
+ bdp = cep->tx_bd_base;
+ printk(" Tx @base %p :\n", bdp);
+ for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
+ printk("%04x %04x %08x\n",
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ bdp->cbd_bufaddr);
+ bdp = cep->rx_bd_base;
+ printk(" Rx @base %p :\n", bdp);
+ for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
+ printk("%04x %04x %08x\n",
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ bdp->cbd_bufaddr);
+ }
+#endif
+ if (!cep->tx_full)
+ netif_wake_queue(dev);
+}
+
+/* The interrupt handler.
+ */
+static void
+fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = dev_id;
+ volatile struct fcc_enet_private *cep;
+ volatile cbd_t *bdp;
+ ushort int_events;
+ int must_restart;
+
+ cep = (struct fcc_enet_private *)dev->priv;
+
+ /* Get the interrupt events that caused us to be here.
+ */
+ int_events = cep->fccp->fcc_fcce;
+ cep->fccp->fcc_fcce = int_events;
+ must_restart = 0;
+
+ /* Handle receive event in its own function.
+ */
+ if (int_events & FCC_ENET_RXF)
+ fcc_enet_rx(dev_id);
+
+ /* Check for a transmit error. The manual is a little unclear
+ * about this, so the debug code until I get it figured out. It
+ * appears that if TXE is set, then TXB is not set. However,
+ * if carrier sense is lost during frame transmission, the TXE
+ * bit is set, "and continues the buffer transmission normally."
+ * I don't know if "normally" implies TXB is set when the buffer
+ * descriptor is closed.....trial and error :-).
+ */
+
+ /* Transmit OK, or non-fatal error. Update the buffer descriptors.
+ */
+ if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) {
+ spin_lock(&cep->lock);
+ bdp = cep->dirty_tx;
+ while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
+ if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
+ break;
+
+ if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */
+ cep->stats.tx_heartbeat_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */
+ cep->stats.tx_window_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */
+ cep->stats.tx_aborted_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */
+ cep->stats.tx_fifo_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+ cep->stats.tx_carrier_errors++;
+
+
+ /* No heartbeat or Lost carrier are not really bad errors.
+ * The others require a restart transmit command.
+ */
+ if (bdp->cbd_sc &
+ (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {
+ must_restart = 1;
+ cep->stats.tx_errors++;
+ }
+
+ cep->stats.tx_packets++;
+
+ /* Deferred means some collisions occurred during transmit,
+ * but we eventually sent the packet OK.
+ */
+ if (bdp->cbd_sc & BD_ENET_TX_DEF)
+ cep->stats.collisions++;
+
+ /* Free the sk buffer associated with this last transmit.
+ */
+ dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
+ cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+ /* Update pointer to next buffer descriptor to be transmitted.
+ */
+ if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+ bdp = cep->tx_bd_base;
+ else
+ bdp++;
+
+ /* I don't know if we can be held off from processing these
+ * interrupts for more than one frame time. I really hope
+ * not. In such a case, we would now want to check the
+ * currently available BD (cur_tx) and determine if any
+ * buffers between the dirty_tx and cur_tx have also been
+ * sent. We would want to process anything in between that
+ * does not have BD_ENET_TX_READY set.
+ */
+
+ /* Since we have freed up a buffer, the ring is no longer
+ * full.
+ */
+ if (cep->tx_full) {
+ cep->tx_full = 0;
+ if (netif_queue_stopped(dev)) {
+ netif_wake_queue(dev);
+ }
+ }
+
+ cep->dirty_tx = (cbd_t *)bdp;
+ }
+
+ if (must_restart) {
+ volatile cpm8260_t *cp;
+
+ /* Some transmit errors cause the transmitter to shut
+ * down. We now issue a restart transmit. Since the
+ * errors close the BD and update the pointers, the restart
+ * _should_ pick up without having to reset any of our
+ * pointers either.
+ */
+
+ cp = cpmp;
+ cp->cp_cpcr =
+ mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock,
+ 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+ }
+ spin_unlock(&cep->lock);
+ }
+
+ /* Check for receive busy, i.e. packets coming but no place to
+ * put them.
+ */
+ if (int_events & FCC_ENET_BSY) {
+ cep->stats.rx_dropped++;
+ }
+ return;
+}
+
+/* During a receive, the cur_rx points to the current incoming buffer.
+ * When we update through the ring, if the next incoming buffer has
+ * not been given to the system, we just set the empty indicator,
+ * effectively tossing the packet.
+ */
+static int
+fcc_enet_rx(struct net_device *dev)
+{
+ struct fcc_enet_private *cep;
+ volatile cbd_t *bdp;
+ struct sk_buff *skb;
+ ushort pkt_len;
+
+ cep = (struct fcc_enet_private *)dev->priv;
+
+ /* First, grab all of the stats for the incoming packet.
+ * These get messed up if we get called due to a busy condition.
+ */
+ bdp = cep->cur_rx;
+
+for (;;) {
+ if (bdp->cbd_sc & BD_ENET_RX_EMPTY)
+ break;
+
+#ifndef final_version
+ /* Since we have allocated space to hold a complete frame, both
+ * the first and last indicators should be set.
+ */
+ if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) !=
+ (BD_ENET_RX_FIRST | BD_ENET_RX_LAST))
+ printk("CPM ENET: rcv is not first+last\n");
+#endif
+
+ /* Frame too long or too short.
+ */
+ if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))
+ cep->stats.rx_length_errors++;
+ if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */
+ cep->stats.rx_frame_errors++;
+ if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */
+ cep->stats.rx_crc_errors++;
+ if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */
+ cep->stats.rx_crc_errors++;
+
+ /* Report late collisions as a frame error.
+ * On this error, the BD is closed, but we don't know what we
+ * have in the buffer. So, just drop this frame on the floor.
+ */
+ if (bdp->cbd_sc & BD_ENET_RX_CL) {
+ cep->stats.rx_frame_errors++;
+ }
+ else {
+
+ /* Process the incoming frame.
+ */
+ cep->stats.rx_packets++;
+ pkt_len = bdp->cbd_datlen;
+ cep->stats.rx_bytes += pkt_len;
+
+ /* This does 16 byte alignment, much more than we need.
+ * The packet length includes FCS, but we don't want to
+ * include that when passing upstream as it messes up
+ * bridging applications.
+ */
+ skb = dev_alloc_skb(pkt_len-4);
+
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ cep->stats.rx_dropped++;
+ }
+ else {
+ skb->dev = dev;
+ skb_put(skb,pkt_len-4); /* Make room */
+ eth_copy_and_sum(skb,
+ (unsigned char *)__va(bdp->cbd_bufaddr),
+ pkt_len-4, 0);
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ }
+ }
+
+ /* Clear the status flags for this buffer.
+ */
+ bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+
+ /* Mark the buffer empty.
+ */
+ bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+
+ /* Update BD pointer to next entry.
+ */
+ if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+ bdp = cep->rx_bd_base;
+ else
+ bdp++;
+
+ }
+ cep->cur_rx = (cbd_t *)bdp;
+
+ return 0;
+}
+
+static int
+fcc_enet_close(struct net_device *dev)
+{
+ /* Don't know what to do yet.
+ */
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev)
+{
+ struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;
+
+ return &cep->stats;
+}
+
+/* The MII is simulated from the 8xx FEC implementation. The FCC
+ * is not responsible for the MII control/status interface.
+ */
+static void
+fcc_enet_mii(struct net_device *dev)
+{
+ struct fcc_enet_private *fep;
+ mii_list_t *mip;
+ uint mii_reg;
+
+ fep = (struct fcc_enet_private *)dev->priv;
+#if 0
+ ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);
+ mii_reg = ep->fec_mii_data;
+#endif
+
+ if ((mip = mii_head) == NULL) {
+ printk("MII and no head!\n");
+ return;
+ }
+
+ if (mip->mii_func != NULL)
+ (*(mip->mii_func))(mii_reg, dev);
+
+ mii_head = mip->mii_next;
+ mip->mii_next = mii_free;
+ mii_free = mip;
+
+#if 0
+ if ((mip = mii_head) != NULL)
+ ep->fec_mii_data = mip->mii_regval;
+#endif
+}
+
+static int
+mii_queue(int regval, void (*func)(uint, struct net_device *))
+{
+ unsigned long flags;
+ mii_list_t *mip;
+ int retval;
+
+ retval = 0;
+
+ save_flags(flags);
+ cli();
+
+ if ((mip = mii_free) != NULL) {
+ mii_free = mip->mii_next;
+ mip->mii_regval = regval;
+ mip->mii_func = func;
+ mip->mii_next = NULL;
+ if (mii_head) {
+ mii_tail->mii_next = mip;
+ mii_tail = mip;
+ }
+ else {
+ mii_head = mii_tail = mip;
+#if 0
+ (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval;
+#endif
+ }
+ }
+ else {
+ retval = 1;
+ }
+
+ restore_flags(flags);
+
+ return(retval);
+}
+
+static volatile uint full_duplex;
+
+static void
+mii_status(uint mii_reg, struct net_device *dev)
+{
+ volatile uint prev_duplex;
+
+ if (((mii_reg >> 18) & 0x1f) == 1) {
+ /* status register.
+ */
+ printk("fec: ");
+ if (mii_reg & 0x0004)
+ printk("link up");
+ else
+ printk("link down");
+
+ if (mii_reg & 0x0010)
+ printk(",remote fault");
+ if (mii_reg & 0x0020)
+ printk(",auto complete");
+ printk("\n");
+ }
+ if (((mii_reg >> 18) & 0x1f) == 0x14) {
+ /* Extended chip status register.
+ */
+ prev_duplex = full_duplex;
+ printk("fec: ");
+ if (mii_reg & 0x0800)
+ printk("100 Mbps");
+ else
+ printk("10 Mbps");
+
+ if (mii_reg & 0x1000) {
+ printk(", Full-Duplex\n");
+ full_duplex = 1;
+ }
+ else {
+ printk(", Half-Duplex\n");
+ full_duplex = 0;
+ }
+#if 0
+ if (prev_duplex != full_duplex)
+ restart_fec(dev);
+#endif
+ }
+ if (((mii_reg >> 18) & 0x1f) == 31) {
+ /* QS6612 PHY Control/Status.
+ * OK, now we have it all, so figure out what is going on.
+ */
+ prev_duplex = full_duplex;
+ printk("fec: ");
+
+ mii_reg = (mii_reg >> 2) & 7;
+
+ if (mii_reg & 1)
+ printk("10 Mbps");
+ else
+ printk("100 Mbps");
+
+ if (mii_reg > 4) {
+ printk(", Full-Duplex\n");
+ full_duplex = 1;
+ }
+ else {
+ printk(", Half-Duplex\n");
+ full_duplex = 0;
+ }
+
+#if 0
+ if (prev_duplex != full_duplex)
+ restart_fec(dev);
+#endif
+ }
+}
+
+static uint phyno;
+
+static void
+mii_discover_phy3(uint mii_reg, struct net_device *dev)
+{
+ phytype <<= 16;
+ phytype |= (mii_reg & 0xffff);
+ printk("fec: Phy @ 0x%x, type 0x%08x\n", phyno, phytype);
+ mii_startup_cmds();
+}
+
+static void
+mii_discover_phy(uint mii_reg, struct net_device *dev)
+{
+ if (phyno < 32) {
+ if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
+ phyaddr = phyno;
+ mii_queue(mk_mii_read(3), mii_discover_phy3);
+ }
+ else {
+ phyno++;
+ mii_queue(mk_mii_phyaddr(phyno), mii_discover_phy);
+ }
+ }
+ else {
+ printk("FEC: No PHY device found.\n");
+ }
+}
+
+static void
+mii_discover_phy_poll(fcc_info_t *fip)
+{
+ uint rv;
+ int i;
+
+ for (i=0; i<32; i++) {
+ rv = mii_send_receive(fip, mk_mii_phyaddr(i));
+ if ((phytype = (rv & 0xffff)) != 0xffff) {
+ phyaddr = i;
+ rv = mii_send_receive(fip, mk_mii_read(3));
+ phytype <<= 16;
+ phytype |= (rv & 0xffff);
+ printk("fec: Phy @ 0x%x, type 0x%08x\n", phyaddr, phytype);
+ }
+ }
+}
+
+static void
+mii_startup_cmds(void)
+{
+
+#if 1
+ /* Level One PHY.
+ */
+
+ /* Read status registers to clear any pending interrupt.
+ */
+ mii_queue(mk_mii_read(1), mii_status);
+ mii_queue(mk_mii_read(18), mii_status);
+
+ /* Read extended chip status register.
+ */
+ mii_queue(mk_mii_read(0x14), mii_status);
+
+ /* Set default operation of 100-TX....for some reason
+ * some of these bits are set on power up, which is wrong.
+ */
+ mii_queue(mk_mii_write(0x13, 0), NULL);
+
+ /* Enable Link status change interrupts.
+ */
+ mii_queue(mk_mii_write(0x11, 0x0002), NULL);
+
+ /* Don't advertize Full duplex.
+ mii_queue(mk_mii_write(0x04, 0x0021), NULL);
+ */
+#endif
+
+}
+
+/* This supports the mii_link interrupt below.
+ * We should get called three times. Once for register 1, once for
+ * register 18, and once for register 20.
+ */
+static uint mii_saved_reg1;
+
+static void
+mii_relink(uint mii_reg, struct net_device *dev)
+{
+ volatile uint prev_duplex;
+ unsigned long flags;
+
+ if (((mii_reg >> 18) & 0x1f) == 1) {
+ /* Just save the status register and get out.
+ */
+ mii_saved_reg1 = mii_reg;
+ return;
+ }
+ if (((mii_reg >> 18) & 0x1f) == 18) {
+ /* Not much here, but has to be read to clear the
+ * interrupt condition.
+ */
+ if ((mii_reg & 0x8000) == 0)
+ printk("fec: re-link and no IRQ?\n");
+ if ((mii_reg & 0x4000) == 0)
+ printk("fec: no PHY power?\n");
+ }
+ if (((mii_reg >> 18) & 0x1f) == 20) {
+ /* Extended chip status register.
+ * OK, now we have it all, so figure out what is going on.
+ */
+ prev_duplex = full_duplex;
+ printk("fec: ");
+ if (mii_saved_reg1 & 0x0004)
+ printk("link up");
+ else
+ printk("link down");
+
+ if (mii_saved_reg1 & 0x0010)
+ printk(", remote fault");
+ if (mii_saved_reg1 & 0x0020)
+ printk(", auto complete");
+
+ if (mii_reg & 0x0800)
+ printk(", 100 Mbps");
+ else
+ printk(", 10 Mbps");
+
+ if (mii_reg & 0x1000) {
+ printk(", Full-Duplex\n");
+ full_duplex = 1;
+ }
+ else {
+ printk(", Half-Duplex\n");
+ full_duplex = 0;
+ }
+ if (prev_duplex != full_duplex) {
+ save_flags(flags);
+ cli();
+#if 0
+ restart_fec(dev);
+#endif
+ restore_flags(flags);
+ }
+ }
+ if (((mii_reg >> 18) & 0x1f) == 31) {
+ /* QS6612 PHY Control/Status.
+ * OK, now we have it all, so figure out what is going on.
+ */
+ prev_duplex = full_duplex;
+ printk("fec: ");
+ if (mii_saved_reg1 & 0x0004)
+ printk("link up");
+ else
+ printk("link down");
+
+ if (mii_saved_reg1 & 0x0010)
+ printk(", remote fault");
+ if (mii_saved_reg1 & 0x0020)
+ printk(", auto complete");
+
+ mii_reg = (mii_reg >> 2) & 7;
+
+ if (mii_reg & 1)
+ printk(", 10 Mbps");
+ else
+ printk(", 100 Mbps");
+
+ if (mii_reg > 4) {
+ printk(", Full-Duplex\n");
+ full_duplex = 1;
+ }
+ else {
+ printk(", Half-Duplex\n");
+ full_duplex = 0;
+ }
+
+#if 0
+ if (prev_duplex != full_duplex) {
+ save_flags(flags);
+ cli();
+ restart_fec(dev);
+ restore_flags(flags);
+ }
+#endif
+ }
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ * Skeleton taken from sunlance driver.
+ * The CPM Ethernet implementation allows Multicast as well as individual
+ * MAC address filtering. Some of the drivers check to make sure it is
+ * a group multicast address, and discard those that are not. I guess I
+ * will do the same for now, but just remove the test if you want
+ * individual filtering as well (do the upper net layers want or support
+ * this kind of feature?).
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+ struct fcc_enet_private *cep;
+ struct dev_mc_list *dmi;
+ u_char *mcptr, *tdptr;
+ volatile fcc_enet_t *ep;
+ int i, j;
+
+ cep = (struct fcc_enet_private *)dev->priv;
+
+return;
+ /* Get pointer to FCC area in parameter RAM.
+ */
+ ep = (fcc_enet_t *)dev->base_addr;
+
+ if (dev->flags&IFF_PROMISC) {
+
+ /* Log any net taps. */
+ printk("%s: Promiscuous mode enabled.\n", dev->name);
+ cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO;
+ } else {
+
+ cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO;
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /* Catch all multicast addresses, so set the
+ * filter to all 1's.
+ */
+ ep->fen_gaddrh = 0xffffffff;
+ ep->fen_gaddrl = 0xffffffff;
+ }
+ else {
+ /* Clear filter and add the addresses in the list.
+ */
+ ep->fen_gaddrh = 0;
+ ep->fen_gaddrl = 0;
+
+ dmi = dev->mc_list;
+
+ for (i=0; i<dev->mc_count; i++) {
+
+ /* Only support group multicast for now.
+ */
+ if (!(dmi->dmi_addr[0] & 1))
+ continue;
+
+ /* The address in dmi_addr is LSB first,
+ * and taddr is MSB first. We have to
+ * copy bytes MSB first from dmi_addr.
+ */
+ mcptr = (u_char *)dmi->dmi_addr + 5;
+ tdptr = (u_char *)&ep->fen_taddrh;
+ for (j=0; j<6; j++)
+ *tdptr++ = *mcptr--;
+
+ /* Ask CPM to run CRC and set bit in
+ * filter mask.
+ */
+ cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage,
+ cep->fip->fc_cpmblock, 0x0c,
+ CPM_CR_SET_GADDR) | CPM_CR_FLG;
+ udelay(10);
+ while (cpmp->cp_cpcr & CPM_CR_FLG);
+ }
+ }
+ }
+}
+
+/* Initialize the CPM Ethernet on FCC.
+ */
+int __init fec_enet_init(void)
+{
+ struct net_device *dev;
+ struct fcc_enet_private *cep;
+ fcc_info_t *fip;
+ int i, np;
+ volatile immap_t *immap;
+ volatile iop8260_t *io;
+
+ immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
+ io = &immap->im_ioport;
+
+ np = sizeof(fcc_ports) / sizeof(fcc_info_t);
+ fip = fcc_ports;
+
+ while (np-- > 0) {
+
+ /* Allocate some private information.
+ */
+ cep = (struct fcc_enet_private *)
+ kmalloc(sizeof(*cep), GFP_KERNEL);
+ __clear_user(cep,sizeof(*cep));
+ spin_lock_init(&cep->lock);
+ cep->fip = fip;
+
+ /* Create an Ethernet device instance.
+ */
+ dev = init_etherdev(0, 0);
+ dev->priv = cep;
+
+ init_fcc_shutdown(fip, cep, immap);
+ init_fcc_ioports(fip, io, immap);
+ init_fcc_param(fip, dev, immap);
+
+ dev->base_addr = (unsigned long)(cep->ep);
+
+ /* The CPM Ethernet specific entries in the device
+ * structure.
+ */
+ dev->open = fcc_enet_open;
+ dev->hard_start_xmit = fcc_enet_start_xmit;
+ dev->tx_timeout = fcc_enet_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->stop = fcc_enet_close;
+ dev->get_stats = fcc_enet_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+
+ init_fcc_startup(fip, dev);
+
+ printk("%s: FCC ENET Version 0.2, ", dev->name);
+ for (i=0; i<5; i++)
+ printk("%02x:", dev->dev_addr[i]);
+ printk("%02x\n", dev->dev_addr[5]);
+
+ /* This is just a hack for now that works only on the EST
+ * board, or anything else that has MDIO/CK configured.
+ * It is mainly to test the MII software clocking.
+ */
+ mii_discover_phy_poll(fip);
+
+ fip++;
+ }
+
+ return 0;
+}
+
+/* Make sure the device is shut down during initialization.
+*/
+static void __init
+init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
+ volatile immap_t *immap)
+{
+ volatile fcc_enet_t *ep;
+ volatile fcc_t *fccp;
+
+ /* Get pointer to FCC area in parameter RAM.
+ */
+ ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]);
+
+ /* And another to the FCC register area.
+ */
+ fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]);
+ cep->fccp = fccp; /* Keep the pointers handy */
+ cep->ep = ep;
+
+ /* Disable receive and transmit in case someone left it running.
+ */
+ fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT);
+}
+
+/* Initialize the I/O pins for the FCC Ethernet.
+*/
+static void __init
+init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
+ volatile immap_t *immap)
+{
+
+ /* FCC1 pins are on port A/C. FCC2/3 are port B/C.
+ */
+ if (fip->fc_proff == PROFF_FCC1) {
+ /* Configure port A and C pins for FCC1 Ethernet.
+ */
+ io->iop_pdira &= ~PA1_DIRA0;
+ io->iop_pdira |= PA1_DIRA1;
+ io->iop_psora &= ~PA1_PSORA0;
+ io->iop_psora |= PA1_PSORA1;
+ io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1);
+ }
+ if (fip->fc_proff == PROFF_FCC2) {
+ /* Configure port B and C pins for FCC Ethernet.
+ */
+ io->iop_pdirb &= ~PB2_DIRB0;
+ io->iop_pdirb |= PB2_DIRB1;
+ io->iop_psorb &= ~PB2_PSORB0;
+ io->iop_psorb |= PB2_PSORB1;
+ io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1);
+ }
+ if (fip->fc_proff == PROFF_FCC3) {
+ /* Configure port B and C pins for FCC Ethernet.
+ */
+ io->iop_pdirb &= ~PB3_DIRB0;
+ io->iop_pdirb |= PB3_DIRB1;
+ io->iop_psorb &= ~PB3_PSORB0;
+ io->iop_psorb |= PB3_PSORB1;
+ io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1);
+ }
+
+ /* Port C has clocks......
+ */
+ io->iop_psorc &= ~(fip->fc_trxclocks);
+ io->iop_pdirc &= ~(fip->fc_trxclocks);
+ io->iop_pparc |= fip->fc_trxclocks;
+
+ /* ....and the MII serial clock/data.
+ */
+ io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck);
+ io->iop_podrc |= fip->fc_mdio;
+ io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck);
+ io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck);
+
+ /* Configure Serial Interface clock routing.
+ * First, clear all FCC bits to zero,
+ * then set the ones we want.
+ */
+ immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask);
+ immap->im_cpmux.cmx_fcr |= fip->fc_clockroute;
+}
+
+static void __init
+init_fcc_param(fcc_info_t *fip, struct net_device *dev,
+ volatile immap_t *immap)
+{
+ unsigned char *eap;
+ unsigned long mem_addr;
+ bd_t *bd;
+ int i, j;
+ struct fcc_enet_private *cep;
+ volatile fcc_enet_t *ep;
+ volatile cbd_t *bdp;
+ volatile cpm8260_t *cp;
+
+ cep = (struct fcc_enet_private *)(dev->priv);
+ ep = cep->ep;
+ cp = cpmp;
+
+ bd = (bd_t *)__res;
+
+ /* Zero the whole thing.....I must have missed some individually.
+ * It works when I do this.
+ */
+ memset((char *)ep, 0, sizeof(fcc_enet_t));
+
+ /* Allocate space for the buffer descriptors in the DP ram.
+ * These are relative offsets in the DP ram address space.
+ * Initialize base addresses for the buffer descriptors.
+ */
+#if 0
+ /* I really want to do this, but for some reason it doesn't
+ * work with the data cache enabled, so I allocate from the
+ * main memory instead.
+ */
+ i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
+ ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i];
+ cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i];
+
+ i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
+ ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i];
+ cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i];
+#else
+ cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
+ ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base);
+ cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
+ ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base);
+#endif
+
+ cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
+ cep->cur_rx = cep->rx_bd_base;
+
+ ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24;
+ ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24;
+
+ /* Set maximum bytes per receive buffer.
+ * It must be a multiple of 32.
+ */
+ ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
+
+ /* Allocate space in the reserved FCC area of DPRAM for the
+ * internal buffers. No one uses this space (yet), so we
+ * can do this. Later, we will add resource management for
+ * this area.
+ */
+ mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128);
+ ep->fen_genfcc.fcc_riptr = mem_addr;
+ ep->fen_genfcc.fcc_tiptr = mem_addr+32;
+ ep->fen_padptr = mem_addr+64;
+ memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32);
+
+ ep->fen_genfcc.fcc_rbptr = 0;
+ ep->fen_genfcc.fcc_tbptr = 0;
+ ep->fen_genfcc.fcc_rcrc = 0;
+ ep->fen_genfcc.fcc_tcrc = 0;
+ ep->fen_genfcc.fcc_res1 = 0;
+ ep->fen_genfcc.fcc_res2 = 0;
+
+ ep->fen_camptr = 0; /* CAM isn't used in this driver */
+
+ /* Set CRC preset and mask.
+ */
+ ep->fen_cmask = 0xdebb20e3;
+ ep->fen_cpres = 0xffffffff;
+
+ ep->fen_crcec = 0; /* CRC Error counter */
+ ep->fen_alec = 0; /* alignment error counter */
+ ep->fen_disfc = 0; /* discard frame counter */
+ ep->fen_retlim = 15; /* Retry limit threshold */
+ ep->fen_pper = 0; /* Normal persistence */
+
+ /* Clear hash filter tables.
+ */
+ ep->fen_gaddrh = 0;
+ ep->fen_gaddrl = 0;
+ ep->fen_iaddrh = 0;
+ ep->fen_iaddrl = 0;
+
+ /* Clear the Out-of-sequence TxBD.
+ */
+ ep->fen_tfcstat = 0;
+ ep->fen_tfclen = 0;
+ ep->fen_tfcptr = 0;
+
+ ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
+ ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
+
+ /* Set Ethernet station address.
+ *
+ * This is supplied in the board information structure, so we
+ * copy that into the controller.
+ * So, far we have only been given one Ethernet address. We make
+ * it unique by setting a few bits in the upper byte of the
+ * non-static part of the address.
+ */
+ eap = (unsigned char *)&(ep->fen_paddrh);
+ for (i=5; i>=0; i--) {
+ if (i == 3) {
+ dev->dev_addr[i] = bd->bi_enetaddr[i];
+ dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum));
+ *eap++ = dev->dev_addr[i];
+ }
+ else {
+ *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
+ }
+ }
+
+ ep->fen_taddrh = 0;
+ ep->fen_taddrm = 0;
+ ep->fen_taddrl = 0;
+
+ ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */
+ ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */
+
+ /* Clear stat counters, in case we ever enable RMON.
+ */
+ ep->fen_octc = 0;
+ ep->fen_colc = 0;
+ ep->fen_broc = 0;
+ ep->fen_mulc = 0;
+ ep->fen_uspc = 0;
+ ep->fen_frgc = 0;
+ ep->fen_ospc = 0;
+ ep->fen_jbrc = 0;
+ ep->fen_p64c = 0;
+ ep->fen_p65c = 0;
+ ep->fen_p128c = 0;
+ ep->fen_p256c = 0;
+ ep->fen_p512c = 0;
+ ep->fen_p1024c = 0;
+
+ ep->fen_rfthr = 0; /* Suggested by manual */
+ ep->fen_rfcnt = 0;
+ ep->fen_cftype = 0;
+
+ /* Now allocate the host memory pages and initialize the
+ * buffer descriptors.
+ */
+ bdp = cep->tx_bd_base;
+ for (i=0; i<TX_RING_SIZE; i++) {
+
+ /* Initialize the BD for every fragment in the page.
+ */
+ bdp->cbd_sc = 0;
+ bdp->cbd_datlen = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap.
+ */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ bdp = cep->rx_bd_base;
+ for (i=0; i<FCC_ENET_RX_PAGES; i++) {
+
+ /* Allocate a page.
+ */
+ mem_addr = __get_free_page(GFP_KERNEL);
+
+ /* Initialize the BD for every fragment in the page.
+ */
+ for (j=0; j<FCC_ENET_RX_FRPPG; j++) {
+ bdp->cbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR;
+ bdp->cbd_datlen = 0;
+ bdp->cbd_bufaddr = __pa(mem_addr);
+ mem_addr += FCC_ENET_RX_FRSIZE;
+ bdp++;
+ }
+ }
+
+ /* Set the last buffer to wrap.
+ */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ /* Let's re-initialize the channel now. We have to do it later
+ * than the manual describes because we have just now finished
+ * the BD initialization.
+ */
+ cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c,
+ CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ while (cp->cp_cpcr & CPM_CR_FLG);
+
+ cep->skb_cur = cep->skb_dirty = 0;
+}
+
+/* Let 'er rip.
+*/
+static void __init
+init_fcc_startup(fcc_info_t *fip, struct net_device *dev)
+{
+ volatile fcc_t *fccp;
+ struct fcc_enet_private *cep;
+
+ cep = (struct fcc_enet_private *)(dev->priv);
+ fccp = cep->fccp;
+
+ fccp->fcc_fcce = 0xffff; /* Clear any pending events */
+
+ /* Enable interrupts for transmit error, complete frame
+ * received, and any transmit buffer we have also set the
+ * interrupt flag.
+ */
+ fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB);
+
+ /* Install our interrupt handler.
+ */
+ if (request_8xxirq(fip->fc_interrupt, fcc_enet_interrupt, 0,
+ "fenet", dev) < 0)
+ printk("Can't get FCC IRQ %d\n", fip->fc_interrupt);
+
+ /* Set GFMR to enable Ethernet operating mode.
+ */
+ fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET);
+
+ /* Set sync/delimiters.
+ */
+ fccp->fcc_fdsr = 0xd555;
+
+ /* Set protocol specific processing mode for Ethernet.
+ * This has to be adjusted for Full Duplex operation after we can
+ * determine how to detect that.
+ */
+ fccp->fcc_fpsmr = FCC_PSMR_ENCRC;
+
+ /* And last, enable the transmit and receive processing.
+ */
+ fccp->fcc_gfmr |= (FCC_GFMR_ENR | FCC_GFMR_ENT);
+}
+
+/* MII command/status interface.
+ * I'm not going to describe all of the details. You can find the
+ * protocol definition in many other places, including the data sheet
+ * of most PHY parts.
+ * I wonder what "they" were thinking (maybe weren't) when they leave
+ * the I2C in the CPM but I have to toggle these bits......
+ */
+static uint
+mii_send_receive(fcc_info_t *fip, uint cmd)
+{
+ unsigned long flags;
+ uint retval;
+ int read_op, i;
+ volatile immap_t *immap;
+ volatile iop8260_t *io;
+
+ immap = (immap_t *)IMAP_ADDR;
+ io = &immap->im_ioport;
+
+ /* When we get here, both clock and data are high, outputs.
+ * Output is open drain.
+ * Data transitions on high->low clock, is valid on low->high clock.
+ * Spec says edge transitions no closer than 160 nSec, minimum clock
+ * cycle 400 nSec. I could only manage about 500 nSec edges with
+ * an XOR loop, so I won't worry about delays yet.
+ * I disable interrupts during bit flipping to ensure atomic
+ * updates of the registers. I do lots of interrupt disable/enable
+ * to ensure we don't hang out too long with interrupts disabled.
+ */
+
+ /* First, crank out 32 1-bits as preamble.
+ * This is 64 transitions to clock the bits, with clock/data
+ * left high.
+ */
+ save_flags(flags);
+ cli();
+ for (i=0; i<64; i++) {
+ io->iop_pdatc ^= fip->fc_mdck;
+ udelay(0);
+ }
+ restore_flags(flags);
+
+ read_op = ((cmd & 0xf0000000) == 0x60000000);
+
+ /* We return the command word on a write op, or the command portion
+ * plus the new data on a read op. This is what the 8xx FEC does,
+ * and it allows the functions to simply look at the returned value
+ * and know the PHY/register as well.
+ */
+ if (read_op)
+ retval = cmd;
+ else
+ retval = (cmd >> 16);
+
+ /* Clock out the first 16 MS bits of the command.
+ */
+ save_flags(flags);
+ cli();
+ for (i=0; i<16; i++) {
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ if (cmd & 0x80000000)
+ io->iop_pdatc |= fip->fc_mdio;
+ else
+ io->iop_pdatc &= ~(fip->fc_mdio);
+ cmd <<= 1;
+ io->iop_pdatc |= fip->fc_mdck;
+ udelay(0);
+ }
+
+ /* Do the turn-around. If read op, we make the IO and input.
+ * If write op, do the 1/0 thing.
+ */
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ if (read_op)
+ io->iop_pdirc &= ~(fip->fc_mdio);
+ else
+ io->iop_pdatc |= fip->fc_mdio;
+ io->iop_pdatc |= fip->fc_mdck;
+
+ /* I do this mainly to get just a little delay.
+ */
+ restore_flags(flags);
+ save_flags(flags);
+ cli();
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ io->iop_pdirc &= ~(fip->fc_mdio);
+ io->iop_pdatc |= fip->fc_mdck;
+
+ restore_flags(flags);
+ save_flags(flags);
+ cli();
+
+ /* For read, clock in 16 bits. For write, clock out
+ * rest of command.
+ */
+ if (read_op) {
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ udelay(0);
+ for (i=0; i<16; i++) {
+ io->iop_pdatc |= fip->fc_mdck;
+ udelay(0);
+ retval <<= 1;
+ if (io->iop_pdatc & fip->fc_mdio)
+ retval |= 1;
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ udelay(0);
+ }
+ }
+ else {
+ for (i=0; i<16; i++) {
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ if (cmd & 0x80000000)
+ io->iop_pdatc |= fip->fc_mdio;
+ else
+ io->iop_pdatc &= ~(fip->fc_mdio);
+ cmd <<= 1;
+ io->iop_pdatc |= fip->fc_mdck;
+ udelay(0);
+ }
+ io->iop_pdatc &= ~(fip->fc_mdck);
+ }
+ restore_flags(flags);
+
+ /* Some diagrams show two 1 bits for "idle". I don't know if
+ * this is really necessary or if it was just to indicate nothing
+ * is going to happen for a while.
+ * Make the data pin an output, set the data high, and clock it.
+ */
+ save_flags(flags);
+ cli();
+ io->iop_pdatc |= fip->fc_mdio;
+ io->iop_pdirc |= fip->fc_mdio;
+ for (i=0; i<3; i++)
+ io->iop_pdatc ^= fip->fc_mdck;
+ restore_flags(flags);
+
+ /* We exit with the same conditions as entry.
+ */
+ return(retval);
+}
}
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;
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.
* 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
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
/* 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.
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);
}
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);
}
#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);
}
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:
#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];
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;
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
#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[];
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");
rec = (struct bi_record *)((unsigned long)rec + rec->size);
}
+#if 0
#define eieio() asm volatile("eieio");
void stop_imac_ethernet(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();
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
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
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
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
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
fi
source drivers/usb/Config.in
-source drivers/input/Config.in
mainmenu_option next_comment
comment 'Kernel hacking'
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
# CONFIG_UID16 is not set
#
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
# 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
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
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
-CONFIG_MAC_FLOPPY=y
-CONFIG_MAC_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-CONFIG_ADB=y
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_MACIO=y
-CONFIG_ADB_PMU=y
-CONFIG_ADB_KEYBOARD=y
-CONFIG_ADBMOUSE=y
+CONFIG_PPC_RTC=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BOOTX_TEXT=y
# CONFIG_MOTOROLA_HOTSWAP is not set
# CONFIG_CMDLINE_BOOL is not set
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
#
# Plug and Play configuration
#
# CONFIG_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
#
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
# 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
# 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
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
# 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
# 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
# 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
#
# 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
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
# 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
#
# 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
# 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
# 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
# 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
# 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
# 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
# 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
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
# 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
# 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
# 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
CONFIG_MAGIC_SYSRQ=y
# CONFIG_KGDB is not set
CONFIG_XMON=y
-
#
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
# 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
# CONFIG_PARPORT is not set
# CONFIG_VGA_CONSOLE is not set
# CONFIG_FB is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADB is not set
+# CONFIG_PPC_RTC is not set
# CONFIG_PROC_DEVICETREE is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_MOTOROLA_HOTSWAP is not set
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
#
# Plug and Play configuration
#
# CONFIG_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
#
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
# 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
# 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
#
# CONFIG_FB is not set
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
#
# Character devices
#
# 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
# 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_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
# 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
#
CONFIG_SCC_ENET=y
CONFIG_SCC1_ENET=y
-# CONFIG_FCC_ENET is not set
+# CONFIG_FEC_ENET is not set
#
# USB support
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
#
# 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
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
# 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
# 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
#
# CONFIG_NET_SCHED is not set
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
#
# SCSI support
#
CONFIG_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
# 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
# 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
#
# 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
# 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
#
# CONFIG_NET_RADIO is not set
#
-# Token Ring driver support
+# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
#
# CONFIG_HAMRADIO is not set
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
#
# ISDN subsystem
#
# 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
# 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
#
# 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
#
# CONFIG_SOUND is not set
+#
+# USB support
+#
+# CONFIG_USB is not set
+
#
# Kernel hacking
#
#
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
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
#
# CONFIG_PARPORT is not set
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
#
# Plug and Play configuration
#
# 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
#
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
# 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
# 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
#
# CONFIG_FB is not set
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
#
# Character devices
#
# 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
# 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_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
# 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
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
#
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
# CONFIG_UID16 is not set
#
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
# 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
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
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
-CONFIG_MAC_FLOPPY=y
-CONFIG_MAC_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-CONFIG_ADB=y
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_MACIO=y
-CONFIG_ADB_PMU=y
-CONFIG_ADB_KEYBOARD=y
-CONFIG_ADBMOUSE=y
+CONFIG_PPC_RTC=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BOOTX_TEXT=y
# CONFIG_MOTOROLA_HOTSWAP is not set
# CONFIG_CMDLINE_BOOL is not set
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
#
# Plug and Play configuration
#
# CONFIG_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
#
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
# 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
# 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
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
# 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
# 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
# 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
#
# 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
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
# 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
#
# 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
# 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
# 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
# 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_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
# 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
# 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
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
# 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
# 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
# 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
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)
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. */
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);
}
- 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;
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;
/* 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 )
{
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;
}
}
+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);
{
struct device_node *py;
+ ppc_md.pcibios_fixup = chrp_pcibios_fixup;
#ifdef CONFIG_POWER4
set_config_access_method(rtas);
pci_dram_offset = 0;
}
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
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);
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];
#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 -
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)
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;
}
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 )
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 */
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)
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);
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;
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);
}
#include <linux/errno.h>
#include <linux/sys.h>
#include <linux/config.h>
+#include "mol.h"
#undef SHOW_SYSCALLS
#undef SHOW_SYSCALLS_TASK
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
/* 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
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
*/
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
#include <asm/errno.h>
#include <asm/ohare.h>
#include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/feature.h>
#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 */
{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 */
*/
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 */
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);
}
} 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;
}
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);
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)
{
}
+/* 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)
{
}
}
-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
{
/* Not yet implemented */
}
-
+#endif /* CONFIG_PMAC_PBOOK */
#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;
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
#include <asm/processor.h>
#include <asm/page.h>
#include <linux/config.h>
+#include "mol.h"
/*
* Load a PTE into the hash table, if possible.
* 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? */
#include <asm/page.h>
#include <linux/config.h>
#include <asm/mmu.h>
+#include "mol.h"
#ifdef CONFIG_APUS
#include <asm/amigappc.h>
mtspr DBAT##n##L,RB; \
1:
#endif /* CONFIG_PPC64BRIDGE */
-
+
.text
.globl _stext
_stext:
/* 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
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.
.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
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 */
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 */
. = 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 */
. = 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 */
. = 0x900
Decrementer:
EXCEPTION_PROLOG
+ MOL_HOOK(4)
addi r3,r1,STACK_FRAME_OVERHEAD
li r20,MSR_KERNEL
bl transfer_to_handler
.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.
.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 )
*/
. = 0x1100
DataLoadTLBMiss:
+ MOL_HOOK_TLBMISS( 15 )
/*
* r0: stored ctr
* r1: linux style pte ( later becomes ppc hardware pte )
*/
. = 0x1200
DataStoreTLBMiss:
+ MOL_HOOK_TLBMISS( 16 )
/*
* r0: stored ctr
* r1: linux style pte ( later becomes ppc hardware pte )
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)
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)
#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
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
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
.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
*/
.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
* 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 */
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
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
/*
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
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) */
*/
.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,
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
* 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
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.
cmd_line:
.space 512
+#ifdef CONFIG_8xx_CPU6
+ .globl cpu6_errata_word
+cpu6_errata_word:
+ .space 16
+#endif
+
case 6: /* 603e */
case 7: /* 603ev */
case 8: /* 750 */
+ case 12: /* 7400 */
save_flags(msr);
__cli();
if (!current->need_resched) {
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 *)
}
}
-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;
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
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
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.
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
((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));
#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
_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
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
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)
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 */
.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
--- /dev/null
+/*
+ * arch/ppc/kernel/mol.h
+ *
+ * <mol.h>
+ *
+ * Mac-on-Linux hook macros
+ * <http://www.maconlinux.org>
+ *
+ * Copyright (C) 2000 Samuel Rydh (samuel@ibrium.se)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ */
+
+#ifndef _PPC_KERNEL_MOL
+#define _PPC_KERNEL_MOL
+
+#include <linux/config.h>
+
+#ifdef CONFIG_MOL
+#define MOL_INTERFACE_VERSION 3
+
+#define MOL_HOOK(hook_num) \
+ lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \
+ cmpwi cr1,r0,0; \
+ beq+ cr1,777f; \
+ mtctr r0; \
+ bctrl; \
+777: lwz r0,GPR0(r21)
+
+#define MOL_HOOK_RESTORE(hook_num) \
+ mfcr r2; \
+ MOL_HOOK(hook_num); \
+ mtcrf 0x80,r2; \
+ lwz r2,_CTR(r21); \
+ mtctr r2; \
+ lwz r2,GPR2(r21)
+
+#define MOL_HOOK_MMU(hook_num, scr) \
+ lis scr,(mol_interface + 4 * hook_num + 4)@ha; \
+ lwz scr,(mol_interface + 4 * hook_num + 4)@l(scr); \
+ cmpwi cr1,scr,0; \
+ beq+ cr1,778f; \
+ mtctr scr; \
+ bctrl; \
+778:
+
+#define MOL_HOOK_TLBMISS(hook_num) \
+ lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \
+ cmpwi r0,0; \
+ beq+ 779f; \
+ mflr r3; \
+ mtlr r0; \
+ blrl; \
+ mtlr r3; \
+779:
+
+#else
+#define MOL_HOOK(num)
+#define MOL_HOOK_RESTORE(num)
+#define MOL_HOOK_MMU(num, scr)
+#define MOL_HOOK_TLBMISS(num)
+#endif
+
+
+#endif /* _PPC_KERNEL_MOL */
/*
* Document me.
*/
-void __init
+long __init
oak_time_init(void)
{
/* XXX - Implement me */
+ return 0;
}
/*
#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 */
int j, pri;
pri = strcmp(np->name, "programmer-switch") ? 2 : 7;
for (j=0;j<np->n_intrs;j++) {
- openpic_initirq( np->intrs[j].line,
- pri,
- np->intrs[j].line,
- 0,
- np->intrs[j].sense);
+ openpic_initirq(np->intrs[j].line,
+ pri,
+ np->intrs[j].line,
+ 0,
+ np->intrs[j].sense);
if (np->intrs[j].sense)
irq_desc[np->intrs[j].line].status = IRQ_LEVEL;
}
#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;
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 )
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)
{
/* 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;
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);
}
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;
}
#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;
}
}
#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);
__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)
__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) {
volatile unsigned int* cfg_addr;
volatile unsigned int* cfg_data;
void* iobase;
+ unsigned long iobase_phys;
};
static struct uninorth_data uninorth_bridges[3];
__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
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.
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);
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)
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 */
#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);
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);
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
pmac_find_bridges();
init_p2pbridge();
- init_uninorth();
/* Checks "l2cr-value" property in the registry */
if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
}
}
-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;
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
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;
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;
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/machdep.h>
-
+#include <asm/hardirq.h>
#include <asm/time.h>
#include <asm/nvram.h>
extern struct timezone sys_tz;
__init
-void pmac_time_init(void)
+long pmac_time_init(void)
{
#ifdef CONFIG_NVRAM
s32 delta = 0;
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 */
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:
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)
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;
}
;
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;
}
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;
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);
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);
}
#include <asm/hw_irq.h>
#include <asm/nvram.h>
#include <asm/mmu_context.h>
+#include <asm/backlight.h>
#ifdef CONFIG_SMP
#include <asm/smplock.h>
#endif /* CONFIG_SMP */
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);
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);
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);
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);
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 */
*/
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);
}
/*
* 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);
}
}
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;
/* 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
{
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
{
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)
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)
{
{
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));
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
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");
childregs->msr &= ~MSR_VEC;
#endif /* CONFIG_ALTIVEC */
-#ifdef CONFIG_SMP
- p->last_processor = NO_PROC_ID;
-#endif /* CONFIG_SMP */
return 0;
}
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;
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;
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;
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)
prom_drawstring(msg);
#endif
return;
- }
-
+ }
for (p = msg; *p != 0; p = q) {
for (q = p; *q != 0 && *q != '\n'; ++q)
/* 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 */
}
#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.
{
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;
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
/*
/* 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];
}
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
}
#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;
}
}
/* 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
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;
}
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));
*/
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++;
* changes.
*/
-__init
void
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;
}
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)
(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;
*(dst_ptr++) = 0;
dst += (bi->dispDeviceRowBytes >> 2);
}
+#ifdef CONFIG_ADB_PMU
+ pmu_resume(); /* PMU will not shut us down ! */
+#endif
}
#endif /* ndef NO_SCROLL */
#include <asm/bootx.h>
#include <asm/machdep.h>
#include <asm/feature.h>
+#include <asm/uaccess.h>
+
#ifdef CONFIG_OAK
#include "oak_setup.h"
#endif /* CONFIG_OAK */
}
/* 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)
{
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
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)
}
-asmlinkage int
+int
sys_sigaltstack(const stack_t *uss, stack_t *uoss)
{
struct pt_regs *regs = (struct pt_regs *) &uss;
* 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;
return ret;
badframe:
- lock_kernel();
do_exit(SIGSEGV);
}
printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
- lock_kernel();
do_exit(SIGSEGV);
}
return ret;
badframe:
- lock_kernel();
do_exit(SIGSEGV);
}
printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
- lock_kernel();
do_exit(SIGSEGV);
}
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);
}
/* FALLTHRU */
default:
- lock_kernel();
sigaddset(¤t->pending.signal, signr);
recalc_sigpending(current);
current->flags |= PF_SIGNALED;
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
+ break;
}
if (regs->trap == 0x0C00 /* System Call! */ &&
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);
* 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);
}
/*
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)
*/
/* This is only used if `cpu' is running an idle task,
so it will reschedule itself anyway... */
- smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0);
+ smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0);
+}
+
+#ifdef CONFIG_XMON
+void smp_send_xmon_break(int cpu)
+{
+ smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0);
+}
+#endif /* CONFIG_XMON */
+
+static void stop_this_cpu(void *dummy)
+{
+ __cli();
+ while (1)
+ ;
}
void smp_send_stop(void)
{
- smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
+ smp_call_function(stop_this_cpu, NULL, 1, 0);
+ smp_num_cpus = 1;
+}
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ * Stolen from the i386 version.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+
+static volatile struct call_data_struct {
+ void (*func) (void *info);
+ void *info;
+ atomic_t started;
+ atomic_t finished;
+ int wait;
+} *call_data = NULL;
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+ int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <nonatomic> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+{
+ struct call_data_struct data;
+ int ret = -1, cpus = smp_num_cpus-1;
+ int timeout;
+
+ if (!cpus)
+ return 0;
+
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+ spin_lock_bh(&call_lock);
+ call_data = &data;
+ /* Send a message to all other CPUs and wait for them to respond */
+ smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0);
+
+ /* Wait for response */
+ timeout = 1000000;
+ while (atomic_read(&data.started) != cpus) {
+ if (--timeout == 0) {
+ printk("smp_call_function on cpu %d: other cpus not responding (%d)\n",
+ smp_processor_id(), atomic_read(&data.started));
+ goto out;
+ }
+ barrier();
+ udelay(1);
+ }
+
+ if (wait) {
+ timeout = 1000000;
+ while (atomic_read(&data.finished) != cpus) {
+ if (--timeout == 0) {
+ printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n",
+ smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started));
+ goto out;
+ }
+ barrier();
+ udelay(1);
+ }
+ }
+ ret = 0;
+
+ out:
+ spin_unlock_bh(&call_lock);
+ return ret;
+}
+
+void smp_call_function_interrupt(void)
+{
+ void (*func) (void *info) = call_data->func;
+ void *info = call_data->info;
+ int wait = call_data->wait;
+
+ /*
+ * Notify initiating CPU that I've grabbed the data and am
+ * about to execute the function
+ */
+ atomic_inc(&call_data->started);
+ /*
+ * At this point the info structure may be out of scope unless wait==1
+ */
+ (*func)(info);
+ if (wait)
+ atomic_inc(&call_data->finished);
}
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- int i;
-
if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
return;
* 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:
#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
{
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)
{
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;
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);
{
/* 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);
}
}
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;
{
}
-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;
*
* 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;
* 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;
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);
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
* (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 )
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;
return err;
}
-asmlinkage int sys_olduname(struct oldold_utsname * name)
+int sys_olduname(struct oldold_utsname * name)
{
int error;
* 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
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,
*/
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);
*/
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
*/
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;
+}
+
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
_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)
{
#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
}
/*
* Document me.
*/
-void __init
+long __init
walnut_time_init(void)
{
/* XXX - Implement me */
+ return 0;
}
/*
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)
#include <asm/processor.h>
#include <asm/errno.h>
-CACHELINE_BYTES = 32
-LG_CACHELINE_BYTES = 5
-CACHELINE_MASK = 0x1f
-CACHELINE_WORDS = 8
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
+#define CACHE_LINE_SIZE 16
+#define LG_CACHE_LINE_SIZE 4
+#define MAX_COPY_PREFETCH 1
+#elif !defined(CONFIG_PPC64BRIDGE)
+#define CACHE_LINE_SIZE 32
+#define LG_CACHE_LINE_SIZE 5
+#define MAX_COPY_PREFETCH 4
+#else
+#define CACHE_LINE_SIZE 128
+#define LG_CACHE_LINE_SIZE 7
+#define MAX_COPY_PREFETCH 1
+#endif /* CONFIG_4xx || CONFIG_8xx */
+
+#define COPY_16_BYTES \
+ lwz r7,4(r4); \
+ lwz r8,8(r4); \
+ lwz r9,12(r4); \
+ lwzu r10,16(r4); \
+ stw r7,4(r6); \
+ stw r8,8(r6); \
+ stw r9,12(r6); \
+ stwu r10,16(r6)
+
+#define COPY_16_BYTES_WITHEX(n) \
+8 ## n ## 0: \
+ lwz r7,4(r4); \
+8 ## n ## 1: \
+ lwz r8,8(r4); \
+8 ## n ## 2: \
+ lwz r9,12(r4); \
+8 ## n ## 3: \
+ lwzu r10,16(r4); \
+8 ## n ## 4: \
+ stw r7,4(r6); \
+8 ## n ## 5: \
+ stw r8,8(r6); \
+8 ## n ## 6: \
+ stw r9,12(r6); \
+8 ## n ## 7: \
+ stwu r10,16(r6)
+
+#define COPY_16_BYTES_EXCODE(n) \
+9 ## n ## 0: \
+ addi r5,r5,-(16 * n); \
+ b 104f; \
+9 ## n ## 1: \
+ addi r5,r5,-(16 * n); \
+ b 105f; \
+.section __ex_table,"a"; \
+ .align 2; \
+ .long 8 ## n ## 0b,9 ## n ## 0b; \
+ .long 8 ## n ## 1b,9 ## n ## 0b; \
+ .long 8 ## n ## 2b,9 ## n ## 0b; \
+ .long 8 ## n ## 3b,9 ## n ## 0b; \
+ .long 8 ## n ## 4b,9 ## n ## 1b; \
+ .long 8 ## n ## 5b,9 ## n ## 1b; \
+ .long 8 ## n ## 6b,9 ## n ## 1b; \
+ .long 8 ## n ## 7b,9 ## n ## 1b; \
+.text
+
+CACHELINE_BYTES = CACHE_LINE_SIZE
+LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE
+CACHELINE_MASK = (CACHE_LINE_SIZE-1)
.globl strcpy
strcpy:
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
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
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
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
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:
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:
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
blr
99: li r3,0 /* bad address, return 0 */
blr
-.section __ex_table,"a"
+
+ .section __ex_table,"a"
.align 2
.long 1b,99b
*/
#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
#include <linux/module.h>
#include <asm/uaccess.h>
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * such as the prep, pmac, chrp, etc. segments as well as the init
+ * segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+ struct exception_table_entry *finish)
+{
+ struct exception_table_entry el, *p, *q;
+
+ /* insertion sort */
+ for (p = start + 1; p < finish; ++p) {
+ /* start .. p-1 is sorted */
+ if (p[0].insn < p[-1].insn) {
+ /* move element p down to its right place */
+ el = *p;
+ q = p;
+ do {
+ /* el comes before q[-1], move q[-1] up one */
+ q[0] = q[-1];
+ --q;
+ } while (q > start && el.insn < q[-1].insn);
+ *q = el;
+ }
+ }
+}
+
+void
+sort_exception_table(void)
+{
+ sort_ex_table(__start___ex_table, __stop___ex_table);
+}
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
{
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;
#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
*/
if (regs->trap == 0x400)
error_code &= 0x48200000;
+ else
+ is_write = error_code & 0x02000000;
#endif /* CONFIG_4xx */
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
#include <linux/delay.h>
#include <linux/openpic.h>
#include <linux/bootmem.h>
+#include <linux/highmem.h>
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h> /* for initrd_* */
#endif
#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[];
#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);
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();
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))
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);
continue;
val->sharedram += atomic_read(&mem_map[i].count) - 1;
}
+ val->totalhigh = totalhigh_pages;
+ val->freehigh = nr_free_highpages();
val->mem_unit = PAGE_SIZE;
}
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)
{
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;
flush_hash_segments(0xd, 0xffffff);
#else
__clear_user(Hash, Hash_size);
+ _tlbia();
#ifdef CONFIG_SMP
smp_send_tlb_invalidate(0);
#endif /* CONFIG_SMP */
}
#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 *);
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;
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.
map_page(v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
+ if (p >= total_lowmem)
+ break;
}
}
}
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
* 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();
/*
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
#endif
break;
case _MACH_Pmac:
- ioremap_base = 0xf8000000;
+ ioremap_base = 0xfe000000;
break;
case _MACH_apus:
/* Map PPC exception vectors. */
#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();
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
}
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);
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.
*/
{
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.
*/
/*
* 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);
}
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 */
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;
}
* 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;
set_phys_avail(&phys_mem);
- return __va(total);
+ return total;
}
#endif /* CONFIG_ALL_PPC */
* 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;
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);
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) */
/*
* 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;
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;
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 */
/* 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 */
* 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;
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 */
* 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[];
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
#include <asm/page.h>
#include <linux/adb.h>
#include <linux/pmu.h>
+#include <linux/cuda.h>
#include <linux/kernel.h>
#include <asm/prom.h>
#include <asm/bootx.h>
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
/* 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;
}
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)
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';
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)
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;
}
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();
*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
+}
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
+#include <linux/smp.h>
#include <asm/ptrace.h>
#include <asm/string.h>
#include <asm/prom.h>
+#include <asm/bitops.h>
#include "nonstdio.h"
#include "privinst.h"
#define scanhex xmon_scanhex
#define skipbl xmon_skipbl
+#ifdef CONFIG_SMP
+static unsigned long cpus_in_xmon = 0;
+static unsigned long got_xmon = 0;
+static volatile int take_xmon = -1;
+#endif /* CONFIG_SMP */
+
static unsigned adrs;
static int size = 1;
static unsigned ndump = 64;
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);
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\
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)
{
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
--bp->count;
remove_bpts();
excprint(regs);
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
regs->msr |= 0x400;
} else {
xmon(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);
--dabr.count;
remove_bpts();
excprint(regs);
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
regs->msr |= 0x400;
} else {
dabr.instr = regs->nip;
--iabr.count;
remove_bpts();
excprint(regs);
- xmon_trace = BRSTEP;
+ xmon_trace[smp_processor_id()] = BRSTEP;
regs->msr |= 0x400;
} else {
xmon(regs);
bp->address);
bp->enabled = 0;
}
+ store_inst((void *) bp->address);
}
#if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4)
if (dabr.enabled)
&& mwrite(bp->address, &bp->instr, 4) != 4)
printf("Couldn't remove breakpoint at %x\n",
bp->address);
+ store_inst((void *) bp->address);
}
}
last_cmd = NULL;
for(;;) {
+#ifdef CONFIG_SMP
+ printf("%d:", smp_processor_id());
+#endif /* CONFIG_SMP */
printf("mon> ");
fflush(stdout);
flush_input();
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,
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
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",
return c;
}
-#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
- || ('a' <= (c) && (c) <= 'f') \
- || ('A' <= (c) && (c) <= 'F'))
void
dump()
{
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;
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;
-/* $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)
-/* $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)
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;
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;
}
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;
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;
}
-/* $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)
-/* $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)
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 {
MOD_SUB_DIRS += macintosh
endif
-ifdef CONFIG_PPC
+ifdef CONFIG_ALL_PPC
SUB_DIRS += macintosh
MOD_SUB_DIRS += macintosh
endif
#ifdef _LINUX
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
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);
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;
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 */
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;
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;
* 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;
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;
static int
statusCmd(void)
{
- int st, retry;
+ int st = -1, retry;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
static int
mcdPlay(struct mcd_Play_msf *arg)
{
- int retry, st;
+ int retry, st = -1;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
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
-#include <linux/autoconf.h>
+#include <linux/config.h>
#include <linux/version.h>
#ifndef CONFIG_SMP
#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)
#ifdef CONFIG_VIDEO_DEV
videodev_init();
#endif
-#ifdef CONFIG_PHONE
- telephony_init();
-#endif
return 0;
}
return 0;
}
-static int destroy_i2o_procfs(void)
+static int __exit destroy_i2o_procfs(void)
{
struct i2o_controller *pctrl = NULL;
int i;
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)
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);
+
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/init.h>
#include "capiutil.h"
#include "capicmd.h"
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
{ "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;
}
}
-static void proc_exit(void)
+static void __exit proc_exit(void)
{
int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
int i;
#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),
}
}
-#ifdef MODULE
-#define capi_init init_module
-#endif
-
static struct capi_interface_user cuser = {
"capi20",
lower_callback,
static char rev[10];
-int capi_init(void)
+int __init capi_init(void)
{
char *p;
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit capi_exit(void)
{
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
unsigned int j;
printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev);
}
+#ifdef MODULE
+module_init(capi_init);
#endif
+module_exit(capi_exit);
+
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/ctype.h>
+#include <linux/init.h>
#include <asm/segment.h>
#include "capiutil.h"
{ "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;
}
}
-static void proc_exit(void)
+static void __exit proc_exit(void)
{
int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
int i;
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;
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit capidrv_exit(void)
{
char rev[10];
char *p;
printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
}
+#ifdef MODULE
+module_init(capidrv_init);
#endif
+module_exit(capidrv_exit);
+
# 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
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)
{
--- /dev/null
+/*
+ * 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 <aidan@kublai.com>
+ * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
+ *
+ * To do:
+ *
+ * Improve Kensington support.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/input.h>
+#include <linux/kbd_ll.h>
+
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
+
+#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("<unknown>.\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);
--- /dev/null
+/*
+ * 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 <linux/config.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/input.h>
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+#include <linux/keyboard.h>
+#include <asm/keyboard.h>
+#include <asm/machdep.h>
+#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 */
+}
#include <linux/kbd_kern.h>
#include <linux/kbd_ll.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#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 */
}
#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. */
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;
}
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;
* ------------------------------------------------------------
*/
#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
*/
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';
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 */
/*
* Register console.
*/
-void __init serial_console_init(void)
+void __init mac_scc_console_init(void)
{
register_console(&sercons);
}
} 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++;
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);
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);
#include <linux/nvram.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/nvram.h>
#define NVRAM_SIZE 8192
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 = {
--- /dev/null
+/*
+ * 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+#include <asm/time.h>
+
+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);
#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");
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()
{
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
return 0;
}
+#ifdef CONFIG_ADB
/* Send an ADB command */
static int
cuda_send_request(struct adb_request *req, int sync)
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 *),
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:
#include <linux/pmu.h>
#include <linux/cuda.h>
#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/init.h>
#include <asm/irq.h>
+#include <asm/hardirq.h>
#include <asm/feature.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
-#include <asm/heathrow.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+/* Some compile options */
+#undef SUSPEND_USES_PMU
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
#define CB2_INT 0x08
#define CB1_INT 0x10 /* transition on CB1 input */
-static enum pmu_state {
+static volatile enum pmu_state {
idle,
sending,
intack,
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;
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);
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);
"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()
{
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",
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")))
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;
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()
{
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.
* 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;
(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 */
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
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) {
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;
}
return pmu_kind;
}
+#ifdef CONFIG_ADB
/* Send an ADB command */
static int __openfirmware
pmu_send_request(struct adb_request *req, int sync)
return 0;
}
+#endif /* CONFIG_ADB */
/* Construct and send a pmu request */
int __openfirmware
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;
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
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, "
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);
}
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]);
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) {
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;
}
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;
{
asleep = 0;
if (len < 1) {
+// xmon_printk("empty ADB\n");
adb_int_pending = 0;
return;
}
}
}
#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
&& 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
}
}
-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();
}
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)
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));
{
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);
/* 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);
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();
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.
/* 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();
u_int cmd, u_long arg)
{
int error;
- __u32 value;
switch (cmd) {
case PMU_IOC_SLEEP:
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:
* 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)
btv->shutdown=1;
wake_up(&btv->gpioq);
+ pci_set_drvdata(pci_dev, NULL);
+
return;
}
}
}
- PCI_SET_DRIVER_DATA(dev,btv);
+ pci_set_drvdata(dev,btv);
if(init_bt848(btv) < 0) {
bttv_remove(dev);
#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 <linux/types.h>
#include <linux/wait.h>
#include <linux/videodev.h>
{
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;
/* 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);
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;
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];
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. */
/* if we get here, we didn't find an MCA adapter */
return -ENODEV;
}
-#endif
+#endif /* CONFIG_MCA */
#ifdef __ISAPNP__
if (nopnp == 1)
}
}
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) {
}
}
}
-#endif
+#endif /* __ISAPNP__ */
{
unsigned int iobase = id_read_eeprom(8);
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)
8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
- Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
- 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:
+
+ -----<snip>-----
+
+ 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
+ <shangh@realtek.com.tw>.
+
+ -----<snip>-----
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
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
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
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
#include <linux/delay.h>
#include <asm/io.h>
-#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__); \
#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};
#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
#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. */
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 */
};
/* Early Rx threshold, none or X/16 */
RxCfgEarlyRxNone = 0,
RxCfgEarlyRxShift = 24,
-
+
/* rx fifo threshold */
RxCfgFIFOShift = 13,
RxCfgFIFONone = (7 << RxCfgFIFOShift),
RxCfgRcv16K = (1 << 11),
RxCfgRcv32K = (1 << 12),
RxCfgRcv64K = (1 << 11) | (1 << 12),
+
+ /* Disable packet wrap at end of Rx buffer */
+ RxNoWrap = (1 << 7),
};
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
#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,
/* 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;
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) ||
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)
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) {
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--)
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);
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);
DPRINTK ("EXIT, returning %d\n", i);
return i;
}
-
+
tp = dev->priv;
-
+
assert (ioaddr != NULL);
assert (dev != NULL);
assert (tp != NULL);
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);
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");
#endif /* RTL8139_NDEBUG */
kfree (dev);
-
+
+ pdev->driver_data = NULL;
+
DPRINTK ("EXIT\n");
}
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;
u8 tmp;
DPRINTK ("ENTER\n");
-
+
/* Soft reset the chip. */
RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
udelay (100);
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);
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));
{
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) {
dev->name, RTL_R8 (Config0),
RTL_R8 (Config1));
- spin_unlock_irq (&tp->lock);
-
tp->timer.expires = jiffies + next_tick;
add_timer (&tp->timer);
}
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,
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);
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) {
tp->stats.tx_dropped++;
}
}
-
- spin_unlock_irq (&tp->lock);
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ /* ...and finally, reset everything */
rtl8139_hw_start (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)
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 */
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++;
#endif /* RTL8139_NDEBUG */
atomic_set (&tp->dirty_tx, dirty_tx);
-
- /* obtain lock need for rtl8139_interrupt */
- spin_lock (&tp->lock);
}
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;
}
-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);
printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
dev->name, pci_cmd_status);
}
-
- return 0;
}
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)
}
spin_unlock (&tp->lock);
-
+
DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
dev->name, RTL_R16 (IntrStatus));
}
dev->name, RTL_R16 (IntrStatus));
del_timer_sync (&tp->timer);
-
+
spin_lock_irqsave (&tp->lock, flags);
/* Disable interrupts by clearing the interrupt mask. */
RTL_W32 (RxMissed, 0);
spin_unlock_irqrestore (&tp->lock, flags);
-
+
/* snooze for a small bit */
if (current->need_resched)
schedule ();
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);
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. */
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);
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
#ifdef CONFIG_ARCNET_COM90xx
com90xx_probe(NULL);
#endif
-#ifdef CONFIG_ARCNET_COM20020_PCI
- com20020pci_probe_all();
-#endif
#endif
}
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 */
remove: com20020pci_remove
};
-int com20020pci_init(void)
+static int __init com20020pci_init(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
#ifndef MODULE
return pci_module_init(&com20020pci_driver);
}
-void com20020pci_cleanup(void)
+static void __exit com20020pci_cleanup(void)
{
pci_unregister_driver(&com20020pci_driver);
}
"auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)";
#endif
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <asm/bitops.h>
BUSY_LOOP_UNTIL(delay)
return probe_irq_off(irqs);
}
+
+EXPORT_SYMBOL(autoirq_setup);
+EXPORT_SYMBOL(autoirq_report);
+
\f
/*
* Local variables:
/* 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
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;
}
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);
* Changes:
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/06/2000
* - check init_etherdev return in gmac_probe1
+ * BenH <bh40@calva.net> - 03/09/2000
+ * - Add support for new PHYs
+ * - Add some PowerBook sleep code
*
*/
#include <linux/module.h>
+
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/feature.h>
+#include <asm/keylargo.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/irq.h>
+#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;
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);
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
*/
* 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)
{
/* 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
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
#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");
}
}
-/*
- * 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);
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);
#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);
}
}
+/* 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
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
*/
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");
gm->next_gmac = gmacs;
gmacs = dev;
+
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&gmac_sleep_notifier);
+#endif
}
MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt");
*/
/* 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) */
#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
#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
+
/*
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;
static void
toshoboe_wakeup (struct toshoboe_cb *self)
{
- struct net_device *dev = self->netdev;
unsigned long flags;
if (!self->stopped)
You can try <http://www.mylex.com> if you want more info, as I've
never even seen one of these cards. :)
+ Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 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 <linux/module.h>
#include <linux/kernel.h>
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;
/* 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;
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;
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");
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",
/* 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;
dev->stop = &lne390_close;
NS8390_init(dev, 0);
return 0;
+cleanup:
+ free_irq(dev->irq, dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return ret;
}
/*
return(0);
}
-#endif
+#endif /* CONFIG_FDDI */
#ifdef CONFIG_HIPPI
return 0;
}
-#endif
+#endif /* CONFIG_HIPPI */
void ether_setup(struct net_device *dev)
{
return;
}
-#endif
+#endif /* CONFIG_FDDI */
#ifdef CONFIG_HIPPI
void hippi_setup(struct net_device *dev)
dev_init_buffers(dev);
}
-#endif
+#endif /* CONFIG_HIPPI */
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
dev_init_buffers(dev);
}
-#endif
+#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
int ether_config(struct net_device *dev, struct ifmap *map)
{
unregister_netdevice(dev);
rtnl_unlock();
}
-#endif
+#endif /* CONFIG_TR */
#ifdef CONFIG_NET_FC
#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:
- */
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;
pppox_create
};
+extern int pppoe_init (void);
+
#ifdef MODULE
int init_module(void)
#else
if (err == 0)
printk(KERN_INFO "Registered PPPoX v0.5\n");
-#ifdef CONFIG_PPPOE
pppoe_init();
-#endif
return err;
}
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);
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;
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;
}
\f
/* Serial EEPROM section. */
{
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);
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);
/* 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);
}
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",
} 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++;
}
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));
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++) {
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);
#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
/* 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
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
+2000-09-16 Cesar Eduardo Barros <cesarb@nitnet.com.br>
+
+ * parport_pc.c (sio_via_686a_probe): Handle case
+ where hardware returns 255 for IRQ or DMA.
+
2000-07-20 Eddie C. Dost <ecd@skynet.be>
* share.c (attach_driver_chain): attach[i](port) needs to be
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;
}
/* 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 */
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;
}
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;
*/
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
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
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)
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__);
}
/****************************************************************
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;
}
* return NULL.
*/
SCpnt = NULL;
- break;
+ goto busy;
}
}
/*
if (SCpnt) {
break;
}
+ busy:
/*
* If we have been asked to wait for a free block, then
* wait here.
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;
* 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
* 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);
}
/*
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,
* 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.
*
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);
}
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;
}
*/
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);
}
/*
SCpnt = __scsi_end_request(SCpnt,
1,
good_sectors,
- result == 0);
+ result == 0,
+ 1);
/*
* If the command completed without error, then either finish off the
}
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;
}
} else {
+ SRpnt = NULL;
STpnt = scsi_get_request_dev(req);
if (!STpnt) {
panic("Unable to find device associated with request");
*/
blkdev_dequeue_request(req);
- if (req != &SCpnt->request) {
+ if (req != &SCpnt->request && req != &SRpnt->sr_request ) {
memcpy(&SCpnt->request, req, sizeof(struct request));
/*
* 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--;
*/
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--;
* 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;
}
*
* 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.
*
* 1998-jul-29 - created DPRINTK macros and made it work under
* linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
+ *
+ * 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.
*/
/*
}
-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;
const char *seagate_st0x_info(struct Scsi_Host *);
int seagate_st0x_reset(Scsi_Cmnd *, unsigned int);
-#include <linux/kdev_t.h>
-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, \
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 */
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 <scsi/sg.h> */
- 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 */
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);
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;
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;
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)
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;
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;
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;
}
* 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;
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);
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. */
}
/* 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"));
#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);
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)
/* 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);
#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))
# 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;
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]))
} 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},
/* 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",
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;
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);
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);
}
static void __exit cleanup_adlib(void)
{
- release_region(cfg.io_base, 4);
sound_unload_synthdev(cfg.slots[0]);
}
/* 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 };
#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 */
#include <linux/adb.h>
#include <linux/nvram.h>
#include <linux/vt_kern.h>
+#ifdef CONFIG_ADB_CUDA
#include <linux/cuda.h>
+#endif
+#ifdef CONFIG_ADB_PMU
#include <linux/pmu.h>
+#endif
#include <asm/uaccess.h>
#include <asm/prom.h>
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 */
/*
* 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
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);
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);
cuda_request(&req, NULL, 5, CUDA_PACKET,
CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
while (!req.complete) cuda_poll();
+#endif /* CONFIG_ADB_CUDA */
}
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 */
#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 *)
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) {
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);
}
#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
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;
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);
kfree(card);
- return;
+ pci_set_drvdata(pci_dev, NULL);
}
MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)");
}
#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) */
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)
* 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
"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;
signature != 0x0f)
{
MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature));
- return 0;
+ goto cleanup_region;
}
if (signature == 0x06) /* OPL2 */
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;
udelay(10);
}
else
+ { /* release OPL4 port */
+ release_region(ioaddr - 8, 2);
detected_model = 3;
+ }
}
opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0);
}
* 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)
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;
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;
{
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);
* 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
*
*/
#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);
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");
uart6850_osp = hw_config->osp;
uart6850_irq = hw_config->irq;
- if (!uart6850_detected)
- {
- sound_unload_mididev(my_dev);
- return;
- }
save_flags(flags);
cli();
sequencer_init();
}
-static int reset_uart6850(void)
+static inline int reset_uart6850(void)
{
uart6850_read();
return 1; /*
*/
}
-
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;
if (probe_uart6850(&cfg_mpu))
return -ENODEV;
+ attach_uart6850(&cfg_mpu);
return 0;
}
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",
#
-# 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
+
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 <eokerson@quicknet.net>");
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;
return probe;
}
+module_init(ixj_init);
+module_exit(ixj_exit);
+
+
static void DAA_Coeff_US(int board)
{
IXJ *j = &ixj[board];
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/phonedev.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/system.h>
* 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);
* (http://www.freecom.de/)
*/
-#include <linux/config.h>
#include "transport.h"
#include "protocol.h"
#include "usb.h"
#include "usb.h"
#include "debug.h"
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/malloc.h>
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/config.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
#include "freecom.h"
#endif
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/version.h>
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/usb.h>
# 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
#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) */
#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 */
#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 */
#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
#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
#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 */
#endif
#endif
+#ifdef CONFIG_ADB_PMU
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
#ifdef CONFIG_FB_COMPAT_XPMAC
#include <asm/vc_ioctl.h>
#endif
#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
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
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;
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);
}
#endif /* CONFIG_MTRR */
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (!console_fb_info)
+ console_fb_info = &info->fb_info;
+#endif
+
return 0;
err_out:
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)
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 */
}
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);
}
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);
/* 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));
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
}
+#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
*/
* 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 !
*/
/******************************************************************************
#ifdef CONFIG_NVRAM
#include <linux/nvram.h>
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
#ifdef __sparc__
#include <asm/pbm.h>
#include <asm/fbio.h>
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
{ 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 = {
};
-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);
}
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;
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 */
} 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);
/* 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;
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;
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);
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)
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 */
}
}
#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)
{
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
#include <linux/adb.h>
#include <linux/pmu.h>
// 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);
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);
/* 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);
}
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,
fb_get_cmap: control_get_cmap,
fb_set_cmap: control_set_cmap,
fb_pan_display: control_pan_display,
+ fb_mmap: control_mmap,
};
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) */
}
}
-#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
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 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;
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];
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;
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;
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
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)
0x0B, 0x0C, 0x0D, 0x0F, 0x10
};
-#ifdef CONFIG_FB_SIS_LINUXBIOS
-
#define Monitor1Sense 0x20
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,
static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
{
- unsigned char ModeID;
u16 modeidlength;
u16 usModeIDOffset;
unsigned short PreviousWord,CurrentWord;
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)
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;
}
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.
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();
struct file_operations def_blk_fops = {
open: blkdev_open,
release: blkdev_close,
+ llseek: block_llseek,
read: block_read,
write: block_write,
fsync: block_fsync,
*/
#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)
{
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();
}
}
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;
}
{
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);
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;
}
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");
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))
}
/* 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;
*/
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/string.h>
#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
/*
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;
}
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;
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++;
}
#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");
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],
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;
* 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 */
/* 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))
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;
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
/* 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;
}
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;
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);
#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);
* "__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);
:"memory");
}
-extern inline int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
{
int result;
return result;
}
-extern inline int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
{
int result;
* 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);
#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;
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)
#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)
* 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"
/* 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"
);
}
-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)
__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)
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;
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;
return t;
}
-extern __inline__ int atomic_inc_return(atomic_t *v)
+extern __inline__ int atomic_inc_return(volatile atomic_t *v)
{
int t;
return t;
}
-extern __inline__ int atomic_dec_return(atomic_t *v)
+extern __inline__ int atomic_dec_return(volatile atomic_t *v)
{
int t;
extern int set_backlight_level(int level);
extern int get_backlight_level(void);
-#endif
\ No newline at end of file
+#endif
tmp = *p;
found_first:
tmp |= ~0UL << size;
+ if (tmp == ~0UL) /* Are any bits zero? */
+ return result + size; /* Nope. */
found_middle:
return result + ffz(tmp);
}
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);
}
#endif
#endif
-
\ No newline at end of file
#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
* 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);
#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
#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)
#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 {
#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 */
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
* 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
*/
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);
#include <asm/smp.h>
/* 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 <linux/irq_cpustat.h> /* 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?
#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 */
--- /dev/null
+/*
+ * 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 <mingo@redhat.com>
+ */
+
+#ifndef _ASM_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#ifdef __KERNEL__
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/kmap_types.h>
+#include <asm/pgtable.h>
+
+/* 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 */
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)); \
#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
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;
#include <asm/mpc8xx.h>
#elif defined(CONFIG_8260)
#include <asm/mpc8260.h>
-#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;
#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
#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);
*/
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);
*/
#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)
--- /dev/null
+/*
+ * 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))
+
--- /dev/null
+#ifndef _ASM_KMAP_TYPES_H
+#define _ASM_KMAP_TYPES_H
+
+enum km_type {
+ KM_BOUNCE_READ,
+ KM_BOUNCE_WRITE,
+ KM_TYPE_NR
+};
+
+#endif
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);
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);
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
#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 */
pmac_nvram_NR /* MacOS Name Registry partition */
};
+#ifdef __KERNEL__
+
/* Return partition offset in nvram */
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
/* 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 */
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;
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)
#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 */
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;
#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)
HUB6_SERIAL_PORT_DFNS \
MCA_SERIAL_PORT_DFNS
-#endif /* CONFIG_PMAC */
#endif /* CONFIG_GEMINI */
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
} 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);
#include <asm/processor.h>
/* 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;
{
#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);
/* 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
".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))
"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))
--- /dev/null
+/*
+ * 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
+
+
+
#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
/*
- * $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
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().
#define dma_cache_wback(_start,_size) do { } while (0)
#define dma_cache_wback_inv(_start,_size) do { } while (0)
+#endif
+
#endif /* !(__SPARC_IO_H) */
-/* $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
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.
*/
#define dma_cache_wback(_start,_size) do { } while (0)
#define dma_cache_wback_inv(_start,_size) do { } while (0)
+#endif
+
#endif /* !(__SPARC64_IO_H) */
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);
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);
void arcnet_raw_init(void);
int com90xx_probe(struct net_device *dev);
-void com20020pci_probe_all(void);
#endif /* __KERNEL__ */
#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)
#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);
* 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 */
#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
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;
};
*/
#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) \
_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
*
* 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);
(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
/*
* 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 */
#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 */
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
*/
/* 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
/*
#endif /* CONFIG_PMAC_PBOOK */
-#endif /* __KERNEL */
+#endif /* __KERNEL__ */
/* 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)
/* We don't use <asm/bitops.h> 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)
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)
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)
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);
}
#include <linux/string.h>
#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; \
#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; \
\
#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:
}
}
-extern inline void sigfillset(sigset_t *set)
+static inline void sigfillset(sigset_t *set)
{
switch (_NSIG_WORDS) {
default:
/* 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) {
}
}
-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) {
DEV_CDROM=1,
DEV_HWMON=2,
DEV_PARPORT=3,
- DEV_RAID=4
+ DEV_RAID=4,
+ DEV_MAC_HID=5
};
/* /proc/sys/dev/cdrom */
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 *);
#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 */
#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--)
#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--)
#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);
#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--)
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)
/*
* 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
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
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;
}
}
-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;
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;
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;
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))
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);
* 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,
__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,
}
-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);
}
#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)
{
#include <net/sock.h>
#include <linux/if_arp.h>
-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;
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;
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 *);
{
__exit_files(tsk);
}
+
static inline void __put_fs_struct(struct fs_struct *fs)
{
/* No need to hold fs->lock if we are killing it */
#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
/* 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;
* 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);
/*
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.
*/
}
}
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;
}
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;
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);
maxlaunder = MAX_LAUNDER;
/* Kflushd takes care of the rest. */
wakeup_bdflush(0);
- current->policy |= SCHED_YIELD;
- schedule();
goto dirty_page_rescan;
}
{
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... */
/* 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 {
do {
made_progress = 0;
- if (!inactive_shortage() && !free_shortage())
- goto done;
-
if (current->need_resched) {
+ __set_current_state(TASK_RUNNING);
schedule();
}
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
* 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;
* 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);
}
}
return;
if (!block) {
- wake_up(&kswapd_wait);
+ if (waitqueue_active(&kswapd_wait))
+ wake_up(&kswapd_wait);
return;
}
*/
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);
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
if (sk->prot->init) {
int err = sk->prot->init(sk);
if (err != 0) {
- sk->dead = 1;
inet_sock_release(sk);
return(err);
}
*
* 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
*
{
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;
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;
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
Public Licence. */
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
*
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h>
/*
* 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]
#include <net/route.h>
#include <net/tcp.h>
-/*
- * 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;
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;
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},
*
* 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, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* J Hadi Salim: ECN support
*/
+#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <net/tcp.h>
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) {
*
* 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
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);
}
{
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))
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;
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();
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);
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:
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $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
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
* 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 <linux/config.h>
kfree_skb(skb);
sk->ack_backlog--;
newsock->sk = newsk;
+ newsock->state = SS_CONNECTED;
return 0;
}
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);
*
* History
* X.25 001 Jonathan Naylor Started coding.
+ * 2000-09-04 Henner Eisen Prevent freeing a dangling skb.
*/
#include <linux/config.h>
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;
}
* 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 <linux/config.h>
init_timer(&x25_neigh->t20timer);
+ dev_hold(dev);
x25_neigh->dev = dev;
x25_neigh->state = X25_LINK_STATE_0;
x25_neigh->extended = 0;
neigh = x25_neigh;
x25_neigh = x25_neigh->next;
- if (neigh->dev == dev)
+ if (neigh->dev == dev){
x25_remove_neigh(neigh);
+ dev_put(dev);
+ }
}
}
* 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 <linux/config.h>
/*
* 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];
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;
} else {
skb_queue_tail(&sk->write_queue, skb);
}
+ return 0;
}
/*
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$//' \